From aec284f125da630566a51438d4f2808cd1ee8270 Mon Sep 17 00:00:00 2001 From: Page Asgardius Date: Fri, 2 Jul 2021 07:59:34 -0700 Subject: [PATCH] server migration --- README.md | 17 + libraries/c/PCD8544/PCD8544.c | 847 ++++++++++++++++++ libraries/c/PCD8544/PCD8544.h | 86 ++ libraries/c/PCD8544/README.md | 23 + libraries/c/PCD8544/samples/PCD8544.h | 86 ++ libraries/c/PCD8544/samples/pcd8544_rpi.c | 219 +++++ libraries/c/PCD8544/samples/pcd8544_test.c | 155 ++++ libraries/c/PCD8544/samples/pcd8544_test2.c | 129 +++ prototyping/fritzing/parts/board/README.md | 24 + .../fritzing/parts/board/Raspberry Pi.fzpz | Bin 0 -> 28073 bytes .../controller_raspberry_pi_breadboard.svg | 272 ++++++ .../svgs/controller_raspberry_pi_logo.svg | 207 +++++ .../svgs/controller_raspberry_pi_pcb.svg | 221 +++++ .../controller_raspberry_pi_schematic.svg | 671 ++++++++++++++ .../fritzing/projects/i2c-shifter/README.md | 24 + .../projects/i2c-shifter/i2c_shifter.fzz | Bin 0 -> 25130 bytes .../Arduino/I2CSlave/Commander.cpp | 65 ++ .../i2c-arduino/Arduino/I2CSlave/Commander.h | 56 ++ .../i2c-arduino/Arduino/I2CSlave/I2CSlave.ino | 227 +++++ snippets/c/i2c-arduino/README.md | 22 + snippets/c/i2c-arduino/i2c-arduino.c | 128 +++ snippets/c/i2c/rtc_ds1307.c | 106 +++ snippets/c/printtest/ip.c | 34 + snippets/c/printtest/time.c | 45 + snippets/c/watchdog/Makefile | 4 + snippets/c/watchdog/wdt_test.c | 77 ++ tools/c/sip-tools/Makefile | 11 + tools/c/sip-tools/README.md | 85 ++ tools/c/sip-tools/sipcall-sample.sh | 58 ++ tools/c/sip-tools/sipcall.c | 581 ++++++++++++ tools/c/sip-tools/sipserv-ctrl.sh | 44 + tools/c/sip-tools/sipserv-sample.cfg | 65 ++ tools/c/sip-tools/sipserv.c | 823 +++++++++++++++++ 33 files changed, 5412 insertions(+) create mode 100644 README.md create mode 100644 libraries/c/PCD8544/PCD8544.c create mode 100644 libraries/c/PCD8544/PCD8544.h create mode 100644 libraries/c/PCD8544/README.md create mode 100644 libraries/c/PCD8544/samples/PCD8544.h create mode 100644 libraries/c/PCD8544/samples/pcd8544_rpi.c create mode 100644 libraries/c/PCD8544/samples/pcd8544_test.c create mode 100644 libraries/c/PCD8544/samples/pcd8544_test2.c create mode 100644 prototyping/fritzing/parts/board/README.md create mode 100644 prototyping/fritzing/parts/board/Raspberry Pi.fzpz create mode 100644 prototyping/fritzing/parts/board/svgs/controller_raspberry_pi_breadboard.svg create mode 100644 prototyping/fritzing/parts/board/svgs/controller_raspberry_pi_logo.svg create mode 100644 prototyping/fritzing/parts/board/svgs/controller_raspberry_pi_pcb.svg create mode 100644 prototyping/fritzing/parts/board/svgs/controller_raspberry_pi_schematic.svg create mode 100644 prototyping/fritzing/projects/i2c-shifter/README.md create mode 100644 prototyping/fritzing/projects/i2c-shifter/i2c_shifter.fzz create mode 100644 snippets/c/i2c-arduino/Arduino/I2CSlave/Commander.cpp create mode 100644 snippets/c/i2c-arduino/Arduino/I2CSlave/Commander.h create mode 100644 snippets/c/i2c-arduino/Arduino/I2CSlave/I2CSlave.ino create mode 100644 snippets/c/i2c-arduino/README.md create mode 100644 snippets/c/i2c-arduino/i2c-arduino.c create mode 100644 snippets/c/i2c/rtc_ds1307.c create mode 100644 snippets/c/printtest/ip.c create mode 100644 snippets/c/printtest/time.c create mode 100644 snippets/c/watchdog/Makefile create mode 100644 snippets/c/watchdog/wdt_test.c create mode 100644 tools/c/sip-tools/Makefile create mode 100644 tools/c/sip-tools/README.md create mode 100644 tools/c/sip-tools/sipcall-sample.sh create mode 100644 tools/c/sip-tools/sipcall.c create mode 100644 tools/c/sip-tools/sipserv-ctrl.sh create mode 100644 tools/c/sip-tools/sipserv-sample.cfg create mode 100644 tools/c/sip-tools/sipserv.c 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 0000000000000000000000000000000000000000..01543e5f0748de6c412d61216b00e60a11e5a38c GIT binary patch literal 28073 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 P(4TwBr@3C*{?qzD;t$id literal 0 HcmV?d00001 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 0000000000000000000000000000000000000000..7cc22b7c3a04080637405825c514cf6c226824b3 GIT binary patch literal 25130 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 literal 0 HcmV?d00001 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