commit aec284f125da630566a51438d4f2808cd1ee8270 Author: Page Asgardius Date: Fri Jul 2 07:59:34 2021 -0700 server migration diff --git a/README.md b/README.md new file mode 100644 index 0000000..747d959 --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +Raspberry Pi Test +============ +In this repository you will find some miscellaneous Raspberry PI stuff by Page Asgardius (Forked from André Wussow's repository). + +You can find original repository at https://github.com/binerry/RaspberryPi. + +License +------- +The repository content provides free software; you can redistribute it +and/or modify it under the terms of the GNU Lesser General Public License +as published by the Free Software Foundation; either version 2.1 of the License, +or (at your option) any later version. + +Everything is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. diff --git a/libraries/c/PCD8544/PCD8544.c b/libraries/c/PCD8544/PCD8544.c new file mode 100644 index 0000000..d6d1051 --- /dev/null +++ b/libraries/c/PCD8544/PCD8544.c @@ -0,0 +1,847 @@ +/* +================================================================================= + Name : PCD8544.c + Version : 0.1 + + Copyright (C) 2010 Limor Fried, Adafruit Industries + CORTEX-M3 version by Le Dang Dung, 2011 LeeDangDung@gmail.com (tested on LPC1769) + Raspberry Pi version by Andre Wussow, 2012, desk@binerry.de + + Description : + A simple PCD8544 LCD (Nokia3310/5110) driver. Target board is Raspberry Pi. + This driver uses 5 GPIOs on target board with a bit-bang SPI implementation + (hence, may not be as fast). + Makes use of WiringPI-library of Gordon Henderson (https://projects.drogon.net/raspberry-pi/wiringpi/) + + Recommended connection (http://www.raspberrypi.org/archives/384): + LCD pins Raspberry Pi + LCD1 - GND P06 - GND + LCD2 - VCC P01 - 3.3V + LCD3 - CLK P11 - GPIO0 + LCD4 - Din P12 - GPIO1 + LCD5 - D/C P13 - GPIO2 + LCD6 - CS P15 - GPIO3 + LCD7 - RST P16 - GPIO4 + LCD8 - LED P01 - 3.3V + + References : + http://www.arduino.cc/playground/Code/PCD8544 + http://ladyada.net/products/nokia5110/ + http://code.google.com/p/meshphone/ + +================================================================================ +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. +================================================================================ + */ +#include +#include "PCD8544.h" + +// An abs() :) +#define abs(a) (((a) < 0) ? -(a) : (a)) + +// bit set +#define _BV(bit) (0x1 << (bit)) + +// LCD port variables +static uint8_t cursor_x, cursor_y, textsize, textcolor; +static int8_t _din, _sclk, _dc, _rst, _cs; + +// font bitmap +static unsigned char font[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3E, 0x5B, 0x4F, 0x5B, 0x3E, + 0x3E, 0x6B, 0x4F, 0x6B, 0x3E, + 0x1C, 0x3E, 0x7C, 0x3E, 0x1C, + 0x18, 0x3C, 0x7E, 0x3C, 0x18, + 0x1C, 0x57, 0x7D, 0x57, 0x1C, + 0x1C, 0x5E, 0x7F, 0x5E, 0x1C, + 0x00, 0x18, 0x3C, 0x18, 0x00, + 0xFF, 0xE7, 0xC3, 0xE7, 0xFF, + 0x00, 0x18, 0x24, 0x18, 0x00, + 0xFF, 0xE7, 0xDB, 0xE7, 0xFF, + 0x30, 0x48, 0x3A, 0x06, 0x0E, + 0x26, 0x29, 0x79, 0x29, 0x26, + 0x40, 0x7F, 0x05, 0x05, 0x07, + 0x40, 0x7F, 0x05, 0x25, 0x3F, + 0x5A, 0x3C, 0xE7, 0x3C, 0x5A, + 0x7F, 0x3E, 0x1C, 0x1C, 0x08, + 0x08, 0x1C, 0x1C, 0x3E, 0x7F, + 0x14, 0x22, 0x7F, 0x22, 0x14, + 0x5F, 0x5F, 0x00, 0x5F, 0x5F, + 0x06, 0x09, 0x7F, 0x01, 0x7F, + 0x00, 0x66, 0x89, 0x95, 0x6A, + 0x60, 0x60, 0x60, 0x60, 0x60, + 0x94, 0xA2, 0xFF, 0xA2, 0x94, + 0x08, 0x04, 0x7E, 0x04, 0x08, + 0x10, 0x20, 0x7E, 0x20, 0x10, + 0x08, 0x08, 0x2A, 0x1C, 0x08, + 0x08, 0x1C, 0x2A, 0x08, 0x08, + 0x1E, 0x10, 0x10, 0x10, 0x10, + 0x0C, 0x1E, 0x0C, 0x1E, 0x0C, + 0x30, 0x38, 0x3E, 0x38, 0x30, + 0x06, 0x0E, 0x3E, 0x0E, 0x06, + 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x5F, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x07, 0x00, + 0x14, 0x7F, 0x14, 0x7F, 0x14, + 0x24, 0x2A, 0x7F, 0x2A, 0x12, + 0x23, 0x13, 0x08, 0x64, 0x62, + 0x36, 0x49, 0x56, 0x20, 0x50, + 0x00, 0x08, 0x07, 0x03, 0x00, + 0x00, 0x1C, 0x22, 0x41, 0x00, + 0x00, 0x41, 0x22, 0x1C, 0x00, + 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, + 0x08, 0x08, 0x3E, 0x08, 0x08, + 0x00, 0x80, 0x70, 0x30, 0x00, + 0x08, 0x08, 0x08, 0x08, 0x08, + 0x00, 0x00, 0x60, 0x60, 0x00, + 0x20, 0x10, 0x08, 0x04, 0x02, + 0x3E, 0x51, 0x49, 0x45, 0x3E, + 0x00, 0x42, 0x7F, 0x40, 0x00, + 0x72, 0x49, 0x49, 0x49, 0x46, + 0x21, 0x41, 0x49, 0x4D, 0x33, + 0x18, 0x14, 0x12, 0x7F, 0x10, + 0x27, 0x45, 0x45, 0x45, 0x39, + 0x3C, 0x4A, 0x49, 0x49, 0x31, + 0x41, 0x21, 0x11, 0x09, 0x07, + 0x36, 0x49, 0x49, 0x49, 0x36, + 0x46, 0x49, 0x49, 0x29, 0x1E, + 0x00, 0x00, 0x14, 0x00, 0x00, + 0x00, 0x40, 0x34, 0x00, 0x00, + 0x00, 0x08, 0x14, 0x22, 0x41, + 0x14, 0x14, 0x14, 0x14, 0x14, + 0x00, 0x41, 0x22, 0x14, 0x08, + 0x02, 0x01, 0x59, 0x09, 0x06, + 0x3E, 0x41, 0x5D, 0x59, 0x4E, + 0x7C, 0x12, 0x11, 0x12, 0x7C, + 0x7F, 0x49, 0x49, 0x49, 0x36, + 0x3E, 0x41, 0x41, 0x41, 0x22, + 0x7F, 0x41, 0x41, 0x41, 0x3E, + 0x7F, 0x49, 0x49, 0x49, 0x41, + 0x7F, 0x09, 0x09, 0x09, 0x01, + 0x3E, 0x41, 0x41, 0x51, 0x73, + 0x7F, 0x08, 0x08, 0x08, 0x7F, + 0x00, 0x41, 0x7F, 0x41, 0x00, + 0x20, 0x40, 0x41, 0x3F, 0x01, + 0x7F, 0x08, 0x14, 0x22, 0x41, + 0x7F, 0x40, 0x40, 0x40, 0x40, + 0x7F, 0x02, 0x1C, 0x02, 0x7F, + 0x7F, 0x04, 0x08, 0x10, 0x7F, + 0x3E, 0x41, 0x41, 0x41, 0x3E, + 0x7F, 0x09, 0x09, 0x09, 0x06, + 0x3E, 0x41, 0x51, 0x21, 0x5E, + 0x7F, 0x09, 0x19, 0x29, 0x46, + 0x26, 0x49, 0x49, 0x49, 0x32, + 0x03, 0x01, 0x7F, 0x01, 0x03, + 0x3F, 0x40, 0x40, 0x40, 0x3F, + 0x1F, 0x20, 0x40, 0x20, 0x1F, + 0x3F, 0x40, 0x38, 0x40, 0x3F, + 0x63, 0x14, 0x08, 0x14, 0x63, + 0x03, 0x04, 0x78, 0x04, 0x03, + 0x61, 0x59, 0x49, 0x4D, 0x43, + 0x00, 0x7F, 0x41, 0x41, 0x41, + 0x02, 0x04, 0x08, 0x10, 0x20, + 0x00, 0x41, 0x41, 0x41, 0x7F, + 0x04, 0x02, 0x01, 0x02, 0x04, + 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x03, 0x07, 0x08, 0x00, + 0x20, 0x54, 0x54, 0x78, 0x40, + 0x7F, 0x28, 0x44, 0x44, 0x38, + 0x38, 0x44, 0x44, 0x44, 0x28, + 0x38, 0x44, 0x44, 0x28, 0x7F, + 0x38, 0x54, 0x54, 0x54, 0x18, + 0x00, 0x08, 0x7E, 0x09, 0x02, + 0x18, 0xA4, 0xA4, 0x9C, 0x78, + 0x7F, 0x08, 0x04, 0x04, 0x78, + 0x00, 0x44, 0x7D, 0x40, 0x00, + 0x20, 0x40, 0x40, 0x3D, 0x00, + 0x7F, 0x10, 0x28, 0x44, 0x00, + 0x00, 0x41, 0x7F, 0x40, 0x00, + 0x7C, 0x04, 0x78, 0x04, 0x78, + 0x7C, 0x08, 0x04, 0x04, 0x78, + 0x38, 0x44, 0x44, 0x44, 0x38, + 0xFC, 0x18, 0x24, 0x24, 0x18, + 0x18, 0x24, 0x24, 0x18, 0xFC, + 0x7C, 0x08, 0x04, 0x04, 0x08, + 0x48, 0x54, 0x54, 0x54, 0x24, + 0x04, 0x04, 0x3F, 0x44, 0x24, + 0x3C, 0x40, 0x40, 0x20, 0x7C, + 0x1C, 0x20, 0x40, 0x20, 0x1C, + 0x3C, 0x40, 0x30, 0x40, 0x3C, + 0x44, 0x28, 0x10, 0x28, 0x44, + 0x4C, 0x90, 0x90, 0x90, 0x7C, + 0x44, 0x64, 0x54, 0x4C, 0x44, + 0x00, 0x08, 0x36, 0x41, 0x00, + 0x00, 0x00, 0x77, 0x00, 0x00, + 0x00, 0x41, 0x36, 0x08, 0x00, + 0x02, 0x01, 0x02, 0x04, 0x02, + 0x3C, 0x26, 0x23, 0x26, 0x3C, + 0x1E, 0xA1, 0xA1, 0x61, 0x12, + 0x3A, 0x40, 0x40, 0x20, 0x7A, + 0x38, 0x54, 0x54, 0x55, 0x59, + 0x21, 0x55, 0x55, 0x79, 0x41, + 0x21, 0x54, 0x54, 0x78, 0x41, + 0x21, 0x55, 0x54, 0x78, 0x40, + 0x20, 0x54, 0x55, 0x79, 0x40, + 0x0C, 0x1E, 0x52, 0x72, 0x12, + 0x39, 0x55, 0x55, 0x55, 0x59, + 0x39, 0x54, 0x54, 0x54, 0x59, + 0x39, 0x55, 0x54, 0x54, 0x58, + 0x00, 0x00, 0x45, 0x7C, 0x41, + 0x00, 0x02, 0x45, 0x7D, 0x42, + 0x00, 0x01, 0x45, 0x7C, 0x40, + 0xF0, 0x29, 0x24, 0x29, 0xF0, + 0xF0, 0x28, 0x25, 0x28, 0xF0, + 0x7C, 0x54, 0x55, 0x45, 0x00, + 0x20, 0x54, 0x54, 0x7C, 0x54, + 0x7C, 0x0A, 0x09, 0x7F, 0x49, + 0x32, 0x49, 0x49, 0x49, 0x32, + 0x32, 0x48, 0x48, 0x48, 0x32, + 0x32, 0x4A, 0x48, 0x48, 0x30, + 0x3A, 0x41, 0x41, 0x21, 0x7A, + 0x3A, 0x42, 0x40, 0x20, 0x78, + 0x00, 0x9D, 0xA0, 0xA0, 0x7D, + 0x39, 0x44, 0x44, 0x44, 0x39, + 0x3D, 0x40, 0x40, 0x40, 0x3D, + 0x3C, 0x24, 0xFF, 0x24, 0x24, + 0x48, 0x7E, 0x49, 0x43, 0x66, + 0x2B, 0x2F, 0xFC, 0x2F, 0x2B, + 0xFF, 0x09, 0x29, 0xF6, 0x20, + 0xC0, 0x88, 0x7E, 0x09, 0x03, + 0x20, 0x54, 0x54, 0x79, 0x41, + 0x00, 0x00, 0x44, 0x7D, 0x41, + 0x30, 0x48, 0x48, 0x4A, 0x32, + 0x38, 0x40, 0x40, 0x22, 0x7A, + 0x00, 0x7A, 0x0A, 0x0A, 0x72, + 0x7D, 0x0D, 0x19, 0x31, 0x7D, + 0x26, 0x29, 0x29, 0x2F, 0x28, + 0x26, 0x29, 0x29, 0x29, 0x26, + 0x30, 0x48, 0x4D, 0x40, 0x20, + 0x38, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x38, + 0x2F, 0x10, 0xC8, 0xAC, 0xBA, + 0x2F, 0x10, 0x28, 0x34, 0xFA, + 0x00, 0x00, 0x7B, 0x00, 0x00, + 0x08, 0x14, 0x2A, 0x14, 0x22, + 0x22, 0x14, 0x2A, 0x14, 0x08, + 0xAA, 0x00, 0x55, 0x00, 0xAA, + 0xAA, 0x55, 0xAA, 0x55, 0xAA, + 0x00, 0x00, 0x00, 0xFF, 0x00, + 0x10, 0x10, 0x10, 0xFF, 0x00, + 0x14, 0x14, 0x14, 0xFF, 0x00, + 0x10, 0x10, 0xFF, 0x00, 0xFF, + 0x10, 0x10, 0xF0, 0x10, 0xF0, + 0x14, 0x14, 0x14, 0xFC, 0x00, + 0x14, 0x14, 0xF7, 0x00, 0xFF, + 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x14, 0x14, 0xF4, 0x04, 0xFC, + 0x14, 0x14, 0x17, 0x10, 0x1F, + 0x10, 0x10, 0x1F, 0x10, 0x1F, + 0x14, 0x14, 0x14, 0x1F, 0x00, + 0x10, 0x10, 0x10, 0xF0, 0x00, + 0x00, 0x00, 0x00, 0x1F, 0x10, + 0x10, 0x10, 0x10, 0x1F, 0x10, + 0x10, 0x10, 0x10, 0xF0, 0x10, + 0x00, 0x00, 0x00, 0xFF, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0xFF, 0x10, + 0x00, 0x00, 0x00, 0xFF, 0x14, + 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0x00, 0x1F, 0x10, 0x17, + 0x00, 0x00, 0xFC, 0x04, 0xF4, + 0x14, 0x14, 0x17, 0x10, 0x17, + 0x14, 0x14, 0xF4, 0x04, 0xF4, + 0x00, 0x00, 0xFF, 0x00, 0xF7, + 0x14, 0x14, 0x14, 0x14, 0x14, + 0x14, 0x14, 0xF7, 0x00, 0xF7, + 0x14, 0x14, 0x14, 0x17, 0x14, + 0x10, 0x10, 0x1F, 0x10, 0x1F, + 0x14, 0x14, 0x14, 0xF4, 0x14, + 0x10, 0x10, 0xF0, 0x10, 0xF0, + 0x00, 0x00, 0x1F, 0x10, 0x1F, + 0x00, 0x00, 0x00, 0x1F, 0x14, + 0x00, 0x00, 0x00, 0xFC, 0x14, + 0x00, 0x00, 0xF0, 0x10, 0xF0, + 0x10, 0x10, 0xFF, 0x10, 0xFF, + 0x14, 0x14, 0x14, 0xFF, 0x14, + 0x10, 0x10, 0x10, 0x1F, 0x00, + 0x00, 0x00, 0x00, 0xF0, 0x10, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xFF, 0xFF, + 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, + 0x38, 0x44, 0x44, 0x38, 0x44, + 0x7C, 0x2A, 0x2A, 0x3E, 0x14, + 0x7E, 0x02, 0x02, 0x06, 0x06, + 0x02, 0x7E, 0x02, 0x7E, 0x02, + 0x63, 0x55, 0x49, 0x41, 0x63, + 0x38, 0x44, 0x44, 0x3C, 0x04, + 0x40, 0x7E, 0x20, 0x1E, 0x20, + 0x06, 0x02, 0x7E, 0x02, 0x02, + 0x99, 0xA5, 0xE7, 0xA5, 0x99, + 0x1C, 0x2A, 0x49, 0x2A, 0x1C, + 0x4C, 0x72, 0x01, 0x72, 0x4C, + 0x30, 0x4A, 0x4D, 0x4D, 0x30, + 0x30, 0x48, 0x78, 0x48, 0x30, + 0xBC, 0x62, 0x5A, 0x46, 0x3D, + 0x3E, 0x49, 0x49, 0x49, 0x00, + 0x7E, 0x01, 0x01, 0x01, 0x7E, + 0x2A, 0x2A, 0x2A, 0x2A, 0x2A, + 0x44, 0x44, 0x5F, 0x44, 0x44, + 0x40, 0x51, 0x4A, 0x44, 0x40, + 0x40, 0x44, 0x4A, 0x51, 0x40, + 0x00, 0x00, 0xFF, 0x01, 0x03, + 0xE0, 0x80, 0xFF, 0x00, 0x00, + 0x08, 0x08, 0x6B, 0x6B, 0x08, + 0x36, 0x12, 0x36, 0x24, 0x36, + 0x06, 0x0F, 0x09, 0x0F, 0x06, + 0x00, 0x00, 0x18, 0x18, 0x00, + 0x00, 0x00, 0x10, 0x10, 0x00, + 0x30, 0x40, 0xFF, 0x01, 0x01, + 0x00, 0x1F, 0x01, 0x01, 0x1E, + 0x00, 0x19, 0x1D, 0x17, 0x12, + 0x00, 0x3C, 0x3C, 0x3C, 0x3C, + 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +// the memory buffer for the LCD +uint8_t pcd8544_buffer[LCDWIDTH * LCDHEIGHT / 8] = {0,}; + +// Le: get the bitmap assistance here! : http://en.radzio.dxp.pl/bitmap_converter/ +// Andre: or here! : http://www.henningkarlsen.com/electronics/t_imageconverter_mono.php +const uint8_t pi_logo [] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x0010 (16) pixels +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xF8, 0xFC, 0xAE, 0x0E, 0x0E, 0x06, 0x0E, 0x06, // 0x0020 (32) pixels +0xCE, 0x86, 0x8E, 0x0E, 0x0E, 0x1C, 0xB8, 0xF0, 0xF8, 0x78, 0x38, 0x1E, 0x0E, 0x8E, 0x8E, 0xC6, // 0x0030 (48) pixels +0x0E, 0x06, 0x0E, 0x06, 0x0E, 0x9E, 0xFE, 0xFC, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x0040 (64) pixels +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x0050 (80) pixels +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x0060 (96) pixels +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x0F, 0xFE, // 0x0070 (112) pixels +0xF8, 0xF0, 0x60, 0x60, 0xE0, 0xE1, 0xE3, 0xF7, 0x7E, 0x3E, 0x1E, 0x1F, 0x1F, 0x1F, 0x3E, 0x7E, // 0x0080 (128) pixels +0xFB, 0xF3, 0xE1, 0xE0, 0x60, 0x70, 0xF0, 0xF8, 0xBE, 0x1F, 0x0F, 0x07, 0x00, 0x00, 0x00, 0x00, // 0x0090 (144) pixels +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00A0 (160) pixels +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00B0 (176) pixels +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, // 0x00C0 (192) pixels +0xE0, 0xFC, 0xFE, 0xFF, 0xF3, 0x38, 0x38, 0x0C, 0x0E, 0x0F, 0x0F, 0x0F, 0x0E, 0x3C, 0x38, 0xF8, // 0x00D0 (208) pixels +0xF8, 0x38, 0x3C, 0x0E, 0x0F, 0x0F, 0x0F, 0x0E, 0x0C, 0x38, 0x38, 0xF3, 0xFF, 0xFF, 0xF8, 0xE0, // 0x00E0 (224) pixels +0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x00F0 (240) pixels +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x0100 (256) pixels +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x0110 (272) pixels +0x00, 0x7F, 0xFF, 0xE7, 0xC3, 0xC1, 0xE0, 0xFF, 0xFF, 0x78, 0xE0, 0xC0, 0xC0, 0xC0, 0xC0, 0xE0, // 0x0120 (288) pixels +0x60, 0x78, 0x38, 0x3F, 0x3F, 0x38, 0x38, 0x60, 0x60, 0xC0, 0xC0, 0xC0, 0xC0, 0xE0, 0xF8, 0x7F, // 0x0130 (304) pixels +0xFF, 0xE0, 0xC1, 0xC3, 0xE7, 0x7F, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x0140 (320) pixels +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x0150 (336) pixels +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x0160 (352) pixels +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x7F, 0xFF, 0xF1, 0xE0, 0xC0, 0x80, 0x01, // 0x0170 (368) pixels +0x03, 0x9F, 0xFF, 0xF0, 0xE0, 0xE0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xE0, 0xE0, 0xF0, 0xFF, 0x9F, // 0x0180 (384) pixels +0x03, 0x01, 0x80, 0xC0, 0xE0, 0xF1, 0x7F, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x0190 (400) pixels +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x01A0 (416) pixels +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x01B0 (432) pixels +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // 0x01C0 (448) pixels +0x03, 0x03, 0x07, 0x07, 0x0F, 0x1F, 0x1F, 0x3F, 0x3B, 0x71, 0x60, 0x60, 0x60, 0x60, 0x60, 0x71, // 0x01D0 (464) pixels +0x3B, 0x1F, 0x0F, 0x0F, 0x0F, 0x07, 0x03, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x01E0 (480) pixels +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x01F0 (496) pixels +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +// reduces how much is refreshed, which speeds it up! +// originally derived from Steve Evans/JCW's mod but cleaned up and optimized +//#define enablePartialUpdate + +static void my_setpixel(uint8_t x, uint8_t y, uint8_t color) +{ + if ((x >= LCDWIDTH) || (y >= LCDHEIGHT)) + return; + // x is which column + if (color) + pcd8544_buffer[x+ (y/8)*LCDWIDTH] |= _BV(y%8); + else + pcd8544_buffer[x+ (y/8)*LCDWIDTH] &= ~_BV(y%8); +} + +void LCDshowLogo() +{ + uint32_t i; + for (i = 0; i < LCDWIDTH * LCDHEIGHT / 8; i++ ) + { + pcd8544_buffer[i] = pi_logo[i]; + } + LCDdisplay(); +} + +#ifdef enablePartialUpdate +static uint8_t xUpdateMin, xUpdateMax, yUpdateMin, yUpdateMax; +#endif + +static void updateBoundingBox(uint8_t xmin, uint8_t ymin, uint8_t xmax, uint8_t ymax) { +#ifdef enablePartialUpdate + if (xmin < xUpdateMin) xUpdateMin = xmin; + if (xmax > xUpdateMax) xUpdateMax = xmax; + if (ymin < yUpdateMin) yUpdateMin = ymin; + if (ymax > yUpdateMax) yUpdateMax = ymax; +#endif +} + +void LCDInit(uint8_t SCLK, uint8_t DIN, uint8_t DC, uint8_t CS, uint8_t RST, uint8_t contrast) +{ + _din = DIN; + _sclk = SCLK; + _dc = DC; + _rst = RST; + _cs = CS; + cursor_x = cursor_y = 0; + textsize = 1; + textcolor = BLACK; + + // set pin directions + pinMode(_din, OUTPUT); + pinMode(_sclk, OUTPUT); + pinMode(_dc, OUTPUT); + pinMode(_rst, OUTPUT); + pinMode(_cs, OUTPUT); + + // toggle RST low to reset; CS low so it'll listen to us + if (_cs > 0) + digitalWrite(_cs, LOW); + + digitalWrite(_rst, LOW); + _delay_ms(500); + digitalWrite(_rst, HIGH); + + // get into the EXTENDED mode! + LCDcommand(PCD8544_FUNCTIONSET | PCD8544_EXTENDEDINSTRUCTION ); + + // LCD bias select (4 is optimal?) + LCDcommand(PCD8544_SETBIAS | 0x4); + + // set VOP + if (contrast > 0x7f) + contrast = 0x7f; + + LCDcommand( PCD8544_SETVOP | contrast); // Experimentally determined + + // normal mode + LCDcommand(PCD8544_FUNCTIONSET); + + // Set display to Normal + LCDcommand(PCD8544_DISPLAYCONTROL | PCD8544_DISPLAYNORMAL); + + // set up a bounding box for screen updates + updateBoundingBox(0, 0, LCDWIDTH-1, LCDHEIGHT-1); + +} + +void LCDdrawbitmap(uint8_t x, uint8_t y,const uint8_t *bitmap, uint8_t w, uint8_t h,uint8_t color) +{ + uint8_t j,i; + for ( j=0; j= LCDHEIGHT) return; + if ((x+5) >= LCDWIDTH) return; + uint8_t i,j; + for ( i =0; i<5; i++ ) + { + uint8_t d = *(font+(c*5)+i); + uint8_t j; + for (j = 0; j<8; j++) + { + if (d & _BV(j)) + { + my_setpixel(x+i, y+j, textcolor); + } + else + { + my_setpixel(x+i, y+j, !textcolor); + } + } + } + + for ( j = 0; j<8; j++) + { + my_setpixel(x+5, y+j, !textcolor); + } + updateBoundingBox(x, y, x+5, y + 8); +} + +void LCDwrite(uint8_t c) +{ + if (c == '\n') + { + cursor_y += textsize*8; + cursor_x = 0; + } + else if (c == '\r') + { + // skip em + } + else + { + LCDdrawchar(cursor_x, cursor_y, c); + cursor_x += textsize*6; + if (cursor_x >= (LCDWIDTH-5)) + { + cursor_x = 0; + cursor_y+=8; + } + if (cursor_y >= LCDHEIGHT) + cursor_y = 0; + } +} + +void LCDsetCursor(uint8_t x, uint8_t y) +{ + cursor_x = x; + cursor_y = y; +} + +// bresenham's algorithm - thx wikpedia +void LCDdrawline(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t color) +{ + uint8_t steep = abs(y1 - y0) > abs(x1 - x0); + if (steep) + { + swap(x0, y0); + swap(x1, y1); + } + + if (x0 > x1) + { + swap(x0, x1); + swap(y0, y1); + } + + // much faster to put the test here, since we've already sorted the points + updateBoundingBox(x0, y0, x1, y1); + + uint8_t dx, dy; + dx = x1 - x0; + dy = abs(y1 - y0); + + int8_t err = dx / 2; + int8_t ystep; + + if (y0 < y1) + { + ystep = 1; + } else + { + ystep = -1; + } + + for (; x0<=x1; x0++) + { + if (steep) + { + my_setpixel(y0, x0, color); + } + else + { + my_setpixel(x0, y0, color); + } + err -= dy; + if (err < 0) + { + y0 += ystep; + err += dx; + } + } +} + +// filled rectangle +void LCDfillrect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t color) +{ + // stupidest version - just pixels - but fast with internal buffer! + uint8_t i,j; + for ( i=x; i= 0) + { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + + my_setpixel(x0 + x, y0 + y, color); + my_setpixel(x0 - x, y0 + y, color); + my_setpixel(x0 + x, y0 - y, color); + my_setpixel(x0 - x, y0 - y, color); + + my_setpixel(x0 + y, y0 + x, color); + my_setpixel(x0 - y, y0 + x, color); + my_setpixel(x0 + y, y0 - x, color); + my_setpixel(x0 - y, y0 - x, color); + + } +} + +void LCDfillcircle(uint8_t x0, uint8_t y0, uint8_t r, uint8_t color) +{ + updateBoundingBox(x0-r, y0-r, x0+r, y0+r); + int8_t f = 1 - r; + int8_t ddF_x = 1; + int8_t ddF_y = -2 * r; + int8_t x = 0; + int8_t y = r; + uint8_t i; + + for (i=y0-r; i<=y0+r; i++) + { + my_setpixel(x0, i, color); + } + + while (x= 0) + { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + + for ( i=y0-y; i<=y0+y; i++) + { + my_setpixel(x0+x, i, color); + my_setpixel(x0-x, i, color); + } + for ( i=y0-x; i<=y0+x; i++) + { + my_setpixel(x0+y, i, color); + my_setpixel(x0-y, i, color); + } + } +} + +// the most basic function, set a single pixel +void LCDsetPixel(uint8_t x, uint8_t y, uint8_t color) +{ + if ((x >= LCDWIDTH) || (y >= LCDHEIGHT)) + return; + + // x is which column + if (color) + pcd8544_buffer[x+ (y/8)*LCDWIDTH] |= _BV(y%8); + else + pcd8544_buffer[x+ (y/8)*LCDWIDTH] &= ~_BV(y%8); + updateBoundingBox(x,y,x,y); +} + +// the most basic function, get a single pixel +uint8_t LCDgetPixel(uint8_t x, uint8_t y) +{ + if ((x >= LCDWIDTH) || (y >= LCDHEIGHT)) + return 0; + + return (pcd8544_buffer[x+ (y/8)*LCDWIDTH] >> (7-(y%8))) & 0x1; +} + +void LCDspiwrite(uint8_t c) +{ + shiftOut(_din, _sclk, MSBFIRST, c); +} + +void LCDcommand(uint8_t c) +{ + digitalWrite( _dc, LOW); + LCDspiwrite(c); +} + +void LCDdata(uint8_t c) +{ + digitalWrite(_dc, HIGH); + LCDspiwrite(c); +} + +void LCDsetContrast(uint8_t val) +{ + if (val > 0x7f) { + val = 0x7f; + } + LCDcommand(PCD8544_FUNCTIONSET | PCD8544_EXTENDEDINSTRUCTION ); + LCDcommand( PCD8544_SETVOP | val); + LCDcommand(PCD8544_FUNCTIONSET); +} + +void LCDdisplay(void) +{ + uint8_t col, maxcol, p; + + for(p = 0; p < 6; p++) + { +#ifdef enablePartialUpdate + // check if this page is part of update + if ( yUpdateMin >= ((p+1)*8) ) + { + continue; // nope, skip it! + } + if (yUpdateMax < p*8) + { + break; + } +#endif + + LCDcommand(PCD8544_SETYADDR | p); + + +#ifdef enablePartialUpdate + col = xUpdateMin; + maxcol = xUpdateMax; +#else + // start at the beginning of the row + col = 0; + maxcol = LCDWIDTH-1; +#endif + + LCDcommand(PCD8544_SETXADDR | col); + + for(; col <= maxcol; col++) { + //uart_putw_dec(col); + //uart_putchar(' '); + LCDdata(pcd8544_buffer[(LCDWIDTH*p)+col]); + } + } + + LCDcommand(PCD8544_SETYADDR ); // no idea why this is necessary but it is to finish the last byte? +#ifdef enablePartialUpdate + xUpdateMin = LCDWIDTH - 1; + xUpdateMax = 0; + yUpdateMin = LCDHEIGHT-1; + yUpdateMax = 0; +#endif + +} + +// clear everything +void LCDclear(void) { + //memset(pcd8544_buffer, 0, LCDWIDTH*LCDHEIGHT/8); + uint32_t i; + for ( i = 0; i < LCDWIDTH*LCDHEIGHT/8 ; i++) + pcd8544_buffer[i] = 0; + updateBoundingBox(0, 0, LCDWIDTH-1, LCDHEIGHT-1); + cursor_y = cursor_x = 0; +} + +// bitbang serial shift out on select GPIO pin. Data rate is defined by CPU clk speed and CLKCONST_2. +// Calibrate these value for your need on target platform. +void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val) +{ + uint8_t i; + uint32_t j; + + for (i = 0; i < 8; i++) { + if (bitOrder == LSBFIRST) + digitalWrite(dataPin, !!(val & (1 << i))); + else + digitalWrite(dataPin, !!(val & (1 << (7 - i)))); + + digitalWrite(clockPin, HIGH); + for (j = CLKCONST_2; j > 0; j--); // clock speed, anyone? (LCD Max CLK input: 4MHz) + digitalWrite(clockPin, LOW); + } +} + +// roughly calibrated spin delay +void _delay_ms(uint32_t t) +{ + uint32_t nCount = 0; + while (t != 0) + { + nCount = CLKCONST_1; + while(nCount != 0) + nCount--; + t--; + } +} \ No newline at end of file diff --git a/libraries/c/PCD8544/PCD8544.h b/libraries/c/PCD8544/PCD8544.h new file mode 100644 index 0000000..e72ee12 --- /dev/null +++ b/libraries/c/PCD8544/PCD8544.h @@ -0,0 +1,86 @@ +/* +================================================================================= + Name : PCD8544.h + Version : 0.1 + + Copyright (C) 2010 Limor Fried, Adafruit Industries + CORTEX-M3 version by Le Dang Dung, 2011 LeeDangDung@gmail.com (tested on LPC1769) + Raspberry Pi version by Andre Wussow, 2012, desk@binerry.de + + Description : PCD8544 LCD library! + +================================================================================ +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. +================================================================================ + */ +#include + +#define BLACK 1 +#define WHITE 0 + +#define LCDWIDTH 84 +#define LCDHEIGHT 48 + +#define PCD8544_POWERDOWN 0x04 +#define PCD8544_ENTRYMODE 0x02 +#define PCD8544_EXTENDEDINSTRUCTION 0x01 + +#define PCD8544_DISPLAYBLANK 0x0 +#define PCD8544_DISPLAYNORMAL 0x4 +#define PCD8544_DISPLAYALLON 0x1 +#define PCD8544_DISPLAYINVERTED 0x5 + +// H = 0 +#define PCD8544_FUNCTIONSET 0x20 +#define PCD8544_DISPLAYCONTROL 0x08 +#define PCD8544_SETYADDR 0x40 +#define PCD8544_SETXADDR 0x80 + +// H = 1 +#define PCD8544_SETTEMP 0x04 +#define PCD8544_SETBIAS 0x10 +#define PCD8544_SETVOP 0x80 + +#define swap(a, b) { uint8_t t = a; a = b; b = t; } + + // calibrate clock constants +#define CLKCONST_1 8000 +#define CLKCONST_2 400 // 400 is a good tested value for Raspberry Pi + +// keywords +#define LSBFIRST 0 +#define MSBFIRST 1 + + void LCDInit(uint8_t SCLK, uint8_t DIN, uint8_t DC, uint8_t CS, uint8_t RST, uint8_t contrast); + void LCDcommand(uint8_t c); + void LCDdata(uint8_t c); + void LCDsetContrast(uint8_t val); + void LCDclear(); + void LCDdisplay(); + void LCDsetPixel(uint8_t x, uint8_t y, uint8_t color); + uint8_t LCDgetPixel(uint8_t x, uint8_t y); + void LCDfillcircle(uint8_t x0, uint8_t y0, uint8_t r,uint8_t color); + void LCDdrawcircle(uint8_t x0, uint8_t y0, uint8_t r,uint8_t color); + void LCDdrawrect(uint8_t x, uint8_t y, uint8_t w, uint8_t h,uint8_t color); + void LCDfillrect(uint8_t x, uint8_t y, uint8_t w, uint8_t h,uint8_t color); + void LCDdrawline(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t color); + void LCDsetCursor(uint8_t x, uint8_t y); + void LCDsetTextSize(uint8_t s); + void LCDsetTextColor(uint8_t c); + void LCDwrite(uint8_t c); + void LCDshowLogo(); + void LCDdrawchar(uint8_t x, uint8_t line, char c); + void LCDdrawstring(uint8_t x, uint8_t line, char *c); + void LCDdrawstring_P(uint8_t x, uint8_t line, const char *c); + void LCDdrawbitmap(uint8_t x, uint8_t y, const uint8_t *bitmap, uint8_t w, uint8_t h, uint8_t color); + void LCDspiwrite(uint8_t c); + void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val); + void _delay_ms(uint32_t t); \ No newline at end of file diff --git a/libraries/c/PCD8544/README.md b/libraries/c/PCD8544/README.md new file mode 100644 index 0000000..9c3ab8c --- /dev/null +++ b/libraries/c/PCD8544/README.md @@ -0,0 +1,23 @@ +Raspberry Pi PCD8544 Library +============================ +A simple PCD8544 LCD (Nokia3310/5110) driver. Target board is Raspberry Pi. +This driver uses 5 GPIOs on target board with a bit-bang SPI implementation (hence, may not be as fast but seems fast enough). +Makes use of WiringPI-library of _Gordon Henderson_ (https://projects.drogon.net/raspberry-pi/wiringpi/) + +Copyright (C) 2010 _Limor Fried_, _Adafruit Industries_ +CORTEX-M3 version by _Le Dang Dung_, 2011 LeeDangDung@gmail.com (tested on LPC1769) +Raspberry Pi version by _Andre Wussow_, 2012, desk@binerry.de + +For more informations please visit http://binerry.de/post/25787954149/pcd8544-library-for-raspberry-pi. + +License +------- +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. \ No newline at end of file diff --git a/libraries/c/PCD8544/samples/PCD8544.h b/libraries/c/PCD8544/samples/PCD8544.h new file mode 100644 index 0000000..93deadd --- /dev/null +++ b/libraries/c/PCD8544/samples/PCD8544.h @@ -0,0 +1,86 @@ +/* +================================================================================= + Name : PCD8544.h + Version : 0.1 + + Copyright (C) 2010 Limor Fried, Adafruit Industries + CORTEX-M3 version by Le Dang Dung, 2011 LeeDangDung@gmail.com (tested on LPC1769) + Raspberry Pi version by Andre Wussow, 2012, desk@binerry.de + + Description : PCD8544 LCD library! + +================================================================================ +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. +================================================================================ + */ +#include + +#define BLACK 1 +#define WHITE 0 + +#define LCDWIDTH 84 +#define LCDHEIGHT 48 + +#define PCD8544_POWERDOWN 0x04 +#define PCD8544_ENTRYMODE 0x02 +#define PCD8544_EXTENDEDINSTRUCTION 0x01 + +#define PCD8544_DISPLAYBLANK 0x0 +#define PCD8544_DISPLAYNORMAL 0x4 +#define PCD8544_DISPLAYALLON 0x1 +#define PCD8544_DISPLAYINVERTED 0x5 + +// H = 0 +#define PCD8544_FUNCTIONSET 0x20 +#define PCD8544_DISPLAYCONTROL 0x08 +#define PCD8544_SETYADDR 0x40 +#define PCD8544_SETXADDR 0x80 + +// H = 1 +#define PCD8544_SETTEMP 0x04 +#define PCD8544_SETBIAS 0x10 +#define PCD8544_SETVOP 0x80 + +#define swap(a, b) { uint8_t t = a; a = b; b = t; } + + // calibrate clock constants +#define CLKCONST_1 8000 +#define CLKCONST_2 400 // 400 is a good tested value for Raspberry Pi + +// keywords +#define LSBFIRST 0 +#define MSBFIRST 1 + + void LCDInit(uint8_t SCLK, uint8_t DIN, uint8_t DC, uint8_t CS, uint8_t RST, uint8_t contrast); + void LCDcommand(uint8_t c); + void LCDdata(uint8_t c); + void LCDsetContrast(uint8_t val); + void LCDclear(); + void LCDdisplay(); + void LCDsetPixel(uint8_t x, uint8_t y, uint8_t color); + uint8_t LCDgetPixel(uint8_t x, uint8_t y); + void LCDfillcircle(uint8_t x0, uint8_t y0, uint8_t r,uint8_t color); + void LCDdrawcircle(uint8_t x0, uint8_t y0, uint8_t r,uint8_t color); + void LCDdrawrect(uint8_t x, uint8_t y, uint8_t w, uint8_t h,uint8_t color); + void LCDfillrect(uint8_t x, uint8_t y, uint8_t w, uint8_t h,uint8_t color); + void LCDdrawline(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t color); + void LCDsetCursor(uint8_t x, uint8_t y); + void LCDsetTextSize(uint8_t s); + void LCDsetTextColor(uint8_t c); + void LCDwrite(uint8_t c); + void LCDshowLogo(); + void LCDdrawchar(uint8_t x, uint8_t line, char c); + void LCDdrawstring(uint8_t x, uint8_t line, char *c); + void LCDdrawstring_P(uint8_t x, uint8_t line, const char *c); + void LCDdrawbitmap(uint8_t x, uint8_t y, const uint8_t *bitmap, uint8_t w, uint8_t h, uint8_t color); + void LCDspiwrite(uint8_t c); + void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val); + void _delay_ms(uint32_t t); \ No newline at end of file diff --git a/libraries/c/PCD8544/samples/pcd8544_rpi.c b/libraries/c/PCD8544/samples/pcd8544_rpi.c new file mode 100644 index 0000000..25ced9b --- /dev/null +++ b/libraries/c/PCD8544/samples/pcd8544_rpi.c @@ -0,0 +1,219 @@ +/* +================================================================================= + Name : pcd8544_rpi.c + Version : 0.1 + + Copyright (C) 2012 by Andre Wussow, 2012, desk@binerry.de + + Description : + A simple PCD8544 LCD (Nokia3310/5110) for Raspberry Pi for displaying some system informations. + Makes use of WiringPI-library of Gordon Henderson (https://projects.drogon.net/raspberry-pi/wiringpi/) + + Recommended connection (http://www.raspberrypi.org/archives/384): + LCD pins Raspberry Pi + LCD1 - GND P06 - GND + LCD2 - VCC P01 - 3.3V + LCD3 - CLK P11 - GPIO0 + LCD4 - Din P12 - GPIO1 + LCD5 - D/C P13 - GPIO2 + LCD6 - CS P15 - GPIO3 + LCD7 - RST P16 - GPIO4 + LCD8 - LED P01 - 3.3V + +================================================================================ +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. +================================================================================ + */ +#include +#include +#include +#include +#include +#include +#include "PCD8544.h" +#include +#include +#include +#include +#include +#include +#include +#include + +// pin setup +int _din = 1; +int _sclk = 0; +int _dc = 2; +int _rst = 4; +int _cs = 3; + +// lcd contrast +int contrast = 50; + +int main (void) +{ + //clock + // variables to store date and time components + int hours, minutes, seconds, day, month, year; + + //network + int fdl; + int fdr; + struct ifreq ifrl; + struct ifreq ifrr; + + // print infos + printf("Raspberry Pi PCD8544 sysinfo display\n"); + printf("========================================\n"); + + // check wiringPi setup + if (wiringPiSetup() == -1) + { + printf("wiringPi-Error\n"); + exit(1); + } + + // init and clear lcd + LCDInit(_sclk, _din, _dc, _cs, _rst, contrast); + LCDclear(); + + // show logo + LCDshowLogo(); + + delay(2000); + + for (;;) + { + + // clear lcd + LCDclear(); + + // temp + char tempInfo[10]; + FILE *temperatureFile; + double T; + temperatureFile = fopen ("/sys/class/thermal/thermal_zone0/temp", "r"); + if (temperatureFile == NULL) + ; //print some message + fscanf (temperatureFile, "%lf", &T); + T /= 1000; + sprintf(tempInfo, "Temp %6.3fC", T); + fclose (temperatureFile); + + char wrinfo[15]; + char wlinfo[15]; + + fdl = socket(AF_INET, SOCK_DGRAM, 0); + + /* I want to get an IPv4 IP address */ + ifrl.ifr_addr.sa_family = AF_INET; + + /* I want IP address attached to "wlan0" */ + strncpy(ifrl.ifr_name, "wlan0", IFNAMSIZ-1); + + ioctl(fdl, SIOCGIFADDR, &ifrl); + /* grab flags associated with this interface */ + ioctl(fdl, SIOCGIFFLAGS, &ifrl); + if (ifrl.ifr_flags & IFF_RUNNING) { + sprintf(wlinfo, "%s", inet_ntoa(((struct sockaddr_in *)&ifrl.ifr_addr)->sin_addr)); + } else { + sprintf(wlinfo, "offline"); + } + close(fdl); + + fdr = socket(AF_INET, SOCK_DGRAM, 0); + + /* I want to get an IPv4 IP address */ + ifrr.ifr_addr.sa_family = AF_INET; + + /* I want IP address attached to "wlan0" */ + strncpy(ifrr.ifr_name, "eth0", IFNAMSIZ-1); + + ioctl(fdr, SIOCGIFADDR, &ifrr); + /* grab flags associated with this interface */ + ioctl(fdr, SIOCGIFFLAGS, &ifrr); + if (ifrr.ifr_flags & IFF_RUNNING) { + sprintf(wrinfo, "%s", inet_ntoa(((struct sockaddr_in *)&ifrr.ifr_addr)->sin_addr)); + } else { + sprintf(wrinfo, "offline"); + } + close(fdr); + + // time_t is arithmetic time type + //time_t now; + + // Obtain current time + // time() returns the current time of the system as a time_t value + //time(&now); + + // localtime converts a time_t value to calendar time and + // returns a pointer to a tm structure with its members + // filled with the corresponding values + //struct tm *local = localtime(&now); + + // get system usage / info + struct sysinfo sys_info; + if(sysinfo(&sys_info) != 0) + { + printf("sysinfo-Error\n"); + } + + + // time info + //char timeInfo[10]; + //unsigned long seconds = local->tm_sec; + //unsigned long minutes = local->tm_min; + //unsigned long hours = local->tm_hour; + //sprintf(timeInfo, " %02d:%02d:%02d", hours, minutes, seconds); + + // uptime + char uptimeInfo[15]; + unsigned long uph = sys_info.uptime / 3600; + unsigned long upm = (sys_info.uptime / 60) - (uph * 60); + unsigned long ups = sys_info.uptime - (upm * 60) - (uph * 3600); + sprintf(uptimeInfo, "Up %02d:%02d:%02d", uph, upm, ups); + + // cpu info + char cpuInfo[10]; + unsigned long avgCpuLoad = sys_info.loads[0] / 4000; + sprintf(cpuInfo, "CPU %ld%%", avgCpuLoad); + + // ram info + char ramInfo[10]; + unsigned long totalRam = (sys_info.totalram - sys_info.freeram - sys_info.bufferram - sys_info.sharedram) / 1024 / 1024; + sprintf(ramInfo, "RAM %ld MB", totalRam); + + + // build screen + LCDdrawstring(0, 0, tempInfo); + //LCDdrawstring(0, 0, "Raspberry Pi:"); + //LCDdrawline(0, 10, 83, 10, BLACK); + LCDdrawstring(0, 8, uptimeInfo); + LCDdrawstring(0, 16, cpuInfo); + LCDdrawstring(0, 24, ramInfo); + LCDdrawstring(0, 32, wlinfo); + LCDdrawstring(0, 40, wrinfo); + LCDdisplay(); + + delay(1000); + } + + //for (;;){ + // printf("LED On\n"); + // digitalWrite(pin, 1); + // delay(250); + // printf("LED Off\n"); + // digitalWrite(pin, 0); + // delay(250); + //} + + return 0; +} diff --git a/libraries/c/PCD8544/samples/pcd8544_test.c b/libraries/c/PCD8544/samples/pcd8544_test.c new file mode 100644 index 0000000..ef706cf --- /dev/null +++ b/libraries/c/PCD8544/samples/pcd8544_test.c @@ -0,0 +1,155 @@ +/* +================================================================================= + Name : pcd8544_test.c + Version : 0.1 + + Copyright (C) 2010 Limor Fried, Adafruit Industries + Raspberry Pi version by Andre Wussow, 2012, desk@binerry.de + + Description : + A simple PCD8544 LCD (Nokia3310/5110) test for Raspberry PI PCD8544 Library. + Based on Limor Fried's PCD8544 Arduino samples + (https://github.com/adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library/blob/master/examples/pcdtest/pcdtest.pde) + Makes use of WiringPI-library of Gordon Henderson (https://projects.drogon.net/raspberry-pi/wiringpi/) + + Recommended connection (http://www.raspberrypi.org/archives/384): + LCD pins Raspberry Pi + LCD1 - GND P06 - GND + LCD2 - VCC P01 - 3.3V + LCD3 - CLK P11 - GPIO0 + LCD4 - Din P12 - GPIO1 + LCD5 - D/C P13 - GPIO2 + LCD6 - CS P15 - GPIO3 + LCD7 - RST P16 - GPIO4 + LCD8 - LED P01 - 3.3V + +================================================================================ +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. +================================================================================ + */ +#include +#include +#include +#include "PCD8544.h" + +// pin setup +int _din = 1; +int _sclk = 0; +int _dc = 2; +int _rst = 4; +int _cs = 3; + +// lcd contrast +int contrast = 50; + +int main (void) +{ + // print infos + printf("Raspberry Pi PCD8544 test\n"); + printf("========================================\n"); + + printf("CLK on Port %i \n", _sclk); + printf("DIN on Port %i \n", _din); + printf("DC on Port %i \n", _dc); + printf("CS on Port %i \n", _cs); + printf("RST on Port %i \n", _rst); + printf("========================================\n"); + + // check wiringPi setup + if (wiringPiSetup() == -1) + { + printf("wiringPi-Error\n"); + exit(1); + } + + // init and clear lcd + LCDInit(_sclk, _din, _dc, _cs, _rst, contrast); + LCDclear(); + + // turn all the pixels on (a handy test) + printf("Test: All pixels on.\n"); + LCDcommand(PCD8544_DISPLAYCONTROL | PCD8544_DISPLAYALLON); + delay(1000); + // back to normal + printf("Test: All pixels off.\n"); + LCDcommand(PCD8544_DISPLAYCONTROL | PCD8544_DISPLAYNORMAL); + LCDclear(); + + // display logo + printf("Test: Display logo.\n"); + LCDshowLogo(); + delay(2000); + LCDclear(); + + // draw a single pixel + printf("Test: Display single pixel.\n"); + LCDsetPixel(10, 10, BLACK); + LCDdisplay(); + delay(2000); + LCDclear(); + + // draw many lines + printf("Test: Draw many lines.\n"); + int i; + for (i=0; i<84; i+=4) { + LCDdrawline(0, 0, i, 47, BLACK); + } + for (i=0; i<48; i+=4) { + LCDdrawline(0, 0, 83, i, BLACK); + } + LCDdisplay(); + delay(2000); + LCDclear(); + + // draw rectangles + printf("Test: Draw rectangles.\n"); + for (i=0; i<48; i+=2) { + LCDdrawrect(i, i, 96-i, 48-i, BLACK); + } + LCDdisplay(); + delay(2000); + LCDclear(); + + // draw multiple rectangles + printf("Test: Draw multiple rectangles.\n"); + for (i=0; i<48; i++) { + // alternate colors for moire effect + LCDfillrect(i, i, 84-i, 48-i, i%2); + } + LCDdisplay(); + delay(2000); + LCDclear(); + + // draw mulitple circles + printf("Test: Draw multiple circles.\n"); + for (i=0; i<48; i+=2) { + LCDdrawcircle(41, 23, i, BLACK); + } + LCDdisplay(); + delay(2000); + LCDclear(); + + // draw the first ~120 characters in the font + printf("Test: Draw the first ~120 chars.\n"); + for (i=0; i < 64; i++) { + LCDdrawchar((i % 14) * 6, (i/14) * 8, i); + } + LCDdisplay(); + delay(2000); + for (i=0; i < 64; i++) { + LCDdrawchar((i % 14) * 6, (i/14) * 8, i + 64); + } + LCDdisplay(); + delay(2000); + LCDclear(); + + return 0; +} \ No newline at end of file diff --git a/libraries/c/PCD8544/samples/pcd8544_test2.c b/libraries/c/PCD8544/samples/pcd8544_test2.c new file mode 100644 index 0000000..86cb1b2 --- /dev/null +++ b/libraries/c/PCD8544/samples/pcd8544_test2.c @@ -0,0 +1,129 @@ +/* +================================================================================= + Name : pcd8544_test2.c + Version : 0.1 + + Copyright (C) 2010 Limor Fried, Adafruit Industries + Raspberry Pi version by Andre Wussow, 2012, desk@binerry.de + + Description : + A simple PCD8544 LCD (Nokia3310/5110) test for Raspberry PI PCD8544 Library. + Based on Limor Fried's PCD8544 Arduino samples + (https://github.com/adafruit/Adafruit-PCD8544-Nokia-5110-LCD-library/blob/master/examples/pcdtest/pcdtest.pde) + Makes use of WiringPI-library of Gordon Henderson (https://projects.drogon.net/raspberry-pi/wiringpi/) + + Recommended connection (http://www.raspberrypi.org/archives/384): + LCD pins Raspberry Pi + LCD1 - GND P06 - GND + LCD2 - VCC P01 - 3.3V + LCD3 - CLK P11 - GPIO0 + LCD4 - Din P12 - GPIO1 + LCD5 - D/C P13 - GPIO2 + LCD6 - CS P15 - GPIO3 + LCD7 - RST P16 - GPIO4 + LCD8 - LED P01 - 3.3V + +================================================================================ +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. +================================================================================ + */ + +#include +#include +#include +#include "PCD8544.h" + +// animation setup +#define NUMFLAKES 8 +#define XPOS 0 +#define YPOS 1 +#define DELTAY 2 + +// pin setup +int _din = 1; +int _sclk = 0; +int _dc = 2; +int _rst = 4; +int _cs = 3; + +// lcd contrast +int contrast = 50; + +// a bitmap of a 16x16 smiley icon +// get the bitmap assistance here! : http://en.radzio.dxp.pl/bitmap_converter/ +// or here! : http://www.henningkarlsen.com/electronics/t_imageconverter_mono.php +const uint8_t smiley[]={ +0x00, 0xE0, 0x30, 0x18, 0x0C, 0x66, 0x62, 0x02, 0x02, 0x62, 0x66, 0x0C, 0x18, 0x30, 0xE0, 0x00, // 0x0010 (16) pixels +0x00, 0x07, 0x0C, 0x18, 0x30, 0x62, 0x44, 0x4C, 0x4C, 0x44, 0x62, 0x30, 0x18, 0x0C, 0x07, 0x00, // 0x0020 (32) pixels +}; +#define SMILEY_HEIGHT 16 +#define SMILEY_WIDTH 16 + +int main (void) +{ + // print infos + printf("Raspberry Pi PCD8544 animation test\n"); + printf("========================================\n"); + + printf("CLK on Port %i \n", _sclk); + printf("DIN on Port %i \n", _din); + printf("DC on Port %i \n", _dc); + printf("CS on Port %i \n", _cs); + printf("RST on Port %i \n", _rst); + printf("========================================\n"); + + // check wiringPi setup + if (wiringPiSetup() == -1) + { + printf("wiringPi-Error\n"); + exit(1); + } + + // init and clear lcd + LCDInit(_sclk, _din, _dc, _cs, _rst, contrast); + LCDclear(); + + // turn all the pixels on (a handy test) + uint8_t icons[NUMFLAKES][3]; + srandom(666); // whatever seed + + // initialize + int f; + for (f=0; f< NUMFLAKES; f++) { + icons[f][XPOS] = random() % LCDWIDTH; + icons[f][YPOS] = 0; + icons[f][DELTAY] = random() % 5 + 1; + } + + while (1) { + // draw each icon + for (f=0; f< NUMFLAKES; f++) { + LCDdrawbitmap(icons[f][XPOS], icons[f][YPOS], smiley, SMILEY_WIDTH, SMILEY_HEIGHT, BLACK); + } + LCDdisplay(); + delay(500); + + // then erase it + move it + for (f=0; f< NUMFLAKES; f++) { + LCDdrawbitmap(icons[f][XPOS], icons[f][YPOS], smiley, SMILEY_WIDTH, SMILEY_HEIGHT, 0); + // move it + icons[f][YPOS] += icons[f][DELTAY]; + // if its gone, reinit + if (icons[f][YPOS] > LCDHEIGHT) { + icons[f][XPOS] = random() % LCDWIDTH; + icons[f][YPOS] = 0; + icons[f][DELTAY] = random() % 5 + 1; + } + } + } + + return 0; +} \ No newline at end of file diff --git a/prototyping/fritzing/parts/board/README.md b/prototyping/fritzing/parts/board/README.md new file mode 100644 index 0000000..ddbffc2 --- /dev/null +++ b/prototyping/fritzing/parts/board/README.md @@ -0,0 +1,24 @@ +Raspberry Pi Fritzing Part +========================== +For doing some prototyping stuff it maybe really helpfull to use Raspberry Pi +within' Fritzing. This is the Fritzing Part (fzpz) of the main board, model b. + +Copyright (C) 2012 by _Andre Wussow_, desk@binerry.de + +Fritzing is an open-source initiative of the University of Applied Sciences Potsdam +to support designers, artists, researchers and hobbyists to work creatively with +interactive electronics. For more informations and downloads visit http://fritzing.org + +For more informations please visit http://binerry.de/post/26227980624/raspberry-pi-fritzing-part + +License +------- +This part is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This part is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. \ No newline at end of file diff --git a/prototyping/fritzing/parts/board/Raspberry Pi.fzpz b/prototyping/fritzing/parts/board/Raspberry Pi.fzpz new file mode 100644 index 0000000..01543e5 Binary files /dev/null and b/prototyping/fritzing/parts/board/Raspberry Pi.fzpz differ diff --git a/prototyping/fritzing/parts/board/svgs/controller_raspberry_pi_breadboard.svg b/prototyping/fritzing/parts/board/svgs/controller_raspberry_pi_breadboard.svg new file mode 100644 index 0000000..1a65cfc --- /dev/null +++ b/prototyping/fritzing/parts/board/svgs/controller_raspberry_pi_breadboard.svg @@ -0,0 +1,272 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Raspberry Pi + + + (C)2011 + + + http://www.raspberrypi.org + + + + + + + + + + + + + OK + + + PWR + + + FDX + + + LNK + + + 10M + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GPIO + + + P1 + + + diff --git a/prototyping/fritzing/parts/board/svgs/controller_raspberry_pi_logo.svg b/prototyping/fritzing/parts/board/svgs/controller_raspberry_pi_logo.svg new file mode 100644 index 0000000..e779649 --- /dev/null +++ b/prototyping/fritzing/parts/board/svgs/controller_raspberry_pi_logo.svg @@ -0,0 +1,207 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/prototyping/fritzing/parts/board/svgs/controller_raspberry_pi_pcb.svg b/prototyping/fritzing/parts/board/svgs/controller_raspberry_pi_pcb.svg new file mode 100644 index 0000000..9bf098a --- /dev/null +++ b/prototyping/fritzing/parts/board/svgs/controller_raspberry_pi_pcb.svg @@ -0,0 +1,221 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/prototyping/fritzing/parts/board/svgs/controller_raspberry_pi_schematic.svg b/prototyping/fritzing/parts/board/svgs/controller_raspberry_pi_schematic.svg new file mode 100644 index 0000000..4a19257 --- /dev/null +++ b/prototyping/fritzing/parts/board/svgs/controller_raspberry_pi_schematic.svg @@ -0,0 +1,671 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SCL0 + SDA0 + + + MOSI + MISO + + SCLK + CE0_N + CE1_N + + + 3V3 + 5V + SPI + GPIO5 + GPIO4 + GPIO3 + GPIO2 + GPIO1 + GPIO0 + TX + RX + TXD + GPIO7 + GPIO6 + RXD + Digital Input/Output + Power + RaspberryPi + + GND + + + I2C + SERIAL + + + + diff --git a/prototyping/fritzing/projects/i2c-shifter/README.md b/prototyping/fritzing/projects/i2c-shifter/README.md new file mode 100644 index 0000000..9e5dba1 --- /dev/null +++ b/prototyping/fritzing/projects/i2c-shifter/README.md @@ -0,0 +1,24 @@ +i2c-shifter/i2c-bridge Fritzing Prototype +========================================= +Prototype for a i2c-level-shifter / i2c-bridge for enabling intercommunication +between two devices at different logic/voltage-levels. + +Copyright (C) 2012 by _Andre Wussow_, desk@binerry.de + +Fritzing is an open-source initiative of the University of Applied Sciences Potsdam +to support designers, artists, researchers and hobbyists to work creatively with +interactive electronics. For more informations and downloads visit http://fritzing.org + +For more informations please visit http://binerry.de/post/27067411903/i2c-level-shifter-i2c-bridge + +License +------- +This prototype is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This prototype is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. \ No newline at end of file diff --git a/prototyping/fritzing/projects/i2c-shifter/i2c_shifter.fzz b/prototyping/fritzing/projects/i2c-shifter/i2c_shifter.fzz new file mode 100644 index 0000000..7cc22b7 Binary files /dev/null and b/prototyping/fritzing/projects/i2c-shifter/i2c_shifter.fzz differ diff --git a/snippets/c/i2c-arduino/Arduino/I2CSlave/Commander.cpp b/snippets/c/i2c-arduino/Arduino/I2CSlave/Commander.cpp new file mode 100644 index 0000000..ae284d9 --- /dev/null +++ b/snippets/c/i2c-arduino/Arduino/I2CSlave/Commander.cpp @@ -0,0 +1,65 @@ +/* +================================================================================= + Name : Commander.cpp + Version : 0.1 + + Copyright (C) 2012 by Andre Wussow, 2012, desk@binerry.de + + Description : + Commander library for Arduino as i2c-slave for processing commands/actions. + + References : + http://binerry.de/post/27128825416/raspberry-pi-with-i2c-arduino-slave + +================================================================================ +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. +================================================================================ +*/ +#include "Arduino.h" +#include "Commander.h" + +// constructor: +Commander::Commander() +{ + for (int i = 0; i < MAX_COMMANDS; i++) { + this->commands[i].isActive = false; + } +} + +// add command method: +void Commander::addCommand(Command_t command) +{ + for (int i = 0; i < MAX_COMMANDS; i++) { + if (!this->commands[i].isActive) + { + this->commands[i] = command; + this->commands[i].isActive = true; + break; + } + } +} + +// process command method: +void Commander::processCommand(String command) +{ + for (int i = 0; i < MAX_COMMANDS; i++) + { + if (this->commands[i].isActive) + { + if (this->commands[i].execCommand == command) + { + // call callback-function + this->commands[i].callback(command); + break; + } + } + } +} \ No newline at end of file diff --git a/snippets/c/i2c-arduino/Arduino/I2CSlave/Commander.h b/snippets/c/i2c-arduino/Arduino/I2CSlave/Commander.h new file mode 100644 index 0000000..1a4201d --- /dev/null +++ b/snippets/c/i2c-arduino/Arduino/I2CSlave/Commander.h @@ -0,0 +1,56 @@ +/* +================================================================================= + Name : Commander.h + Version : 0.1 + + Copyright (C) 2012 by Andre Wussow, 2012, desk@binerry.de + + Description : + Commander library for Arduino as i2c-slave for processing commands/actions. + + References : + http://binerry.de/post/27128825416/raspberry-pi-with-i2c-arduino-slave + +================================================================================ +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. +================================================================================ +*/ +#include "Arduino.h" + +// ensure this library description is only included once: +#ifndef Commander_h +#define Commander_h + +// constants: +#define MAX_COMMANDS 8 // max supported commands + +// structs: +// Command-Struct: +typedef struct { + String execCommand; // command for execution + void (*callback)(String); // callback function + uint8_t isActive :1; // true if this command is enabled +} Command_t; + +// Commander library interface description: +class Commander { + public: + // constructor: + Commander(); + + // methods: + void addCommand(Command_t command); + void processCommand(String command); + private: + // properties + Command_t commands[MAX_COMMANDS]; +}; +#endif \ No newline at end of file diff --git a/snippets/c/i2c-arduino/Arduino/I2CSlave/I2CSlave.ino b/snippets/c/i2c-arduino/Arduino/I2CSlave/I2CSlave.ino new file mode 100644 index 0000000..7b91070 --- /dev/null +++ b/snippets/c/i2c-arduino/Arduino/I2CSlave/I2CSlave.ino @@ -0,0 +1,227 @@ +/* +================================================================================= + Name : I2CSlave.ino + Version : 0.1 + + Copyright (C) 2012 by Andre Wussow, 2012, desk@binerry.de + + Description : + Sample of controlling an Arduino connected to Raspberry Pi via I2C. + + Recommended connection (http://www.raspberrypi.org/archives/384): + Arduino pins I2C-Shifter Raspberry Pi + GND P06 - GND + 5V 5V + SDA SDA2 + SCL SCL2 + 3V3 P01 - 3.3V + SDA1 P03 - SDA + SCL1 P05 - SCL + D2 LED1 with 1k resistor to GND + D3 LED2 with 1k resistor to GND + D4 LED3 with 1k resistor to GND + D5 Relay with transistor driver + + + References : + http://binerry.de/post/27128825416/raspberry-pi-with-i2c-arduino-slave + +================================================================================ +This sample is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This sample is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. +================================================================================ +*/ + +#include "Commander.h" +#include "Wire.h" + +/* + General Setup +*/ +// define i2c commands +#define LED1_ON_COMMAND "L11" +#define LED1_OFF_COMMAND "L10" +#define LED2_ON_COMMAND "L21" +#define LED2_OFF_COMMAND "L20" +#define LED3_ON_COMMAND "L31" +#define LED3_OFF_COMMAND "L30" +#define RELAY_ON_COMMAND "R11" +#define RELAY_OFF_COMMAND "R10" + +// define slave address (0x2A = 42 [the answer to the ultimate question of life, the universe, and everything ;)] ) +#define SLAVE_ADDRESS 0x2A + +// instantiate i2cCommander +Commander commander = Commander(); + +// pin setup +int led1pin = 2; +int led2pin = 3; +int led3pin = 4; +int relaypin = 5; + +// other vars +int answer = 0; + +void setup() { + // initialize the digital pins for leds and relay as an output + pinMode(led1pin, OUTPUT); + pinMode(led2pin, OUTPUT); + pinMode(led3pin, OUTPUT); + pinMode(relaypin, OUTPUT); + + // create commands for i2cCommander + // led 1: + Command_t cmdLed1On; + cmdLed1On.execCommand = LED1_ON_COMMAND; + cmdLed1On.callback = led1On; + + Command_t cmdLed1Off; + cmdLed1Off.execCommand = LED1_OFF_COMMAND; + cmdLed1Off.callback = led1Off; + + // led 2: + Command_t cmdLed2On; + cmdLed2On.execCommand = LED2_ON_COMMAND; + cmdLed2On.callback = led2On; + + Command_t cmdLed2Off; + cmdLed2Off.execCommand = LED2_OFF_COMMAND; + cmdLed2Off.callback = led2Off; + + // led 3: + Command_t cmdLed3On; + cmdLed3On.execCommand = LED3_ON_COMMAND; + cmdLed3On.callback = led3On; + + Command_t cmdLed3Off; + cmdLed3Off.execCommand = LED3_OFF_COMMAND; + cmdLed3Off.callback = led3Off; + + // relay: + Command_t cmdRelayOn; + cmdRelayOn.execCommand = RELAY_ON_COMMAND; + cmdRelayOn.callback = relayOn; + + Command_t cmdRelayOff; + cmdRelayOff.execCommand = RELAY_OFF_COMMAND; + cmdRelayOff.callback = relayOff; + + // add commands to i2cCommander + commander.addCommand(cmdLed1On); + commander.addCommand(cmdLed1Off); + commander.addCommand(cmdLed2On); + commander.addCommand(cmdLed2Off); + commander.addCommand(cmdLed3On); + commander.addCommand(cmdLed3Off); + commander.addCommand(cmdRelayOn); + commander.addCommand(cmdRelayOff); + + // initialize i2c as slave + Wire.begin(SLAVE_ADDRESS); + + // define callbacks for i2c communication + Wire.onReceive(receiveData); + Wire.onRequest(sendData); +} + +void loop() { + +} + +// callback for received data +void receiveData(int byteCount) +{ + String requestCommand = ""; + while(Wire.available()) + { + requestCommand = requestCommand + (char)Wire.read(); + } + commander.processCommand(requestCommand); +} + +// callback for sending data +void sendData() +{ + Wire.write(answer); + answer = 0; +} + +void led1On(String command) +{ + // switch led 1 on + digitalWrite(led1pin, HIGH); + + // reply with command and success info + answer = 1; +} + +void led1Off(String command) +{ + // switch led 1 off + digitalWrite(led1pin, LOW); + + // reply with command and success info + answer = 1; +} + +void led2On(String command) +{ + // switch led 2 on + digitalWrite(led2pin, HIGH); + + // reply with command and success info + answer = 1; +} + +void led2Off(String command) +{ + // switch led 2 off + digitalWrite(led2pin, LOW); + + // reply with command and success info + answer = 1; +} + +void led3On(String command) +{ + // switch led 3 on + digitalWrite(led3pin, HIGH); + + // reply with command and success info + answer = 1; +} + +void led3Off(String command) +{ + // switch led 3 off + digitalWrite(led3pin, LOW); + + // reply with command and success info + answer = 1; +} + +void relayOn(String command) +{ + // switch relay 3 on + digitalWrite(relaypin, HIGH); + + // reply with command and success info + answer = 1; +} + +void relayOff(String command) +{ + // switch relay off + digitalWrite(relaypin, LOW); + + // reply with command and success info + answer = 1; +} \ No newline at end of file diff --git a/snippets/c/i2c-arduino/README.md b/snippets/c/i2c-arduino/README.md new file mode 100644 index 0000000..fea4c8e --- /dev/null +++ b/snippets/c/i2c-arduino/README.md @@ -0,0 +1,22 @@ +Raspberry Pi with Arduino as I2C-Slave +====================================== +Sample of controlling an Arduino connected to Raspberry Pi via I2C. + +http://www.raspberrypi.org +http://arduino.cc + +Copyright (C) 2012 by _Andre Wussow_, 2012, desk@binerry.de + +For more informations please visit http://binerry.de/post/27128825416/raspberry-pi-with-i2c-arduino-slave. + +License +------- +This sample is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This sample is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. \ No newline at end of file diff --git a/snippets/c/i2c-arduino/i2c-arduino.c b/snippets/c/i2c-arduino/i2c-arduino.c new file mode 100644 index 0000000..1362adf --- /dev/null +++ b/snippets/c/i2c-arduino/i2c-arduino.c @@ -0,0 +1,128 @@ +/* +================================================================================= + Name : i2c-arduino.c + Version : 0.1 + + Copyright (C) 2012 by Andre Wussow, 2012, desk@binerry.de + + Description : + Sample of controlling an Arduino connected to Raspberry Pi via I2C. + + Recommended connection (http://www.raspberrypi.org/archives/384): + Arduino pins I2C-Shifter Raspberry Pi + GND P06 - GND + 5V 5V + SDA SDA2 + SCL SCL2 + 3V3 P01 - 3.3V + SDA1 P03 - SDA + SCL1 P05 - SCL + + References : + http://binerry.de/post/27128825416/raspberry-pi-with-i2c-arduino-slave + +================================================================================ +This sample is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This sample is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. +================================================================================ +*/ + +#include +#include +#include +#include +#include + +int deviceHandle; +int readBytes; +char buffer[7]; + +void testCommand(char command[3], char identifier[5]); + +int main (void) +{ + // print infos + printf("Raspberry Pi I2C Arduino Sample\n"); + printf("========================================\n"); + + // initialize buffer + buffer[0] = 0x00; + + // address of i2c Arduino device + int deviceI2CAddress = 0x2A; // (0x2A = 42) + + // open device on /dev/i2c-0 + if ((deviceHandle = open("/dev/i2c-0", O_RDWR)) < 0) { + printf("Error: Couldn't open device! %d\n", deviceHandle); + return 1; + } + + // connect to arduino as i2c slave + if (ioctl(deviceHandle, I2C_SLAVE, deviceI2CAddress) < 0) { + printf("Error: Couldn't find arduino on address!\n"); + return 1; + } + + // begin transmission and request acknowledgement + readBytes = write(deviceHandle, buffer, 1); + if (readBytes != 1) + { + printf("Error: Received no ACK-Bit, couldn't established connection!"); + } + else + { + // drive some tests + testCommand("L11", "LED1 on"); + usleep(2000000); // 2s + testCommand("L10", "LED1 off"); + usleep(2000000); // 2s + testCommand("L21", "LED2 on"); + usleep(2000000); // 2s + testCommand("L20", "LED2 off"); + usleep(2000000); // 2s + testCommand("L31", "LED3 on"); + usleep(2000000); // 2s + testCommand("L30", "LED3 off"); + usleep(2000000); // 2s + testCommand("R11", "Relay on"); + usleep(2000000); // 2s + testCommand("R10", "Relay off"); + } + + // close connection and return + close(deviceHandle); + return 0; +} + +// function for testing command +void testCommand(char command[3], char action[10]) +{ + // switch on + printf("Switching %s ... ", action); + readBytes = write(deviceHandle, command, 3); + + // give arduino some reaction time + usleep(100000); // 100ms + + // read success + readBytes = read(deviceHandle, buffer, 1); + if (readBytes != 1) + { + printf("Error: Received no data!"); + } + else + { + // check response: 0 = error / 1 = success + if (buffer[0] == 1) + { + printf("OK!\n"); + } + } +} \ No newline at end of file diff --git a/snippets/c/i2c/rtc_ds1307.c b/snippets/c/i2c/rtc_ds1307.c new file mode 100644 index 0000000..adf6a1b --- /dev/null +++ b/snippets/c/i2c/rtc_ds1307.c @@ -0,0 +1,106 @@ +/* +================================================================================= + Name : rtc_ds1307.c + Version : 0.1 + + Copyright (C) 2012 by Andre Wussow, 2012, desk@binerry.de + + Description : + A simple test for querying the RTC DS1307. + + Connection (http://www.raspberrypi.org/archives/384): + DS1307 pins Raspberry Pi Other + 1 - X1 Clock oscillator X1 + 2 - X2 Clock oscillator X2 + 3 - VBat Coin cell battery CR2032 3V + 4 - GND P05 - GND + 5 - Vcc P01 - 5V + 6 - SQW/OUT + 7 - SCL P04 - SCL0 + 8 - SDA P02 - SDA0 + + References : + http://binerry.de/post/26685647322/raspberry-pi-and-i2c + http://pdfserv.maxim-ic.com/en/ds/DS1307.pdf + +================================================================================ +This sample is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This sample is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. +================================================================================ + */ +#include +#include +#include +#include + +int main (void) +{ + // print infos + printf("Raspberry Pi RTC DS1307 Sample\n"); + printf("========================================\n"); + + int deviceHandle; + int readBytes; + char buffer[7]; + + // initialize buffer + buffer[0] = 0x00; + + // address of DS1307 RTC device + int deviceI2CAddress = 0x68; + + // open device on /dev/i2c-0 + if ((deviceHandle = open("/dev/i2c-0", O_RDWR)) < 0) { + printf("Error: Couldn't open device! %d\n", deviceHandle); + return 1; + } + + // connect to DS1307 as i2c slave + if (ioctl(deviceHandle, I2C_SLAVE, deviceI2CAddress) < 0) { + printf("Error: Couldn't find device on address!\n"); + return 1; + } + + // begin transmission and request acknowledgement + readBytes = write(deviceHandle, buffer, 1); + if (readBytes != 1) + { + printf("Error: Received no ACK-Bit, couldn't established connection!"); + } + else + { + // read response + readBytes = read(deviceHandle, buffer, 7); + if (readBytes != 7) + { + printf("Error: Received no data!"); + } + else + { + // get data + int seconds = buffer[0]; // 0-59 + int minutes = buffer[1]; // 0-59 + int hours = buffer[2]; // 1-23 + int dayOfWeek = buffer[3]; // 1-7 + int day = buffer[4]; // 1-28/29/30/31 + int month = buffer[5]; // 1-12 + int year = buffer[6]; // 0-99; + + // and print results + printf("Actual RTC-time:\n"); + printf("Date: %x-%x-%x\n", year, month, day); + printf("Time: %x:%x:%x\n", hours, minutes, seconds); + } + } + + // close connection and return + close(deviceHandle); + return 0; +} \ No newline at end of file diff --git a/snippets/c/printtest/ip.c b/snippets/c/printtest/ip.c new file mode 100644 index 0000000..db3038b --- /dev/null +++ b/snippets/c/printtest/ip.c @@ -0,0 +1,34 @@ +#include +#include +#include /* for strncpy */ + +#include +#include +#include +#include +#include +#include + +int +main() +{ + int fd; + struct ifreq ifr; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + + /* I want to get an IPv4 IP address */ + ifr.ifr_addr.sa_family = AF_INET; + + /* I want IP address attached to "eth0" */ + strncpy(ifr.ifr_name, "eth0", IFNAMSIZ-1); + + ioctl(fd, SIOCGIFADDR, &ifr); + + close(fd); + + /* display result */ + printf("%s\n", inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr)); + + return 0; +} diff --git a/snippets/c/printtest/time.c b/snippets/c/printtest/time.c new file mode 100644 index 0000000..b518d8b --- /dev/null +++ b/snippets/c/printtest/time.c @@ -0,0 +1,45 @@ +#include +#include +#include + +// Print current date and time in C +int main(void) +{ + // variables to store date and time components + int hours, minutes, seconds, day, month, year; + + // time_t is arithmetic time type + time_t now; + + // Obtain current time + // time() returns the current time of the system as a time_t value + time(&now); + + // Convert to local time format and print to stdout + printf("Today is : %s", ctime(&now)); + + // localtime converts a time_t value to calendar time and + // returns a pointer to a tm structure with its members + // filled with the corresponding values + struct tm *local = localtime(&now); + + hours = local->tm_hour; // get hours since midnight (0-23) + minutes = local->tm_min; // get minutes passed after the hour (0-59) + seconds = local->tm_sec; // get seconds passed after minute (0-59) + + day = local->tm_mday; // get day of month (1 to 31) + month = local->tm_mon + 1; // get month of year (0 to 11) + year = local->tm_year + 1900; // get year since 1900 + + // print local time + if (hours < 12) // before midday + printf("Time is : %02d:%02d:%02d am\n", hours, minutes, seconds); + + else // after midday + printf("Time is : %02d:%02d:%02d pm\n", hours - 12, minutes, seconds); + + // print current date + printf("Date is : %02d/%02d/%d\n", day, month, year); + + return 0; +} diff --git a/snippets/c/watchdog/Makefile b/snippets/c/watchdog/Makefile new file mode 100644 index 0000000..fbb5df4 --- /dev/null +++ b/snippets/c/watchdog/Makefile @@ -0,0 +1,4 @@ +all: wdt_test.c + cc -o wdt_test wdt_test.c +clean: + rm -rf wdt_test \ No newline at end of file diff --git a/snippets/c/watchdog/wdt_test.c b/snippets/c/watchdog/wdt_test.c new file mode 100644 index 0000000..c132fe2 --- /dev/null +++ b/snippets/c/watchdog/wdt_test.c @@ -0,0 +1,77 @@ +/* +================================================================================= + Name : wdt_test.c + Version : 0.1 + + Copyright (C) 2012 by Andre Wussow, 2012, desk@binerry.de + + Description : + A simple test for working with the Raspberry Pi BCM2835 Watchdog. + + References : + http://binerry.de/post/28263824530/raspberry-pi-watchdog-timer + +================================================================================ +This sample is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This sample is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. +================================================================================ + */ +#include +#include +#include + +int main (int argc, char *argv[]) +{ + // print infos + printf("Raspberry Pi BCM2835 Watchdog Sample\n"); + printf("========================================\n"); + + int deviceHandle; + int disableWatchdog = 1; + + // test watchdog reset via t-param + if (argc > 1) { + if (!strncasecmp(argv[1], "-t", 2)) { + disableWatchdog = 0; + } + } + + printf("Disabling watchdog before closing device: %d\n", disableWatchdog); + + // open watchdog device on /dev/watchdog + if ((deviceHandle = open("/dev/watchdog", O_RDWR | O_NOCTTY)) < 0) { + printf("Error: Couldn't open watchdog device! %d\n", deviceHandle); + return 1; + } + + // get timeout info of watchdog (try to set it to 15s before) + int timeout = 15; + ioctl(deviceHandle, WDIOC_SETTIMEOUT, &timeout); + ioctl(deviceHandle, WDIOC_GETTIMEOUT, &timeout); + printf("The watchdog timeout is %d seconds.\n\n", timeout); + + // feed watchdog 3 times with heartbeats + int i; + for (i = 0; i < 3; i++) { + printf("Feeding the dog with a heartbeat.\n"); + ioctl(deviceHandle, WDIOC_KEEPALIVE, 0); + sleep(10); + } + + if (disableWatchdog) + { + printf("Disable watchdog.\n"); + write(deviceHandle, "V", 1); + } + + // close connection and return + close(deviceHandle); + return 0; +} \ No newline at end of file diff --git a/tools/c/sip-tools/Makefile b/tools/c/sip-tools/Makefile new file mode 100644 index 0000000..7e7e771 --- /dev/null +++ b/tools/c/sip-tools/Makefile @@ -0,0 +1,11 @@ +all: sipcall sipserv + +sipcall: sipcall.c + cc -o $@ $< `pkg-config --cflags --libs libpjproject` + +sipserv: sipserv.c + cc -o $@ $< `pkg-config --cflags --libs libpjproject` + +clean: + rm -rf sipcall + rm -rf sipserv \ No newline at end of file diff --git a/tools/c/sip-tools/README.md b/tools/c/sip-tools/README.md new file mode 100644 index 0000000..4ffd22d --- /dev/null +++ b/tools/c/sip-tools/README.md @@ -0,0 +1,85 @@ +Sip-Tools - Automated calls and answering machine +================================================= +sipcall - Automated calls over SIP/VOIP with TTS +sipserv - Answering machine for SIP/VOIP with TTS + +Dependencies: +- PJSUA API (http://www.pjsip.org) +- eSpeak (http://espeak.sourceforge.net) + +Copyright (C) 2012 by _Andre Wussow_, 2012, desk@binerry.de + +For more informations please visit http://binerry.de/post/29180946733/raspberry-pi-caller-and-answering-machine. + + + +sipcall +------- +Usage: + sipcall [options] + +Mandatory options: + -sd=string _Set sip provider domain._ + -su=string _Set sip username._ + -sp=string _Set sip password._ + -pn=string _Set target phone number to call_ + -tts=string _Text to speak_ + +Optional options: + -ttsf=string _TTS speech file name_ + -rcf=string _Record call file name_ + -mr=int _Repeat message x-times_ + -s=int _Silent mode (hide info messages) (0/1)_ + + +_see also source of sipcall-sample.sh_ + + + +sipserv +------- +Usage: + sipserv [options] + +Commandline: +Mandatory options: + --config-file=string _Set config file_ + +Optional options: + -s=int _Silent mode (hide info messages) (0/1)_ + + +Config file: +Mandatory options: + sd=string _Set sip provider domain._ + su=string _Set sip username._ + sp=string _Set sip password._ + + _and at least one dtmf configuration (X = dtmf-key index):_ + dtmf.X.active=int _Set dtmf-setting active (0/1)._ + dtmf.X.description=string _Set description._ + dtmf.X.tts-intro=string _Set tts intro._ + dtmf.X.tts-answer=string _Set tts answer._ + dtmf.X.cmd=string _Set dtmf command._ + +Optional options: + rc=int _Record call (0/1)_ + + +_a sample configuration can be found in sipserv-sample.cfg_ + +_sipserv can be controlled with ./sipserv-ctrl.sh start and ./sipserv-ctrl.sh stop_ + + + +License +------- +This tools are free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This tools are distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. \ No newline at end of file diff --git a/tools/c/sip-tools/sipcall-sample.sh b/tools/c/sip-tools/sipcall-sample.sh new file mode 100644 index 0000000..c011d57 --- /dev/null +++ b/tools/c/sip-tools/sipcall-sample.sh @@ -0,0 +1,58 @@ +#!/bin/bash +# +#================================================================================= +# Name : sipcall-sample.sh +# Version : 0.1 +# +# Copyright (C) 2012 by Andre Wussow, 2012, desk@binerry.de +# +# Description : +# Sample Script for checking average load and making call with sipcall. +# +# Dependencies: +# - sipcall +# +# References : +# http://binerry.de/post/29180946733/raspberry-pi-caller-and-answering-machine +# +#================================================================================ +#This script is free software; you can redistribute it and/or +#modify it under the terms of the GNU Lesser General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +# +#This script is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#Lesser General Public License for more details. +#================================================================================ + +# define sip-settings +sip_domain="samplesip.com"; +sip_user="12345678"; +sip_password="XXXXXX"; +play_file="play.wav"; + +# define number to call +phone_number="0123456789"; + +# define allowed load limit +maxload=0; + +# read actual load values +avgload1="$(uptime |awk -F'average: ' '{print $2}' |awk -F', ' '{print $1}')"; +avgload5="$(uptime |awk -F'average: ' '{print $2}' |awk -F', ' '{print $2}')"; +avgload15="$(uptime |awk -F'average: ' '{print $2}' |awk -F', ' '{print $3}')"; + +# check average load within last 5 minutes +avgload="$(echo $avgload5 | awk -F',' '{print $1}')"; + +check="$(($avgload >= $maxload))"; + +# creating text to speak +tts="$(echo This is raspberry pi and the load is high. The average load within the last 5 minutes was $avgload5)"; + +if [ $check = 1 ]; then + # make call with sipcall + $(./sipcall -sd $sip_domain -su $sip_user -sp $sip_password -pn $phone_number -s 1 -mr 2 -tts "$tts" -ttsf $play_file > /dev/null); +fi \ No newline at end of file diff --git a/tools/c/sip-tools/sipcall.c b/tools/c/sip-tools/sipcall.c new file mode 100644 index 0000000..c3b8758 --- /dev/null +++ b/tools/c/sip-tools/sipcall.c @@ -0,0 +1,581 @@ +/* +================================================================================= + Name : sipcall.c + Version : 0.1 alpha + + Copyright (C) 2012 by Andre Wussow, 2012, desk@binerry.de + + Description : + Tool for making automated calls over SIP/VOIP with PJSUA library and eSpeak. + + Dependencies: + - PJSUA API (PJSIP) + - eSpeak + + References : + http://www.pjsip.org/ + http://www.pjsip.org/docs/latest/pjsip/docs/html/group__PJSUA__LIB.htm + http://espeak.sourceforge.net/ + http://binerry.de/post/29180946733/raspberry-pi-caller-and-answering-machine + +================================================================================ +This tool is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This tool is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. +================================================================================ +*/ + +// definition of endianess (e.g. needed on raspberry pi) +#define PJ_IS_LITTLE_ENDIAN 1 +#define PJ_IS_BIG_ENDIAN 0 + +// includes +#include +#include +#include +#include +#include +#include + +// some espeak options +#define ESPEAK_LANGUAGE "en" +#define ESPEAK_AMPLITUDE 100 +#define ESPEAK_CAPITALS_PITCH 20 +#define ESPEAK_SPEED 150 +#define ESPEAK_PITCH 75 + +// disable pjsua logging +#define PJSUA_LOG_LEVEL 0 + +// struct for app configuration settings +struct app_config { + char *sip_domain; + char *sip_user; + char *sip_password; + char *phone_number; + char *tts; + char *tts_file; + int record_call; + char *record_file; + int repetition_limit; + int silent_mode; +} app_cfg; + +// global helper vars +int call_confirmed = 0; +int media_counter = 0; +int app_exiting = 0; + +// global vars for pjsua +pjsua_acc_id acc_id; +pjsua_player_id play_id = PJSUA_INVALID_ID; +pjmedia_port *play_port; +pjsua_recorder_id rec_id = PJSUA_INVALID_ID; + +// header of helper-methods +static void create_player(pjsua_call_id); +static void create_recorder(pjsua_call_info); +static void log_message(char *); +static void make_sip_call(); +static void register_sip(void); +static void setup_sip(void); +static void synthesize_speech(char *); +static void usage(int); +static int try_get_argument(int, char *, char **, int, char *[]); + +// header of callback-methods +static void on_call_media_state(pjsua_call_id); +static void on_call_state(pjsua_call_id, pjsip_event *); +static pj_status_t on_media_finished(pjmedia_port *, void *); +static void signal_handler(int); + +// header of app-control-methods +static void app_exit(); +static void error_exit(const char *, pj_status_t); + +// main application +int main(int argc, char *argv[]) +{ + // first set some default values + app_cfg.tts_file = "play.wav"; + app_cfg.record_call = 0; + app_cfg.repetition_limit = 3; + app_cfg.silent_mode = 0; + + // parse arguments + if (argc > 1) + { + int arg; + for( arg = 1; arg < argc; arg+=2 ) + { + // check if usage info needs to be displayed + if (!strcasecmp(argv[arg], "--help")) + { + // display usage info and exit app + usage(0); + exit(0); + } + + // check for sip domain + if (try_get_argument(arg, "-sd", &app_cfg.sip_domain, argc, argv) == 1) + { + continue; + } + + // check for sip user + if (try_get_argument(arg, "-su", &app_cfg.sip_user, argc, argv) == 1) + { + continue; + } + + // check for sip password + if (try_get_argument(arg, "-sp", &app_cfg.sip_password, argc, argv) == 1) + { + continue; + } + + // check for target phone number + if (try_get_argument(arg, "-pn", &app_cfg.phone_number, argc, argv) == 1) + { + continue; + } + + // check for text to speak + if (try_get_argument(arg, "-tts", &app_cfg.tts, argc, argv) == 1) + { + continue; + } + + // check for record call option + if (try_get_argument(arg, "-ttsf", &app_cfg.tts_file, argc, argv) == 1) + { + continue; + } + + // check for record call option + if (try_get_argument(arg, "-rcf", &app_cfg.record_file, argc, argv) == 1) + { + app_cfg.record_call = 1; + continue; + } + + // check for message repetition option + char *mr; + if (try_get_argument(arg, "-mr", &mr, argc, argv) == 1) + { + app_cfg.repetition_limit = atoi(mr); + continue; + } + + // check for silent mode option + char *s; + try_get_argument(arg, "-s", &s, argc, argv); + if (!strcasecmp(s, "1")) + { + app_cfg.silent_mode = 1; + continue; + } + } + } + else + { + // no arguments specified - display usage info and exit app + usage(1); + exit(1); + } + + if (!app_cfg.sip_domain || !app_cfg.sip_user || !app_cfg.sip_password || !app_cfg.phone_number || !app_cfg.tts) + { + // too few arguments specified - display usage info and exit app + usage(1); + exit(1); + } + + // print infos + log_message("SIP Call - Simple TTS-based Automated Calls\n"); + log_message("===========================================\n"); + + // register signal handler for break-in-keys (e.g. ctrl+c) + signal(SIGINT, signal_handler); + signal(SIGKILL, signal_handler); + + // synthesize speech + synthesize_speech(app_cfg.tts_file); + + // setup up sip library pjsua + setup_sip(); + + // create account and register to sip server + register_sip(); + + // initiate call + make_sip_call(); + + // app loop + for (;;) { } + + // exit app + app_exit(); + + return 0; +} + +// helper for displaying usage infos +static void usage(int error) +{ + if (error == 1) + { + puts("Error, to few arguments."); + puts (""); + } + puts ("Usage:"); + puts (" sipcall [options]"); + puts (""); + puts ("Mandatory options:"); + puts (" -sd=string Set sip provider domain."); + puts (" -su=string Set sip username."); + puts (" -sp=string Set sip password."); + puts (" -pn=string Set target phone number to call"); + puts (" -tts=string Text to speak"); + puts (""); + puts ("Optional options:"); + puts (" -ttsf=string TTS speech file name to save text"); + puts (" -rcf=string Record call file name to save answer"); + puts (" -mr=int Repeat message x-times"); + puts (" -s=int Silent mode (hide info messages) (0/1)"); + puts (""); + + fflush(stdout); +} + +// helper for parsing command-line-argument +static int try_get_argument(int arg, char *arg_id, char **arg_val, int argc, char *argv[]) +{ + int found = 0; + + // check if actual argument is searched argument + if (!strcasecmp(argv[arg], arg_id)) + { + // check if actual argument has a value + if (argc >= (arg+1)) + { + // set value + *arg_val = argv[arg+1]; + found = 1; + } + } + return found; +} + +// helper for logging messages to console (disabled if silent mode is active) +static void log_message(char *message) +{ + if (!app_cfg.silent_mode) + { + fprintf(stderr, message); + } +} + +// helper for setting up sip library pjsua +static void setup_sip(void) +{ + pj_status_t status; + + log_message("Setting up pjsua ... "); + + // create pjsua + status = pjsua_create(); + if (status != PJ_SUCCESS) error_exit("Error in pjsua_create()", status); + + // configure pjsua + pjsua_config cfg; + pjsua_config_default(&cfg); + + // enable just 1 simultaneous call + cfg.max_calls = 1; + + // callback configuration + cfg.cb.on_call_media_state = &on_call_media_state; + cfg.cb.on_call_state = &on_call_state; + + // logging configuration + pjsua_logging_config log_cfg; + pjsua_logging_config_default(&log_cfg); + log_cfg.console_level = PJSUA_LOG_LEVEL; + + // initialize pjsua + status = pjsua_init(&cfg, &log_cfg, NULL); + if (status != PJ_SUCCESS) error_exit("Error in pjsua_init()", status); + + // add udp transport + pjsua_transport_config udpcfg; + pjsua_transport_config_default(&udpcfg); + + udpcfg.port = 5060; + status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &udpcfg, NULL); + if (status != PJ_SUCCESS) error_exit("Error creating transport", status); + + // initialization is done, start pjsua + status = pjsua_start(); + if (status != PJ_SUCCESS) error_exit("Error starting pjsua", status); + + // disable sound - use null sound device + status = pjsua_set_null_snd_dev(); + if (status != PJ_SUCCESS) error_exit("Error disabling audio", status); + + log_message("Done.\n"); +} + +// helper for creating and registering sip-account +static void register_sip(void) +{ + pj_status_t status; + + log_message("Registering account ... "); + + // prepare account configuration + pjsua_acc_config cfg; + pjsua_acc_config_default(&cfg); + + // build sip-user-url + char sip_user_url[40]; + sprintf(sip_user_url, "sip:%s@%s", app_cfg.sip_user, app_cfg.sip_domain); + + // build sip-provder-url + char sip_provider_url[40]; + sprintf(sip_provider_url, "sip:%s", app_cfg.sip_domain); + + // create and define account + cfg.id = pj_str(sip_user_url); + cfg.reg_uri = pj_str(sip_provider_url); + cfg.cred_count = 1; + cfg.cred_info[0].realm = pj_str(app_cfg.sip_domain); + cfg.cred_info[0].scheme = pj_str("digest"); + cfg.cred_info[0].username = pj_str(app_cfg.sip_user); + cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD; + cfg.cred_info[0].data = pj_str(app_cfg.sip_password); + + // add account + status = pjsua_acc_add(&cfg, PJ_TRUE, &acc_id); + if (status != PJ_SUCCESS) error_exit("Error adding account", status); + + log_message("Done.\n"); +} + +// helper for making calls over sip-account +static void make_sip_call() +{ + pj_status_t status; + + log_message("Starting call ... "); + + // build target sip-url + char sip_target_url[40]; + sprintf(sip_target_url, "sip:%s@%s", app_cfg.phone_number, app_cfg.sip_domain); + + // start call with sip-url + pj_str_t uri = pj_str(sip_target_url); + status = pjsua_call_make_call(acc_id, &uri, 0, NULL, NULL, NULL); + if (status != PJ_SUCCESS) error_exit("Error making call", status); + + log_message("Done.\n"); +} + +// helper for creating call-media-player +static void create_player(pjsua_call_id call_id) +{ + // get call infos + pjsua_call_info ci; + pjsua_call_get_info(call_id, &ci); + + pj_str_t name; + pj_status_t status = PJ_ENOTFOUND; + + log_message("Creating player ... "); + + // create player for playback media + status = pjsua_player_create(pj_cstr(&name, app_cfg.tts_file), 0, &play_id); + if (status != PJ_SUCCESS) error_exit("Error playing sound-playback", status); + + // connect active call to media player + pjsua_conf_connect(pjsua_player_get_conf_port(play_id), ci.conf_slot); + + // get media port (play_port) from play_id + status = pjsua_player_get_port(play_id, &play_port); + if (status != PJ_SUCCESS) error_exit("Error getting sound player port", status); + + // register media finished callback + status = pjmedia_wav_player_set_eof_cb(play_port, NULL, &on_media_finished); + if (status != PJ_SUCCESS) error_exit("Error adding sound-playback callback", status); + + log_message("Done.\n"); +} + +// helper for creating call-recorder +static void create_recorder(pjsua_call_info ci) +{ + // specify target file + pj_str_t rec_file = pj_str(app_cfg.record_file); + pj_status_t status = PJ_ENOTFOUND; + + log_message("Creating recorder ... "); + + // Create recorder for call + status = pjsua_recorder_create(&rec_file, 0, NULL, 0, 0, &rec_id); + if (status != PJ_SUCCESS) error_exit("Error recording answer", status); + + // connect active call to call recorder + pjsua_conf_port_id rec_port = pjsua_recorder_get_conf_port(rec_id); + pjsua_conf_connect(ci.conf_slot, rec_port); + + log_message("Done.\n"); +} + +// synthesize speech / create message via espeak +static void synthesize_speech(char *file) +{ + log_message("Synthesizing speech ... "); + + int speech_status = -1; + char speech_command[200]; + sprintf(speech_command, "espeak -v%s -a%i -k%i -s%i -p%i -w %s '%s'", ESPEAK_LANGUAGE, ESPEAK_AMPLITUDE, ESPEAK_CAPITALS_PITCH, ESPEAK_SPEED, ESPEAK_PITCH, file, app_cfg.tts); + speech_status = system(speech_command); + if (speech_status != 0) error_exit("Error while creating phone text", speech_status); + + log_message("Done.\n"); +} + +// handler for call-media-state-change-events +static void on_call_media_state(pjsua_call_id call_id) +{ + // get call infos + pjsua_call_info ci; + pjsua_call_get_info(call_id, &ci); + + pj_status_t status = PJ_ENOTFOUND; + + // check state if call is established/active + if (ci.media_status == PJSUA_CALL_MEDIA_ACTIVE) { + + log_message("Call media activated.\n"); + + // create and start media player + create_player(call_id); + + // create and start call recorder + if (app_cfg.record_call) + { + create_recorder(ci); + } + } +} + +// handler for call-state-change-events +static void on_call_state(pjsua_call_id call_id, pjsip_event *e) +{ + // get call infos + pjsua_call_info ci; + pjsua_call_get_info(call_id, &ci); + + // prevent warning about unused argument e + PJ_UNUSED_ARG(e); + + // check call state + if (ci.state == PJSIP_INV_STATE_CONFIRMED) + { + log_message("Call confirmed.\n"); + + call_confirmed = 1; + + // ensure that message is played from start + if (play_id != PJSUA_INVALID_ID) + { + pjmedia_wav_player_port_set_pos(play_port, 0); + } + } + if (ci.state == PJSIP_INV_STATE_DISCONNECTED) + { + log_message("Call disconnected.\n"); + + // exit app if call is finished/disconnected + app_exit(); + } +} + +// handler for media-finished-events +static pj_status_t on_media_finished(pjmedia_port *media_port, void *user_data) +{ + PJ_UNUSED_ARG(media_port); + PJ_UNUSED_ARG(user_data); + + if (call_confirmed) + { + // count repetition + media_counter++; + + // exit app if repetition limit is reached + if (app_cfg.repetition_limit <= media_counter) + { + app_exit(); + } + } + + pj_status_t status; + return status; +} + +// handler for "break-in-key"-events (e.g. ctrl+c) +static void signal_handler(int signal) +{ + // exit app + app_exit(); +} + +// clean application exit +static void app_exit() +{ + if (!app_exiting) + { + app_exiting = 1; + log_message("Stopping application ... "); + + // check if player/recorder is active and stop them + if (play_id != -1) pjsua_player_destroy(play_id); + if (rec_id != -1) pjsua_recorder_destroy(rec_id); + + // hangup open calls and stop pjsua + pjsua_call_hangup_all(); + pjsua_destroy(); + + log_message("Done.\n"); + + exit(0); + } +} + +// display error and exit application +static void error_exit(const char *title, pj_status_t status) +{ + if (!app_exiting) + { + app_exiting = 1; + + pjsua_perror("SIP Call", title, status); + + // check if player/recorder is active and stop them + if (play_id != -1) pjsua_player_destroy(play_id); + if (rec_id != -1) pjsua_recorder_destroy(rec_id); + + // hangup open calls and stop pjsua + pjsua_call_hangup_all(); + pjsua_destroy(); + + exit(1); + } +} \ No newline at end of file diff --git a/tools/c/sip-tools/sipserv-ctrl.sh b/tools/c/sip-tools/sipserv-ctrl.sh new file mode 100644 index 0000000..c61dbf8 --- /dev/null +++ b/tools/c/sip-tools/sipserv-ctrl.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# +#================================================================================= +# Name : sipserv-ctrl.sh +# Version : 0.1 +# +# Copyright (C) 2012 by Andre Wussow, 2012, desk@binerry.de +# +# Description : +# Sample Script for controlling sipserv. +# +# Dependencies: +# - sipcall +# +# References : +# http://binerry.de/post/29180946733/raspberry-pi-caller-and-answering-machine +# +#================================================================================ +#This script is free software; you can redistribute it and/or +#modify it under the terms of the GNU Lesser General Public +#License as published by the Free Software Foundation; either +#version 2.1 of the License, or (at your option) any later version. +# +#This script is distributed in the hope that it will be useful, +#but WITHOUT ANY WARRANTY; without even the implied warranty of +#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +#Lesser General Public License for more details. +#================================================================================ + +# define config-file +serv_cfg="sipserv.cfg"; + +if [ $1 = "start" ]; then + # start sipserv in background + $(./sipserv -s 1 --config-file $serv_cfg > /dev/null &); + echo "sipserv started."; +fi + +if [ $1 = "stop" ]; then + # stop sipserv + pid="$(ps aux | awk '/[s]ipserv/ {print $2}' | head -1)"; + $(kill $pid > /dev/null); + echo "sipserv stopped."; +fi \ No newline at end of file diff --git a/tools/c/sip-tools/sipserv-sample.cfg b/tools/c/sip-tools/sipserv-sample.cfg new file mode 100644 index 0000000..ef7f56e --- /dev/null +++ b/tools/c/sip-tools/sipserv-sample.cfg @@ -0,0 +1,65 @@ +# SIP account data +sd=samplesip.com +su=12345678 +sp=XXXXXX + +# disable call recording +rc=0 + +# intro message +tts=Hello, this is raspberry pi and this are your options: + +# dtmf configuration +dtmf.1.active=1 +dtmf.1.description=Get average load +dtmf.1.tts-intro=Press 1 to get the average system load within last 5 minutes. +dtmf.1.tts-answer=The average load within last 5 minutes is %s. +dtmf.1.cmd=uptime |awk -F'average: ' '{print $2}' |awk -F', ' '{print $2}' + +dtmf.2.active=1 +dtmf.2.description=Get free memory +dtmf.2.tts-intro=Press 2 to get the actual free memory. +dtmf.2.tts-answer=The currently free memory is %s megabytes. +dtmf.2.cmd=free |awk '/^Mem:/{print ($2/1024)}' + +dtmf.3.active=0 +dtmf.3.description= +dtmf.3.tts-intro= +dtmf.3.tts-answer= +dtmf.3.cmd= + +dtmf.4.active=0 +dtmf.4.description= +dtmf.4.tts-intro= +dtmf.4.tts-answer= +dtmf.4.cmd= + +dtmf.5.active=0 +dtmf.5.description= +dtmf.5.tts-intro= +dtmf.5.tts-answer= +dtmf.5.cmd= + +dtmf.6.active=0 +dtmf.6.description= +dtmf.6.tts-intro= +dtmf.6.tts-answer= +dtmf.6.cmd= + +dtmf.7.active=0 +dtmf.7.description= +dtmf.7.tts-intro= +dtmf.7.tts-answer= +dtmf.7.cmd= + +dtmf.8.active=0 +dtmf.8.description= +dtmf.8.tts-intro= +dtmf.8.tts-answer= +dtmf.8.cmd= + +dtmf.9.active=0 +dtmf.9.description= +dtmf.9.tts-intro= +dtmf.9.tts-answer= +dtmf.9.cmd= \ No newline at end of file diff --git a/tools/c/sip-tools/sipserv.c b/tools/c/sip-tools/sipserv.c new file mode 100644 index 0000000..0eab6b8 --- /dev/null +++ b/tools/c/sip-tools/sipserv.c @@ -0,0 +1,823 @@ +/* +================================================================================= + Name : sipserv.c + Version : 0.1 + + Copyright (C) 2012 by Andre Wussow, 2012, desk@binerry.de + + Description : + Tool for automated, flexible answered calls over SIP/VOIP with PJSUA library and eSpeak. + + Dependencies: + - PJSUA API (PJSIP) + - eSpeak + + References : + http://www.pjsip.org/ + http://www.pjsip.org/docs/latest/pjsip/docs/html/group__PJSUA__LIB.htm + http://espeak.sourceforge.net/ + http://binerry.de/post/29180946733/raspberry-pi-caller-and-answering-machine + +================================================================================ +This tool is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This tool is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. +================================================================================ +*/ + +// definition of endianess (e.g. needed on raspberry pi) +#define PJ_IS_LITTLE_ENDIAN 1 +#define PJ_IS_BIG_ENDIAN 0 + +// includes +#include +#include +#include +#include +#include +#include + +// some espeak options +#define ESPEAK_LANGUAGE "en" +#define ESPEAK_AMPLITUDE 100 +#define ESPEAK_CAPITALS_PITCH 20 +#define ESPEAK_SPEED 125 +#define ESPEAK_PITCH 75 + +// disable pjsua logging +#define PJSUA_LOG_LEVEL 0 + +// define max supported dtmf settings +#define MAX_DTMF_SETTINGS 9 + +// struct for app dtmf settings +struct dtmf_config { + int id; + int active; + int processing_active; + char *description; + char *tts_intro; + char *tts_answer; + char *cmd; +}; + +// struct for app configuration settings +struct app_config { + char *sip_domain; + char *sip_user; + char *sip_password; + int record_calls; + int silent_mode; + char *tts; + char *log_file; + struct dtmf_config dtmf_cfg[MAX_DTMF_SETTINGS]; +} app_cfg; + +// global holder vars for further app arguments +char *tts_file = "play.wav"; +char *tts_answer_file = "ans.wav"; +char *rec_ans_file = "rec.wav"; + +// global helper vars +int call_confirmed = 0; +int media_counter = 0; +int app_exiting = 0; + +// global vars for pjsua +pjsua_acc_id acc_id; +pjsua_player_id play_id = PJSUA_INVALID_ID; +pjmedia_port *play_port; +pjsua_recorder_id rec_id = PJSUA_INVALID_ID; +pjsua_call_id current_call = PJSUA_INVALID_ID; + +// header of helper-methods +static void create_player(pjsua_call_id, char *); +static void create_recorder(pjsua_call_info); +static void log_message(char *); +static void parse_config_file(char *); +static void register_sip(void); +static void setup_sip(void); +static int synthesize_speech(char *, char *); +static void usage(int); +static int try_get_argument(int, char *, char **, int, char *[]); + +// header of callback-methods +static void on_incoming_call(pjsua_acc_id, pjsua_call_id, pjsip_rx_data *); +static void on_call_media_state(pjsua_call_id); +static void on_call_state(pjsua_call_id, pjsip_event *); +static void on_dtmf_digit(pjsua_call_id, int); +static void signal_handler(int); +static char *trim_string(char *); + +// header of app-control-methods +static void app_exit(); +static void error_exit(const char *, pj_status_t); + +// main application +int main(int argc, char *argv[]) +{ + // first set some default values + app_cfg.record_calls = 0; + app_cfg.silent_mode = 0; + + // init dtmf settings (dtmf 0 is reserved for exit call) + int i; + for (i = 0; i < MAX_DTMF_SETTINGS; i++) + { + struct dtmf_config *d_cfg = &app_cfg.dtmf_cfg[i]; + d_cfg->id = i+1; + d_cfg->active = 0; + d_cfg->processing_active = 0; + } + + // parse arguments + if (argc > 1) + { + int arg; + for( arg = 1; arg < argc; arg+=2 ) + { + // check if usage info needs to be displayed + if (!strcasecmp(argv[arg], "--help")) + { + // display usage info and exit app + usage(0); + exit(0); + } + + // check for config file location + if (!strcasecmp(argv[arg], "--config-file")) + { + if (argc >= (arg+1)) + { + app_cfg.log_file = argv[arg+1]; + } + continue; + } + + // check for silent mode option + char *s; + try_get_argument(arg, "-s", &s, argc, argv); + if (!strcasecmp(s, "1")) + { + app_cfg.silent_mode = 1; + continue; + } + } + } + + if (!app_cfg.log_file) + { + // too few arguments specified - display usage info and exit app + usage(1); + exit(1); + } + + // read app configuration from config file + parse_config_file(app_cfg.log_file); + + if (!app_cfg.sip_domain || !app_cfg.sip_user || !app_cfg.sip_password) + { + // too few arguments specified - display usage info and exit app + usage(1); + exit(1); + } + + // print infos + log_message("SIP Call - Simple TTS/DTMF-based answering machine\n"); + log_message("==================================================\n"); + + // register signal handler for break-in-keys (e.g. ctrl+c) + signal(SIGINT, signal_handler); + signal(SIGKILL, signal_handler); + + // generate texts + log_message("Generating texts ... "); + + char tts_buffer[1024]; + strcpy(tts_buffer, app_cfg.tts); + strcat(tts_buffer, " "); + + for (i = 0; i < MAX_DTMF_SETTINGS; i++) + { + struct dtmf_config *d_cfg = &app_cfg.dtmf_cfg[i]; + + if (d_cfg->active == 1) + { + strcat(tts_buffer, d_cfg->tts_intro); + strcat(tts_buffer, " "); + } + } + + log_message("Done.\n"); + + // synthesizing speech + log_message("Synthesizing speech ... "); + + int synth_status = -1; + synth_status = synthesize_speech(tts_buffer, tts_file); + if (synth_status != 0) error_exit("Error while creating phone text", synth_status); + log_message("Done.\n"); + + // setup up sip library pjsua + setup_sip(); + + // create account and register to sip server + register_sip(); + + // app loop + for (;;) { } + + // exit app + app_exit(); + + return 0; +} + +// helper for displaying usage infos +static void usage(int error) +{ + if (error == 1) + { + puts("Error, to few arguments."); + puts (""); + } + puts ("Usage:"); + puts (" sipserv [options]"); + puts (""); + puts ("Commandline:"); + puts ("Mandatory options:"); + puts (" --config-file=string Set config file"); + puts (""); + puts ("Optional options:"); + puts (" -s=int Silent mode (hide info messages) (0/1)"); + puts (""); + puts (""); + puts ("Config file:"); + puts ("Mandatory options:"); + puts (" sd=string Set sip provider domain."); + puts (" su=string Set sip username."); + puts (" sp=string Set sip password."); + puts (""); + puts (" and at least one dtmf configuration (X = dtmf-key index):"); + puts (" dtmf.X.active=int Set dtmf-setting active (0/1)."); + puts (" dtmf.X.description=string Set description."); + puts (" dtmf.X.tts-intro=string Set tts intro."); + puts (" dtmf.X.tts-answer=string Set tts answer."); + puts (" dtmf.X.cmd=string Set dtmf command."); + puts (""); + puts ("Optional options:"); + puts (" rc=int Record call (0/1)"); + puts (""); + + fflush(stdout); +} + +// helper for parsing command-line-argument +static int try_get_argument(int arg, char *arg_id, char **arg_val, int argc, char *argv[]) +{ + int found = 0; + + // check if actual argument is searched argument + if (!strcasecmp(argv[arg], arg_id)) + { + // check if actual argument has a value + if (argc >= (arg+1)) + { + // set value + *arg_val = argv[arg+1]; + found = 1; + } + } + return found; +} + +// helper for parsing config file +static void parse_config_file(char *cfg_file) +{ + // open config file + char line[200]; + FILE *file = fopen(cfg_file, "r"); + + if (file!=NULL) + { + // start parsing file + while(fgets(line, 200, file) != NULL) + { + char *arg, *val; + + // ignore comments and just new lines + if(line[0] == '#') continue; + if(line[0] == '\n') continue; + + // split string at '='-char + arg = strtok(line, "="); + if (arg == NULL) continue; + val = strtok(NULL, "="); + + // check for new line char and remove it + char *nl_check; + nl_check = strstr (val, "\n"); + if (nl_check != NULL) strncpy(nl_check, " ", 1); + + // remove trailing spaces + + + // duplicate string for having own instance of it + char *arg_val = strdup(val); + + // check for sip domain argument + if (!strcasecmp(arg, "sd")) + { + app_cfg.sip_domain = trim_string(arg_val); + continue; + } + + // check for sip user argument + if (!strcasecmp(arg, "su")) + { + app_cfg.sip_user = trim_string(arg_val); + continue; + } + + // check for sip domain argument + if (!strcasecmp(arg, "sp")) + { + app_cfg.sip_password = trim_string(arg_val); + continue; + } + + // check for record calls argument + if (!strcasecmp(arg, "rc")) + { + app_cfg.record_calls = atoi(val); + continue; + } + + // check for silent mode argument + if (!strcasecmp(arg, "s")) + { + app_cfg.silent_mode = atoi(val); + continue; + } + + // check for tts intro + if (!strcasecmp(arg, "tts")) + { + app_cfg.tts = arg_val; + continue; + } + + // check for a dtmf argument + char dtmf_id[1]; + char dtmf_setting[25]; + if(sscanf(arg, "dtmf.%1[^.].%s", dtmf_id, dtmf_setting) == 2) + { + // parse dtmf id (key) + int d_id; + d_id = atoi(dtmf_id); + + // check if actual dtmf id blasts maxium settings + if (d_id >= MAX_DTMF_SETTINGS) continue; + + // get pointer to actual dtmf_cfg entry + struct dtmf_config *d_cfg = &app_cfg.dtmf_cfg[d_id-1]; + + // check for dtmf active setting + if (!strcasecmp(dtmf_setting, "active")) + { + d_cfg->active = atoi(val); + continue; + } + + // check for dtmf description setting + if (!strcasecmp(dtmf_setting, "description")) + { + d_cfg->description = arg_val; + continue; + } + + // check for dtmf tts intro setting + if (!strcasecmp(dtmf_setting, "tts-intro")) + { + d_cfg->tts_intro = arg_val; + continue; + } + + // check for dtmf tts answer setting + if (!strcasecmp(dtmf_setting, "tts-answer")) + { + d_cfg->tts_answer = arg_val; + continue; + } + + // check for dtmf cmd setting + if (!strcasecmp(dtmf_setting, "cmd")) + { + d_cfg->cmd = arg_val; + continue; + } + } + + // write warning if unknown configuration setting is found + char warning[200]; + sprintf(warning, "Warning: Unknown configuration with arg '%s' and val '%s'\n", arg, val); + log_message(warning); + } + } + else + { + // return if config file not found + log_message("Error while parsing config file: Not found.\n"); + exit(1); + } +} + +// helper for removing leading and trailing strings (source taken from kernel source, lib/string.c) +static char *trim_string(char *str) +{ + while (isspace(*str)) ++str; + + char *s = (char *)str; + + size_t size; + char *end; + + size = strlen(s); + if (!size) return s; + + end = s + size - 1; + while (end >= s && isspace(*end)) end--; + *(end + 1) = '\0'; + + return s; +} + + +// helper for logging messages to console (disabled if silent mode is active) +static void log_message(char *message) +{ + if (!app_cfg.silent_mode) + { + fprintf(stderr, message); + } +} + +// helper for setting up sip library pjsua +static void setup_sip(void) +{ + pj_status_t status; + + log_message("Setting up pjsua ... "); + + // create pjsua + status = pjsua_create(); + if (status != PJ_SUCCESS) error_exit("Error in pjsua_create()", status); + + // configure pjsua + pjsua_config cfg; + pjsua_config_default(&cfg); + + // enable just 1 simultaneous call + cfg.max_calls = 1; + + // callback configuration + cfg.cb.on_incoming_call = &on_incoming_call; + cfg.cb.on_call_media_state = &on_call_media_state; + cfg.cb.on_call_state = &on_call_state; + cfg.cb.on_dtmf_digit = &on_dtmf_digit; + + // logging configuration + pjsua_logging_config log_cfg; + pjsua_logging_config_default(&log_cfg); + log_cfg.console_level = PJSUA_LOG_LEVEL; + + // media configuration + pjsua_media_config media_cfg; + pjsua_media_config_default(&media_cfg); + media_cfg.snd_play_latency = 100; + media_cfg.clock_rate = 8000; + media_cfg.snd_clock_rate = 8000; + media_cfg.quality = 10; + + // initialize pjsua + status = pjsua_init(&cfg, &log_cfg, &media_cfg); + if (status != PJ_SUCCESS) error_exit("Error in pjsua_init()", status); + + // add udp transport + pjsua_transport_config udpcfg; + pjsua_transport_config_default(&udpcfg); + + udpcfg.port = 5060; + status = pjsua_transport_create(PJSIP_TRANSPORT_UDP, &udpcfg, NULL); + if (status != PJ_SUCCESS) error_exit("Error creating transport", status); + + // initialization is done, start pjsua + status = pjsua_start(); + if (status != PJ_SUCCESS) error_exit("Error starting pjsua", status); + + // disable sound - use null sound device + status = pjsua_set_null_snd_dev(); + if (status != PJ_SUCCESS) error_exit("Error disabling audio", status); + + log_message("Done.\n"); +} + +// helper for creating and registering sip-account +static void register_sip(void) +{ + pj_status_t status; + + log_message("Registering account ... "); + + // prepare account configuration + pjsua_acc_config cfg; + pjsua_acc_config_default(&cfg); + + // build sip-user-url + char sip_user_url[40]; + sprintf(sip_user_url, "sip:%s@%s", app_cfg.sip_user, app_cfg.sip_domain); + + // build sip-provder-url + char sip_provider_url[40]; + sprintf(sip_provider_url, "sip:%s", app_cfg.sip_domain); + + // create and define account + cfg.id = pj_str(sip_user_url); + cfg.reg_uri = pj_str(sip_provider_url); + cfg.cred_count = 1; + cfg.cred_info[0].realm = pj_str(app_cfg.sip_domain); + cfg.cred_info[0].scheme = pj_str("digest"); + cfg.cred_info[0].username = pj_str(app_cfg.sip_user); + cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD; + cfg.cred_info[0].data = pj_str(app_cfg.sip_password); + + // add account + status = pjsua_acc_add(&cfg, PJ_TRUE, &acc_id); + if (status != PJ_SUCCESS) error_exit("Error adding account", status); + + log_message("Done.\n"); +} + +// helper for creating call-media-player +static void create_player(pjsua_call_id call_id, char *file) +{ + // get call infos + pjsua_call_info ci; + pjsua_call_get_info(call_id, &ci); + + pj_str_t name; + pj_status_t status = PJ_ENOTFOUND; + + log_message("Creating player ... "); + + // create player for playback media + status = pjsua_player_create(pj_cstr(&name, file), PJMEDIA_FILE_NO_LOOP, &play_id); + if (status != PJ_SUCCESS) error_exit("Error playing sound-playback", status); + + // connect active call to media player + pjsua_conf_connect(pjsua_player_get_conf_port(play_id), ci.conf_slot); + + // get media port (play_port) from play_id + status = pjsua_player_get_port(play_id, &play_port); + if (status != PJ_SUCCESS) error_exit("Error getting sound player port", status); + + log_message("Done.\n"); +} + +// helper for creating call-recorder +static void create_recorder(pjsua_call_info ci) +{ + // specify target file + pj_str_t rec_file = pj_str(rec_ans_file); + pj_status_t status = PJ_ENOTFOUND; + + log_message("Creating recorder ... "); + + // Create recorder for call + status = pjsua_recorder_create(&rec_file, 0, NULL, 0, 0, &rec_id); + if (status != PJ_SUCCESS) error_exit("Error recording answer", status); + + // connect active call to call recorder + pjsua_conf_port_id rec_port = pjsua_recorder_get_conf_port(rec_id); + pjsua_conf_connect(ci.conf_slot, rec_port); + + log_message("Done.\n"); +} + +// synthesize speech / create message via espeak +static int synthesize_speech(char *speech, char *file) +{ + int speech_status = -1; + + char speech_command[1024]; + sprintf(speech_command, "espeak -v%s -a%i -k%i -s%i -p%i -w %s '%s'", ESPEAK_LANGUAGE, ESPEAK_AMPLITUDE, ESPEAK_CAPITALS_PITCH, ESPEAK_SPEED, ESPEAK_PITCH, file, speech); + speech_status = system(speech_command); + + return speech_status; +} + +// handler for incoming-call-events +static void on_incoming_call(pjsua_acc_id acc_id, pjsua_call_id call_id, pjsip_rx_data *rdata) +{ + // get call infos + pjsua_call_info ci; + pjsua_call_get_info(call_id, &ci); + + PJ_UNUSED_ARG(acc_id); + PJ_UNUSED_ARG(rdata); + + current_call = call_id; + + // log call info + char info[100]; + sprintf(info, "Incoming call from %s\n", ci.remote_info.ptr); + log_message(info); + + // automatically answer incoming call with 200 status/OK + pjsua_call_answer(call_id, 200, NULL, NULL); +} + +// handler for call-media-state-change-events +static void on_call_media_state(pjsua_call_id call_id) +{ + // get call infos + pjsua_call_info ci; + pjsua_call_get_info(call_id, &ci); + + pj_status_t status = PJ_ENOTFOUND; + + // check state if call is established/active + if (ci.media_status == PJSUA_CALL_MEDIA_ACTIVE) { + + log_message("Call media activated.\n"); + + // create and start media player + create_player(call_id, tts_file); + + // create and start call recorder + if (app_cfg.record_calls) + { + create_recorder(ci); + } + } +} + +// handler for call-state-change-events +static void on_call_state(pjsua_call_id call_id, pjsip_event *e) +{ + // get call infos + pjsua_call_info ci; + pjsua_call_get_info(call_id, &ci); + + // prevent warning about unused argument e + PJ_UNUSED_ARG(e); + + // check call state + if (ci.state == PJSIP_INV_STATE_CONFIRMED) + { + log_message("Call confirmed.\n"); + + call_confirmed = 1; + + // ensure that message is played from start + if (play_id != PJSUA_INVALID_ID) + { + pjmedia_wav_player_port_set_pos(play_port, 0); + } + } + if (ci.state == PJSIP_INV_STATE_DISCONNECTED) + { + log_message("Call disconnected.\n"); + + // disable player + if (play_id != -1) pjsua_player_destroy(play_id); + } +} + +// handler for dtmf-events +static void on_dtmf_digit(pjsua_call_id call_id, int digit) +{ + // get call infos + pjsua_call_info ci; + pjsua_call_get_info(call_id, &ci); + + // work on detected dtmf digit + int dtmf_key = digit - 48; + + char info[100]; + sprintf(info, "DTMF command detected: %i\n", dtmf_key); + log_message(info); + + struct dtmf_config *d_cfg = &app_cfg.dtmf_cfg[dtmf_key-1]; + if (d_cfg->processing_active == 0) + { + d_cfg->processing_active = 1; + + if (d_cfg->active == 1) + { + log_message("Active DTMF command found for received digit.\n"); + log_message("Creating answer ... "); + + int error = 0; + FILE *fp; + + fp = popen(d_cfg->cmd, "r"); + if (fp == NULL) { + error = 1; + log_message(" (Failed to run command) "); + } + + char result[20]; + if (!error) + { + if (fgets(result, sizeof(result)-1, fp) == NULL) + { + error = 1; + log_message(" (Failed to read result) "); + } + } + + if (!error) + { + if (play_id != -1) pjsua_player_destroy(play_id); + + char tts_buffer[200]; + sprintf(tts_buffer, d_cfg->tts_answer, result); + + int synth_status = -1; + synth_status = synthesize_speech(tts_buffer, tts_answer_file); + if (synth_status != 0) log_message(" (Failed to synthesize speech) "); + + create_player(call_id, tts_answer_file); + } + + log_message("Done.\n"); + } + else + { + log_message("No active DTMF command found for received digit.\n"); + } + + d_cfg->processing_active = 0; + } + else + { + log_message("DTMF command dropped - state is actual processing.\n"); + } +} + +// handler for "break-in-key"-events (e.g. ctrl+c) +static void signal_handler(int signal) +{ + // exit app + app_exit(); +} + +// clean application exit +static void app_exit() +{ + if (!app_exiting) + { + app_exiting = 1; + log_message("Stopping application ... "); + + // check if player/recorder is active and stop them + if (play_id != -1) pjsua_player_destroy(play_id); + if (rec_id != -1) pjsua_recorder_destroy(rec_id); + + // hangup open calls and stop pjsua + pjsua_call_hangup_all(); + pjsua_destroy(); + + log_message("Done.\n"); + + exit(0); + } +} + +// display error and exit application +static void error_exit(const char *title, pj_status_t status) +{ + if (!app_exiting) + { + app_exiting = 1; + + pjsua_perror("SIP Call", title, status); + + // check if player/recorder is active and stop them + if (play_id != -1) pjsua_player_destroy(play_id); + if (rec_id != -1) pjsua_recorder_destroy(rec_id); + + // hangup open calls and stop pjsua + pjsua_call_hangup_all(); + pjsua_destroy(); + + exit(1); + } +} \ No newline at end of file