From 8bb3cfb2e14214ae19e8531c989d1e81c9660614 Mon Sep 17 00:00:00 2001 From: Olivier Date: Wed, 18 Jan 2017 21:57:07 +0100 Subject: [PATCH] MySensors 2.1.1 release (#752) * Bump version to 2.2.0-beta (#713) * OTA: Add incoming FW block check (#718) * Linux: Add support for SPIDEV (#734) RPi and Linux refactor. Add GPIO Sysfs for GPIO operations. Update configure script. Fix some cppcheck warnings. Add serial emulation that prints to stdout. Fix some file headers. * Fix getControllerConfig() (#737) * Rename MyHwATmega328 to MyHwAVR (#738) * AVR: Restrict fast pin function use (#739) * Fix signing presentation bug (#740) * Consolidate open PRs for bugfix release (#741) * Revert "Bump version to 2.2.0-beta" (#744) * Merge Master into Dev (#745) * Fix spi flash error when compiling in Arduino IDE 1.6.6 * Bump minor version * Fixed "invalid suffix on literal" warning * Fix addressing bug in _doSign bitfield * Make sure nodes not supporting signing informs GW A node that does not support signing, still needs to inform the gateway about this to make sure the gateway carries a valid signing requirement table when a node Id that was requiering signing stops doing this. This fixes #286. * Prevent SecureActuator from accepting ACKs as commands As ACKs are not currently signed, allowing ACKs as commands is a considerable security hole for this sketch. This is now resolved. * Backport of bugfix (#259) in repeaters when forwarding signed messages * Bumped version to 1.5.2 * Corrected doSign variable name (was _doSign) * Bumped version to 1.5.3 * Add NULL termination to payloads Messages addressed to "this" node, will have a null char appended to the payload after message verification is done, because some "getters" assume the message being a string. * MySensors 2.1.1 release --- Makefile | 16 + MyConfig.h | 6 +- MySensors.h | 8 +- README.md | 2 +- configure | 82 +++-- core/{MyHwATMega328.cpp => MyHwAVR.cpp} | 2 +- core/{MyHwATMega328.h => MyHwAVR.h} | 6 +- core/MyHwLinuxGeneric.cpp | 17 +- core/MyHwLinuxGeneric.h | 13 +- core/MyHwRPi.cpp | 146 --------- core/MyIndication.h | 1 + core/MyMainLinux.cpp | 30 +- core/MyOTAFirmwareUpdate.cpp | 17 +- core/MyOTAFirmwareUpdate.h | 1 + core/MySensorsCore.cpp | 2 +- core/MySigning.cpp | 39 +-- core/Version.h | 4 +- .../AVR/DigitalWriteFast/digitalWriteFast.h | 79 +---- drivers/{RPi => BCM}/SPI.cpp | 11 +- drivers/{RPi => BCM}/SPI.h | 114 ++++--- drivers/{RPi => BCM}/Wire.cpp | 0 drivers/{RPi => BCM}/Wire.h | 1 + drivers/Linux/Arduino.h | 43 ++- drivers/Linux/EthernetClient.cpp | 9 +- drivers/Linux/EthernetClient.h | 14 +- drivers/Linux/EthernetServer.cpp | 8 +- drivers/Linux/EthernetServer.h | 32 +- drivers/Linux/GPIO.cpp | 211 +++++++++++++ drivers/Linux/GPIO.h | 91 ++++++ drivers/Linux/IPAddress.h | 4 +- drivers/Linux/Print.cpp | 4 +- drivers/Linux/SerialPort.cpp | 14 +- drivers/Linux/SerialPort.h | 6 +- drivers/Linux/SerialSimulator.cpp | 56 ++++ drivers/Linux/SerialSimulator.h | 76 +++++ drivers/Linux/SoftEeprom.cpp | 8 +- drivers/Linux/SoftEeprom.h | 18 +- drivers/Linux/Stream.h | 1 + drivers/Linux/compatibility.cpp | 30 +- .../{RPi/rpi_util.cpp => Linux/interrupt.cpp} | 158 +++------- core/MyHwRPi.h => drivers/Linux/interrupt.h | 52 ++-- drivers/Linux/log.c | 19 ++ drivers/Linux/log.h | 19 ++ drivers/RF24/RF24.cpp | 4 +- drivers/RF24/RF24.h | 2 +- drivers/RFM95/RFM95.cpp | 4 +- drivers/RPi/RPi.cpp | 127 ++++++++ drivers/RPi/RPi.h | 89 ++++++ drivers/RPi/piHiPri.c | 49 --- drivers/RPi/rpi_util.h | 76 ----- drivers/SPIDEV/SPI.cpp | 289 ++++++++++++++++++ drivers/SPIDEV/SPI.h | 206 +++++++++++++ drivers/SPIFlash/SPIFlash.cpp | 6 +- examples/MockMySensors/MockMySensors.ino | 2 +- examples/PingPongSensor/PingPongSensor.ino | 6 +- examples_linux/mysgw.cpp | 6 +- library.json | 20 +- library.properties | 2 +- .../ota_firmware_update_nrf24.ino | 26 ++ 59 files changed, 1665 insertions(+), 719 deletions(-) rename core/{MyHwATMega328.cpp => MyHwAVR.cpp} (99%) rename core/{MyHwATMega328.h => MyHwAVR.h} (98%) delete mode 100644 core/MyHwRPi.cpp rename drivers/{RPi => BCM}/SPI.cpp (90%) rename drivers/{RPi => BCM}/SPI.h (60%) rename drivers/{RPi => BCM}/Wire.cpp (100%) rename drivers/{RPi => BCM}/Wire.h (99%) create mode 100644 drivers/Linux/GPIO.cpp create mode 100644 drivers/Linux/GPIO.h create mode 100644 drivers/Linux/SerialSimulator.cpp create mode 100644 drivers/Linux/SerialSimulator.h rename drivers/{RPi/rpi_util.cpp => Linux/interrupt.cpp} (61%) rename core/MyHwRPi.h => drivers/Linux/interrupt.h (54%) create mode 100644 drivers/RPi/RPi.cpp create mode 100644 drivers/RPi/RPi.h delete mode 100644 drivers/RPi/piHiPri.c delete mode 100644 drivers/RPi/rpi_util.h create mode 100644 drivers/SPIDEV/SPI.cpp create mode 100644 drivers/SPIDEV/SPI.h create mode 100644 tests/Arduino/sketches/ota_firmware_update_nrf24/ota_firmware_update_nrf24.ino diff --git a/Makefile b/Makefile index 742dd82d0..a0a4bd997 100644 --- a/Makefile +++ b/Makefile @@ -34,6 +34,22 @@ GATEWAY_OBJECTS+=$(patsubst %.c,$(BUILDDIR)/%.o,$(RPI_C_SOURCES)) $(patsubst %.c INCLUDES+=-I./drivers/RPi endif +ifeq ($(SPI_DRIVER), BCM) +SPI_DRIVER_C_SOURCES=$(wildcard drivers/BCM/*.c) +SPI_DRIVER_CPP_SOURCES=$(wildcard drivers/BCM/*.cpp) +GATEWAY_OBJECTS+=$(patsubst %.c,$(BUILDDIR)/%.o,$(SPI_DRIVER_C_SOURCES)) $(patsubst %.cpp,$(BUILDDIR)/%.o,$(SPI_DRIVER_CPP_SOURCES)) + +INCLUDES+=-I./drivers/BCM +endif + +ifeq ($(SPI_DRIVER), SPIDEV) +SPI_DRIVER_C_SOURCES=$(wildcard drivers/SPIDEV/*.c) +SPI_DRIVER_CPP_SOURCES=$(wildcard drivers/SPIDEV/*.cpp) +GATEWAY_OBJECTS+=$(patsubst %.c,$(BUILDDIR)/%.o,$(SPI_DRIVER_C_SOURCES)) $(patsubst %.cpp,$(BUILDDIR)/%.o,$(SPI_DRIVER_CPP_SOURCES)) + +INCLUDES+=-I./drivers/SPIDEV +endif + # Gets include flags for library get_library_includes = $(if $(and $(wildcard $(1)/src), $(wildcard $(1)/library.properties)), \ -I$(1)/src, \ diff --git a/MyConfig.h b/MyConfig.h index 16f6da722..43ab089d0 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -903,12 +903,12 @@ #endif /** - * @def MY_IS_SERIAL_PTY + * @def MY_LINUX_IS_SERIAL_PTY * @brief Set serial as a pseudo terminal. * * Enable this if you need to connect to a controller running on the same device. */ -//#define MY_IS_SERIAL_PTY +//#define MY_LINUX_IS_SERIAL_PTY /** * @def MY_LINUX_SERIAL_PTY @@ -956,7 +956,7 @@ #define MY_NODE_LOCK_FEATURE #define MY_REPEATER_FEATURE #define MY_LINUX_SERIAL_GROUPNAME -#define MY_IS_SERIAL_PTY +#define MY_LINUX_IS_SERIAL_PTY #define MY_RFM95_ATC_MODE_DISABLED #define MY_RFM95_RST_PIN #endif diff --git a/MySensors.h b/MySensors.h index 3c5bf3b15..3073be7fa 100644 --- a/MySensors.h +++ b/MySensors.h @@ -62,16 +62,12 @@ #include "core/MyHwESP8266.cpp" #elif defined(ARDUINO_ARCH_AVR) #include "drivers/AVR/DigitalWriteFast/digitalWriteFast.h" -#include "core/MyHwATMega328.cpp" +#include "core/MyHwAVR.cpp" #elif defined(ARDUINO_ARCH_SAMD) #include "core/MyHwSAMD.cpp" #elif defined(__linux__) -#ifdef LINUX_ARCH_RASPBERRYPI -#include "core/MyHwRPi.cpp" -#else #include "core/MyHwLinuxGeneric.cpp" #endif -#endif // LEDS #if !defined(MY_DEFAULT_ERR_LED_PIN) && defined(MY_HW_ERR_LED_PIN) @@ -254,7 +250,7 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs #include "drivers/AVR/DigitalIO/DigitalIO.h" #endif -#if defined(MY_RADIO_NRF24) && defined(__linux__) && !defined(LINUX_ARCH_RASPBERRYPI) +#if defined(MY_RADIO_NRF24) && defined(__linux__) && !(defined(LINUX_SPI_BCM) || defined(LINUX_SPI_SPIDEV)) #error No support for nRF24 radio on this platform #endif diff --git a/README.md b/README.md index ee6593b32..f55491de1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -MySensors Library v2.1.0 +MySensors Library v2.1.1 Please visit www.mysensors.org for more information diff --git a/configure b/configure index 7fee365a8..30fe60828 100755 --- a/configure +++ b/configure @@ -11,6 +11,11 @@ Options: Help: -h, --help print this message +SPI driver options: + --spi-driver=[BCM|SPIDEV] + --spi-spidev-device= + Device path. [/dev/spidev0.0] + Building options: --soc=[BCM2835|BCM2836|AM33XX|A10|A13|A20|H3] SoC type to be used. [configure autodetected] @@ -58,6 +63,8 @@ MySensors options: --my-rf24-channel=<0-125> RF channel for the sensor net, 0-125. [76] --my-rf24-pa-level=[RF24_PA_MAX|RF24_PA_LOW] RF24 PA level. [RF24_PA_MAX] + --my-rf24-ce-pin= Pin number to use for rf24 Chip-Enable. + --my-rf24-cs-pin= Pin number to use for rf24 Chip-Select. --my-rf24-irq-pin= Pin number connected to nRF24L01 IRQ pin. --my-rf24-encryption-enabled Enables RF24 encryption. @@ -209,7 +216,7 @@ function gcc_cpu_flags { flags="-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard" ;; H3) - flags="-march=armv8-a -mtune=cortex-a53 -mfpu=neon-vfpv4 -mfloat-abi=hard" + flags="-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard" ;; *) flags="" @@ -224,7 +231,7 @@ transport_type=nrf24 signing=none signing_request_signatures=false -params="SOC CFLAGS CXXFLAGS CPPFLAGS LDFLAGS PREFIX CC CXX ARDUINO_LIB_DIR BUILDDIR BINDIR GATEWAY_DIR INIT_SYSTEM" +params="SOC CFLAGS CXXFLAGS CPPFLAGS LDFLAGS PREFIX CC CXX ARDUINO_LIB_DIR BUILDDIR BINDIR GATEWAY_DIR INIT_SYSTEM SPI_DRIVER" for opt do if [ "$opt" = "-h" ] || [ "$opt" = "--help" ]; then @@ -233,6 +240,12 @@ for opt do fi optarg="${opt#*=}" case "$opt" in + --spi-driver=*) + SPI_DRIVER="$optarg" + ;; + --spi-spidev-device=*) + CPPFLAGS="-DSPI_SPIDEV_DEVICE=\\\"${optarg}\\\" $CPPFLAGS" + ;; --soc=*) SOC="$optarg" ;; @@ -308,7 +321,7 @@ for opt do CPPFLAGS="-DMY_BAUD_RATE=${optarg} $CPPFLAGS" ;; --my-serial-is-pty*) - CPPFLAGS="-DMY_IS_SERIAL_PTY $CPPFLAGS" + CPPFLAGS="-DMY_LINUX_IS_SERIAL_PTY $CPPFLAGS" ;; --my-serial-pty=*) CPPFLAGS="-DMY_LINUX_SERIAL_PTY=\\\"${optarg}\\\" $CPPFLAGS" @@ -322,6 +335,12 @@ for opt do --my-rf24-pa-level=*) CPPFLAGS="-DMY_RF24_PA_LEVEL=${optarg} $CPPFLAGS" ;; + --my-rf24-ce-pin=*) + CPPFLAGS="-DMY_RF24_CE_PIN=${optarg} $CPPFLAGS" + ;; + --my-rf24-cs-pin=*) + CPPFLAGS="-DMY_RF24_CS_PIN=${optarg} $CPPFLAGS" + ;; --my-controller-url-address=*) CPPFLAGS="-DMY_CONTROLLER_URL_ADDRESS=\\\"${optarg}\\\" $CPPFLAGS" ;; @@ -406,7 +425,7 @@ if [ -z "${SOC}" ]; then SOC=${info[0]} TYPE=${info[1]} CPU=${info[2]} - echo "[OK] machine detected: SoC=${SOC}, Type=${TYPE}, CPU=${CPU}." + echo " [OK] machine detected: SoC=${SOC}, Type=${TYPE}, CPU=${CPU}." fi if [ -z "${CPUFLAGS}" ]; then @@ -415,6 +434,40 @@ fi if [[ $SOC == "BCM2835" || $SOC == "BCM2836" ]]; then CPPFLAGS="-DLINUX_ARCH_RASPBERRYPI $CPPFLAGS" +else + echo "[SECTION] Checking GPIO Sysfs." + if [[ $(eval 'ls /sys/class/gpio/export 2>/dev/null') ]]; then + echo " [OK] /sys/class/gpio/export found" + else + echo " [WARNING] /sys/class/gpio/export not found." + fi +fi + +if [ -z "${SPI_DRIVER}" ]; then + echo "[SECTION] Detecting SPI driver." + if [[ $SOC == "BCM2835" || $SOC == "BCM2836" ]]; then + SPI_DRIVER=BCM + elif [[ $(eval 'ls /dev/spidev* 2>/dev/null') ]]; then + SPI_DRIVER=SPIDEV + fi + if [ -n "${SPI_DRIVER}" ]; then + echo " [OK] SPI driver detected:${SPI_DRIVER}." + else + echo " [WARNING] No supported SPI driver detected." + fi +fi +if [ -n "${SPI_DRIVER}" ]; then + case ${SPI_DRIVER} in + BCM) + CPPFLAGS="-DLINUX_SPI_BCM $CPPFLAGS" + ;; + SPIDEV) + CPPFLAGS="-DLINUX_SPI_SPIDEV $CPPFLAGS" + ;; + *) + die "Unsupported SPI driver: ${SPI_DRIVER}." 1 + ;; + esac fi if [[ ${debug} == "enable" ]]; then @@ -431,9 +484,7 @@ elif [[ ${gateway_type} == "serial" ]]; then elif [[ ${gateway_type} == "mqtt" ]]; then CPPFLAGS="-DMY_GATEWAY_LINUX -DMY_GATEWAY_MQTT_CLIENT $CPPFLAGS" else - echo "Invalid gateway type." - echo "Aborting." - exit 1 + die "Invalid gateway type." 2 fi if [[ ${transport_type} == "none" ]]; then @@ -446,9 +497,7 @@ elif [[ ${transport_type} == "rs485" ]]; then elif [[ ${transport_type} == "rfm95" ]]; then CPPFLAGS="-DMY_RADIO_RFM95 $CPPFLAGS" else - echo "Invalid transport type." - echo "Aborting." - exit 1 + die "Invalid transport type." 3 fi if [[ ${signing} == "none" ]]; then @@ -460,24 +509,23 @@ elif [[ ${signing} == "software" ]]; then CPPFLAGS="-DMY_SIGNING_REQUEST_SIGNATURES $CPPFLAGS" fi else - echo "Invalid message signing option." - echo "Aborting." - exit 1 + die "Invalid message signing option." 4 fi LDFLAGS="-pthread $LDFLAGS" CPPFLAGS="$CPUFLAGS $CPPFLAGS" +echo "[SECTION] Detecting init system." if [ "${NO_INIT}" ]; then - echo "[OK] no init system chosen." + echo " [OK] no init system chosen." elif [ -x /usr/bin/systemctl ] || [ -x /bin/systemctl ]; then INIT_SYSTEM=systemd - echo "[OK] init system detected: systemd" + echo " [OK] init system detected: systemd." elif [ -f /etc/init.d/cron ] && [ ! -h /etc/init.d/cron ]; then INIT_SYSTEM=sysvinit - echo "[OK] init system detected: sysvinit" + echo " [OK] init system detected: sysvinit." else - echo "[FAILED] unknown init system" + echo " [FAILED] unknown init system." fi echo "[SECTION] Saving configuration." diff --git a/core/MyHwATMega328.cpp b/core/MyHwAVR.cpp similarity index 99% rename from core/MyHwATMega328.cpp rename to core/MyHwAVR.cpp index 50c2e5115..6e27c4bb1 100644 --- a/core/MyHwATMega328.cpp +++ b/core/MyHwAVR.cpp @@ -19,7 +19,7 @@ #ifdef ARDUINO_ARCH_AVR -#include "MyHwATMega328.h" +#include "MyHwAVR.h" #define INVALID_INTERRUPT_NUM (0xFFu) diff --git a/core/MyHwATMega328.h b/core/MyHwAVR.h similarity index 98% rename from core/MyHwATMega328.h rename to core/MyHwAVR.h index 7f120319b..6b157177b 100644 --- a/core/MyHwATMega328.h +++ b/core/MyHwAVR.h @@ -17,8 +17,8 @@ * version 2 as published by the Free Software Foundation. */ -#ifndef MyHwATMega328_h -#define MyHwATMega328_h +#ifndef MyHwAVR_h +#define MyHwAVR_h #include "MyHw.h" #include @@ -58,12 +58,10 @@ // Define these as macros to save valuable space - #define hwDigitalWrite(__pin, __value) digitalWriteFast(__pin, __value) #define hwDigitalRead(__pin) digitalReadFast(__pin) #define hwPinMode(__pin, __value) pinModeFast(__pin, __value) - #if defined(MY_DISABLED_SERIAL) #define hwInit() #else diff --git a/core/MyHwLinuxGeneric.cpp b/core/MyHwLinuxGeneric.cpp index e90b596a1..9e5f90076 100644 --- a/core/MyHwLinuxGeneric.cpp +++ b/core/MyHwLinuxGeneric.cpp @@ -28,8 +28,8 @@ static SoftEeprom eeprom = SoftEeprom(MY_LINUX_CONFIG_FILE, 1024); // ATMega328 void hwInit() { -#ifdef MY_GATEWAY_SERIAL MY_SERIALDEVICE.begin(MY_BAUD_RATE); +#ifdef MY_GATEWAY_SERIAL #ifdef MY_LINUX_SERIAL_GROUPNAME if (!MY_SERIALDEVICE.setGroupPerm(MY_LINUX_SERIAL_GROUPNAME)) { logError("Unable to change permission for serial port device.\n"); @@ -120,6 +120,21 @@ uint16_t hwFreeMem() } #endif +void hwDigitalWrite(uint8_t pin, uint8_t value) +{ + digitalWrite(pin, value); +} + +int hwDigitalRead(uint8_t pin) +{ + return digitalRead(pin); +} + +void hwPinMode(uint8_t pin, uint8_t mode) +{ + pinMode(pin, mode); +} + #ifdef MY_DEBUG void hwDebugPrint(const char *fmt, ...) { diff --git a/core/MyHwLinuxGeneric.h b/core/MyHwLinuxGeneric.h index 234156f78..acb21680a 100644 --- a/core/MyHwLinuxGeneric.h +++ b/core/MyHwLinuxGeneric.h @@ -24,12 +24,17 @@ #include #include "MyHw.h" #include "SerialPort.h" +#include "SerialSimulator.h" -#ifdef MY_IS_SERIAL_PTY +#ifdef MY_GATEWAY_SERIAL +#ifdef MY_LINUX_IS_SERIAL_PTY SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PTY, true); #else SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PORT); #endif +#else +SerialSimulator Serial = SerialSimulator(); +#endif #ifndef MY_SERIALDEVICE #define MY_SERIALDEVICE Serial @@ -39,9 +44,9 @@ SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PORT); #define hwWatchdogReset() #define hwReboot() -#define hwDigitalWrite(__pin, __value) _Pragma("GCC error \"Not supported on linux-generic\"") -#define hwDigitalRead(__pin) _Pragma("GCC error \"Not supported on linux-generic\"") -#define hwPinMode(__pin, __value) _Pragma("GCC error \"Not supported on linux-generic\"") +inline void hwDigitalWrite(uint8_t, uint8_t); +inline int hwDigitalRead(uint8_t); +inline void hwPinMode(uint8_t, uint8_t); void hwInit(); inline void hwReadConfigBlock(void* buf, void* addr, size_t length); diff --git a/core/MyHwRPi.cpp b/core/MyHwRPi.cpp deleted file mode 100644 index 989af5fa9..000000000 --- a/core/MyHwRPi.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/** - * The MySensors Arduino library handles the wireless radio link and protocol - * between your home built sensors/actuators and HA controller of choice. - * The sensors forms a self healing radio network with optional repeaters. Each - * repeater and gateway builds a routing tables in EEPROM which keeps track of the - * network topology allowing messages to be routed to nodes. - * - * Created by Henrik Ekblad - * Copyright (C) 2013-2016 Sensnology AB - * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors - * - * Documentation: http://www.mysensors.org - * Support Forum: http://forum.mysensors.org - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - */ - -#include "MyHwRPi.h" - -#include -#include -#include "SoftEeprom.h" - -static SoftEeprom eeprom = SoftEeprom(MY_LINUX_CONFIG_FILE, 1024); // ATMega328 has 1024 bytes - -void hwInit() -{ -#ifdef MY_GATEWAY_SERIAL - MY_SERIALDEVICE.begin(MY_BAUD_RATE); -#ifdef MY_LINUX_SERIAL_GROUPNAME - if (!MY_SERIALDEVICE.setGroupPerm(MY_LINUX_SERIAL_GROUPNAME)) { - logError("Unable to change permission for serial port device.\n"); - exit(1); - } -#endif -#endif -} - -void hwReadConfigBlock(void* buf, void* adr, size_t length) -{ - eeprom.readBlock(buf, adr, length); -} - -void hwWriteConfigBlock(void* buf, void* adr, size_t length) -{ - eeprom.writeBlock(buf, adr, length); -} - -uint8_t hwReadConfig(int adr) -{ - return eeprom.readByte(adr); -} - -void hwWriteConfig(int adr, uint8_t value) -{ - eeprom.writeByte(adr, value); -} - -void hwRandomNumberInit() -{ - randomSeed(time(NULL)); -} - -unsigned long hwMillis() -{ - return millis(); -} - -// Not supported! -int8_t hwSleep(unsigned long ms) -{ - (void)ms; - - return MY_SLEEP_NOT_POSSIBLE; -} - -// Not supported! -int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) -{ - (void)interrupt; - (void)mode; - (void)ms; - - return MY_SLEEP_NOT_POSSIBLE; -} - -// Not supported! -int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, - unsigned long ms) -{ - (void)interrupt1; - (void)mode1; - (void)interrupt2; - (void)mode2; - (void)ms; - - return MY_SLEEP_NOT_POSSIBLE; -} - -#if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG) -uint16_t hwCPUVoltage() -{ - // TODO: Not supported! - return 0; -} - -uint16_t hwCPUFrequency() -{ - // TODO: Not supported! - return 0; -} - -uint16_t hwFreeMem() -{ - // TODO: Not supported! - return 0; -} -#endif - -#ifdef MY_DEBUG -void hwDebugPrint(const char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - vlogDebug(fmt, args); - va_end(args); -} -#endif - -void hwDigitalWrite(uint8_t pin, uint8_t value) -{ - digitalWrite(pin, value); -} - -int hwDigitalRead(uint8_t pin) -{ - return digitalRead(pin); -} - -void hwPinMode(uint8_t pin, uint8_t mode) -{ - pinMode(pin, mode); -} diff --git a/core/MyIndication.h b/core/MyIndication.h index 0e2f8ea2b..7d6b7baca 100644 --- a/core/MyIndication.h +++ b/core/MyIndication.h @@ -44,6 +44,7 @@ typedef enum { INDICATION_WAKEUP, //!< Node just woke from sleep. INDICATION_FW_UPDATE_START, //!< Start of OTA firmware update process. INDICATION_FW_UPDATE_RX, //!< Received a piece of firmware data. + INDICATION_FW_UPDATE_RX_ERR, //!< Received wrong piece of firmware data. INDICATION_ERR_START = 100, INDICATION_ERR_TX, //!< Failed to transmit message. diff --git a/core/MyMainLinux.cpp b/core/MyMainLinux.cpp index 5e875ecea..c2a4d395c 100644 --- a/core/MyMainLinux.cpp +++ b/core/MyMainLinux.cpp @@ -50,7 +50,7 @@ void handle_sigint(int sig) closelog(); - exit(0); + exit(EXIT_SUCCESS); } static int daemonize(void) @@ -167,12 +167,12 @@ void generate_soft_sign_hmac_key() void set_soft_sign_hmac_key(char *key_str) { uint8_t key[32]; - int n; if (strlen(key_str) != 64) { printf("invalid key!\n"); } else { for (int i = 0; i < 64; ++i) { + int n; char c = key_str[i]; if (c <= '9') { n = c - '0'; @@ -242,12 +242,12 @@ void generate_soft_sign_serial_key() void set_soft_sign_serial_key(char *key_str) { uint8_t key[9]; - int n; if (strlen(key_str) != 18) { printf("invalid key!\n"); } else { for (int i = 0; i < 18; ++i) { + int n; char c = key_str[i]; if (c <= '9') { n = c - '0'; @@ -317,12 +317,12 @@ void generate_aes_key() void set_aes_key(char *key_str) { uint8_t key[16]; - int n; if (strlen(key_str) != 32) { printf("invalid key!\n"); } else { for (int i = 0; i < 32; ++i) { + int n; char c = key_str[i]; if (c <= '9') { n = c - '0'; @@ -375,7 +375,7 @@ int main(int argc, char *argv[]) switch (opt) { case 'h': print_usage(); - exit(0); + exit(EXIT_SUCCESS); case 'd': debug = 1; break; @@ -384,37 +384,37 @@ int main(int argc, char *argv[]) break; case 'A': generate_soft_sign_hmac_key(); - exit(0); + exit(EXIT_SUCCESS); case 'B': generate_soft_sign_serial_key(); - exit(0); + exit(EXIT_SUCCESS); case 'C': generate_aes_key(); - exit(0); + exit(EXIT_SUCCESS); case 'D': print_soft_sign_hmac_key(); - exit(0); + exit(EXIT_SUCCESS); case 'E': print_soft_sign_serial_key(); - exit(0); + exit(EXIT_SUCCESS); case 'F': print_aes_key(); - exit(0); + exit(EXIT_SUCCESS); case 'G': key = strdup(optarg); set_soft_sign_hmac_key(key); - exit(0); + exit(EXIT_SUCCESS); case 'H': key = strdup(optarg); set_soft_sign_serial_key(key); - exit(0); + exit(EXIT_SUCCESS); case 'I': key = strdup(optarg); set_aes_key(key); - exit(0); + exit(EXIT_SUCCESS); default: print_usage(); - exit(0); + exit(EXIT_SUCCESS); } } diff --git a/core/MyOTAFirmwareUpdate.cpp b/core/MyOTAFirmwareUpdate.cpp index 1757c6b8f..2ac5f2109 100644 --- a/core/MyOTAFirmwareUpdate.cpp +++ b/core/MyOTAFirmwareUpdate.cpp @@ -93,19 +93,26 @@ bool firmwareOTAUpdateProcess(void) OTA_DEBUG(PSTR("OTA:FWP:UPDATE SKIPPED\n")); // FW update skipped, no newer version available } else if (_msg.type == ST_FIRMWARE_RESPONSE) { if (_firmwareUpdateOngoing) { - // Save block to flash - setIndication(INDICATION_FW_UPDATE_RX); - OTA_DEBUG(PSTR("OTA:FWP:RECV B=%04X\n"), _firmwareBlock); // received FW block // extract FW block replyFirmwareBlock_t *firmwareResponse = (replyFirmwareBlock_t *)_msg.data; - // write to flash + + OTA_DEBUG(PSTR("OTA:FWP:RECV B=%04X\n"), firmwareResponse->block); // received FW block + if (firmwareResponse->block != _firmwareBlock - 1) { + OTA_DEBUG(PSTR("!OTA:FWP:WRONG FWB\n")); // received FW block + // wrong firmware block received + setIndication(INDICATION_FW_UPDATE_RX_ERR); + // no further processing required + return true; + } + setIndication(INDICATION_FW_UPDATE_RX); + // Save block to flash _flash.writeBytes( ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE); // wait until flash written while (_flash.busy()) {} _firmwareBlock--; if (!_firmwareBlock) { - // We're finished! Do a checksum and reboot. + // We're done! Do a checksum and reboot. OTA_DEBUG(PSTR("OTA:FWP:FW END\n")); // received FW block _firmwareUpdateOngoing = false; if (transportIsValidFirmware()) { diff --git a/core/MyOTAFirmwareUpdate.h b/core/MyOTAFirmwareUpdate.h index 9372fd2c9..cb1775711 100644 --- a/core/MyOTAFirmwareUpdate.h +++ b/core/MyOTAFirmwareUpdate.h @@ -40,6 +40,7 @@ * |!| OTA | FWP | FLASH INIT FAIL | Failed to initialise flash * | | OTA | FWP | UPDATE SKIPPED | FW update skipped, no newer version available * | | OTA | FWP | RECV B=%04X | Received FW block (B) +* |!| OTA | FWP | WRONG FWB | Wrong FW block received * | | OTA | FWP | FW END | FW received, proceed to CRC verification * | | OTA | FWP | CRC OK | FW CRC verification OK * |!| OTA | FWP | CRC FAIL | FW CRC verification failed diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 3dfed8739..d41bd1ad8 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -262,7 +262,7 @@ uint8_t getDistanceGW(void) return result; } -controllerConfig_t getConfig(void) +controllerConfig_t getControllerConfig(void) { return _coreConfig.controllerConfig; } diff --git a/core/MySigning.cpp b/core/MySigning.cpp index 35c2ff550..326e82555 100644 --- a/core/MySigning.cpp +++ b/core/MySigning.cpp @@ -337,7 +337,8 @@ static bool skipSign(MyMessage &msg) msg.type == I_FIND_PARENT_REQUEST || msg.type == I_FIND_PARENT_RESPONSE || msg.type == I_HEARTBEAT_REQUEST || msg.type == I_HEARTBEAT_RESPONSE || msg.type == I_PING || msg.type == I_PONG || - msg.type == I_REGISTRATION_REQUEST )) { + msg.type == I_REGISTRATION_REQUEST || msg.type == I_DISCOVER_REQUEST || + msg.type == I_DISCOVER_RESPONSE )) { SIGN_DEBUG(PSTR("Skipping security for command %d type %d\n"), mGetCommand(msg), msg.type); ret = true; } else if (mGetCommand(msg) == C_STREAM && @@ -366,6 +367,7 @@ static void prepareSigningPresentation(MyMessage &msg, uint8_t destination) // Helper to process presentation mesages static bool signerInternalProcessPresentation(MyMessage &msg) { + const uint8_t sender = msg.sender; #if defined(MY_SIGNING_FEATURE) if (msg.data[0] != SIGNING_PRESENTATION_VERSION_1) { SIGN_DEBUG(PSTR("Unsupported signing presentation version (%d)!\n"), msg.data[0]); @@ -374,21 +376,21 @@ static bool signerInternalProcessPresentation(MyMessage &msg) // We only handle version 1 here... if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_SIGNATURES) { // We received an indicator that the sender require us to sign all messages we send to it - SIGN_DEBUG(PSTR("Mark node %d as one that require signed messages\n"), msg.sender); - SET_SIGN(msg.sender); + SIGN_DEBUG(PSTR("Mark node %d as one that require signed messages\n"), sender); + SET_SIGN(sender); } else { // We received an indicator that the sender does not require us to sign all messages we send to it - SIGN_DEBUG(PSTR("Mark node %d as one that do not require signed messages\n"), msg.sender); - CLEAR_SIGN(msg.sender); + SIGN_DEBUG(PSTR("Mark node %d as one that do not require signed messages\n"), sender); + CLEAR_SIGN(sender); } if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_WHITELISTING) { // We received an indicator that the sender require us to salt signatures with serial - SIGN_DEBUG(PSTR("Mark node %d as one that require whitelisting\n"), msg.sender); - SET_WHITELIST(msg.sender); + SIGN_DEBUG(PSTR("Mark node %d as one that require whitelisting\n"), sender); + SET_WHITELIST(sender); } else { // We received an indicator that the sender does not require us to sign all messages we send to it - SIGN_DEBUG(PSTR("Mark node %d as one that do not require whitelisting\n"), msg.sender); - CLEAR_WHITELIST(msg.sender); + SIGN_DEBUG(PSTR("Mark node %d as one that do not require whitelisting\n"), sender); + CLEAR_WHITELIST(sender); } // Save updated tables @@ -400,12 +402,12 @@ static bool signerInternalProcessPresentation(MyMessage &msg) // Inform sender about our preference if we are a gateway, but only require signing if the sender // required signing unless we explicitly configure it to #if defined(MY_GATEWAY_FEATURE) - prepareSigningPresentation(msg, msg.sender); + prepareSigningPresentation(msg, sender); #if defined(MY_SIGNING_REQUEST_SIGNATURES) #if defined(MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL) msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES; #else - if (DO_SIGN(msg.sender)) { + if (DO_SIGN(sender)) { msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES; } #endif @@ -414,20 +416,20 @@ static bool signerInternalProcessPresentation(MyMessage &msg) #if defined(MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL) msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING; #else - if (DO_WHITELIST(msg.sender)) { + if (DO_WHITELIST(sender)) { msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING; } #endif #endif // MY_SIGNING_NODE_WHITELISTING if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_SIGNATURES) { - SIGN_DEBUG(PSTR("Informing node %d that we require signatures\n"), msg.sender); + SIGN_DEBUG(PSTR("Informing node %d that we require signatures\n"), sender); } else { - SIGN_DEBUG(PSTR("Informing node %d that we do not require signatures\n"), msg.sender); + SIGN_DEBUG(PSTR("Informing node %d that we do not require signatures\n"), sender); } if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_WHITELISTING) { - SIGN_DEBUG(PSTR("Informing node %d that we require whitelisting\n"), msg.sender); + SIGN_DEBUG(PSTR("Informing node %d that we require whitelisting\n"), sender); } else { - SIGN_DEBUG(PSTR("Informing node %d that we do not require whitelisting\n"), msg.sender); + SIGN_DEBUG(PSTR("Informing node %d that we do not require whitelisting\n"), sender); } if (!_sendRoute(msg)) { SIGN_DEBUG(PSTR("Failed to transmit signing presentation!\n")); @@ -437,10 +439,10 @@ static bool signerInternalProcessPresentation(MyMessage &msg) #if defined(MY_GATEWAY_FEATURE) // If we act as gateway and do not have the signing feature and receive a signing request we still // need to do make sure the requester does not believe the gateway still require signatures - prepareSigningPresentation(msg, msg.sender); + prepareSigningPresentation(msg, sender); SIGN_DEBUG( PSTR("Informing node %d that we do not require signatures because we do not support it\n"), - msg.sender); + sender); if (!_sendRoute(msg)) { SIGN_DEBUG(PSTR("Failed to transmit signing presentation!\n")); } @@ -448,6 +450,7 @@ static bool signerInternalProcessPresentation(MyMessage &msg) // If we act as a node and do not have the signing feature then we just silently drop any signing // presentation messages received (void)msg; + (void)sender; SIGN_DEBUG(PSTR("Received signing presentation, but signing is not supported (message ignored)\n")); #endif // not MY_GATEWAY_FEATURE #endif // not MY_SIGNING_FEATURE diff --git a/core/Version.h b/core/Version.h index 5f365ff64..43e8acdd6 100644 --- a/core/Version.h +++ b/core/Version.h @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2015 Sensnology AB + * Copyright (C) 2013-2017 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -24,6 +24,6 @@ #ifndef Version_h #define Version_h -#define MYSENSORS_LIBRARY_VERSION "2.1.0" +#define MYSENSORS_LIBRARY_VERSION "2.1.1" #endif diff --git a/drivers/AVR/DigitalWriteFast/digitalWriteFast.h b/drivers/AVR/DigitalWriteFast/digitalWriteFast.h index 33d023ebb..1cf5bde81 100644 --- a/drivers/AVR/DigitalWriteFast/digitalWriteFast.h +++ b/drivers/AVR/DigitalWriteFast/digitalWriteFast.h @@ -6,67 +6,7 @@ #ifndef __digitalWriteFast_h_ #define __digitalWriteFast_h_ -#if defined(ARDUINO_AVR_MEGA) || defined(ARDUINO_AVR_MEGA1280) || defined(ARDUINO_AVR_MEGA2560) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) -#define __digitalPinToPortReg(__pin) \ - (((__pin) >= 22 && (__pin) <= 29) ? &PORTA : \ - ((((__pin) >= 10 && (__pin) <= 13) || ((__pin) >= 50 && (__pin) <= 53)) ? &PORTB : \ - (((__pin) >= 30 && (__pin) <= 37) ? &PORTC : \ - ((((__pin) >= 18 && (__pin) <= 21) || (__pin) == 38) ? &PORTD : \ - ((((__pin) <= 3) || (__pin) == 5) ? &PORTE : \ - (((__pin) >= 54 && (__pin) <= 61) ? &PORTF : \ - ((((__pin) >= 39 && (__pin) <= 41) || (__pin) == 4) ? &PORTG : \ - ((((__pin) >= 6 && (__pin) <= 9) || (__pin) == 16 || (__pin) == 17) ? &PORTH : \ - (((__pin) == 14 || (__pin) == 15) ? &PORTJ : \ - (((__pin) >= 62 && (__pin) <= 69) ? &PORTK : &PORTL)))))))))) -#define __digitalPinToDDRReg(__pin) \ - (((__pin) >= 22 && (__pin) <= 29) ? &DDRA : \ - ((((__pin) >= 10 && (__pin) <= 13) || ((__pin) >= 50 && (__pin) <= 53)) ? &DDRB : \ - (((__pin) >= 30 && (__pin) <= 37) ? &DDRC : \ - ((((__pin) >= 18 && (__pin) <= 21) || (__pin) == 38) ? &DDRD : \ - ((((__pin) <= 3) || (__pin) == 5) ? &DDRE : \ - (((__pin) >= 54 && (__pin) <= 61) ? &DDRF : \ - ((((__pin) >= 39 && (__pin) <= 41) || (__pin) == 4) ? &DDRG : \ - ((((__pin) >= 6 && (__pin) <= 9) || (__pin) == 16 || (__pin) == 17) ? &DDRH : \ - (((__pin) == 14 || (__pin) == 15) ? &DDRJ : \ - (((__pin) >= 62 && (__pin) <= 69) ? &DDRK : &DDRL)))))))))) -#define __digitalPinToPINReg(__pin) \ - (((__pin) >= 22 && (__pin) <= 29) ? &PINA : \ - ((((__pin) >= 10 && (__pin) <= 13) || ((__pin) >= 50 && (__pin) <= 53)) ? &PINB : \ - (((__pin) >= 30 && (__pin) <= 37) ? &PINC : \ - ((((__pin) >= 18 && (__pin) <= 21) || (__pin) == 38) ? &PIND : \ - ((((__pin) <= 3) || (__pin) == 5) ? &PINE : \ - (((__pin) >= 54 && (__pin) <= 61) ? &PINF : \ - ((((__pin) >= 39 && (__pin) <= 41) || (__pin) == 4) ? &PING : \ - ((((__pin) >= 6 && (__pin) <= 9) || (__pin) == 16 || (__pin) == 17) ? &PINH : \ - (((__pin) == 14 || (__pin) == 15) ? &PINJ : \ - (((__pin) >= 62 && (__pin) <= 69) ? &PINK : &PINL)))))))))) -#define __digitalPinToBit(__pin) \ - (((__pin) >= 7 && (__pin) <= 9) ? (__pin) - 3 : \ - (((__pin) >= 10 && (__pin) <= 13) ? (__pin) - 6 : \ - (((__pin) >= 22 && (__pin) <= 29) ? (__pin) - 22 : \ - (((__pin) >= 30 && (__pin) <= 37) ? 37 - (__pin) : \ - (((__pin) >= 39 && (__pin) <= 41) ? 41 - (__pin) : \ - (((__pin) >= 42 && (__pin) <= 49) ? 49 - (__pin) : \ - (((__pin) >= 50 && (__pin) <= 53) ? 53 - (__pin) : \ - (((__pin) >= 54 && (__pin) <= 61) ? (__pin) - 54 : \ - (((__pin) >= 62 && (__pin) <= 69) ? (__pin) - 62 : \ - (((__pin) == 0 || (__pin) == 15 || (__pin) == 17 || (__pin) == 21) ? 0 : \ - (((__pin) == 1 || (__pin) == 14 || (__pin) == 16 || (__pin) == 20) ? 1 : \ - (((__pin) == 19) ? 2 : \ - (((__pin) == 5 || (__pin) == 6 || (__pin) == 18) ? 3 : \ - (((__pin) == 2) ? 4 : \ - (((__pin) == 3 || (__pin) == 4) ? 5 : 7))))))))))))))) -#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) -#define __digitalPinToPortReg(__pin) (((__pin) <= 7) ? &PORTB : (((__pin) >= 8 && (__pin) <= 15) ? &PORTD : (((__pin) >= 16 && (__pin) <= 23) ? &PORTC : &PORTA))) -#define __digitalPinToDDRReg(__pin) (((__pin) <= 7) ? &DDRB : (((__pin) >= 8 && (__pin) <= 15) ? &DDRD : (((__pin) >= 8 && (__pin) <= 15) ? &DDRC : &DDRA))) -#define __digitalPinToPINReg(__pin) (((__pin) <= 7) ? &PINB : (((__pin) >= 8 && (__pin) <= 15) ? &PIND : (((__pin) >= 8 && (__pin) <= 15) ? &PINC : &PINA))) -#define __digitalPinToBit(__pin) (((__pin) <= 7) ? (__pin) : (((__pin) >= 8 && (__pin) <= 15) ? (__pin) - 8 : (((__pin) >= 16 && (__pin) <= 23) ? (__pin) - 16 : (__pin) - 24))) -#elif defined(ARDUINO_AVR_LEONARDO) || defined(__AVR_ATmega16U4__) || defined(__AVR_ATmega32U4__) -#define __digitalPinToPortReg(__pin) ((((__pin) <= 4) || (__pin) == 6 || (__pin) == 12 || (__pin) == 24 || (__pin) == 25 || (__pin) == 29) ? &PORTD : (((__pin) == 5 || (__pin) == 13) ? &PORTC : (((__pin) >= 18 && (__pin) <= 23)) ? &PORTF : (((__pin) == 7) ? &PORTE : &PORTB))) -#define __digitalPinToDDRReg(__pin) ((((__pin) <= 4) || (__pin) == 6 || (__pin) == 12 || (__pin) == 24 || (__pin) == 25 || (__pin) == 29) ? &DDRD : (((__pin) == 5 || (__pin) == 13) ? &DDRC : (((__pin) >= 18 && (__pin) <= 23)) ? &DDRF : (((__pin) == 7) ? &DDRE : &DDRB))) -#define __digitalPinToPINReg(__pin) ((((__pin) <= 4) || (__pin) == 6 || (__pin) == 12 || (__pin) == 24 || (__pin) == 25 || (__pin) == 29) ? &PIND : (((__pin) == 5 || (__pin) == 13) ? &PINC : (((__pin) >= 18 && (__pin) <= 23)) ? &PINF : (((__pin) == 7) ? &PINE : &PINB))) -#define __digitalPinToBit(__pin) (((__pin) >= 8 && (__pin) <= 11) ? (__pin) - 4 : (((__pin) >= 18 && (__pin) <= 21) ? 25 - (__pin) : (((__pin) == 0) ? 2 : (((__pin) == 1) ? 3 : (((__pin) == 2) ? 1 : (((__pin) == 3) ? 0 : (((__pin) == 4) ? 4 : (((__pin) == 6) ? 7 : (((__pin) == 13) ? 7 : (((__pin) == 14) ? 3 : (((__pin) == 15) ? 1 : (((__pin) == 16) ? 2 : (((__pin) == 17) ? 0 : (((__pin) == 22) ? 1 : (((__pin) == 23) ? 0 : (((__pin) == 24) ? 4 : (((__pin) == 25) ? 7 : (((__pin) == 26) ? 4 : (((__pin) == 27) ? 5 : 6 ))))))))))))))))))) -#elif defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_DUEMILANOVE) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) +#if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_DUEMILANOVE) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) || defined (__AVR_ATmega168__) #if defined(__AVR_ATmega328PB__) #define __digitalPinToPortReg(__pin) (((__pin) <= 7) ? &PORTD : (((__pin) >= 8 && (__pin) <= 13) ? &PORTB : (((__pin) >= 14 && (__pin) <= 19) ? &PORTC : &PORTE))) #define __digitalPinToDDRReg(__pin) (((__pin) <= 7) ? &DDRD : (((__pin) >= 8 && (__pin) <= 13) ? &DDRB : (((__pin) >= 14 && (__pin) <= 19) ? &DDRC : &DDRE))) @@ -78,21 +18,14 @@ #define __digitalPinToPINReg(__pin) (((__pin) <= 7) ? &PIND : (((__pin) >= 8 && (__pin) <= 13) ? &PINB : &PINC)) #define __digitalPinToBit(__pin) (((__pin) <= 7) ? (__pin) : (((__pin) >= 8 && (__pin) <= 13) ? (__pin) - 8 : (__pin) - 14)) #endif -#endif - -#if defined(ARDUINO_ARCH_AVR) -#if !defined(__atomicWrite) -#define __atomicWrite(A,P,V) do { if ((A) < 0x40) {bitWrite((A), (P), (V) );} else {uint8_t register saveSreg = SREG;cli();bitWrite((A), (P), (V));SREG = saveSreg;}} while(0) -#endif -#if !defined(digitalWriteFast) #define digitalWriteFast(__pin, __value) do { if (__builtin_constant_p(__pin) && __builtin_constant_p(__value)) { bitWrite(*__digitalPinToPortReg(__pin), (uint8_t)__digitalPinToBit(__pin), (__value)); } else { digitalWrite((__pin), (__value)); } } while (0) -#endif -#if !defined(pinModeFast) #define pinModeFast(__pin, __mode) do { if (__builtin_constant_p(__pin) && __builtin_constant_p(__mode) && (__mode!=INPUT_PULLUP)) { bitWrite(*__digitalPinToDDRReg(__pin), (uint8_t)__digitalPinToBit(__pin), (__mode)); } else { pinMode((__pin), (__mode)); } } while (0) -#endif -#if !defined(digitalReadFast) #define digitalReadFast(__pin) ( (bool) (__builtin_constant_p(__pin) ) ? (( bitRead(*__digitalPinToPINReg(__pin), (uint8_t)__digitalPinToBit(__pin))) ) : digitalRead((__pin)) ) -#endif +#else +// for all other archs use built-in pin access functions +#define digitalWriteFast(__pin, __value) digitalWrite(__pin, __value) +#define pinModeFast(__pin, __value) pinMode(__pin, __value) +#define digitalReadFast(__pin) digitalRead(__pin) #endif #endif \ No newline at end of file diff --git a/drivers/RPi/SPI.cpp b/drivers/BCM/SPI.cpp similarity index 90% rename from drivers/RPi/SPI.cpp rename to drivers/BCM/SPI.cpp index 1b8684e64..ea8273b9e 100644 --- a/drivers/RPi/SPI.cpp +++ b/drivers/BCM/SPI.cpp @@ -5,9 +5,9 @@ * repeater and gateway builds a routing tables in EEPROM which keeps track of the * network topology allowing messages to be routed to nodes. * - * Created by Marcelo Aquino - * Copyright (C) 2016 Marcelo Aquino - * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org * Support Forum: http://forum.mysensors.org @@ -31,11 +31,6 @@ SPIClass SPI = SPIClass(); uint8_t SPIClass::initialized = 0; -uint8_t SPIClass::is_initialized() -{ - return initialized; -} - void SPIClass::begin() { if (!initialized) { diff --git a/drivers/RPi/SPI.h b/drivers/BCM/SPI.h similarity index 60% rename from drivers/RPi/SPI.h rename to drivers/BCM/SPI.h index 7aba9c395..bcb2c4eec 100644 --- a/drivers/RPi/SPI.h +++ b/drivers/BCM/SPI.h @@ -5,9 +5,9 @@ * repeater and gateway builds a routing tables in EEPROM which keeps track of the * network topology allowing messages to be routed to nodes. * - * Created by Marcelo Aquino - * Copyright (C) 2016 Marcelo Aquino - * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org * Support Forum: http://forum.mysensors.org @@ -24,17 +24,30 @@ #include #include "bcm2835.h" +#include "RPi.h" #define SPI_HAS_TRANSACTION +#define SPI_CLOCK_BASE 256000000 + // SPI Clock divider -#define SPI_CLOCK_DIV2 2 -#define SPI_CLOCK_DIV4 4 -#define SPI_CLOCK_DIV8 8 -#define SPI_CLOCK_DIV16 16 -#define SPI_CLOCK_DIV32 32 -#define SPI_CLOCK_DIV64 64 -#define SPI_CLOCK_DIV128 128 +#define SPI_CLOCK_DIV1 BCM2835_SPI_CLOCK_DIVIDER_1 +#define SPI_CLOCK_DIV2 BCM2835_SPI_CLOCK_DIVIDER_2 +#define SPI_CLOCK_DIV4 BCM2835_SPI_CLOCK_DIVIDER_4 +#define SPI_CLOCK_DIV8 BCM2835_SPI_CLOCK_DIVIDER_8 +#define SPI_CLOCK_DIV16 BCM2835_SPI_CLOCK_DIVIDER_16 +#define SPI_CLOCK_DIV32 BCM2835_SPI_CLOCK_DIVIDER_32 +#define SPI_CLOCK_DIV64 BCM2835_SPI_CLOCK_DIVIDER_64 +#define SPI_CLOCK_DIV128 BCM2835_SPI_CLOCK_DIVIDER_128 +#define SPI_CLOCK_DIV256 BCM2835_SPI_CLOCK_DIVIDER_256 +#define SPI_CLOCK_DIV512 BCM2835_SPI_CLOCK_DIVIDER_512 +#define SPI_CLOCK_DIV1024 BCM2835_SPI_CLOCK_DIVIDER_1024 +#define SPI_CLOCK_DIV2048 BCM2835_SPI_CLOCK_DIVIDER_2048 +#define SPI_CLOCK_DIV4096 BCM2835_SPI_CLOCK_DIVIDER_4096 +#define SPI_CLOCK_DIV8192 BCM2835_SPI_CLOCK_DIVIDER_8192 +#define SPI_CLOCK_DIV16384 BCM2835_SPI_CLOCK_DIVIDER_16384 +#define SPI_CLOCK_DIV32768 BCM2835_SPI_CLOCK_DIVIDER_32768 +#define SPI_CLOCK_DIV65536 BCM2835_SPI_CLOCK_DIVIDER_65536 // SPI Data mode #define SPI_MODE0 BCM2835_SPI_MODE0 @@ -42,6 +55,14 @@ #define SPI_MODE2 BCM2835_SPI_MODE2 #define SPI_MODE3 BCM2835_SPI_MODE3 +#define LSBFIRST BCM2835_SPI_BIT_ORDER_LSBFIRST +#define MSBFIRST BCM2835_SPI_BIT_ORDER_MSBFIRST + +const uint8_t SS = 24; +const uint8_t MOSI = 19; +const uint8_t MISO = 21; +const uint8_t SCK = 23; + /** * SPISettings class */ @@ -56,7 +77,7 @@ class SPISettings */ SPISettings() { - init(BCM2835_SPI_CLOCK_DIVIDER_32, BCM2835_SPI_BIT_ORDER_MSBFIRST, BCM2835_SPI_MODE0); + init(SPI_CLOCK_DIV32, MSBFIRST, SPI_MODE0); } /** * @brief SPISettings constructor. @@ -69,28 +90,43 @@ class SPISettings { uint16_t divider; - switch (clock) { - case 500000: - divider = BCM2835_SPI_CLOCK_DIVIDER_512; - break; - case 1000000: - divider = BCM2835_SPI_CLOCK_DIVIDER_256; - break; - case 2000000: - divider = BCM2835_SPI_CLOCK_DIVIDER_128; - break; - case 4000000: - divider = BCM2835_SPI_CLOCK_DIVIDER_64; - break; - case 8000000: - divider = BCM2835_SPI_CLOCK_DIVIDER_32; - break; - case 16000000: - divider = BCM2835_SPI_CLOCK_DIVIDER_16; - break; - default: - // 8Mhz - divider = BCM2835_SPI_CLOCK_DIVIDER_32; + if (clock >= SPI_CLOCK_BASE) { + divider = SPI_CLOCK_DIV1; + } else if (clock >= SPI_CLOCK_BASE / 2) { + divider = SPI_CLOCK_DIV2; + } else if (clock >= SPI_CLOCK_BASE / 4) { + divider = SPI_CLOCK_DIV4; + } else if (clock >= SPI_CLOCK_BASE / 8) { + divider = SPI_CLOCK_DIV8; + } else if (clock >= SPI_CLOCK_BASE / 16) { + divider = SPI_CLOCK_DIV16; + } else if (clock >= SPI_CLOCK_BASE / 32) { + divider = SPI_CLOCK_DIV32; + } else if (clock >= SPI_CLOCK_BASE / 64) { + divider = SPI_CLOCK_DIV64; + } else if (clock >= SPI_CLOCK_BASE / 128) { + divider = SPI_CLOCK_DIV128; + } else if (clock >= SPI_CLOCK_BASE / 256) { + divider = SPI_CLOCK_DIV256; + } else if (clock >= SPI_CLOCK_BASE / 512) { + divider = SPI_CLOCK_DIV512; + } else if (clock >= SPI_CLOCK_BASE / 1024) { + divider = SPI_CLOCK_DIV1024; + } else if (clock >= SPI_CLOCK_BASE / 2048) { + divider = SPI_CLOCK_DIV2048; + } else if (clock >= SPI_CLOCK_BASE / 4096) { + divider = SPI_CLOCK_DIV4096; + } else if (clock >= SPI_CLOCK_BASE / 8192) { + divider = SPI_CLOCK_DIV8192; + } else if (clock >= SPI_CLOCK_BASE / 16384) { + divider = SPI_CLOCK_DIV16384; + } else if (clock >= SPI_CLOCK_BASE / 32768) { + divider = SPI_CLOCK_DIV32768; + } else if (clock >= SPI_CLOCK_BASE / 65536) { + divider = SPI_CLOCK_DIV65536; + } else { + // Default to 8Mhz + divider = SPI_CLOCK_DIV32; } init(divider, bitOrder, dataMode); @@ -124,16 +160,7 @@ class SPISettings class SPIClass { -private: - static uint8_t initialized; //!< @brief SPI initialized flag. - public: - /** - * @brief Checks if SPI was initialized. - * - * @return 0 if wasn't initialized, else 1 or more. - */ - static uint8_t is_initialized(); /** * @brief Send and receive a byte. * @@ -210,6 +237,9 @@ class SPIClass * @param interruptNumber ignored parameter. */ static void notUsingInterrupt(uint8_t interruptNumber); + +private: + static uint8_t initialized; //!< @brief SPI initialized flag. }; uint8_t SPIClass::transfer(uint8_t data) diff --git a/drivers/RPi/Wire.cpp b/drivers/BCM/Wire.cpp similarity index 100% rename from drivers/RPi/Wire.cpp rename to drivers/BCM/Wire.cpp diff --git a/drivers/RPi/Wire.h b/drivers/BCM/Wire.h similarity index 99% rename from drivers/RPi/Wire.h rename to drivers/BCM/Wire.h index 57c799b37..065ab7919 100644 --- a/drivers/RPi/Wire.h +++ b/drivers/BCM/Wire.h @@ -28,6 +28,7 @@ #if !DOXYGEN #include #include "Stream.h" +#include "RPi.h" #define BUFFER_LENGTH 32 diff --git a/drivers/Linux/Arduino.h b/drivers/Linux/Arduino.h index 1446b98e3..54c076541 100644 --- a/drivers/Linux/Arduino.h +++ b/drivers/Linux/Arduino.h @@ -1,3 +1,22 @@ +/* + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + #ifndef Arduino_h #define Arduino_h @@ -14,10 +33,21 @@ #include "stdlib_noniso.h" #ifdef LINUX_ARCH_RASPBERRYPI -#include "rpi_util.h" -using namespace rpi_util; +#include "RPi.h" +#define pinMode(pin, direction) rpi.pinMode(pin, direction) +#define digitalWrite(pin, value) rpi.digitalWrite(pin, value) +#define digitalRead(pin) rpi.digitalRead(pin) +#define digitalPinToInterrupt(pin) rpi.digitalPinToInterrupt(pin) +#else +#include "GPIO.h" +#define pinMode(pin, direction) gpio.pinMode(pin, direction) +#define digitalWrite(pin, value) gpio.digitalWrite(pin, value) +#define digitalRead(pin) gpio.digitalRead(pin) +#define digitalPinToInterrupt(pin) gpio.digitalPinToInterrupt(pin) #endif +#include "interrupt.h" + #undef PSTR #define PSTR(x) (x) #undef F @@ -57,7 +87,11 @@ using namespace rpi_util; #define random(...) GET_MACRO(_0, ##__VA_ARGS__, randMinMax, randMax, rand)(__VA_ARGS__) #ifndef delay -#define delay _delay_ms +#define delay _delay_milliseconds +#endif + +#ifndef delayMicroseconds +#define delayMicroseconds _delay_microseconds #endif using std::string; @@ -73,7 +107,8 @@ typedef char __FlashStringHelper; void yield(void); unsigned long millis(void); unsigned long micros(void); -void _delay_ms(unsigned int millis); +void _delay_milliseconds(unsigned int millis); +void _delay_microseconds(unsigned int micro); void randomSeed(unsigned long seed); long randMax(long howbig); long randMinMax(long howsmall, long howbig); diff --git a/drivers/Linux/EthernetClient.cpp b/drivers/Linux/EthernetClient.cpp index 1b2f0931b..640000b0c 100644 --- a/drivers/Linux/EthernetClient.cpp +++ b/drivers/Linux/EthernetClient.cpp @@ -5,9 +5,9 @@ * repeater and gateway builds a routing tables in EEPROM which keeps track of the * network topology allowing messages to be routed to nodes. * - * Created by Marcelo Aquino - * Copyright (C) 2016 Marcelo Aquino - * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org * Support Forum: http://forum.mysensors.org @@ -103,7 +103,6 @@ size_t EthernetClient::write(uint8_t b) size_t EthernetClient::write(const uint8_t *buf, size_t size) { - int rc = 0; int bytes = 0; if (_sock == -1) { @@ -111,7 +110,7 @@ size_t EthernetClient::write(const uint8_t *buf, size_t size) } while (size > 0) { - rc = send(_sock, buf + bytes, size, MSG_NOSIGNAL | MSG_DONTWAIT); + int rc = send(_sock, buf + bytes, size, MSG_NOSIGNAL | MSG_DONTWAIT); if (rc == -1) { logError("send: %s\n", strerror(errno)); close(_sock); diff --git a/drivers/Linux/EthernetClient.h b/drivers/Linux/EthernetClient.h index 6297ec050..df0b7e8f9 100644 --- a/drivers/Linux/EthernetClient.h +++ b/drivers/Linux/EthernetClient.h @@ -5,9 +5,9 @@ * repeater and gateway builds a routing tables in EEPROM which keeps track of the * network topology allowing messages to be routed to nodes. * - * Created by Marcelo Aquino - * Copyright (C) 2016 Marcelo Aquino - * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org * Support Forum: http://forum.mysensors.org @@ -43,9 +43,6 @@ class EthernetClient : public Client { -private: - int _sock; //!< @brief Network socket. - public: /** * @brief EthernetClient constructor. @@ -56,7 +53,7 @@ class EthernetClient : public Client * * @param sock Network socket. */ - EthernetClient(int sock); + explicit EthernetClient(int sock); /** * @brief Initiate a connection with host:port. * @@ -196,6 +193,9 @@ class EthernetClient : public Client }; friend class EthernetServer; + +private: + int _sock; //!< @brief Network socket. }; #endif diff --git a/drivers/Linux/EthernetServer.cpp b/drivers/Linux/EthernetServer.cpp index e92f0970f..79aaccb6e 100644 --- a/drivers/Linux/EthernetServer.cpp +++ b/drivers/Linux/EthernetServer.cpp @@ -5,9 +5,9 @@ * repeater and gateway builds a routing tables in EEPROM which keeps track of the * network topology allowing messages to be routed to nodes. * - * Created by Marcelo Aquino - * Copyright (C) 2016 Marcelo Aquino - * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org * Support Forum: http://forum.mysensors.org @@ -33,7 +33,7 @@ #include "EthernetServer.h" EthernetServer::EthernetServer(uint16_t port, uint16_t max_clients) : port(port), - max_clients(max_clients) + max_clients(max_clients), sockfd(-1) { clients.reserve(max_clients); } diff --git a/drivers/Linux/EthernetServer.h b/drivers/Linux/EthernetServer.h index 376f3d7f1..2719cb62c 100644 --- a/drivers/Linux/EthernetServer.h +++ b/drivers/Linux/EthernetServer.h @@ -5,9 +5,9 @@ * repeater and gateway builds a routing tables in EEPROM which keeps track of the * network topology allowing messages to be routed to nodes. * - * Created by Marcelo Aquino - * Copyright (C) 2016 Marcelo Aquino - * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org * Support Forum: http://forum.mysensors.org @@ -42,19 +42,6 @@ class EthernetClient; class EthernetServer : public Server { -private: - uint16_t port; //!< @brief Port number for the network socket. - std::list new_clients; //!< Socket list of new clients. - std::vector clients; //!< @brief Socket list of clients. - uint16_t max_clients; //!< @brief The maximum number of allowed clients. - int sockfd; //!< @brief Network socket used to accept connections. - - /** - * @brief Accept new clients if the total of connected clients is below max_clients. - * - */ - void _accept(); - public: /** * @brief EthernetServer constructor. @@ -116,6 +103,19 @@ class EthernetServer : public Server * @return 0 if FAILURE else the number of characters sent. */ size_t write(const char *buffer, size_t size); + +private: + uint16_t port; //!< @brief Port number for the network socket. + std::list new_clients; //!< Socket list of new clients. + std::vector clients; //!< @brief Socket list of clients. + uint16_t max_clients; //!< @brief The maximum number of allowed clients. + int sockfd; //!< @brief Network socket used to accept connections. + + /** + * @brief Accept new clients if the total of connected clients is below max_clients. + * + */ + void _accept(); }; #endif diff --git a/drivers/Linux/GPIO.cpp b/drivers/Linux/GPIO.cpp new file mode 100644 index 000000000..d8fba28e3 --- /dev/null +++ b/drivers/Linux/GPIO.cpp @@ -0,0 +1,211 @@ +/* + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include "GPIO.h" +#include +#include +#include +#include +#include +#include +#include "log.h" + +// Declare a single default instance +GPIO gpio = GPIO(); + +GPIO::GPIO() +{ + FILE *f; + DIR* dp; + char file[64]; + + dp = opendir("/sys/class/gpio"); + if (dp == NULL) { + logError("Could not open /sys/class/gpio directory"); + exit(1); + } + + lastPinNum = 0; + + while (true) { + dirent *de = readdir(dp); + if (de == NULL) { + break; + } + + if (strncmp("gpiochip", de->d_name, 8) == 0) { + sprintf(file, "/sys/class/gpio/%s/base", de->d_name); + f = fopen(file, "r"); + int base; + if (fscanf(f, "%d", &base) == EOF) { + logError("Failed to open %s\n", file); + base = 0; + } + fclose(f); + + sprintf(file, "/sys/class/gpio/%s/ngpio", de->d_name); + f = fopen(file, "r"); + int ngpio; + if (fscanf(f, "%d", &ngpio) == EOF) { + logError("Failed to open %s\n", file); + ngpio = 0; + } + fclose(f); + + int max = ngpio + base - 1; + if (lastPinNum < max) { + lastPinNum = max; + } + } + } + closedir(dp); + + exportedPins = new uint8_t[lastPinNum + 1]; + + for (int i = 0; i < lastPinNum + 1; ++i) { + exportedPins[i] = 0; + } +} + +GPIO::GPIO(const GPIO& other) +{ + lastPinNum = other.lastPinNum; + + exportedPins = new uint8_t[lastPinNum + 1]; + for (int i = 0; i < lastPinNum + 1; ++i) { + exportedPins[i] = other.exportedPins[i]; + } +} + +GPIO::~GPIO() +{ + FILE *f; + + for (int i = 0; i < lastPinNum + 1; ++i) { + if (exportedPins[i]) { + f = fopen("/sys/class/gpio/unexport", "w"); + fprintf(f, "%d\n", i); + fclose(f); + } + } + + delete [] exportedPins; +} + +void GPIO::pinMode(uint8_t pin, uint8_t mode) +{ + FILE *f; + + if (pin > lastPinNum) { + return; + } + + f = fopen("/sys/class/gpio/export", "w"); + fprintf(f, "%d\n", pin); + fclose(f); + + int counter = 0; + char file[128]; + sprintf(file, "/sys/class/gpio/gpio%d/direction", pin); + + while ((f = fopen(file,"w")) == NULL) { + // Wait 10 seconds for the file to be accessible if not open on first attempt + sleep(1); + counter++; + if (counter > 10) { + logError("Could not open /sys/class/gpio/gpio%u/direction", pin); + exit(1); + } + } + if (mode == INPUT) { + fprintf(f, "in\n"); + } else { + fprintf(f, "out\n"); + } + + exportedPins[pin] = 1; + + fclose(f); +} + +void GPIO::digitalWrite(uint8_t pin, uint8_t value) +{ + FILE *f; + char file[128]; + + if (pin > lastPinNum) { + return; + } + if (0 == exportedPins[pin]) { + pinMode(pin, OUTPUT); + } + + sprintf(file, "/sys/class/gpio/gpio%d/value", pin); + f = fopen(file, "w"); + + if (value == 0) { + fprintf(f, "0\n"); + } else { + fprintf(f, "1\n"); + } + + fclose(f); +} + +uint8_t GPIO::digitalRead(uint8_t pin) +{ + FILE *f; + char file[128]; + + if (pin > lastPinNum) { + return 0; + } + if (0 == exportedPins[pin]) { + pinMode(pin, INPUT); + } + + sprintf(file, "/sys/class/gpio/gpio%d/value", pin); + f = fopen(file, "r"); + + int i; + if (fscanf(f, "%d", &i) == EOF) { + logError("digitalRead: failed to read pin %u\n", pin); + i = 0; + } + fclose(f); + return i; +} + +uint8_t GPIO::digitalPinToInterrupt(uint8_t pin) +{ + return pin; +} + +GPIO& GPIO::operator=(const GPIO& other) +{ + if (this != &other) { + lastPinNum = other.lastPinNum; + + exportedPins = new uint8_t[lastPinNum + 1]; + for (int i = 0; i < lastPinNum + 1; ++i) { + exportedPins[i] = other.exportedPins[i]; + } + } + return *this; +} diff --git a/drivers/Linux/GPIO.h b/drivers/Linux/GPIO.h new file mode 100644 index 000000000..e3d9a4008 --- /dev/null +++ b/drivers/Linux/GPIO.h @@ -0,0 +1,91 @@ +/* + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifndef GPIO_h +#define GPIO_h + +#include + +#define INPUT 0 +#define OUTPUT 1 + +#define LOW 0 +#define HIGH 1 + +/** + * @brief GPIO class + */ +class GPIO +{ + +public: + /** + * @brief GPIO constructor. + */ + GPIO(); + /** + * @brief GPIO copy constructor. + */ + GPIO(const GPIO& other); + /** + * @brief GPIO destructor. + */ + ~GPIO(); + /** + * @brief Configures the specified pin to behave either as an input or an output. + * + * @param pin The number of the pin. + * @param mode INPUT or OUTPUT. + */ + void pinMode(uint8_t pin, uint8_t mode); + /** + * @brief Write a high or a low value for the given pin. + * + * @param pin number. + * @param value HIGH or LOW. + */ + void digitalWrite(uint8_t pin, uint8_t value); + /** + * @brief Reads the value from a specified pin. + * + * @param pin The number of the pin. + * @return HIGH or LOW. + */ + uint8_t digitalRead(uint8_t pin); + /** + * @brief Arduino compatibility function, returns the same given pin. + * + * @param pin The number of the pin. + * @return The same parameter pin number. + */ + uint8_t digitalPinToInterrupt(uint8_t pin); + /** + * @brief Overloaded assign operator. + * + */ + GPIO& operator=(const GPIO& other); + +private: + int lastPinNum; //!< @brief Highest pin number supported. + uint8_t *exportedPins; //!< @brief Array with information of which pins were exported. +}; + +extern GPIO gpio; + +#endif diff --git a/drivers/Linux/IPAddress.h b/drivers/Linux/IPAddress.h index 68b9fb250..43e131e4a 100644 --- a/drivers/Linux/IPAddress.h +++ b/drivers/Linux/IPAddress.h @@ -70,13 +70,13 @@ class IPAddress * * @param address to be set from a 32 bits integer. */ - IPAddress(uint32_t address); + explicit IPAddress(uint32_t address); /** * @brief IPAddress constructor. * * @param address to be set from a byte array. */ - IPAddress(const uint8_t *address); + explicit IPAddress(const uint8_t *address); /** * @brief Set the IP from a array of characters. * diff --git a/drivers/Linux/Print.cpp b/drivers/Linux/Print.cpp index 86c0e20c5..a915e33fe 100644 --- a/drivers/Linux/Print.cpp +++ b/drivers/Linux/Print.cpp @@ -210,9 +210,9 @@ size_t Print::printNumber(unsigned long n, uint8_t base) } do { - unsigned long m = n; + char c = n % base; n /= base; - char c = m - base * n; + *--str = c < 10 ? c + '0' : c + 'A' - 10; } while(n); diff --git a/drivers/Linux/SerialPort.cpp b/drivers/Linux/SerialPort.cpp index 5adca054a..6621e70eb 100644 --- a/drivers/Linux/SerialPort.cpp +++ b/drivers/Linux/SerialPort.cpp @@ -5,9 +5,9 @@ * repeater and gateway builds a routing tables in EEPROM which keeps track of the * network topology allowing messages to be routed to nodes. * - * Created by Marcelo Aquino - * Copyright (C) 2016 Marcelo Aquino - * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org * Support Forum: http://forum.mysensors.org @@ -179,25 +179,23 @@ bool SerialPort::open(int bauds) bool SerialPort::setGroupPerm(const char *groupName) { - struct group* devGrp; const mode_t ttyPermissions = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; - const char *dev; - int ret; if (sd != -1 && groupName != NULL) { - devGrp = getgrnam(groupName); + struct group *devGrp = getgrnam(groupName); if (devGrp == NULL) { logError("getgrnam: %s failed. (%d) %s\n", groupName, errno, strerror(errno)); return false; } + const char *dev; if (isPty) { dev = ptsname(sd); } else { dev = serialPort.c_str(); } - ret = chown(dev, -1, devGrp->gr_gid); + int ret = chown(dev, -1, devGrp->gr_gid); if (ret == -1) { logError("Could not change PTY owner! (%d) %s\n", errno, strerror(errno)); return false; diff --git a/drivers/Linux/SerialPort.h b/drivers/Linux/SerialPort.h index 4279b3c95..edd301672 100644 --- a/drivers/Linux/SerialPort.h +++ b/drivers/Linux/SerialPort.h @@ -5,9 +5,9 @@ * repeater and gateway builds a routing tables in EEPROM which keeps track of the * network topology allowing messages to be routed to nodes. * - * Created by Marcelo Aquino - * Copyright (C) 2016 Marcelo Aquino - * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org * Support Forum: http://forum.mysensors.org diff --git a/drivers/Linux/SerialSimulator.cpp b/drivers/Linux/SerialSimulator.cpp new file mode 100644 index 000000000..b14cb6576 --- /dev/null +++ b/drivers/Linux/SerialSimulator.cpp @@ -0,0 +1,56 @@ +/* + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include +#include "SerialSimulator.h" + +void SerialSimulator::begin(int baud) +{ + (void)baud; +} + +int SerialSimulator::available() +{ + return 1; +} + +int SerialSimulator::read() +{ + return getchar(); +} + +size_t SerialSimulator::write(uint8_t b) +{ + return (size_t)::printf("%c", b); +} + +int SerialSimulator::peek() +{ + return -1; +} + +void SerialSimulator::flush() +{ + fflush(stdout); +} + +void SerialSimulator::end() +{ + flush(); +} diff --git a/drivers/Linux/SerialSimulator.h b/drivers/Linux/SerialSimulator.h new file mode 100644 index 000000000..2007d2185 --- /dev/null +++ b/drivers/Linux/SerialSimulator.h @@ -0,0 +1,76 @@ +/* + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifndef SerialSimulator_h +#define SerialSimulator_h + +#include +#include +#include +#include "Stream.h" + +/** + * @brief A class equivalent to Serial in Arduino but outputs to stdout + */ +class SerialSimulator : public Stream +{ + +public: + /** + * @brief This function does nothing. + * + * @param baud Ignored parameter. + */ + void begin(int baud); + /** + * @brief This function does nothing. + * + * @return always returns 1. + */ + int available(); + /** + * @brief Reads 1 key pressed from the keyboard. + * + * @return key character pressed cast to an int. + */ + int read(); + /** + * @brief Writes a single byte to stdout. + * + * @param b byte to write. + * @return -1 if error else, number of bytes written. + */ + size_t write(uint8_t b); + /** + * @brief Not supported. + * + * @return always returns -1. + */ + int peek(); + /** + * @brief Flush stdout. + */ + void flush(); + /** + * @brief Nothing to do, flush stdout. + */ + void end(); +}; + +#endif diff --git a/drivers/Linux/SoftEeprom.cpp b/drivers/Linux/SoftEeprom.cpp index 8a07ee5d2..4c04f5ddc 100644 --- a/drivers/Linux/SoftEeprom.cpp +++ b/drivers/Linux/SoftEeprom.cpp @@ -1,13 +1,13 @@ -/** +/* * The MySensors Arduino library handles the wireless radio link and protocol * between your home built sensors/actuators and HA controller of choice. * The sensors forms a self healing radio network with optional repeaters. Each * repeater and gateway builds a routing tables in EEPROM which keeps track of the * network topology allowing messages to be routed to nodes. * - * Created by Marcelo Aquino - * Copyright (C) 2016 Marcelo Aquino - * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org * Support Forum: http://forum.mysensors.org diff --git a/drivers/Linux/SoftEeprom.h b/drivers/Linux/SoftEeprom.h index 7b096e570..6b2431830 100644 --- a/drivers/Linux/SoftEeprom.h +++ b/drivers/Linux/SoftEeprom.h @@ -1,13 +1,13 @@ -/** +/* * The MySensors Arduino library handles the wireless radio link and protocol * between your home built sensors/actuators and HA controller of choice. * The sensors forms a self healing radio network with optional repeaters. Each * repeater and gateway builds a routing tables in EEPROM which keeps track of the * network topology allowing messages to be routed to nodes. * - * Created by Marcelo Aquino - * Copyright (C) 2016 Marcelo Aquino - * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org * Support Forum: http://forum.mysensors.org @@ -33,11 +33,6 @@ class SoftEeprom { -private: - size_t _length; //!< @brief Eeprom max size. - char *_fileName; //!< @brief file where the eeprom values are stored. - uint8_t *_values; //!< @brief copy of the eeprom values held in memory for a faster reading. - public: /** * @brief SoftEeprom constructor. @@ -86,6 +81,11 @@ class SoftEeprom * */ SoftEeprom& operator=(const SoftEeprom& other); + +private: + size_t _length; //!< @brief Eeprom max size. + char *_fileName; //!< @brief file where the eeprom values are stored. + uint8_t *_values; //!< @brief copy of the eeprom values held in memory for a faster reading. }; #endif diff --git a/drivers/Linux/Stream.h b/drivers/Linux/Stream.h index 8bacd5040..0a46b7273 100644 --- a/drivers/Linux/Stream.h +++ b/drivers/Linux/Stream.h @@ -57,6 +57,7 @@ class Stream: public Print Stream() { _timeout = 1000; + _startMillis = 0; } // parsing methods diff --git a/drivers/Linux/compatibility.cpp b/drivers/Linux/compatibility.cpp index 1f8f74837..bfd3545c5 100644 --- a/drivers/Linux/compatibility.cpp +++ b/drivers/Linux/compatibility.cpp @@ -1,3 +1,22 @@ +/* + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + #include #include #include @@ -34,7 +53,7 @@ unsigned long micros() return ((curTime.tv_sec - millis_at_start) * 1000000) + (curTime.tv_usec); } -void _delay_ms(unsigned int millis) +void _delay_milliseconds(unsigned int millis) { struct timespec sleeper; @@ -43,6 +62,15 @@ void _delay_ms(unsigned int millis) nanosleep(&sleeper, NULL); } +void _delay_microseconds(unsigned int micro) +{ + struct timespec sleeper; + + sleeper.tv_sec = (time_t)(micro / 1000000); + sleeper.tv_nsec = (long)(micro % 1000000) * 1000; + nanosleep(&sleeper, NULL); +} + void randomSeed(unsigned long seed) { if (seed != 0) { diff --git a/drivers/RPi/rpi_util.cpp b/drivers/Linux/interrupt.cpp similarity index 61% rename from drivers/RPi/rpi_util.cpp rename to drivers/Linux/interrupt.cpp index 5c24d8bdc..6730c7fe3 100644 --- a/drivers/RPi/rpi_util.cpp +++ b/drivers/Linux/interrupt.cpp @@ -5,9 +5,9 @@ * repeater and gateway builds a routing tables in EEPROM which keeps track of the * network topology allowing messages to be routed to nodes. * - * Created by Marcelo Aquino - * Copyright (C) 2016 Marcelo Aquino - * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org * Support Forum: http://forum.mysensors.org @@ -19,7 +19,7 @@ * Based on wiringPi Copyright (c) 2012 Gordon Henderson. */ -#include "rpi_util.h" +#include "interrupt.h" #include #include #include @@ -32,22 +32,14 @@ #include #include #include -#include "SPI.h" +#include #include "log.h" -#include "cpuinfo.h" - -extern "C" { - int piHiPri(const int pri); -} struct ThreadArgs { void (*func)(); int gpioPin; }; -static const int *pin_to_gpio = 0; -static rpi_info rpiinfo; - volatile bool interruptsEnabled = true; static pthread_mutex_t intMutex = PTHREAD_MUTEX_INITIALIZER; @@ -62,36 +54,23 @@ static int sysFds[64] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; -int get_gpio_number(uint8_t physPin, uint8_t *gpio) +/* + * Part of wiringPi: Simple way to get your program running at high priority + * with realtime schedulling. + */ +int piHiPri(const int pri) { - if (pin_to_gpio == 0) { - // detect board revision and set up accordingly - if (get_rpi_info(&rpiinfo)) { - logError("This module can only be run on a Raspberry Pi!\n"); - exit(1); - } + struct sched_param sched ; - if (rpiinfo.p1_revision == 1) { - pin_to_gpio = &pin_to_gpio_rev1[0]; - } else if (rpiinfo.p1_revision == 2) { - pin_to_gpio = &pin_to_gpio_rev2[0]; - } else { // assume model B+ or A+ or 2B - pin_to_gpio = &pin_to_gpio_rev3[0]; - } - } - - if ((rpiinfo.p1_revision != 3 && physPin > 26) - || (rpiinfo.p1_revision == 3 && physPin > 40)) { - return -1; - } + memset (&sched, 0, sizeof(sched)) ; - if (*(pin_to_gpio+physPin) == -1) { - return -1; + if (pri > sched_get_priority_max (SCHED_RR)) { + sched.sched_priority = sched_get_priority_max (SCHED_RR) ; } else { - *gpio = *(pin_to_gpio+physPin); + sched.sched_priority = pri ; } - return 0; + return sched_setscheduler (0, SCHED_RR, &sched) ; } void *interruptHandler(void *args) @@ -125,8 +104,14 @@ void *interruptHandler(void *args) // Do a dummy read to clear the interrupt // A one character read appars to be enough. // Followed by a seek to reset it. - (void)read (fd, &c, 1) ; - lseek (fd, 0, SEEK_SET) ; + if (read (fd, &c, 1) < 0) { + logError("Interrupt handler error: %s\n", strerror(errno)); + break; + } + if (lseek (fd, 0, SEEK_SET) < 0) { + logError("Interrupt handler error: %s\n", strerror(errno)); + break; + } // Call user function. pthread_mutex_lock(&intMutex); if (interruptsEnabled) { @@ -142,73 +127,12 @@ void *interruptHandler(void *args) return NULL; } -void rpi_util::pinMode(uint8_t physPin, uint8_t mode) -{ - uint8_t gpioPin; - - if (get_gpio_number(physPin, &gpioPin)) { - logError("pinMode: invalid pin: %d\n", physPin); - return; - } - - // Check if SPI is in use and target pin is related to SPI - if (SPIClass::is_initialized() && gpioPin >= RPI_GPIO_P1_26 && gpioPin <= RPI_GPIO_P1_23) { - return; - } else { - bcm2835_gpio_fsel(gpioPin, mode); - } -} - -void rpi_util::digitalWrite(uint8_t physPin, uint8_t value) -{ - uint8_t gpioPin; - - if (get_gpio_number(physPin, &gpioPin)) { - logError("digitalWrite: invalid pin: %d\n", physPin); - return; - } - - // Check if SPI is in use and target pin is related to SPI - if (SPIClass::is_initialized() && gpioPin >= RPI_GPIO_P1_26 && gpioPin <= RPI_GPIO_P1_23) { - if (value == LOW && (gpioPin == RPI_GPIO_P1_24 || gpioPin == RPI_GPIO_P1_26)) { - SPI.chipSelect(gpioPin); - } - } else { - bcm2835_gpio_write(gpioPin, value); - // Delay to allow any change in state to be reflected in the LEVn, register bit. - delayMicroseconds(1); - } -} - -uint8_t rpi_util::digitalRead(uint8_t physPin) -{ - uint8_t gpioPin; - - if (get_gpio_number(physPin, &gpioPin)) { - logError("digitalRead: invalid pin: %d\n", physPin); - return 0; - } - - // Check if SPI is in use and target pin is related to SPI - if (SPIClass::is_initialized() && gpioPin >= RPI_GPIO_P1_26 && gpioPin <= RPI_GPIO_P1_23) { - return 0; - } else { - return bcm2835_gpio_lev(gpioPin); - } -} - -void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode) +void attachInterrupt(uint8_t gpioPin, void (*func)(), uint8_t mode) { FILE *fd; char fName[40]; char c; int count, i; - uint8_t gpioPin; - - if (get_gpio_number(physPin, &gpioPin)) { - logError("attachInterrupt: invalid pin: %d\n", physPin); - return; - } if (threadIds[gpioPin] == NULL) { threadIds[gpioPin] = new pthread_t; @@ -216,24 +140,24 @@ void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode) // Cancel the existing thread for that pin pthread_cancel(*threadIds[gpioPin]); // Wait a bit - delay(1L); + usleep(1000); } // Export pin for interrupt if ((fd = fopen("/sys/class/gpio/export", "w")) == NULL) { - logError("attachInterrupt: Unable to export pin %d for interrupt: %s\n", physPin, strerror(errno)); + logError("attachInterrupt: Unable to export pin %d for interrupt: %s\n", gpioPin, strerror(errno)); exit(1); } fprintf(fd, "%d\n", gpioPin); fclose(fd); // Wait a bit the system to create /sys/class/gpio/gpio - delay(1L); + usleep(1000); snprintf(fName, sizeof(fName), "/sys/class/gpio/gpio%d/direction", gpioPin) ; if ((fd = fopen (fName, "w")) == NULL) { logError("attachInterrupt: Unable to open GPIO direction interface for pin %d: %s\n", - physPin, strerror(errno)); + gpioPin, strerror(errno)); exit(1) ; } fprintf(fd, "in\n") ; @@ -241,10 +165,11 @@ void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode) snprintf(fName, sizeof(fName), "/sys/class/gpio/gpio%d/edge", gpioPin) ; if ((fd = fopen(fName, "w")) == NULL) { - logError("attachInterrupt: Unable to open GPIO edge interface for pin %d: %s\n", physPin, + logError("attachInterrupt: Unable to open GPIO edge interface for pin %d: %s\n", gpioPin, strerror(errno)); exit(1) ; } + switch (mode) { case CHANGE: fprintf(fd, "both\n"); @@ -268,7 +193,7 @@ void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode) if (sysFds[gpioPin] == -1) { snprintf(fName, sizeof(fName), "/sys/class/gpio/gpio%d/value", gpioPin); if ((sysFds[gpioPin] = open(fName, O_RDWR)) < 0) { - logError("Error reading pin %d: %s\n", physPin, strerror(errno)); + logError("Error reading pin %d: %s\n", gpioPin, strerror(errno)); exit(1); } } @@ -289,15 +214,8 @@ void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode) pthread_create(threadIds[gpioPin], NULL, interruptHandler, (void *)threadArgs); } -void rpi_util::detachInterrupt(uint8_t physPin) +void detachInterrupt(uint8_t gpioPin) { - uint8_t gpioPin; - - if (get_gpio_number(physPin, &gpioPin)) { - logError("detachInterrupt: invalid pin: %d\n", physPin); - return; - } - // Cancel the thread if (threadIds[gpioPin] != NULL) { pthread_cancel(*threadIds[gpioPin]); @@ -320,20 +238,14 @@ void rpi_util::detachInterrupt(uint8_t physPin) fclose(fp); } -uint8_t rpi_util::digitalPinToInterrupt(uint8_t physPin) -{ - // No need to convert the pin to gpio, we do it in attachInterrupt(). - return physPin; -} - -void rpi_util::interrupts() +void interrupts() { pthread_mutex_lock(&intMutex); interruptsEnabled = true; pthread_mutex_unlock(&intMutex); } -void rpi_util::noInterrupts() +void noInterrupts() { pthread_mutex_lock(&intMutex); interruptsEnabled = false; diff --git a/core/MyHwRPi.h b/drivers/Linux/interrupt.h similarity index 54% rename from core/MyHwRPi.h rename to drivers/Linux/interrupt.h index 2e39d136a..4e5c3fd9c 100644 --- a/core/MyHwRPi.h +++ b/drivers/Linux/interrupt.h @@ -1,4 +1,4 @@ -/** +/* * The MySensors Arduino library handles the wireless radio link and protocol * between your home built sensors/actuators and HA controller of choice. * The sensors forms a self healing radio network with optional repeaters. Each @@ -6,8 +6,8 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2016 Sensnology AB - * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org * Support Forum: http://forum.mysensors.org @@ -15,41 +15,31 @@ * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. + * + * Based on wiringPi Copyright (c) 2012 Gordon Henderson. */ -#ifndef MyHwRPi_h -#define MyHwRPi_h +#ifndef interrupt_h +#define interrupt_h #include -#include -#include "MyHwLinuxGeneric.h" -#include "log.h" -#include "bcm2835.h" -class Bcm2835Init -{ -public: - Bcm2835Init() - { - if (!bcm2835_init()) { - logError("Failed to initialized bcm2835.\n"); - exit(1); - } - } - ~Bcm2835Init() - { - bcm2835_close(); - } -}; -Bcm2835Init bcm2835Init; +#define CHANGE 1 +#define FALLING 2 +#define RISING 3 +#define NONE 4 -#undef hwDigitalWrite -inline void hwDigitalWrite(uint8_t, uint8_t); +#ifdef __cplusplus +extern "C" { +#endif -#undef hwDigitalRead -inline int hwDigitalRead(uint8_t); +void attachInterrupt(uint8_t gpioPin, void(*func)(), uint8_t mode); +void detachInterrupt(uint8_t gpioPin); +void interrupts(); +void noInterrupts(); -#undef hwPinMode -inline void hwPinMode(uint8_t, uint8_t); +#ifdef __cplusplus +} +#endif #endif diff --git a/drivers/Linux/log.c b/drivers/Linux/log.c index a7650d149..8d33c6fe5 100644 --- a/drivers/Linux/log.c +++ b/drivers/Linux/log.c @@ -1,3 +1,22 @@ +/* + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + #include "log.h" #include #include diff --git a/drivers/Linux/log.h b/drivers/Linux/log.h index db67cf349..b49758086 100644 --- a/drivers/Linux/log.h +++ b/drivers/Linux/log.h @@ -1,3 +1,22 @@ +/* + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + #ifndef LOG_H #define LOG_H diff --git a/drivers/RF24/RF24.cpp b/drivers/RF24/RF24.cpp index 7cb3bc868..a52cba439 100644 --- a/drivers/RF24/RF24.cpp +++ b/drivers/RF24/RF24.cpp @@ -29,7 +29,7 @@ LOCAL uint8_t MY_RF24_NODE_ADDRESS = AUTO; LOCAL RF24_receiveCallbackType RF24_receiveCallback = NULL; #endif -#ifdef LINUX_ARCH_RASPBERRYPI +#ifdef LINUX_SPI_BCM uint8_t spi_rxbuff[32+1] ; //SPI receive buffer (payload max 32 bytes) uint8_t spi_txbuff[32+1] ; //SPI transmit buffer (payload max 32 bytes + 1 byte for the command) #endif @@ -56,7 +56,7 @@ LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_t RF24_csn(LOW); // timing delayMicroseconds(10); -#ifdef LINUX_ARCH_RASPBERRYPI +#ifdef LINUX_SPI_BCM uint8_t * prx = spi_rxbuff; uint8_t * ptx = spi_txbuff; uint8_t size = len + 1; // Add register value to transmit buffer diff --git a/drivers/RF24/RF24.h b/drivers/RF24/RF24.h index 15218e498..202a5dde6 100644 --- a/drivers/RF24/RF24.h +++ b/drivers/RF24/RF24.h @@ -48,7 +48,7 @@ _SPI; #define _BV(x) (1<<(x)) -#if defined(__arm__) +#if defined(__arm__) || defined(__linux__) #include #else extern HardwareSPI SPI; diff --git a/drivers/RFM95/RFM95.cpp b/drivers/RFM95/RFM95.cpp index a1cf7ba55..5ea8aba88 100644 --- a/drivers/RFM95/RFM95.cpp +++ b/drivers/RFM95/RFM95.cpp @@ -24,7 +24,7 @@ #include "RFM95.h" -#if defined(LINUX_ARCH_RASPBERRYPI) +#if defined(LINUX_SPI_BCM) // SPI RX and TX buffers (max packet len + 1 byte for the command) uint8_t spi_rxbuff[RFM95_MAX_PACKET_LEN + 1]; uint8_t spi_txbuff[RFM95_MAX_PACKET_LEN + 1]; @@ -47,7 +47,7 @@ LOCAL uint8_t RFM95_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_ MY_RFM95_SPI_DATA_MODE)); #endif RFM95_csn(LOW); -#if defined(LINUX_ARCH_RASPBERRYPI) +#if defined(LINUX_SPI_BCM) uint8_t * prx = spi_rxbuff; uint8_t * ptx = spi_txbuff; uint8_t size = len + 1; // Add register value to transmit buffer diff --git a/drivers/RPi/RPi.cpp b/drivers/RPi/RPi.cpp new file mode 100644 index 000000000..566eb44fb --- /dev/null +++ b/drivers/RPi/RPi.cpp @@ -0,0 +1,127 @@ +/* + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include "RPi.h" +#include +#include "log.h" + +const static int pin_to_gpio_rev1[41] = {-1, -1, -1, 0, -1, 1, -1, 4, 14, -1, 15, 17, 18, 21, -1, 22, 23, -1, 24, 10, -1, 9, 25, 11, 8, -1, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +const static int pin_to_gpio_rev2[41] = {-1, -1, -1, 2, -1, 3, -1, 4, 14, -1, 15, 17, 18, 27, -1, 22, 23, -1, 24, 10, -1, 9, 25, 11, 8, -1, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +const static int pin_to_gpio_rev3[41] = {-1, -1, -1, 2, -1, 3, -1, 4, 14, -1, 15, 17, 18, 27, -1, 22, 23, -1, 24, 10, -1, 9, 25, 11, 8, -1, 7, -1, -1, 5, -1, 6, 12, 13, -1, 19, 16, 26, 20, -1, 21 }; + +// Declare a single default instance +RPi rpi = RPi(); + +const int* RPi::pin_to_gpio = NULL; +rpi_info RPi::rpiinfo; + +RPi::RPi() +{ + if (!bcm2835_init()) { + logError("Failed to initialized bcm2835.\n"); + exit(1); + } +} + +RPi::~RPi() +{ + bcm2835_close(); +} + +void RPi::pinMode(uint8_t physPin, uint8_t mode) +{ + uint8_t gpioPin; + + if (physToGPIO(physPin, &gpioPin)) { + logError("pinMode: invalid pin: %d\n", physPin); + return; + } + + bcm2835_gpio_fsel(gpioPin, mode); +} + +void RPi::digitalWrite(uint8_t physPin, uint8_t value) +{ + uint8_t gpioPin; + + if (physToGPIO(physPin, &gpioPin)) { + logError("digitalWrite: invalid pin: %d\n", physPin); + return; + } + + bcm2835_gpio_write(gpioPin, value); + // Delay to allow any change in state to be reflected in the LEVn, register bit. + delayMicroseconds(1); +} + +uint8_t RPi::digitalRead(uint8_t physPin) +{ + uint8_t gpioPin; + + if (physToGPIO(physPin, &gpioPin)) { + logError("digitalRead: invalid pin: %d\n", physPin); + return 0; + } + + return bcm2835_gpio_lev(gpioPin); +} + +uint8_t RPi::digitalPinToInterrupt(uint8_t physPin) +{ + uint8_t gpioPin; + + if (physToGPIO(physPin, &gpioPin)) { + logError("digitalPinToInterrupt: invalid pin: %d\n", physPin); + return 0; + } + + return gpioPin; +} + +int RPi::physToGPIO(uint8_t physPin, uint8_t *gpio) +{ + if (pin_to_gpio == NULL) { + // detect board revision and set up accordingly + if (get_rpi_info(&rpiinfo)) { + logError("This module can only be run on a Raspberry Pi!\n"); + exit(1); + } + + if (rpiinfo.p1_revision == 1) { + pin_to_gpio = &pin_to_gpio_rev1[0]; + } else if (rpiinfo.p1_revision == 2) { + pin_to_gpio = &pin_to_gpio_rev2[0]; + } else { // assume model B+ or A+ or 2B + pin_to_gpio = &pin_to_gpio_rev3[0]; + } + } + + if ((rpiinfo.p1_revision != 3 && physPin > 26) + || (rpiinfo.p1_revision == 3 && physPin > 40)) { + return -1; + } + + if (*(pin_to_gpio+physPin) == -1) { + return -1; + } else { + *gpio = *(pin_to_gpio+physPin); + } + + return 0; +} diff --git a/drivers/RPi/RPi.h b/drivers/RPi/RPi.h new file mode 100644 index 000000000..5173c1fd6 --- /dev/null +++ b/drivers/RPi/RPi.h @@ -0,0 +1,89 @@ +/* + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifndef RPi_h +#define RPi_h + +#include +#include "bcm2835.h" +#include "cpuinfo.h" + +#define INPUT BCM2835_GPIO_FSEL_INPT +#define OUTPUT BCM2835_GPIO_FSEL_OUTP + +/** + * @brief RPi class + */ +class RPi +{ + +public: + /** + * @brief RPi constructor. + */ + RPi(); + /** + * @brief RPi destructor. + */ + ~RPi(); + /** + * @brief Configures the specified pin to behave either as an input or an output. + * + * @param physPin The physical number of the pin. + * @param mode INPUT or OUTPUT. + */ + void pinMode(uint8_t physPin, uint8_t mode); + /** + * @brief Write a high or a low value for the given pin. + * + * @param physPin The physical number of the pin. + * @param value HIGH or LOW. + */ + void digitalWrite(uint8_t physPin, uint8_t value); + /** + * @brief Reads the value from a specified pin. + * + * @param physPin The physical number of the pin. + * @return HIGH or LOW. + */ + uint8_t digitalRead(uint8_t physPin); + /** + * @brief Translate the physical pin number to the GPIO number for use in interrupt. + * + * @param physPin The physical number of the pin. + * @return The GPIO pin number. + */ + uint8_t digitalPinToInterrupt(uint8_t physPin); + /** + * @brief Translate the physical pin number to the GPIO number. + * + * @param physPin The physical number of the pin. + * @param gpio Pointer to write the GPIO pin number when success. + * @return -1 if FAILURE or 0 if SUCCESS. + */ + static int physToGPIO(uint8_t physPin, uint8_t *gpio); + +private: + static const int *pin_to_gpio; //!< @brief Pointer to array of GPIO pins numbers. + static rpi_info rpiinfo; //!< @brief Board information. +}; + +extern RPi rpi; + +#endif diff --git a/drivers/RPi/piHiPri.c b/drivers/RPi/piHiPri.c deleted file mode 100644 index 2300298c0..000000000 --- a/drivers/RPi/piHiPri.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * piHiPri: - * Simple way to get your program running at high priority - * with realtime schedulling. - * - * Copyright (c) 2012 Gordon Henderson - *********************************************************************** - * This file is part of wiringPi: - * https://projects.drogon.net/raspberry-pi/wiringpi/ - * - * wiringPi 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 3 of the - * License, or (at your option) any later version. - * - * wiringPi 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. - * - * You should have received a copy of the GNU Lesser General Public - * License along with wiringPi. - * If not, see . - *********************************************************************** - */ - -#include -#include - -/* - * piHiPri: - * Attempt to set a high priority schedulling for the running program - ********************************************************************************* - */ - -int piHiPri (const int pri) -{ - struct sched_param sched ; - - memset (&sched, 0, sizeof(sched)) ; - - if (pri > sched_get_priority_max (SCHED_RR)) { - sched.sched_priority = sched_get_priority_max (SCHED_RR) ; - } else { - sched.sched_priority = pri ; - } - - return sched_setscheduler (0, SCHED_RR, &sched) ; -} diff --git a/drivers/RPi/rpi_util.h b/drivers/RPi/rpi_util.h deleted file mode 100644 index 9e115d2ce..000000000 --- a/drivers/RPi/rpi_util.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * The MySensors Arduino library handles the wireless radio link and protocol - * between your home built sensors/actuators and HA controller of choice. - * The sensors forms a self healing radio network with optional repeaters. Each - * repeater and gateway builds a routing tables in EEPROM which keeps track of the - * network topology allowing messages to be routed to nodes. - * - * Created by Marcelo Aquino - * Copyright (C) 2016 Marcelo Aquino - * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors - * - * Documentation: http://www.mysensors.org - * Support Forum: http://forum.mysensors.org - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * Based on wiringPi Copyright (c) 2012 Gordon Henderson. - */ - -#ifndef rpi_util_h -#define rpi_util_h - -#include -#include "bcm2835.h" - -const int pin_to_gpio_rev1[41] = {-1, -1, -1, 0, -1, 1, -1, 4, 14, -1, 15, 17, 18, 21, -1, 22, 23, -1, 24, 10, -1, 9, 25, 11, 8, -1, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; -const int pin_to_gpio_rev2[41] = {-1, -1, -1, 2, -1, 3, -1, 4, 14, -1, 15, 17, 18, 27, -1, 22, 23, -1, 24, 10, -1, 9, 25, 11, 8, -1, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; -const int pin_to_gpio_rev3[41] = {-1, -1, -1, 2, -1, 3, -1, 4, 14, -1, 15, 17, 18, 27, -1, 22, 23, -1, 24, 10, -1, 9, 25, 11, 8, -1, 7, -1, -1, 5, -1, 6, 12, 13, -1, 19, 16, 26, 20, -1, 21 }; - -namespace rpi_util -{ - -typedef enum { - LSBFIRST = BCM2835_SPI_BIT_ORDER_LSBFIRST, - MSBFIRST = BCM2835_SPI_BIT_ORDER_MSBFIRST -} rpi_bitorder; - -typedef enum { - INPUT = BCM2835_GPIO_FSEL_INPT, - OUTPUT = BCM2835_GPIO_FSEL_OUTP -} rpi_pinmode; - -typedef enum { - CHANGE = 1, - FALLING = 2, - RISING = 3, - NONE = 4 -} rpi_pinedge; - -typedef enum { - PIN_SPI_SS = 24, - PIN_SPI_MOSI = 19, - PIN_SPI_MISO = 21, - PIN_SPI_SCK = 23 -} rpi_spipins; - -const uint8_t SS = PIN_SPI_SS; -const uint8_t MOSI = PIN_SPI_MOSI; -const uint8_t MISO = PIN_SPI_MISO; -const uint8_t SCK = PIN_SPI_SCK; - -/* Some useful arduino functions */ -void pinMode(uint8_t physPin, uint8_t mode); -void digitalWrite(uint8_t physPin, uint8_t value); -uint8_t digitalRead(uint8_t physPin); -void attachInterrupt(uint8_t physPin,void (*func)(), uint8_t mode); -void detachInterrupt(uint8_t physPin); -uint8_t digitalPinToInterrupt(uint8_t physPin); -void interrupts(); -void noInterrupts(); - -} - -#endif diff --git a/drivers/SPIDEV/SPI.cpp b/drivers/SPIDEV/SPI.cpp new file mode 100644 index 000000000..2f6c5b30d --- /dev/null +++ b/drivers/SPIDEV/SPI.cpp @@ -0,0 +1,289 @@ +/* + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * Based on TMRh20 RF24 library, Copyright (c) 2015 Charles-Henri Hallard + */ + +#include "SPI.h" +#include +#include +#include +#include +#include +#include +#include "log.h" + +static pthread_mutex_t spiMutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutexattr_t attr; + +// Declare a single default instance +SPIClass SPI = SPIClass(); + +uint8_t SPIClass::initialized = 0; +int SPIClass::fd = -1; +std::string SPIClass::device = SPI_SPIDEV_DEVICE; +uint32_t SPIClass::speed = SPI_CLOCK_BASE; +uint32_t SPIClass::speed_temp = SPI_CLOCK_BASE; +struct spi_ioc_transfer SPIClass::tr = {0,0,0,0,0,8,1,0,0,0}; // 8 bits_per_word, 1 cs_change + +SPIClass::SPIClass() +{ + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&spiMutex, &attr); +} + +void SPIClass::begin(int busNo) +{ + if (!initialized) { + /* set spidev accordingly to busNo like: + * busNo = 23 -> /dev/spidev2.3 + * + * a bit messy but simple + * */ + device[11] += (busNo / 10) % 10; + device[13] += busNo % 10; + + init(); + } + + initialized++; // reference count +} + +void SPIClass::end() +{ + if (initialized) { + initialized--; + } + + if (!initialized) { + if (!(fd < 0)) { + close(fd); + fd = -1; + } + } +} + +void SPIClass::setBitOrder(uint8_t bit_order) +{ + pthread_mutex_lock(&spiMutex); + + /* + * bit order + */ + int lsb_setting = bit_order; + int ret = ioctl(fd, SPI_IOC_WR_LSB_FIRST, &lsb_setting); + if (ret == -1) { + logError("Can't set SPI bit order.\n"); + abort(); + } + + pthread_mutex_unlock(&spiMutex); +} + +void SPIClass::setDataMode(uint8_t data_mode) +{ + pthread_mutex_lock(&spiMutex); + + /* + * spi mode + */ + int ret = ioctl(fd, SPI_IOC_WR_MODE, &data_mode); + if (ret == -1) { + logError("Can't set SPI mode.\n"); + abort(); + } + + pthread_mutex_unlock(&spiMutex); +} + +void SPIClass::setClockDivider(uint16_t divider) +{ + pthread_mutex_lock(&spiMutex); + + /* + * max speed hz + */ + speed = SPI_CLOCK_BASE / divider; + int ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); + if (ret == -1) { + logError("Can't set SPI max speed hz.\n"); + abort(); + } + + pthread_mutex_unlock(&spiMutex); +} + +void SPIClass::chipSelect(int csn_chip) +{ + if (csn_chip >= 0 && csn_chip <= 9) { + device[13] = '0' + (csn_chip % 10); + + init(); + } +} + +uint8_t SPIClass::transfer(uint8_t data) +{ + int ret; + uint8_t tx[1] = {data}; + uint8_t rx[1] = {0}; + + pthread_mutex_lock(&spiMutex); + + tr.tx_buf = (unsigned long)&tx[0]; + tr.rx_buf = (unsigned long)&rx[0]; + tr.len = 1; + tr.speed_hz = speed; + + ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); + if (ret < 1) { + logError("Can't send spi message.\n"); + abort(); + } + + pthread_mutex_unlock(&spiMutex); + + return rx[0]; +} + +void SPIClass::transfernb(char* tbuf, char* rbuf, uint32_t len) +{ + int ret; + + pthread_mutex_lock(&spiMutex); + + tr.tx_buf = (unsigned long)tbuf; + tr.rx_buf = (unsigned long)rbuf; + tr.len = len; + tr.speed_hz = speed; + + ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr); + if (ret < 1) { + logError("Can't send spi message.\n"); + abort(); + } + + pthread_mutex_unlock(&spiMutex); +} + +void SPIClass::transfern(char* buf, uint32_t len) +{ + transfernb(buf, buf, len); +} + +void SPIClass::beginTransaction(SPISettings settings) +{ + int ret; + + pthread_mutex_lock(&spiMutex); + + /* + * spi mode + */ + ret = ioctl(fd, SPI_IOC_WR_MODE, &settings.dmode); + if (ret == -1) { + logError("Can't set spi mode.\n"); + abort(); + } + + // Save the current speed + speed_temp = speed; + speed = settings.clock; + + /* + * bit order + */ + ret = ioctl(fd, SPI_IOC_WR_LSB_FIRST, &settings.border); + if (ret == -1) { + logError("Can't set bits per word.\n"); + abort(); + } +} + +void SPIClass::endTransaction() +{ + speed = speed_temp; + pthread_mutex_unlock(&spiMutex); +} + +void SPIClass::usingInterrupt(uint8_t interruptNumber) +{ + (void)interruptNumber; +} + +void SPIClass::notUsingInterrupt(uint8_t interruptNumber) +{ + (void)interruptNumber; +} + +void SPIClass::init() +{ + pthread_mutex_lock(&spiMutex); + + if (fd >= 0) { + close(fd); + } + + fd = open(device.c_str(), O_RDWR); + if (fd < 0) { + logError("Can't open SPI device: %s\n", device.c_str()); + abort(); + } + + /* + * spi mode + */ + uint8_t mode = SPI_MODE0; + int ret = ioctl(fd, SPI_IOC_WR_MODE, &mode); + if (ret == -1) { + logError("Can't set SPI mode.\n"); + abort(); + } + + /* + * bits per word + */ + uint8_t bits = 0; // 0 corresponds to 8 bits per word + ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits); + if (ret == -1) { + logError("Can't set SPI bits per word.\n"); + abort(); + } + + /* + * max speed hz + */ + speed = SPI_CLOCK_BASE; + ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed); + if (ret == -1) { + logError("Can't set SPI max speed hz.\n"); + abort(); + } + + /* + * bit order + */ + int lsb_setting = MSBFIRST; + ret = ioctl(fd, SPI_IOC_WR_LSB_FIRST, &lsb_setting); + if (ret == -1) { + logError("Can't set SPI bit order.\n"); + abort(); + } + + pthread_mutex_unlock(&spiMutex); +} diff --git a/drivers/SPIDEV/SPI.h b/drivers/SPIDEV/SPI.h new file mode 100644 index 000000000..85ed6c810 --- /dev/null +++ b/drivers/SPIDEV/SPI.h @@ -0,0 +1,206 @@ +/* + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2017 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * Based on TMRh20 RF24 library, Copyright (c) 2015 Charles-Henri Hallard + */ + +#ifndef SPI_H +#define SPI_H + +#include +#include +#include + +#define SPI_HAS_TRANSACTION + +#define MSBFIRST 0 +#define LSBFIRST SPI_LSB_FIRST + +#define SPI_CLOCK_BASE 16000000 // 16Mhz + +#define SPI_CLOCK_DIV2 2 +#define SPI_CLOCK_DIV4 4 +#define SPI_CLOCK_DIV8 8 +#define SPI_CLOCK_DIV16 16 +#define SPI_CLOCK_DIV32 32 +#define SPI_CLOCK_DIV64 64 +#define SPI_CLOCK_DIV128 128 + +// SPI Data mode +#define SPI_MODE0 SPI_MODE_0 +#define SPI_MODE1 SPI_MODE_1 +#define SPI_MODE2 SPI_MODE_2 +#define SPI_MODE3 SPI_MODE_3 + +#ifndef SPI_SPIDEV_DEVICE +#define SPI_SPIDEV_DEVICE "/dev/spidev0.0" +#endif + +// Default to Raspberry Pi +const uint8_t SS = 24; +const uint8_t MOSI = 19; +const uint8_t MISO = 21; +const uint8_t SCK = 23; + +/** + * SPISettings class + */ +class SPISettings +{ + +public: + /** + * @brief SPISettings constructor. + */ + SPISettings() + { + init(SPI_CLOCK_BASE, MSBFIRST, SPI_MODE0); + } + /** + * @brief SPISettings constructor. + * + * @param clock SPI clock speed in Hz. + * @param bitOrder SPI bit order. + * @param dataMode SPI data mode. + */ + SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) + { + init(clock, bitOrder, dataMode); + } + + uint32_t clock; //!< @brief SPI clock. + uint8_t border; //!< @brief SPI bit order. + uint8_t dmode; //!< @brief SPI data mode. + +private: + /** + * @brief Initialized class members. + * + * @param clk SPI clock. + * @param bitOrder SPI bit order. + * @param dataMode SPI data mode. + */ + void init(uint32_t clk, uint8_t bitOrder, uint8_t dataMode) + { + clock = clk; + border = bitOrder; + dmode = dataMode; + } + + friend class SPIClass; +}; + +class SPIClass +{ + +public: + /** + * @brief SPIClass constructor. + */ + SPIClass(); + /** + * @brief Start SPI operations. + */ + static void begin(int busNo=0); + /** + * @brief End SPI operations. + */ + static void end(); + /** + * @brief Sets the SPI bit order. + * + * @param bit_order The desired bit order. + */ + static void setBitOrder(uint8_t bit_order); + /** + * @brief Sets the SPI data mode. + * + * @param data_mode The desired data mode. + */ + static void setDataMode(uint8_t data_mode); + /** + * @brief Sets the SPI clock divider and therefore the SPI clock speed. + * + * @param divider The desired SPI clock divider. + */ + static void setClockDivider(uint16_t divider); + /** + * @brief Sets the chip select pin. + * + * @param csn_chip Specifies the CS chip. + */ + static void chipSelect(int csn_chip); + /** + * @brief Transfer a single byte + * + * @param data Byte to send + * @return Data returned via spi + */ + static uint8_t transfer(uint8_t data); + /** + * @brief Transfer a buffer of data + * + * @param tbuf Transmit buffer + * @param rbuf Receive buffer + * @param len Length of the data + */ + static void transfernb(char* tbuf, char* rbuf, uint32_t len); + /** + * @briefTransfer a buffer of data without an rx buffer + * + * @param buf Pointer to a buffer of data + * @param len Length of the data + */ + static void transfern(char* buf, uint32_t len); + /** + * @brief Start SPI transaction. + * + * @param settings for SPI. + */ + static void beginTransaction(SPISettings settings); + /** + * @brief End SPI transaction. + */ + static void endTransaction(); + /** + * @brief Not implemented. + * + * @param interruptNumber ignored parameter. + */ + static void usingInterrupt(uint8_t interruptNumber); + /** + * @brief Not implemented. + * + * @param interruptNumber ignored parameter. + */ + static void notUsingInterrupt(uint8_t interruptNumber); + +private: + static uint8_t initialized; //!< @brief SPI initialized flag. + static int fd; //!< @brief SPI device file descriptor. + static std::string device; //!< @brief Default SPI device. + static uint32_t speed; //!< @brief SPI speed. + static uint32_t speed_temp; //!< @brief Used when doing transaction. + static struct spi_ioc_transfer tr; //!< @brief Auxiliar struct for data transfer. + + static void init(); +}; + +extern SPIClass SPI; + +#endif diff --git a/drivers/SPIFlash/SPIFlash.cpp b/drivers/SPIFlash/SPIFlash.cpp index cd3d8738a..f1427667b 100644 --- a/drivers/SPIFlash/SPIFlash.cpp +++ b/drivers/SPIFlash/SPIFlash.cpp @@ -60,7 +60,7 @@ void SPIFlash::select() #ifndef SPI_HAS_TRANSACTION noInterrupts(); #endif -#ifndef ESP8266 +#if defined(SPCR) && defined(SPSR) _SPCR = SPCR; _SPSR = SPSR; #endif @@ -88,7 +88,7 @@ void SPIFlash::unselect() #else interrupts(); #endif -#ifndef ESP8266 +#if defined(SPCR) && defined(SPSR) SPCR = _SPCR; SPSR = _SPSR; #endif @@ -97,7 +97,7 @@ void SPIFlash::unselect() /// setup SPI, read device ID etc... boolean SPIFlash::initialize() { -#ifndef ESP8266 +#if defined(SPCR) && defined(SPSR) _SPCR = SPCR; _SPSR = SPSR; #endif diff --git a/examples/MockMySensors/MockMySensors.ino b/examples/MockMySensors/MockMySensors.ino index 6850f9a47..197369271 100644 --- a/examples/MockMySensors/MockMySensors.ino +++ b/examples/MockMySensors/MockMySensors.ino @@ -350,7 +350,7 @@ void presentation() // Get controller configuration Serial.print("Get Config: "); - metric = getConfig().isMetric; + metric = getControllerConfig().isMetric; Serial.println(metric ? "Metric":"Imperial"); wait(LONG_WAIT); diff --git a/examples/PingPongSensor/PingPongSensor.ino b/examples/PingPongSensor/PingPongSensor.ino index b21de5637..7f7023ad0 100644 --- a/examples/PingPongSensor/PingPongSensor.ino +++ b/examples/PingPongSensor/PingPongSensor.ino @@ -84,7 +84,7 @@ void sendPingOrPongResponse( MyMessage msg ) nodeTypeAsCharRepresentation(msg.sender)); // Set payload to current time in millis to ensure each message is unique - response.set( millis() ); + response.set( (uint32_t)millis() ); response.setDestination(msg.sender); send(response); } @@ -92,7 +92,7 @@ void sendPingOrPongResponse( MyMessage msg ) void setNodeId(byte nodeID) { LOG(F("Setting node id to: %i.\n***Please restart the node for changes to take effect.\n"), nodeID); - eeprom_write_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, (byte)nodeID); + hwWriteConfig(EEPROM_NODE_ID_ADDRESS, (byte)nodeID); } const char * msgTypeAsCharRepresentation( mysensor_data mType ) @@ -103,4 +103,4 @@ const char * msgTypeAsCharRepresentation( mysensor_data mType ) const char * nodeTypeAsCharRepresentation( uint8_t node ) { return node == YING ? "Ying Node" : "Yang Node"; -} +} \ No newline at end of file diff --git a/examples_linux/mysgw.cpp b/examples_linux/mysgw.cpp index 9812c4f55..483124099 100644 --- a/examples_linux/mysgw.cpp +++ b/examples_linux/mysgw.cpp @@ -1,4 +1,4 @@ -/** +/* * The MySensors Arduino library handles the wireless radio link and protocol * between your home built sensors/actuators and HA controller of choice. * The sensors forms a self healing radio network with optional repeaters. Each @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2016 Sensnology AB + * Copyright (C) 2013-2017 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -33,7 +33,7 @@ // Enable this if you are using an Arduino connected to the USB //#define MY_LINUX_SERIAL_PORT "/dev/ttyACM0" // Enable this if you need to connect to a controller running on the same device -//#define MY_IS_SERIAL_PTY +//#define MY_LINUX_IS_SERIAL_PTY // Choose a symlink name for the PTY device //#define MY_LINUX_SERIAL_PTY "/dev/ttyMySensorsGateway" // Grant access to the specified system group for the serial device diff --git a/library.json b/library.json index 4ed3cc680..39bb8f328 100644 --- a/library.json +++ b/library.json @@ -7,22 +7,18 @@ "type": "git", "url": "https://github.com/mysensors/MySensors.git" }, - "version": "2.1.0", + "version": "2.1.1", "frameworks": "arduino", "platforms": [ "atmelavr", "atmelsam", - "espressif" + "espressif8266" ], - "exclude": [ - "tests", - "Documentation" - ], - "build": { - "srcFilter": [ - "+<*.c>", - "+<*.cpp>", - "+<*.h>" + "export": { + "exclude": [ + "tests", + "Documentation", + "Doxyfile" ] } -} +} \ No newline at end of file diff --git a/library.properties b/library.properties index 9171bac3f..1ed0798f5 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=MySensors -version=2.1.0 +version=2.1.1 author=The MySensors Team maintainer=The MySensors Team sentence=Home Automation Framework diff --git a/tests/Arduino/sketches/ota_firmware_update_nrf24/ota_firmware_update_nrf24.ino b/tests/Arduino/sketches/ota_firmware_update_nrf24/ota_firmware_update_nrf24.ino new file mode 100644 index 000000000..038cb37ea --- /dev/null +++ b/tests/Arduino/sketches/ota_firmware_update_nrf24/ota_firmware_update_nrf24.ino @@ -0,0 +1,26 @@ +/* + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2015 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + ******************************* + */ +#include +#include +#define MY_DEBUG +#define MY_RADIO_NRF24 +#define MY_OTA_FIRMWARE_FEATURE +#include