From 50b6277c4574952d4311ee1ee1d1dd2be0426585 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sun, 10 Jul 2016 00:20:45 +0200 Subject: [PATCH 001/167] Update README.md Fixed doxygen links (these are broken on master as well). --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 25b462a0b..db75a27f4 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Please visit www.mysensors.org for more information Doxygen ------- -[master](https://ci.mysensors.org/job/MySensorsArduino/branch/master/Doxygen_HTML/index.html) [development](https://ci.mysensors.org/job/MySensorsArduino/branch/development/Doxygen_HTML/index.html) +[master](https://ci.mysensors.org/job/Verifiers/job/MySensorsArduino/branch/master/Doxygen_HTML/index.html) [development](https://ci.mysensors.org/job/Verifiers/job/MySensorsArduino/branch/development/Doxygen_HTML/index.html) CI statuses ----------- From a36299f3d96bca67e9a6b9a8624a22bb60e8bf6c Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 13 Jul 2016 15:05:14 +0300 Subject: [PATCH 002/167] Fix repo url; update version; explain builder which files to build --- library.json | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/library.json b/library.json index 9bd099ad1..639f9236b 100644 --- a/library.json +++ b/library.json @@ -2,13 +2,19 @@ "name": "MySensors", "keywords": "framework, sensor, rf", "description": "Home Automation Framework. Create your own wireless sensor mesh using NRF24L01+ and RFM69 radios running on Arduino or ESP8266. Over-the-air updates and MySensors support in 16+ home automation controllers.", - "include": "libraries/MySensors", "repository": { "type": "git", - "url": "https://github.com/mysensors/Arduino.git" + "url": "https://github.com/mysensors/MySensors.git" }, - "version": "2.0.0-beta", + "version": "2.0.0", "frameworks": "arduino", - "platforms": "*" + "platforms": "*", + "build": { + "srcFilter": [ + "+<*.c>", + "+<*.cpp>", + "+<*.h>" + ] + } } From 293604c9a2f7e6c7feb15f8dcb1eacc525408393 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 13 Jul 2016 15:20:33 +0300 Subject: [PATCH 003/167] Exclude not required for build process content --- library.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library.json b/library.json index 639f9236b..d23b5386c 100644 --- a/library.json +++ b/library.json @@ -10,6 +10,10 @@ "version": "2.0.0", "frameworks": "arduino", "platforms": "*", + "exclude": [ + "tests", + "Documentation" + ], "build": { "srcFilter": [ "+<*.c>", From eeee3310f9ac838de8f199aa20ff8594542ce931 Mon Sep 17 00:00:00 2001 From: tekka007 Date: Wed, 13 Jul 2016 21:16:50 +0200 Subject: [PATCH 004/167] Move setup() call after node registration --- core/MySensorsCore.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 7ab8b20b6..bbe1566ed 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -145,10 +145,6 @@ void _begin() { } #endif - // Call sketch setup - if (setup) - setup(); - #if defined(MY_RADIO_FEATURE) presentNode(); #endif @@ -156,6 +152,11 @@ void _begin() { // register node _registerNode(); + // Call sketch setup + if (setup) { + setup(); + } + debug(PSTR("Init complete, id=%d, parent=%d, distance=%d, registration=%d\n"), _nc.nodeId, _nc.parentNodeId, _nc.distance, _nodeRegistered); } From 5f9c51c2d4ad68033ccf9c0d5455234535ca6f97 Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Wed, 13 Jul 2016 22:40:05 +0300 Subject: [PATCH 005/167] Update version to beta --- library.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.json b/library.json index d23b5386c..ded8f1295 100644 --- a/library.json +++ b/library.json @@ -7,7 +7,7 @@ "type": "git", "url": "https://github.com/mysensors/MySensors.git" }, - "version": "2.0.0", + "version": "2.0.0-beta", "frameworks": "arduino", "platforms": "*", "exclude": [ From 312a69bb6ce3b76d7b1ab014a1ac4324dbd338f0 Mon Sep 17 00:00:00 2001 From: tekka007 Date: Thu, 14 Jul 2016 21:48:01 +0200 Subject: [PATCH 006/167] Calling WiFi.config() before WiFi.begin() --- core/MyGatewayTransportEthernet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/MyGatewayTransportEthernet.cpp b/core/MyGatewayTransportEthernet.cpp index 2db3b5ac8..3d6b0fc4f 100644 --- a/core/MyGatewayTransportEthernet.cpp +++ b/core/MyGatewayTransportEthernet.cpp @@ -106,10 +106,10 @@ bool gatewayTransportInit() { #if defined(MY_ESP8266_HOSTNAME) WiFi.hostname(MY_ESP8266_HOSTNAME); #endif - (void)WiFi.begin(MY_ESP8266_SSID, MY_ESP8266_PASSWORD); #ifdef MY_IP_ADDRESS WiFi.config(_ethernetGatewayIP, _gatewayIp, _subnetIp); #endif + (void)WiFi.begin(MY_ESP8266_SSID, MY_ESP8266_PASSWORD); while (WiFi.status() != WL_CONNECTED) { delay(500); From f0f2542df40c1ac3d4bb6d43b856bc8c6fc61a21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Sat, 16 Jul 2016 10:01:28 +0200 Subject: [PATCH 007/167] Various fixes for SAMD (#510) * Only serial GW should hold back on USB * Fixing some examples on archs other than avr * HwInit() is needed on samd, to init I2C --- core/MyHwSAMD.cpp | 8 +- .../AirQualitySensor/AirQualitySensor.ino | 118 ++--- .../BinarySwitchSleepSensor.ino | 32 +- .../DimmableLEDActuator.ino | 47 +- examples/DimmableLight/DimmableLight.ino | 39 +- examples/DustSensor/DustSensor.ino | 2 +- examples/LightSensor/LightSensor.ino | 2 +- examples/MockMySensors/MockMySensors.ino | 443 +++++++++--------- .../SecurityPersonalizer.ino | 2 +- examples/VibrationSensor/VibrationSensor.ino | 20 +- 10 files changed, 352 insertions(+), 361 deletions(-) diff --git a/core/MyHwSAMD.cpp b/core/MyHwSAMD.cpp index 115400a28..264da9c17 100644 --- a/core/MyHwSAMD.cpp +++ b/core/MyHwSAMD.cpp @@ -68,7 +68,7 @@ void hwReadConfigBlock(void* buf, void* adr, size_t length) int offs = reinterpret_cast(adr); while (length-- > 0) { - *dst++ = i2c_eeprom_read_byte(offs++); + *dst++ = i2c_eeprom_read_byte(offs++); } } @@ -100,7 +100,7 @@ void hwWriteConfig(int adr, uint8_t value) void hwInit() { MY_SERIALDEVICE.begin(MY_BAUD_RATE); - #ifndef MY_GATEWAY_W5100 + #if defined(MY_GATEWAY_SERIAL) while (!MY_SERIALDEVICE) {} #endif Wire.begin(); @@ -142,12 +142,12 @@ uint16_t hwCPUVoltage() { // TODO: Not supported! return 0; } - + uint16_t hwCPUFrequency() { // TODO: Not supported! return 0; } - + uint16_t hwFreeMem() { // TODO: Not supported! return 0; diff --git a/examples/AirQualitySensor/AirQualitySensor.ino b/examples/AirQualitySensor/AirQualitySensor.ino index 369cf8d89..f2bc01bbb 100644 --- a/examples/AirQualitySensor/AirQualitySensor.ino +++ b/examples/AirQualitySensor/AirQualitySensor.ino @@ -21,30 +21,30 @@ * DESCRIPTION * * Connect the MQ2 sensor as follows : - * + * * A H A >>> 5V * B >>> A0 * H >>> GND * B >>> 10K ohm >>> GND - * + * * Contribution: epierre * Based on http://sandboxelectronics.com/?p=165 * License: Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0) * Modified by HEK to work in 1.4 - * + * */ // Enable debug prints to serial monitor -#define MY_DEBUG +#define MY_DEBUG // Enable and select radio type attached #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 #include -#include +#include -#define CHILD_ID_MQ 0 +#define CHILD_ID_MQ 0 /************************Hardware Related Macros************************************/ #define MQ_SENSOR_ANALOG_PIN (0) //define which analog input channel you are going to use #define RL_VALUE (5) //define the load resistance on the board, in kilo ohms @@ -55,7 +55,7 @@ #define CALIBRATION_SAMPLE_INTERVAL (500) //define the time interal(in milisecond) between each samples in the //cablibration phase #define READ_SAMPLE_INTERVAL (50) //define how many samples you are going to take in normal operation -#define READ_SAMPLE_TIMES (5) //define the time interal(in milisecond) between each samples in +#define READ_SAMPLE_TIMES (5) //define the time interal(in milisecond) between each samples in //normal operation /**********************Application Related Macros**********************************/ #define GAS_LPG (0) @@ -68,25 +68,25 @@ float Ro = 10000.0; // this has to be tuned 10K Ohm int val = 0; // variable to store the value coming from the sensor float valMQ =0.0; float lastMQ =0.0; -float LPGCurve[3] = {2.3,0.21,-0.47}; //two points are taken from the curve. +float LPGCurve[3] = {2.3,0.21,-0.47}; //two points are taken from the curve. //with these two points, a line is formed which is "approximately equivalent" - //to the original curve. - //data format:{ x, y, slope}; point1: (lg200, 0.21), point2: (lg10000, -0.59) -float COCurve[3] = {2.3,0.72,-0.34}; //two points are taken from the curve. - //with these two points, a line is formed which is "approximately equivalent" //to the original curve. - //data format:{ x, y, slope}; point1: (lg200, 0.72), point2: (lg10000, 0.15) -float SmokeCurve[3] ={2.3,0.53,-0.44}; //two points are taken from the curve. - //with these two points, a line is formed which is "approximately equivalent" + //data format:{ x, y, slope}; point1: (lg200, 0.21), point2: (lg10000, -0.59) +float COCurve[3] = {2.3,0.72,-0.34}; //two points are taken from the curve. + //with these two points, a line is formed which is "approximately equivalent" + //to the original curve. + //data format:{ x, y, slope}; point1: (lg200, 0.72), point2: (lg10000, 0.15) +float SmokeCurve[3] ={2.3,0.53,-0.44}; //two points are taken from the curve. + //with these two points, a line is formed which is "approximately equivalent" //to the original curve. - //data format:{ x, y, slope}; point1: (lg200, 0.53), point2:(lg10000,-0.22) + //data format:{ x, y, slope}; point1: (lg200, 0.53), point2:(lg10000,-0.22) MyMessage msg(CHILD_ID_MQ, V_LEVEL); -void setup() -{ - Ro = MQCalibration(MQ_SENSOR_ANALOG_PIN); //Calibrating the sensor. Please make sure the sensor is in clean air +void setup() +{ + Ro = MQCalibration(MQ_SENSOR_ANALOG_PIN); //Calibrating the sensor. Please make sure the sensor is in clean air } void presentation() { @@ -94,33 +94,33 @@ void presentation() { sendSketchInfo("Air Quality Sensor", "1.0"); // Register all sensors to gateway (they will be created as child devices) - present(CHILD_ID_MQ, S_AIR_QUALITY); + present(CHILD_ID_MQ, S_AIR_QUALITY); } -void loop() -{ +void loop() +{ uint16_t valMQ = MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_CO); Serial.println(val); - - Serial.print("LPG:"); + + Serial.print("LPG:"); Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_LPG) ); Serial.print( "ppm" ); - Serial.print(" "); - Serial.print("CO:"); + Serial.print(" "); + Serial.print("CO:"); Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_CO) ); Serial.print( "ppm" ); - Serial.print(" "); - Serial.print("SMOKE:"); + Serial.print(" "); + Serial.print("SMOKE:"); Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_SMOKE) ); Serial.print( "ppm" ); Serial.print("\n"); - + if (valMQ != lastMQ) { - send(msg.set((int)ceil(valMQ))); + send(msg.set((int16_t)ceil(valMQ))); lastMQ = ceil(valMQ); } - - sleep(SLEEP_TIME); //sleep for: sleepTime + + sleep(SLEEP_TIME); //sleep for: sleepTime } /****************** MQResistanceCalculation **************************************** @@ -129,35 +129,35 @@ Output: the calculated sensor resistance Remarks: The sensor and the load resistor forms a voltage divider. Given the voltage across the load resistor and its resistance, the resistance of the sensor could be derived. -************************************************************************************/ +************************************************************************************/ float MQResistanceCalculation(int raw_adc) { return ( ((float)RL_VALUE*(1023-raw_adc)/raw_adc)); } - + /***************************** MQCalibration **************************************** Input: mq_pin - analog channel Output: Ro of the sensor -Remarks: This function assumes that the sensor is in clean air. It use - MQResistanceCalculation to calculates the sensor resistance in clean air - and then divides it with RO_CLEAN_AIR_FACTOR. RO_CLEAN_AIR_FACTOR is about +Remarks: This function assumes that the sensor is in clean air. It use + MQResistanceCalculation to calculates the sensor resistance in clean air + and then divides it with RO_CLEAN_AIR_FACTOR. RO_CLEAN_AIR_FACTOR is about 10, which differs slightly between different sensors. -************************************************************************************/ +************************************************************************************/ float MQCalibration(int mq_pin) { int i; float val=0; - + for (i=0;i Vera Arduino Sensor project. + * This sketch provides a Dimmable LED Light using PWM and based Henrik Ekblad + * Vera Arduino Sensor project. * Developed by Bruce Lacey, inspired by Hek's MySensor's example sketches. - * - * The circuit uses a MOSFET for Pulse-Wave-Modulation to dim the attached LED or LED strip. + * + * The circuit uses a MOSFET for Pulse-Wave-Modulation to dim the attached LED or LED strip. * The MOSFET Gate pin is connected to Arduino pin 3 (LED_PIN), the MOSFET Drain pin is connected - * to the LED negative terminal and the MOSFET Source pin is connected to ground. + * to the LED negative terminal and the MOSFET Source pin is connected to ground. * * This sketch is extensible to support more than one MOSFET/PWM dimmer per circuit. * http://www.mysensors.org/build/dimmer */ // Enable debug prints to serial monitor -#define MY_DEBUG +#define MY_DEBUG // Enable and select radio type attached #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 #include -#include +#include #define SN "DimmableLED" #define SV "1.1" @@ -51,7 +51,7 @@ #define LED_PIN 3 // Arduino pin attached to MOSFET Gate pin #define FADE_DELAY 10 // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim) -static int currentLevel = 0; // Current dim level... +static int16_t currentLevel = 0; // Current dim level... MyMessage dimmerMsg(0, V_DIMMER); MyMessage lightMsg(0, V_LIGHT); @@ -59,8 +59,8 @@ MyMessage lightMsg(0, V_LIGHT); /*** * Dimmable LED initialization method */ -void setup() -{ +void setup() +{ // Pull the gateway's current dim level - restore light level upon sendor node power-up request( 0, V_DIMMER ); } @@ -68,14 +68,14 @@ void setup() void presentation() { // Register the LED Dimmable Light with the gateway present( 0, S_DIMMER ); - + sendSketchInfo(SN, SV); } /*** - * Dimmable LED main processing loop + * Dimmable LED main processing loop */ -void loop() +void loop() { } @@ -83,31 +83,31 @@ void loop() void receive(const MyMessage &message) { if (message.type == V_LIGHT || message.type == V_DIMMER) { - + // Retrieve the power or dim level from the incoming request message int requestedLevel = atoi( message.data ); - + // Adjust incoming level if this is a V_LIGHT variable update [0 == off, 1 == on] requestedLevel *= ( message.type == V_LIGHT ? 100 : 1 ); - + // Clip incoming level to valid range of 0 to 100 requestedLevel = requestedLevel > 100 ? 100 : requestedLevel; requestedLevel = requestedLevel < 0 ? 0 : requestedLevel; - + Serial.print( "Changing level to " ); Serial.print( requestedLevel ); - Serial.print( ", from " ); + Serial.print( ", from " ); Serial.println( currentLevel ); fadeToLevel( requestedLevel ); - + // Inform the gateway of the current DimmableLED's SwitchPower1 and LoadLevelStatus value... - send(lightMsg.set(currentLevel > 0 ? 1 : 0)); + send(lightMsg.set(currentLevel > 0)); // hek comment: Is this really nessesary? send( dimmerMsg.set(currentLevel) ); - + } } @@ -117,11 +117,10 @@ void receive(const MyMessage &message) { void fadeToLevel( int toLevel ) { int delta = ( toLevel - currentLevel ) < 0 ? -1 : 1; - + while ( currentLevel != toLevel ) { currentLevel += delta; analogWrite( LED_PIN, (int)(currentLevel / 100. * 255) ); delay( FADE_DELAY ); } } - diff --git a/examples/DimmableLight/DimmableLight.ino b/examples/DimmableLight/DimmableLight.ino index c0f6e13ba..e834dafae 100644 --- a/examples/DimmableLight/DimmableLight.ino +++ b/examples/DimmableLight/DimmableLight.ino @@ -20,13 +20,13 @@ * * REVISION HISTORY * Version 1.0 - January 30, 2015 - Developed by GizMoCuz (Domoticz) - * + * * DESCRIPTION - * This sketch provides an example how to implement a Dimmable Light + * This sketch provides an example how to implement a Dimmable Light * It is pure virtual and it logs messages to the serial output * It can be used as a base sketch for actual hardware. * Stores the last light state and level in eeprom. - * + * */ // Enable debug prints @@ -37,7 +37,7 @@ //#define MY_RADIO_RFM69 #include -#include +#include #define CHILD_ID_LIGHT 1 @@ -50,19 +50,19 @@ #define SN "Dimable Light" #define SV "1.0" -int LastLightState=LIGHT_OFF; -int LastDimValue=100; +int16_t LastLightState=LIGHT_OFF; +int16_t LastDimValue=100; MyMessage lightMsg(CHILD_ID_LIGHT, V_LIGHT); MyMessage dimmerMsg(CHILD_ID_LIGHT, V_DIMMER); -void setup() -{ +void setup() +{ //Retreive our last light state from the eprom - int LightState=loadState(EPROM_LIGHT_STATE); + int LightState=loadState(EPROM_LIGHT_STATE); if (LightState<=1) { LastLightState=LightState; - int DimValue=loadState(EPROM_DIMMER_LEVEL); + int DimValue=loadState(EPROM_DIMMER_LEVEL); if ((DimValue>0)&&(DimValue<=100)) { //There should be no Dim value of 0, this would mean LIGHT_OFF LastDimValue=DimValue; @@ -71,8 +71,8 @@ void setup() //Here you actualy switch on/off the light with the last known dim level SetCurrentState2Hardware(); - - Serial.println( "Node ready to receive messages..." ); + + Serial.println( "Node ready to receive messages..." ); } void presentation() { @@ -82,7 +82,7 @@ void presentation() { present(CHILD_ID_LIGHT, S_DIMMER ); } -void loop() +void loop() { } @@ -90,7 +90,7 @@ void receive(const MyMessage &message) { if (message.type == V_LIGHT) { Serial.println( "V_LIGHT command received..." ); - + int lstate= atoi( message.data ); if ((lstate<0)||(lstate>1)) { Serial.println( "V_LIGHT data invalid (should be 0/1)" ); @@ -98,7 +98,7 @@ void receive(const MyMessage &message) } LastLightState=lstate; saveState(EPROM_LIGHT_STATE, LastLightState); - + if ((LastLightState==LIGHT_ON)&&(LastDimValue==0)) { //In the case that the Light State = On, but the dimmer value is zero, //then something (probably the controller) did something wrong, @@ -106,13 +106,13 @@ void receive(const MyMessage &message) LastDimValue=100; saveState(EPROM_DIMMER_LEVEL, LastDimValue); } - + //When receiving a V_LIGHT command we switch the light between OFF and the last received dimmer value //This means if you previously set the lights dimmer value to 50%, and turn the light ON //it will do so at 50% } else if (message.type == V_DIMMER) { - Serial.println( "V_DIMMER command received..." ); + Serial.println( "V_DIMMER command received..." ); int dimvalue= atoi( message.data ); if ((dimvalue<0)||(dimvalue>100)) { Serial.println( "V_DIMMER data invalid (should be 0..100)" ); @@ -128,7 +128,7 @@ void receive(const MyMessage &message) } } else { - Serial.println( "Invalid command received..." ); + Serial.println( "Invalid command received..." ); return; } @@ -153,10 +153,9 @@ void SetCurrentState2Hardware() void SendCurrentState2Controller() { if ((LastLightState==LIGHT_OFF)||(LastDimValue==0)) { - send(dimmerMsg.set(0)); + send(dimmerMsg.set((int16_t)0)); } else { send(dimmerMsg.set(LastDimValue)); } } - diff --git a/examples/DustSensor/DustSensor.ino b/examples/DustSensor/DustSensor.ino index 3f9883e63..8b4cedd1d 100644 --- a/examples/DustSensor/DustSensor.ino +++ b/examples/DustSensor/DustSensor.ino @@ -94,7 +94,7 @@ void loop() { Serial.println(dustDensity); // unit: ug/m3 if (ceil(dustDensity) != lastDUST) { - send(dustMsg.set((int)ceil(dustDensity))); + send(dustMsg.set((int16_t)ceil(dustDensity))); lastDUST = ceil(dustDensity); } diff --git a/examples/LightSensor/LightSensor.ino b/examples/LightSensor/LightSensor.ino index e6f4fa87c..193130d7c 100644 --- a/examples/LightSensor/LightSensor.ino +++ b/examples/LightSensor/LightSensor.ino @@ -55,7 +55,7 @@ void presentation() { void loop() { - int lightLevel = (1023-analogRead(LIGHT_SENSOR_ANALOG_PIN))/10.23; + int16_t lightLevel = (1023-analogRead(LIGHT_SENSOR_ANALOG_PIN))/10.23; Serial.println(lightLevel); if (lightLevel != lastLightLevel) { send(msg.set(lightLevel)); diff --git a/examples/MockMySensors/MockMySensors.ino b/examples/MockMySensors/MockMySensors.ino index 93c8c7268..dfed9bedc 100644 --- a/examples/MockMySensors/MockMySensors.ino +++ b/examples/MockMySensors/MockMySensors.ino @@ -7,7 +7,7 @@ */ // Enable debug prints to serial monitor -#define MY_DEBUG +#define MY_DEBUG // Enable and select radio type attached #define MY_RADIO_NRF24 @@ -16,7 +16,7 @@ #define MY_NODE_ID 254 #include -#include +#include #define RADIO_ERROR_LED_PIN 4 // Error led pin #define RADIO_RX_LED_PIN 6 // Receive led pin @@ -37,7 +37,7 @@ */ ////#define ID_S_ARDUINO_NODE //auto defined in initialization -////#define ID_S_ARDUINO_REPEATER_NODE //auto defined in initialization +////#define ID_S_ARDUINO_REPEATER_NODE //auto defined in initialization // Some of these ID's have not been updated for v1.5. Uncommenting too many of them @@ -57,15 +57,15 @@ //#define ID_S_WIND 10 //#define ID_S_RAIN 11 //#define ID_S_UV 12 -//#define ID_S_WEIGHT 13 +//#define ID_S_WEIGHT 13 //#define ID_S_POWER 14 //#define ID_S_HEATER 15 //#define ID_S_DISTANCE 16 -//#define ID_S_LIGHT_LEVEL 17 +//#define ID_S_LIGHT_LEVEL 17 //#define ID_S_LOCK 18 //#define ID_S_IR 19 -//#define ID_S_WATER 20 -//#define ID_S_AIR_QUALITY 21 +//#define ID_S_WATER 20 +//#define ID_S_AIR_QUALITY 21 //#define ID_S_DUST 22 //#define ID_S_SCENE_CONTROLLER 23 //// Lib 1.5 sensors @@ -170,20 +170,20 @@ long randNumber; #ifdef ID_S_HEATER //////// REVIEW IMPLEMENTATION //////////// - + MyMessage msg_S_HEATER_SET_POINT(ID_S_HEATER,V_HVAC_SETPOINT_HEAT); // HVAC/Heater setpoint (Integer between 0-100). S_HEATER, S_HVAC MyMessage msg_S_HEATER_FLOW_STATE(ID_S_HEATER,V_HVAC_FLOW_STATE); // Mode of header. One of "Off", "HeatOn", "CoolOn", or "AutoChangeOver" // S_HVAC, S_HEATER - + //MyMessage msg_S_HEATER_STATUS(ID_S_HEATER,V_STATUS); //MyMessage msg_S_HEATER_TEMP(ID_S_HEATER,V_TEMP); - + float heater_setpoint=21.5; String heater_flow_state="Off"; - + // float heater_temp=23.5; // bool heater_status=false; - - + + // V_TEMP // Temperature // V_STATUS // Binary status. 0=off 1=on // V_HVAC_FLOW_STATE // Mode of header. One of "Off", "HeatOn", "CoolOn", or "AutoChangeOver" @@ -229,22 +229,22 @@ long randNumber; // not sure if scene controller sends int or chars // betting on ints as Touch Display Scen by Hek // compiler warnings char *scenes[] = { - (char *)"Good Morning", - (char *)"Clean Up!", - (char *)"All Lights Off", + (char *)"Good Morning", + (char *)"Clean Up!", + (char *)"All Lights Off", (char *)"Music On/Off" }; - + int sceneVal=0; int sceneValPrevious=0; - + #endif -#ifdef ID_S_RGB_LIGHT +#ifdef ID_S_RGB_LIGHT MyMessage msg_S_RGB_LIGHT_V_RGB(ID_S_RGB_LIGHT,V_RGB); MyMessage msg_S_RGB_LIGHT_V_WATT(ID_S_RGB_LIGHT,V_WATT); String rgbState="000000"; - //RGB light V_RGB, V_WATT + //RGB light V_RGB, V_WATT //RGB value transmitted as ASCII hex string (I.e "ff0000" for red) #endif @@ -268,20 +268,20 @@ long randNumber; MyMessage msg_S_HVAC_V_HVAC_FLOW_STATET(ID_S_HVAC,V_HVAC_FLOW_STATE); MyMessage msg_S_HVAC_V_HVAC_FLOW_MODE(ID_S_HVAC,V_HVAC_FLOW_MODE); MyMessage msg_S_HVAC_V_HVAC_SPEED(ID_S_HVAC,V_HVAC_SPEED); - + float hvac_SetPointHeat = 16.5; float hvac_SetPointCool = 25.5; String hvac_FlowState = "AutoChangeOver"; String hvac_FlowMode = "Auto"; String hvac_Speed = "Normal"; - //Thermostat/HVAC device + //Thermostat/HVAC device //V_HVAC_SETPOINT_HEAT, // HVAC/Heater setpoint //V_HVAC_SETPOINT_COOL, // HVAC cold setpoint //V_HVAC_FLOW_STATE, // Mode of header. One of "Off", "HeatOn", "CoolOn", or "AutoChangeOver" //V_HVAC_FLOW_MODE, // Flow mode for HVAC ("Auto", "ContinuousOn", "PeriodicOn") //V_HVAC_SPEED // HVAC/Heater fan speed ("Min", "Normal", "Max", "Auto") - + // NOT IMPLEMENTED YET //V_TEMP // Temperature //V_STATUS // Binary status. 0=off 1=on @@ -300,7 +300,7 @@ long randNumber; #ifdef ID_S_SPRINKLER // S_SPRINKLER 31 Sprinkler device V_STATUS (turn on/off), V_TRIPPED (if fire detecting device) - // V_STATUS 2 Binary status. 0=off 1=on + // V_STATUS 2 Binary status. 0=off 1=on // V_ARMED 15 Armed status of a security sensor. 1=Armed, 0=Bypassed // V_TRIPPED 16 Tripped status of a security sensor. 1=Tripped, 0=Untripped #endif @@ -316,7 +316,7 @@ long randNumber; #ifdef ID_S_MOISTURE MyMessage msg_S_MOISTURE(ID_S_MOISTURE,V_LEVEL); -#endif +#endif #ifdef ID_S_CUSTOM MyMessage msg_S_CUSTOM_1(ID_S_CUSTOM,V_VAR1); @@ -329,11 +329,11 @@ long randNumber; -void setup() -{ +void setup() +{ // Random SEED randomSeed(analogRead(0)); - + wait(LONG_WAIT); Serial.println("GW Started"); } @@ -345,190 +345,190 @@ void presentation() { Serial.print(SKETCH_NAME); Serial.println(SKETCH_VERSION); wait(LONG_WAIT); - + // Get controller configuration Serial.print("Get Config: "); metric = getConfig().isMetric; Serial.println(metric ? "Metric":"Imperial"); wait(LONG_WAIT); - + // Init Armed #ifdef ID_S_ARMED isArmed = true; #endif - + // Register all sensors to gw (they will be created as child devices) Serial.println("Presenting Nodes"); Serial.println("________________"); - + #ifdef ID_S_DOOR Serial.println(" S_DOOR"); present(ID_S_DOOR,S_DOOR,"Outside Door"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_MOTION Serial.println(" S_MOTION"); present(ID_S_MOTION,S_MOTION,"Outside Motion"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_SMOKE Serial.println(" S_SMOKE"); present(ID_S_SMOKE,S_SMOKE,"Kitchen Smoke"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_LIGHT Serial.println(" S_LIGHT"); present(ID_S_LIGHT,S_LIGHT,"Hall Light"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_DIMMER Serial.println(" S_DIMMER"); present(ID_S_DIMMER,S_DIMMER,"Living room dimmer"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_COVER Serial.println(" S_COVER"); present(ID_S_COVER,S_COVER,"Window cover"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_TEMP Serial.println(" S_TEMP"); present(ID_S_TEMP,S_TEMP,"House Temperarue"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_HUM Serial.println(" S_HUM"); present(ID_S_HUM,S_HUM,"Current Humidity"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_BARO Serial.println(" S_BARO"); present(ID_S_BARO,S_BARO," Air pressure"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_WIND Serial.println(" S_WIND"); present(ID_S_WIND,S_WIND,"Wind Station"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_RAIN Serial.println(" S_RAIN"); present(ID_S_RAIN,S_RAIN,"Rain Station"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_UV Serial.println(" S_UV"); present(ID_S_UV,S_UV,"Ultra Violet"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_WEIGHT Serial.println(" S_WEIGHT"); present(ID_S_WEIGHT,S_WEIGHT,"Outdoor Scale"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_POWER Serial.println(" S_POWER"); present(ID_S_POWER,S_POWER,"Power Metric"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_HEATER Serial.println(" S_HEATER"); present(ID_S_HEATER,S_HEATER,"Garage Heater"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_DISTANCE Serial.println(" S_DISTANCE"); present(ID_S_DISTANCE,S_DISTANCE,"Distance Measure"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_LIGHT_LEVEL Serial.println(" S_LIGHT_LEVEL"); present(ID_S_LIGHT_LEVEL,S_LIGHT_LEVEL,"Outside Light Level"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_LOCK Serial.println(" S_LOCK"); present(ID_S_LOCK,S_LOCK,"Front Door Lock"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_IR Serial.println(" S_IR"); present(ID_S_IR,S_IR,"Univeral Command"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_WATER Serial.println(" S_WATER"); present(ID_S_WATER,S_WATER,"Water Level"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_AIR_QUALITY Serial.println(" S_AIR_QUALITY"); present(ID_S_AIR_QUALITY,S_AIR_QUALITY,"Air Station"); wait(SHORT_WAIT); #endif - - #ifdef ID_S_DUST + + #ifdef ID_S_DUST Serial.println(" S_DUST"); present(ID_S_DUST,S_DUST,"Dust Level"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_SCENE_CONTROLLER Serial.println(" S_SCENE_CONTROLLER"); present(ID_S_SCENE_CONTROLLER,S_SCENE_CONTROLLER,"Scene Controller"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_RGB_LIGHT Serial.println(" RGB_LIGHT"); present(ID_S_RGB_LIGHT,S_RGB_LIGHT,"Mood Light"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_RGBW_LIGHT Serial.println(" RGBW_LIGHT"); present(ID_S_RGBW_LIGHT,S_RGBW_LIGHT,"Mood Light 2"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_COLOR_SENSOR Serial.println(" COLOR_SENSOR"); present(ID_S_COLOR_SENSOR,S_COLOR_SENSOR,"Hall Painting"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_HVAC Serial.println(" HVAC"); present(ID_S_HVAC,S_HVAC,"HVAC"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_MULTIMETER Serial.println(" MULTIMETER"); present(ID_S_MULTIMETER,S_MULTIMETER,"Electric Staion"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_SPRINKLER #endif #ifdef ID_S_WATER_LEAK @@ -545,7 +545,7 @@ void presentation() { present(ID_S_MOISTURE,S_MOISTURE,"Basement Sensor"); wait(SHORT_WAIT); #endif - + #ifdef ID_S_CUSTOM Serial.println(" S_CUSTOM"); present(ID_S_CUSTOM,S_CUSTOM,"Other Stuff"); @@ -558,139 +558,139 @@ Serial.println("________________"); } -void loop() -{ +void loop() +{ Serial.println(""); Serial.println(""); Serial.println(""); - Serial.println("#########################"); + Serial.println("#########################"); randNumber=random(0,101); - + Serial.print("RandomNumber:"); Serial.println(randNumber); // Send fake battery level Serial.println("Send Battery Level"); sendBatteryLevel(randNumber); wait(LONG_WAIT); - + // Request time Serial.println("Request Time"); requestTime(); wait(LONG_WAIT); - + //Read Sensors - #ifdef ID_S_DOOR - door(); + #ifdef ID_S_DOOR + door(); #endif - + #ifdef ID_S_MOTION motion(); #endif - + #ifdef ID_S_SMOKE smoke(); #endif - + #ifdef ID_S_LIGHT light(); #endif - + #ifdef ID_S_DIMMER dimmer(); #endif - + #ifdef ID_S_COVER cover(); #endif - + #ifdef ID_S_TEMP temp(); #endif - + #ifdef ID_S_HUM hum(); #endif - + #ifdef ID_S_BARO baro(); #endif - + #ifdef ID_S_WIND wind(); #endif - + #ifdef ID_S_RAIN rain(); #endif - + #ifdef ID_S_UV uv(); #endif - + #ifdef ID_S_WEIGHT weight(); #endif - + #ifdef ID_S_POWER power(); #endif - + #ifdef ID_S_HEATER heater(); #endif - + #ifdef ID_S_DISTANCE distance(); #endif - + #ifdef ID_S_LIGHT_LEVEL light_level(); #endif - + #ifdef ID_S_LOCK lock(); #endif - + #ifdef ID_S_IR ir(); #endif - + #ifdef ID_S_WATER water(); #endif - + #ifdef ID_S_AIR_QUALITY air(); #endif - + #ifdef ID_S_DUST dust(); #endif - + #ifdef ID_S_SCENE_CONTROLLER scene(); #endif - + #ifdef ID_S_RGB_LIGHT rgbLight(); #endif - + #ifdef ID_S_RGBW_LIGHT rgbwLight(); #endif - + #ifdef ID_S_COLOR_SENSOR color(); #endif - + #ifdef ID_S_HVAC hvac(); #endif - + #ifdef ID_S_MULTIMETER multimeter(); #endif - + #ifdef ID_S_SPRINKLER #endif #ifdef ID_S_WATER_LEAK @@ -701,15 +701,15 @@ void loop() #endif #ifdef ID_S_MOISTURE #endif - + #ifdef ID_S_MOISTURE moisture(); - #endif - + #endif + #ifdef ID_S_CUSTOM custom(); #endif - + sendBatteryLevel(randNumber); wait(SHORT_WAIT); Serial.println("#########################"); @@ -728,15 +728,15 @@ void receiveTime(unsigned long controllerTime) { #ifdef ID_S_DOOR void door(){ - + Serial.print("Door is: " ); - + if (randNumber <= 50) { Serial.println("Open"); - send(msg_S_DOOR_T.set(1)); + send(msg_S_DOOR_T.set((int16_t)1)); } else { Serial.println("Closed"); - send(msg_S_DOOR_T.set(0)); + send(msg_S_DOOR_T.set((int16_t)0)); } #ifdef ID_S_ARMED Serial.print("System is: " ); @@ -748,9 +748,9 @@ void door(){ #ifdef ID_S_MOTION void motion(){ - + Serial.print("Motion is: " ); - + if (randNumber <= 50) { Serial.println("Active"); send(msg_S_MOTION_T.set(1)); @@ -758,7 +758,7 @@ void motion(){ Serial.println("Quiet"); send(msg_S_MOTION_T.set(0)); } - + #ifdef ID_S_ARMED Serial.print("System is: " ); Serial.println((isArmed ? "Armed":"Disarmed")); @@ -771,7 +771,7 @@ void motion(){ void smoke(){ Serial.print("Smoke is: " ); - + if (randNumber <= 50) { Serial.println("Active"); send(msg_S_SMOKE_T.set(1)); @@ -779,13 +779,13 @@ void smoke(){ Serial.println("Quiet"); send(msg_S_SMOKE_T.set(0)); } - + #ifdef ID_S_ARMED Serial.print("System is: " ); Serial.println((isArmed ? "Armed":"Disarmed")); send(msg_S_SMOKE_A.set(isArmed)); #endif - + } #endif @@ -794,7 +794,7 @@ void light(){ Serial.print("Light is: " ); Serial.println((isLightOn ? "On":"Off")); - + send(msg_S_LIGHT.set(isLightOn)); } @@ -805,7 +805,7 @@ void dimmer(){ Serial.print("Dimmer is set to: " ); Serial.println(dimmerVal); - + send(msg_S_DIMMER.set(dimmerVal)); } @@ -832,73 +832,73 @@ void cover(){ #ifdef ID_S_TEMP void temp(){ - + Serial.print("Temperature is: " ); Serial.println(map(randNumber,1,100,0,45)); - + send(msg_S_TEMP.set(map(randNumber,1,100,0,45))); - + } #endif #ifdef ID_S_HUM void hum(){ - + Serial.print("Humitidty is: " ); Serial.println(randNumber); - + send(msg_S_HUM.set(randNumber)); - + } #endif #ifdef ID_S_BARO void baro(){ - + const char *weather[] = {"stable","sunny","cloudy","unstable","thunderstorm","unknown"}; long pressure = map(randNumber,1,100,870,1086);// hPa? int forecast = map(randNumber,1,100,0,5); - + Serial.print("Atmosferic Pressure is: " ); Serial.println(pressure); send(msg_S_BARO_P.set(pressure)); - + Serial.print("Weather forecast: " ); Serial.println(weather[forecast]); send(msg_S_BARO_F.set(weather[forecast])); - + } #endif #ifdef ID_S_WIND void wind(){ - + Serial.print("Wind Speed is: " ); Serial.println(randNumber); send(msg_S_WIND_S.set(randNumber)); - + Serial.print("Wind Gust is: " ); Serial.println(randNumber+10); send(msg_S_WIND_G.set(randNumber+10)); - + Serial.print("Wind Direction is: " ); Serial.println(map(randNumber,1,100,0,360)); send(msg_S_WIND_D.set(map(randNumber,1,100,0,360))); - + } #endif #ifdef ID_S_RAIN void rain(){ - + Serial.print("Rain ammount is: " ); Serial.println(randNumber); - + send(msg_S_RAIN_A.set(randNumber)); - + Serial.print("Rain rate is: " ); Serial.println(randNumber/60); - + send(msg_S_RAIN_R.set(randNumber/60,1)); } @@ -906,10 +906,10 @@ void rain(){ #ifdef ID_S_UV void uv(){ - + Serial.print("Ultra Violet level is: " ); Serial.println(map(randNumber,1,100,0,15)); - + send(msg_S_UV.set(map(randNumber,1,100,0,15))); } @@ -917,10 +917,10 @@ void uv(){ #ifdef ID_S_WEIGHT void weight(){ - + Serial.print("Weight is: " ); Serial.println(map(randNumber,1,100,0,150)); - + send(msg_S_WEIGHT.set(map(randNumber,1,100,0,150))); } @@ -928,13 +928,13 @@ void weight(){ #ifdef ID_S_POWER void power(){ - + Serial.print("Watt is: " ); - Serial.println(map(randNumber,1,100,0,150)); + Serial.println(map(randNumber,1,100,0,150)); send(msg_S_POWER_W.set(map(randNumber,1,100,0,150))); Serial.print("KWH is: " ); - Serial.println(map(randNumber,1,100,0,150)); + Serial.println(map(randNumber,1,100,0,150)); send(msg_S_POWER_K.set(map(randNumber,1,100,0,150))); } @@ -946,7 +946,7 @@ void heater(){ // float heater_temp=23.5; // bool heater_status=false; // String heatState="Off"; - + Serial.print("Heater flow state is: " ); Serial.println(heater_flow_state); send(msg_S_HEATER_FLOW_STATE.set(heater_flow_state.c_str())); @@ -954,7 +954,7 @@ void heater(){ // Serial.print("Heater on/off is: " ); // Serial.println((heater_status==true)?"On":"Off"); // send(msg_S_HEATER_STATUS.set(heater_status)); - + // Serial.print("Heater Temperature is: " ); // Serial.println(heater_temp,1); // send(msg_S_HEATER_TEMP.set(heater_temp,1)); @@ -967,10 +967,10 @@ void heater(){ #ifdef ID_S_DISTANCE void distance(){ - + Serial.print("Distance is: " ); Serial.println(map(randNumber,1,100,0,150)); - + send(msg_S_DISTANCE.set(map(randNumber,1,100,0,150))); } @@ -978,10 +978,10 @@ void distance(){ #ifdef ID_S_LIGHT_LEVEL void light_level(){ - + Serial.print("Light is: " ); Serial.println(map(randNumber,1,100,0,150)); - + send(msg_S_LIGHT_LEVEL.set(map(randNumber,1,100,0,150))); } @@ -993,33 +993,33 @@ void lock(){ Serial.print("Lock is: " ); Serial.println((isLocked ? "Locked":"Unlocked")); send(msg_S_LOCK.set(isLocked)); - + } #endif #ifdef ID_S_IR void ir(){ - + Serial.print("Infrared is: " ); Serial.println(irVal); - + send(msg_S_IR_S.set(irVal)); send(msg_S_IR_R.set(irVal)); - + } #endif #ifdef ID_S_WATER void water(){ - + Serial.print("Water flow is: " ); Serial.println(map(randNumber,1,100,0,150)); - + send(msg_S_WATER_F.set(map(randNumber,1,100,0,150))); - + Serial.print("Water volume is: " ); Serial.println(map(randNumber,1,100,0,150)); - + send(msg_S_WATER_V.set(map(randNumber,1,100,0,150))); } @@ -1027,10 +1027,10 @@ void water(){ #ifdef ID_S_AIR_QUALITY void air(){ - + Serial.print("Air Quality is: " ); Serial.println(randNumber); - + send(msg_S_AIR_QUALITY.set(randNumber)); } @@ -1038,10 +1038,10 @@ void air(){ #ifdef ID_S_DUST void dust(){ - + Serial.print("Dust level is: " ); Serial.println(randNumber); - + send(msg_S_DUST.set(randNumber)); } @@ -1052,90 +1052,90 @@ void scene(){ Serial.print("Scene is: " ); Serial.println(scenes[sceneVal]); - + if(sceneValPrevious != sceneVal){ send(msg_S_SCENE_CONTROLLER_OF.set(sceneValPrevious)); send(msg_S_SCENE_CONTROLLER_ON.set(sceneVal)); sceneValPrevious=sceneVal; } - + } #endif #ifdef ID_S_RGB_LIGHT void rgbLight(){ - + Serial.print("RGB Light state is: " ); Serial.println(rgbState); send(msg_S_RGB_LIGHT_V_RGB.set(rgbState.c_str())); - + Serial.print("RGB Light Watt is: " ); - Serial.println(map(randNumber,1,100,0,150)); + Serial.println(map(randNumber,1,100,0,150)); send(msg_S_RGB_LIGHT_V_WATT.set(map(randNumber,1,100,0,150))); - + } #endif #ifdef ID_S_RGBW_LIGHT void rgbwLight(){ - + Serial.print("RGBW Light state is: " ); Serial.println(rgbwState); send(msg_S_RGBW_LIGHT_V_RGBW.set(rgbwState.c_str())); - + Serial.print("RGBW Light Watt is: " ); - Serial.println(map(randNumber,1,100,0,150)); + Serial.println(map(randNumber,1,100,0,150)); send(msg_S_RGBW_LIGHT_V_WATT.set(map(randNumber,1,100,0,150))); - + } #endif #ifdef ID_S_COLOR_SENSOR void color(){ String colorState; - + String red = String(random(0,256),HEX); String green = String(random(0,256),HEX); String blue = String(random(0,256),HEX); - + colorState=String(red + green + blue); Serial.print("Color state is: " ); Serial.println(colorState); send(msg_S_COLOR_SENSOR_V_RGB.set(colorState.c_str())); - + } #endif #ifdef ID_S_HVAC void hvac(){ - + // float hvac_SetPointHeat = 16.5; // float hvac_SetPointCool = 25.5; // String hvac_FlowState = "AutoChangeOver"; // String hvac_FlowMode = "Auto"; // String hvac_Speed = "Normal"; - + Serial.print("HVAC Set Point Heat is: " ); Serial.println(hvac_SetPointHeat); send(msg_S_HVAC_V_HVAC_SETPOINT_HEAT.set(hvac_SetPointHeat,1)); - + Serial.print("HVAC Set Point Cool is: " ); Serial.println(hvac_SetPointCool); send(msg_S_HVAC_V_HVAC_SETPOINT_COOL.set(hvac_SetPointCool,1)); - + Serial.print("HVAC Flow State is: " ); Serial.println(hvac_FlowState); send(msg_S_HVAC_V_HVAC_FLOW_STATET.set(hvac_FlowState.c_str())); - + Serial.print("HVAC Flow Mode is: " ); Serial.println(hvac_FlowMode); send(msg_S_HVAC_V_HVAC_FLOW_MODE.set(hvac_FlowMode.c_str())); - + Serial.print("HVAC Speed is: " ); Serial.println(hvac_Speed); send(msg_S_HVAC_V_HVAC_SPEED.set(hvac_Speed.c_str())); - + } #endif @@ -1144,7 +1144,7 @@ void multimeter(){ int impedance=map(randNumber,1,100,0,15000); int volt=map(randNumber,1,100,0,380); int amps=map(randNumber,1,100,0,16); - + Serial.print("Impedance is: " ); Serial.println(impedance); send(msg_S_MULTIMETER_V_IMPEDANCE.set(impedance)); @@ -1155,7 +1155,7 @@ void multimeter(){ Serial.print("Current is: " ); Serial.println(amps); - send(msg_S_MULTIMETER_V_CURRENT.set(amps)); + send(msg_S_MULTIMETER_V_CURRENT.set(amps)); } #endif @@ -1173,20 +1173,20 @@ void multimeter(){ #ifdef ID_S_MOISTURE void moisture(){ - + Serial.print("Moisture level is: " ); Serial.println(randNumber); - + send(msg_S_MOISTURE.set(randNumber)); } #endif #ifdef ID_S_CUSTOM void custom(){ - + Serial.print("Custom value is: " ); Serial.println(randNumber); - + send(msg_S_CUSTOM_1.set(randNumber)); send(msg_S_CUSTOM_2.set(randNumber)); send(msg_S_CUSTOM_3.set(randNumber)); @@ -1217,8 +1217,8 @@ void receive(const MyMessage &message) { #endif break; #endif - - + + case V_STATUS: // V_LIGHT: #ifdef ID_S_LIGHT if(message.sensor==ID_S_LIGHT){ @@ -1241,8 +1241,8 @@ void receive(const MyMessage &message) { // } // #endif break; - - + + #ifdef ID_S_DIMMER case V_DIMMER: if ((message.getInt()<0)||(message.getInt()>100)) { @@ -1257,8 +1257,8 @@ void receive(const MyMessage &message) { dimmer();// temp ack break; #endif - - #ifdef ID_S_COVER + + #ifdef ID_S_COVER case V_UP: coverState=1; Serial.print("Incoming change for ID_S_COVER:"); @@ -1267,7 +1267,7 @@ void receive(const MyMessage &message) { Serial.println("V_UP"); cover(); // temp ack break; - + case V_DOWN: coverState=-1; Serial.print("Incoming change for ID_S_COVER:"); @@ -1276,7 +1276,7 @@ void receive(const MyMessage &message) { Serial.println("V_DOWN"); cover(); //temp ack break; - + case V_STOP: coverState=0; Serial.print("Incoming change for ID_S_COVER:"); @@ -1286,14 +1286,14 @@ void receive(const MyMessage &message) { cover(); //temp ack break; #endif - - + + case V_HVAC_SETPOINT_HEAT: - + #ifdef ID_S_HEATER if(message.sensor == ID_S_HEATER){ heater_setpoint=message.getFloat(); - + Serial.print("Incoming set point for ID_S_HEATER:"); Serial.print(message.sensor); Serial.print(", New status: "); @@ -1301,7 +1301,7 @@ void receive(const MyMessage &message) { heater();//temp ack } #endif - + #ifdef ID_S_HVAC if(message.sensor == ID_S_HVAC){ hvac_SetPointHeat=message.getFloat(); @@ -1325,11 +1325,11 @@ void receive(const MyMessage &message) { heater();//temp ack } #endif - + #ifdef ID_S_HVAC if(message.sensor == ID_S_HVAC){ hvac_FlowState=message.getString(); - + Serial.print("Incoming set point for ID_S_HVAC:"); Serial.print(message.sensor); Serial.print(", New status: "); @@ -1338,7 +1338,7 @@ void receive(const MyMessage &message) { } #endif break; - + #ifdef ID_S_LOCK case V_LOCK_STATUS: isLocked = message.getBool(); @@ -1349,7 +1349,7 @@ void receive(const MyMessage &message) { lock(); //temp ack break; #endif - + #ifdef ID_S_IR case V_IR_SEND: irVal = message.getLong(); @@ -1368,7 +1368,7 @@ void receive(const MyMessage &message) { ir(); // temp ack break; #endif - + #ifdef ID_S_SCENE_CONTROLLER case V_SCENE_ON: sceneVal = message.getInt(); @@ -1389,7 +1389,7 @@ void receive(const MyMessage &message) { scene();// temp ack break; #endif - + #ifdef ID_S_RGB_LIGHT case V_RGB: rgbState=message.getString(); @@ -1398,10 +1398,10 @@ void receive(const MyMessage &message) { Serial.print(", New status: "); Serial.println(rgbState); rgbLight(); // temp ack - + break; #endif - + #ifdef ID_S_RGBW_LIGHT case V_RGBW: rgbwState=message.getString(); @@ -1412,37 +1412,37 @@ void receive(const MyMessage &message) { rgbwLight(); break; #endif - + #ifdef ID_S_HVAC - // hvac_SetPointHeat - // hvac_SetPointCool - // hvac_FlowState - // hvac_FlowMode - // hvac_Speed - + // hvac_SetPointHeat + // hvac_SetPointCool + // hvac_FlowState + // hvac_FlowMode + // hvac_Speed + case V_HVAC_SETPOINT_COOL: hvac_SetPointCool=message.getFloat(); - + Serial.print("Incoming set point for ID_S_HVAC:"); Serial.print(message.sensor); Serial.print(", New status: "); Serial.println(hvac_SetPointCool,1); hvac();//temp ack break; - + case V_HVAC_FLOW_MODE: hvac_Speed=message.getString(); - + Serial.print("Incoming set point for ID_S_HVAC:"); Serial.print(message.sensor); Serial.print(", New status: "); Serial.println(hvac_Speed); hvac();//temp ack break; - + case V_HVAC_SPEED: hvac_FlowMode=message.getString(); - + Serial.print("Incoming set point for ID_S_HVAC:"); Serial.print(message.sensor); Serial.print(", New status: "); @@ -1450,17 +1450,10 @@ void receive(const MyMessage &message) { hvac();//temp ack break; #endif - - default: + + default: Serial.print("Unknown/UnImplemented message type: "); Serial.println(message.type); } } - - - - - - - diff --git a/examples/SecurityPersonalizer/SecurityPersonalizer.ino b/examples/SecurityPersonalizer/SecurityPersonalizer.ino index 502a32abb..7c7954be2 100644 --- a/examples/SecurityPersonalizer/SecurityPersonalizer.ino +++ b/examples/SecurityPersonalizer/SecurityPersonalizer.ino @@ -879,7 +879,7 @@ void setup() (void)key; Serial.begin(115200); - + hwInit(); Serial.println(F("Personalization sketch for MySensors usage.")); Serial.println(F("-------------------------------------------")); diff --git a/examples/VibrationSensor/VibrationSensor.ino b/examples/VibrationSensor/VibrationSensor.ino index 8dfc1e230..f0609823c 100644 --- a/examples/VibrationSensor/VibrationSensor.ino +++ b/examples/VibrationSensor/VibrationSensor.ino @@ -33,7 +33,7 @@ **/ // Enable debug prints to serial monitor -#define MY_DEBUG +#define MY_DEBUG // Enable and select radio type attached #define MY_RADIO_NRF24 @@ -57,7 +57,7 @@ unsigned char state = 0; MyMessage vibrationMsg(CHILD_ID_VIBRATION, V_LEVEL); -void setup() +void setup() { pinMode(VIBRATION_SENSOR_DIGITAL_PIN, INPUT); attachInterrupt(digitalPinToInterrupt(VIBRATION_SENSOR_DIGITAL_PIN), blink, FALLING); // Trigger the blink function when the falling edge is detected @@ -72,19 +72,19 @@ void presentation() { present(CHILD_ID_VIBRATION, S_VIBRATION); } -void loop() -{ - +void loop() +{ + if(state>=40){ // basically below 40 so ignire basic level - send(vibrationMsg.set(int(state))); - state = 0; + send(vibrationMsg.set(int16_t(state))); + state = 0; digitalWrite(SensorLED,HIGH); } else { - state = 0; + state = 0; digitalWrite(SensorLED,LOW); - } + } + - // Power down the radio. Note that the radio will get powered back up // on the next write() call. delay(1000); //delay to allow serial to fully print before sleep From 1305aeca8a4312eeaa172b8c72518ca3bd0b6054 Mon Sep 17 00:00:00 2001 From: Embedded Innovation Date: Sun, 17 Jul 2016 09:52:56 +0200 Subject: [PATCH 008/167] Fix race in sleep with interrupts (#519) * Interrupts occurring during sleep-setup possibly fail to wake mcu * Detach interrupt handler in interrupt handler to correctly handle level-interrupts --- core/MyHwATMega328.cpp | 88 +++++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 40 deletions(-) diff --git a/core/MyHwATMega328.cpp b/core/MyHwATMega328.cpp index 9aad4fd1d..11e0912e0 100644 --- a/core/MyHwATMega328.cpp +++ b/core/MyHwATMega328.cpp @@ -21,15 +21,26 @@ #include "MyHwATMega328.h" -volatile int8_t pinIntTrigger = 0; +#define INVALID_INTERRUPT_NUM (0xFFu) -void wakeUp() //place to send the interrupts +volatile uint8_t _wokeUpByInterrupt = INVALID_INTERRUPT_NUM; // Interrupt number that woke the mcu. +volatile uint8_t _wakeUp1Interrupt = INVALID_INTERRUPT_NUM; // Interrupt number for wakeUp1-callback. +volatile uint8_t _wakeUp2Interrupt = INVALID_INTERRUPT_NUM; // Interrupt number for wakeUp2-callback. + +void wakeUp1() //place to send the interrupts { - pinIntTrigger = 1; + detachInterrupt(_wakeUp1Interrupt); + _wokeUpByInterrupt = _wakeUp1Interrupt; } void wakeUp2() //place to send the second interrupts { - pinIntTrigger = 2; + detachInterrupt(_wakeUp2Interrupt); + _wokeUpByInterrupt = _wakeUp2Interrupt; +} + +bool interruptWakeUp() +{ + return _wokeUpByInterrupt != INVALID_INTERRUPT_NUM; } // Watchdog Timer interrupt service routine. This routine is required @@ -39,7 +50,6 @@ ISR (WDT_vect) } void hwPowerDown(period_t period) { - // disable ADC for power saving ADCSRA &= ~(1 << ADEN); // save WDT settings @@ -56,11 +66,12 @@ void hwPowerDown(period_t period) { set_sleep_mode(SLEEP_MODE_PWR_DOWN); cli(); sleep_enable(); -#if defined __AVR_ATmega328P__ - sleep_bod_disable(); -#endif + #if defined __AVR_ATmega328P__ + sleep_bod_disable(); + #endif + // Enable interrupts & sleep until WDT or ext. interrupt sei(); - // sleep until WDT or ext. interrupt + // Directly sleep CPU, to prevent race conditions! (see chapter 7.7 of ATMega328P datasheet) sleep_cpu(); sleep_disable(); // restore previous WDT settings @@ -77,21 +88,19 @@ void hwPowerDown(period_t period) { void hwInternalSleep(unsigned long ms) { // Let serial prints finish (debug, log etc) - #ifndef MY_DISABLED_SERIAL - MY_SERIALDEVICE.flush(); - #endif - // reset interrupt trigger var - pinIntTrigger = 0; - while (!pinIntTrigger && ms >= 8000) { hwPowerDown(SLEEP_8S); ms -= 8000; } - if (!pinIntTrigger && ms >= 4000) { hwPowerDown(SLEEP_4S); ms -= 4000; } - if (!pinIntTrigger && ms >= 2000) { hwPowerDown(SLEEP_2S); ms -= 2000; } - if (!pinIntTrigger && ms >= 1000) { hwPowerDown(SLEEP_1S); ms -= 1000; } - if (!pinIntTrigger && ms >= 500) { hwPowerDown(SLEEP_500MS); ms -= 500; } - if (!pinIntTrigger && ms >= 250) { hwPowerDown(SLEEP_250MS); ms -= 250; } - if (!pinIntTrigger && ms >= 125) { hwPowerDown(SLEEP_120MS); ms -= 120; } - if (!pinIntTrigger && ms >= 64) { hwPowerDown(SLEEP_60MS); ms -= 60; } - if (!pinIntTrigger && ms >= 32) { hwPowerDown(SLEEP_30MS); ms -= 30; } - if (!pinIntTrigger && ms >= 16) { hwPowerDown(SLEEP_15MS); ms -= 15; } + #ifndef MY_DISABLED_SERIAL + MY_SERIALDEVICE.flush(); + #endif + while (!interruptWakeUp() && ms >= 8000) { hwPowerDown(SLEEP_8S); ms -= 8000; } + if (!interruptWakeUp() && ms >= 4000) { hwPowerDown(SLEEP_4S); ms -= 4000; } + if (!interruptWakeUp() && ms >= 2000) { hwPowerDown(SLEEP_2S); ms -= 2000; } + if (!interruptWakeUp() && ms >= 1000) { hwPowerDown(SLEEP_1S); ms -= 1000; } + if (!interruptWakeUp() && ms >= 500) { hwPowerDown(SLEEP_500MS); ms -= 500; } + if (!interruptWakeUp() && ms >= 250) { hwPowerDown(SLEEP_250MS); ms -= 250; } + if (!interruptWakeUp() && ms >= 125) { hwPowerDown(SLEEP_120MS); ms -= 120; } + if (!interruptWakeUp() && ms >= 64) { hwPowerDown(SLEEP_60MS); ms -= 60; } + if (!interruptWakeUp() && ms >= 32) { hwPowerDown(SLEEP_30MS); ms -= 30; } + if (!interruptWakeUp() && ms >= 16) { hwPowerDown(SLEEP_15MS); ms -= 15; } } int8_t hwSleep(unsigned long ms) { @@ -100,15 +109,18 @@ int8_t hwSleep(unsigned long ms) { } int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { - return hwSleep(interrupt,mode,0xFF,0x00,ms); + return hwSleep(interrupt,mode,INVALID_INTERRUPT_NUM,0u,ms); } int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { - // reset interrupt trigger var - pinIntTrigger = 0; + // Disable interrupts until going to sleep, otherwise interrupts occurring between attachInterrupt() + // and sleep might cause the ATMega to not wakeup from sleep as interrupt has already be handled! + cli(); // attach interrupts - attachInterrupt(interrupt1, wakeUp, mode1); - if (interrupt2!=0xFF) attachInterrupt(interrupt2, wakeUp2, mode2); + _wakeUp1Interrupt = interrupt1; + _wakeUp2Interrupt = interrupt2; + if (interrupt1 != INVALID_INTERRUPT_NUM) attachInterrupt(interrupt1, wakeUp1, mode1); + if (interrupt2 != INVALID_INTERRUPT_NUM) attachInterrupt(interrupt2, wakeUp2, mode2); if (ms>0) { // sleep for defined time @@ -118,18 +130,14 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo hwPowerDown(SLEEP_FOREVER); } - detachInterrupt(interrupt1); - if (interrupt2!=0xFF) detachInterrupt(interrupt2); - - // default: no interrupt triggered, timer wake up - int8_t retVal = -1; + // Return what woke the mcu. + int ret = -1; // default: no interrupt triggered, timer wake up + if (interruptWakeUp()) ret = static_cast(_wokeUpByInterrupt); - if (pinIntTrigger == 1) { - retVal = (int8_t)interrupt1; - } else if (pinIntTrigger == 2) { - retVal = (int8_t)interrupt2; - } - return retVal; + // Clear woke-up-by-interrupt flag, so next sleeps won't return immediately. + _wokeUpByInterrupt = INVALID_INTERRUPT_NUM; + + return ret; } uint16_t hwCPUVoltage() { From 83cbb921f513d7e87cdca4a9baf40f8b7d1465e8 Mon Sep 17 00:00:00 2001 From: Embedded Innovation Date: Sun, 17 Jul 2016 10:28:00 +0200 Subject: [PATCH 009/167] Unify interrupt handling (#520) ATMega328 hardware abstraction used a mix of AVR cli/sei and Arduino noInterrupts/interrupts calls. Changed to use AVR cli/sei only. --- core/MyHwATMega328.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/MyHwATMega328.cpp b/core/MyHwATMega328.cpp index 11e0912e0..349e77540 100644 --- a/core/MyHwATMega328.cpp +++ b/core/MyHwATMega328.cpp @@ -161,7 +161,7 @@ uint16_t hwCPUVoltage() { } uint16_t hwCPUFrequency() { - noInterrupts(); + cli(); // setup timer1 TIFR1 = 0xFF; TCNT1 = 0; @@ -183,7 +183,7 @@ uint16_t hwCPUFrequency() { wdt_reset(); WDTCSR |= (1 << WDCE) | (1 << WDE); WDTCSR = WDTsave; - interrupts(); + sei(); // return frequency in 1/10MHz (accuracy +- 10%) return TCNT1 * 2048UL / 100000UL; } From 0a7208ece08f9c43a3502e9a911e48baba9a30b8 Mon Sep 17 00:00:00 2001 From: Shiny Date: Sun, 17 Jul 2016 20:28:57 +1200 Subject: [PATCH 010/167] spelling and grammar fix ups (#515) Signed-off-by: Brenda Wallace --- .../GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino | 2 +- examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino b/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino index d61bb5ebc..164aa12f3 100644 --- a/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino +++ b/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino @@ -73,7 +73,7 @@ #define MY_GATEWAY_MQTT_CLIENT #define MY_GATEWAY_ESP8266 -// Set this nodes subscripe and publish topic prefix +// Set this node's subscribe and publish topic prefix #define MY_MQTT_PUBLISH_TOPIC_PREFIX "mygateway1-out" #define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX "mygateway1-in" diff --git a/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino b/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino index ad30eeaaf..8e98e808a 100644 --- a/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino +++ b/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino @@ -68,7 +68,7 @@ #define MY_GATEWAY_MQTT_CLIENT -// Set this nodes subscripe and publish topic prefix +// Set this node's subscribe and publish topic prefix #define MY_MQTT_PUBLISH_TOPIC_PREFIX "mygateway1-out" #define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX "mygateway1-in" @@ -147,7 +147,7 @@ void presentation() { void loop() { - // Send locally attech sensors data here + // Send locally attached sensors data here } From 56693d5b73f024cd9c41d529efe170e53da9585d Mon Sep 17 00:00:00 2001 From: tekka007 Date: Thu, 21 Jul 2016 21:53:13 +0200 Subject: [PATCH 011/167] Bumped version to 2.0.1-beta --- core/Version.h | 2 +- library.json | 2 +- library.properties | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/Version.h b/core/Version.h index d61a364d5..e91949fe7 100644 --- a/core/Version.h +++ b/core/Version.h @@ -6,6 +6,6 @@ #ifndef Version_h #define Version_h -#define MYSENSORS_LIBRARY_VERSION "2.0.0-beta" +#define MYSENSORS_LIBRARY_VERSION "2.0.1-beta" #endif diff --git a/library.json b/library.json index ded8f1295..0bd39628c 100644 --- a/library.json +++ b/library.json @@ -7,7 +7,7 @@ "type": "git", "url": "https://github.com/mysensors/MySensors.git" }, - "version": "2.0.0-beta", + "version": "2.0.1-beta", "frameworks": "arduino", "platforms": "*", "exclude": [ diff --git a/library.properties b/library.properties index 60d1ce7d9..9915004d9 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=MySensors -version=2.0.0-beta +version=2.0.1-beta author=The MySensors Team maintainer=The MySensors Team sentence=Home Automation Framework From f2a379f44928df909d4e26c17ed9bba6ed200e80 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Fri, 22 Jul 2016 19:23:39 +0200 Subject: [PATCH 012/167] New repository location fix --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d1617fd8f..ca7cd1614 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1 +1 @@ -To get started, sign the Contributor License Agreement. \ No newline at end of file +To get started, sign the Contributor License Agreement. From 24e3dfa36c711b4174ed615408994e8624a2b1f3 Mon Sep 17 00:00:00 2001 From: tekka007 Date: Mon, 18 Jul 2016 21:56:18 +0200 Subject: [PATCH 013/167] Updates to MyTransport --- core/MySensorsCore.cpp | 2 +- core/MyTransport.cpp | 367 +++++++++++++++++++++++------------------ core/MyTransport.h | 152 +++++++++++++++-- 3 files changed, 350 insertions(+), 171 deletions(-) diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index bbe1566ed..41c6c72ab 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -94,7 +94,7 @@ void _begin() { // Save static parent id in eeprom (used by bootloader) hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, MY_PARENT_NODE_ID); transportInitialize(); - while (!isTransportOK()) { + while (!isTransportReady()) { hwWatchdogReset(); transportProcess(); #if defined(ARDUINO_ARCH_ESP8266) diff --git a/core/MyTransport.cpp b/core/MyTransport.cpp index 4061808a2..eb80ad7ff 100644 --- a/core/MyTransport.cpp +++ b/core/MyTransport.cpp @@ -17,136 +17,161 @@ * version 2 as published by the Free Software Foundation. */ - #include "MyTransport.h" -static uint32_t _transport_lastUplinkCheck; //!< last uplink check, to prevent GW flooding - -// repeaters (this includes GW) should perform regular sanity checks for network reliability -#if defined(MY_TRANSPORT_SANITY_CHECK) || defined(MY_REPEATER_FEATURE) - uint32_t _transport_lastSanityCheck; //!< last sanity check +// debug +#if defined(MY_DEBUG) + #define TRANSPORT_DEBUG(x,...) debug(x, ##__VA_ARGS__) +#else + #define TRANSPORT_DEBUG(x,...) #endif -// SM: transitions and update states -static State stInit = { stInitTransition, NULL }; -static State stParent = { stParentTransition, stParentUpdate }; -static State stID = { stIDTransition, stIDUpdate }; -static State stUplink = { stUplinkTransition, NULL }; -static State stOK = { stOKTransition, stOKUpdate }; -static State stFailure = { stFailureTransition, stFailureUpdate }; +// SM: transitions and update states +static transportState stInit = { stInitTransition, NULL }; +static transportState stParent = { stParentTransition, stParentUpdate }; +static transportState stID = { stIDTransition, stIDUpdate }; +static transportState stUplink = { stUplinkTransition, NULL }; +static transportState stReady = { stReadyTransition, stReadyUpdate }; +static transportState stFailure = { stFailureTransition, stFailureUpdate }; + +// transport SM variables static transportSM _transportSM; // stInit: initialize transport HW void stInitTransition() { - debug(PSTR("TSM:INIT\n")); + TRANSPORT_DEBUG(PSTR("TSM:INIT\n")); // initialize status variables - _transportSM.failedUplinkTransmissions = 0; _transportSM.pingActive = false; _transportSM.transportActive = false; #if defined(MY_TRANSPORT_SANITY_CHECK) || defined(MY_REPEATER_FEATURE) - _transport_lastSanityCheck = hwMillis(); + _transportSM.lastSanityCheck = hwMillis(); #endif - _transport_lastUplinkCheck = 0; + _transportSM.lastUplinkCheck = 0; // Read node settings (ID, parentId, GW distance) from EEPROM hwReadConfigBlock((void*)&_nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); // initialize radio if (!transportInit()) { - debug(PSTR("!TSM:RADIO:FAIL\n")); + TRANSPORT_DEBUG(PSTR("!TSM:INIT:TSP FAIL\n")); setIndication(INDICATION_ERR_INIT_TRANSPORT); transportSwitchSM(stFailure); } else { - debug(PSTR("TSM:RADIO:OK\n")); + TRANSPORT_DEBUG(PSTR("TSM:INIT:TSP OK\n")); _transportSM.transportActive = true; #if defined(MY_GATEWAY_FEATURE) // Set configuration for gateway - debug(PSTR("TSM:GW MODE\n")); + TRANSPORT_DEBUG(PSTR("TSM:INIT:GW MODE\n")); _nc.parentNodeId = GATEWAY_ADDRESS; _nc.distance = 0; _nc.nodeId = GATEWAY_ADDRESS; transportSetAddress(GATEWAY_ADDRESS); - transportSwitchSM(stOK); + // GW mode: skip FPAR,ID,UPL states + transportSwitchSM(stReady); #else - if (MY_NODE_ID != AUTO) { + if ((uint8_t)MY_NODE_ID != AUTO) { + TRANSPORT_DEBUG(PSTR("TSM:INIT:STATID,ID=%d\n"),MY_NODE_ID); // Set static id _nc.nodeId = MY_NODE_ID; // Save static id in eeprom hwWriteConfig(EEPROM_NODE_ID_ADDRESS, MY_NODE_ID); } // set ID if static or set in EEPROM - if(_nc.nodeId!=AUTO) transportAssignNodeID(_nc.nodeId); - transportSwitchSM(stParent); + if (_nc.nodeId == AUTO || transportAssignNodeID(_nc.nodeId)) { + // if node ID > 0, proceed to next state + transportSwitchSM(stParent); + } + else { + // ID invalid (=0), nothing we can do + transportSwitchSM(stFailure); + } #endif } } // stParent: find parent void stParentTransition() { - debug(PSTR("TSM:FPAR\n")); // find parent - _transportSM.preferredParentFound = false; - _transportSM.findingParentNode = true; - _transportSM.failedUplinkTransmissions = 0; - _transportSM.uplinkOk = false; - // Set distance to max and invalidate parent node id - _nc.distance = DISTANCE_INVALID; - _nc.parentNodeId = AUTO; - // Broadcast find parent request + TRANSPORT_DEBUG(PSTR("TSM:FPAR\n")); // find parent setIndication(INDICATION_FIND_PARENT); - transportRouteMessage(build(_msgTmp, _nc.nodeId, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT, false).set("")); + _transportSM.uplinkOk = false; + _transportSM.preferredParentFound = false; + #if defined(MY_PARENT_NODE_IS_STATIC) + TRANSPORT_DEBUG(PSTR("TSM:FPAR:STATP=%d\n"),MY_PARENT_NODE_ID); // static parent + _transportSM.findingParentNode = false; + _nc.distance = 1; // assumption, CHKUPL:GWDC will update this variable + _nc.parentNodeId = MY_PARENT_NODE_ID; + // skipping find parent + transportSwitchSM(stID); + #else + _transportSM.findingParentNode = true; + _nc.distance = DISTANCE_INVALID; // Set distance to max and invalidate parent node ID + _nc.parentNodeId = AUTO; + // Broadcast find parent request + transportRouteMessage(build(_msgTmp, _nc.nodeId, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT, false).set("")); + #endif } // stParentUpdate void stParentUpdate() { - if (transportTimeInState() > STATE_TIMEOUT || _transportSM.preferredParentFound) { - // timeout or preferred parent found - if (_nc.parentNodeId != AUTO) { - debug(PSTR("TSM:FPAR:OK\n")); // find parent ok - _transportSM.findingParentNode = false; - setIndication(INDICATION_GOT_PARENT); - transportSwitchSM(stID); - } - else if (transportTimeInState() > STATE_TIMEOUT) { - if (_transportSM.retries < STATE_RETRIES) { - // reenter if timeout and retries left - transportSwitchSM(stParent); + #if !defined(MY_PARENT_NODE_IS_STATIC) + if (transportTimeInState() > STATE_TIMEOUT || _transportSM.preferredParentFound) { + // timeout or preferred parent found + if (_nc.parentNodeId != AUTO) { + // parent assigned + TRANSPORT_DEBUG(PSTR("TSM:FPAR:OK\n")); // find parent ok + _transportSM.findingParentNode = false; + setIndication(INDICATION_GOT_PARENT); + // go to next state + transportSwitchSM(stID); } - else { - debug(PSTR("!TSM:FPAR:FAIL\n")); // find parent fail - setIndication(INDICATION_ERR_FIND_PARENT); - transportSwitchSM(stFailure); + else if (transportTimeInState() > STATE_TIMEOUT) { + // timeout w/o reply or valid parent + if (_transportSM.retries < STATE_RETRIES) { + // retries left + TRANSPORT_DEBUG(PSTR("!TSM:FPAR:NO REPLY\n")); // find parent, no reply + // reenter state + transportSwitchSM(stParent); + } + else { + // no retries left, finding parent failed + TRANSPORT_DEBUG(PSTR("!TSM:FPAR:FAIL\n")); // find parent fail + setIndication(INDICATION_ERR_FIND_PARENT); + transportSwitchSM(stFailure); + } } } - } + #endif } // stID: verify and request ID if necessary void stIDTransition() { - debug(PSTR("TSM:ID\n")); + TRANSPORT_DEBUG(PSTR("TSM:ID\n")); // verify/request node ID if (_nc.nodeId == AUTO) { // send ID request setIndication(INDICATION_REQ_NODEID); + TRANSPORT_DEBUG(PSTR("TSM:ID:REQ\n")); // request node ID transportRouteMessage(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_ID_REQUEST, false).set("")); } } void stIDUpdate() { if (_nc.nodeId != AUTO) { - // current node ID is valid, proceed to uplink check - debug(PSTR("TSM:CHKID:OK (ID=%d)\n"), _nc.nodeId); + // current node ID is valid + TRANSPORT_DEBUG(PSTR("TSM:ID:OK,ID=%d\n"), _nc.nodeId); setIndication(INDICATION_GOT_NODEID); - // check uplink + // proceed to next state transportSwitchSM(stUplink); } else if (transportTimeInState() > STATE_TIMEOUT) { + // timeout if (_transportSM.retries < STATE_RETRIES) { - // re-enter if retries left + // reenter transportSwitchSM(stID); } else { - // fail - debug(PSTR("!TSM:CHKID:FAIL (ID=%d)\n"), _nc.nodeId); + // no retries left + TRANSPORT_DEBUG(PSTR("!TSM:ID:FAIL,ID=%d\n"), _nc.nodeId); setIndication(INDICATION_ERR_GET_NODEID); transportSwitchSM(stFailure); } @@ -154,56 +179,65 @@ void stIDUpdate() { } void stUplinkTransition() { - debug(PSTR("TSM:UPL\n")); + TRANSPORT_DEBUG(PSTR("TSM:UPL\n")); + // check uplink if(transportCheckUplink(true)) { - debug(PSTR("TSM:UPL:OK\n")); - transportSwitchSM(stOK); + // uplink ok, i.e. GW replied + TRANSPORT_DEBUG(PSTR("TSM:UPL:OK\n")); // uplink ok + // proceed to next state + transportSwitchSM(stReady); } else { - debug(PSTR("!TSM:UPL:FAIL\n")); + // uplink failed, at this point, no retries or timeout + TRANSPORT_DEBUG(PSTR("!TSM:UPL:FAIL\n")); // uplink failed + // go back to stParent transportSwitchSM(stParent); } } -void stOKTransition() { - debug(PSTR("TSM:READY\n")); // transport is ready +void stReadyTransition() { + // transport is ready and fully operational + TRANSPORT_DEBUG(PSTR("TSM:READY\n")); // transport is ready _transportSM.uplinkOk = true; + _transportSM.failedUplinkTransmissions = 0; // reset counter } -// stOK update: monitors uplink failures -void stOKUpdate() { +// stReadyUpdate: monitors uplink failures +void stReadyUpdate() { #if !defined(MY_GATEWAY_FEATURE) if (_transportSM.failedUplinkTransmissions > TRANSMISSION_FAILURES) { - // too many uplink transmissions failed, find new parent - #if !defined(MY_PARENT_NODE_IS_STATIC) - debug(PSTR("!TSM:UPL FAIL, SNP\n")); - transportSwitchSM(stParent); - #else - debug(PSTR("!TSM:UPL FAIL, STATP\n")); - _transportSM.failedUplinkTransmissions = 0; - #endif + // too many uplink transmissions failed, find new parent (if non-static) + #if !defined(MY_PARENT_NODE_IS_STATIC) + TRANSPORT_DEBUG(PSTR("!TSM:READY:UPL FAIL,SNP\n")); // uplink failed, search new parent + transportSwitchSM(stParent); + #else + TRANSPORT_DEBUG(PSTR("!TSM:READY:UPL FAIL,STATP\n")); // uplink failed, static parent + // reset counter + _transportSM.failedUplinkTransmissions = 0; + #endif } #endif } // stFailure: entered upon HW init failure or max retries exceeded void stFailureTransition() { - debug(PSTR("!TSM:FAILURE\n")); - _transportSM.uplinkOk = false; - _transportSM.transportActive = false; + TRANSPORT_DEBUG(PSTR("TSM:FAILURE\n")); + _transportSM.uplinkOk = false; // uplink nok + _transportSM.transportActive = false; // transport inactive setIndication(INDICATION_ERR_INIT_TRANSPORT); // power down transport, no need until re-init - debug(PSTR("TSM:PDT\n")); + TRANSPORT_DEBUG(PSTR("TSM:FAILURE:PDT\n")); // power down transport transportPowerDown(); } void stFailureUpdate() { if (transportTimeInState()> TIMEOUT_FAILURE_STATE) { + TRANSPORT_DEBUG(PSTR("TSM:FAILURE:RE-INIT\n")); // attempt to re-initialize transport transportSwitchSM(stInit); } } -void transportSwitchSM(State& newState) { +void transportSwitchSM(transportState& newState) { if (_transportSM.currentState != &newState) { // state change, reset retry counter _transportSM.retries = 0; @@ -227,10 +261,13 @@ void transportUpdateSM(){ if (_transportSM.currentState->Update) _transportSM.currentState->Update(); } -bool isTransportOK() { - return (_transportSM.uplinkOk); +bool isTransportReady() { + return _transportSM.uplinkOk; } +bool isTransportSearchingParent() { + return _transportSM.findingParentNode; +} void transportInitialize() { // intial state @@ -248,8 +285,8 @@ void transportProcess() { bool transportCheckUplink(bool force) { - if (!force && (hwMillis() - _transport_lastUplinkCheck) < CHKUPL_INTERVAL) { - debug(PSTR("TSP:CHKUPL:OK (FLDCTRL)\n")); // flood control + if (!force && (hwMillis() - _transportSM.lastUplinkCheck) < CHKUPL_INTERVAL) { + TRANSPORT_DEBUG(PSTR("TSF:CHKUPL:OK,FCTRL\n")); // flood control return true; } // ping GW @@ -257,35 +294,35 @@ bool transportCheckUplink(bool force) { // verify hops if (hopsCount != INVALID_HOPS) { // update - _transport_lastUplinkCheck = hwMillis(); - debug(PSTR("TSP:CHKUPL:OK\n")); - // did distance to GW change upstream, i.e. re-routing of uplink nodes? + _transportSM.lastUplinkCheck = hwMillis(); + TRANSPORT_DEBUG(PSTR("TSF:CHKUPL:OK\n")); + // did distance to GW change upstream, eg. re-routing of uplink nodes if (hopsCount != _nc.distance) { - debug(PSTR("TSP:CHKUPL:DGWC (old=%d,new=%d)"), _nc.distance, hopsCount); // distance to GW changed + TRANSPORT_DEBUG(PSTR("TSF:CHKUPL:DGWC,O=%d,N=%d\n"), _nc.distance, hopsCount); // distance to GW changed _nc.distance = hopsCount; } return true; } else { - debug(PSTR("TSP:CHKUPL:FAIL (hops=%d)\n"), hopsCount); + TRANSPORT_DEBUG(PSTR("TSF:CHKUPL:FAIL\n")); return false; } } -void transportAssignNodeID(uint8_t newNodeId) { +bool transportAssignNodeID(uint8_t newNodeId) { // verify if ID valid if (newNodeId != GATEWAY_ADDRESS && newNodeId != AUTO) { _nc.nodeId = newNodeId; transportSetAddress(newNodeId); // Write ID to EEPROM hwWriteConfig(EEPROM_NODE_ID_ADDRESS, newNodeId); - debug(PSTR("TSP:ASSIGNID:OK (ID=%d)\n"),newNodeId); + TRANSPORT_DEBUG(PSTR("TSF:ASID:OK,ID=%d\n"),newNodeId); + return true; } else { - debug(PSTR("!TSP:ASSIGNID:FAIL (ID=%d)\n"),newNodeId); + TRANSPORT_DEBUG(PSTR("!TSF:ASID:FAIL,ID=%d\n"),newNodeId); setIndication(INDICATION_ERR_NET_FULL); - // Nothing else we can do... - transportSwitchSM(stFailure); + return false; } } @@ -294,7 +331,7 @@ bool transportRouteMessage(MyMessage &message) { uint8_t route; if (_transportSM.findingParentNode && destination != BROADCAST_ADDRESS) { - debug(PSTR("!TSP:FPAR:ACTIVE (msg not send)\n")); + TRANSPORT_DEBUG(PSTR("!TSF:ROUTE:FPAR ACTIVE\n")); // find parent active, message not sent // request to send a non-BC message while finding parent active, abort return false; } @@ -313,7 +350,7 @@ bool transportRouteMessage(MyMessage &message) { // route unknown if (message.last != _nc.parentNodeId) { // message not from parent, i.e. child node - route it to parent - debug(PSTR("!TSP:ROUTING:DEST UNKNOWN (dest=%d, STP=%d)\n"), destination, _nc.parentNodeId); + TRANSPORT_DEBUG(PSTR("!TSF:ROUTE:%d UNKNOWN\n"), destination); route = _nc.parentNodeId; } else { @@ -338,19 +375,18 @@ bool transportRouteMessage(MyMessage &message) { } #else if(!ok) setIndication(INDICATION_ERR_TX); - #endif return ok; } bool transportSendRoute(MyMessage &message) { - if (isTransportOK()) { + if (isTransportReady()) { return transportRouteMessage(message); } else { // TNR: transport not ready - debug(PSTR("!TSP:SEND:TNR\n")); + TRANSPORT_DEBUG(PSTR("!TSF:SEND:TNR\n")); return false; } } @@ -380,7 +416,7 @@ uint8_t transportPingNode(uint8_t targetId) { } _transportSM.pingActive = true; _transportSM.pingResponse = INVALID_HOPS; - debug(PSTR("TSP:PING:SEND (dest=%d)\n"), targetId); + TRANSPORT_DEBUG(PSTR("TSF:PING:SEND,TO=%d\n"), targetId); transportRouteMessage(build(_msgTmp, _nc.nodeId, targetId, NODE_SENSOR_ID, C_INTERNAL, I_PING, false).set((uint8_t)0x01)); // Wait for ping reply or timeout transportWait(2000, C_INTERNAL, I_PONG); @@ -397,7 +433,7 @@ void transportClearRoutingTable() { for (uint8_t i = 0; i != 255; i++) { hwWriteConfig(EEPROM_ROUTES_ADDRESS + i, BROADCAST_ADDRESS); } - debug(PSTR("TSP:CRT:OK\n")); // clear routing table + TRANSPORT_DEBUG(PSTR("TSF:CRT:OK\n")); // clear routing table } uint32_t transportGetHeartbeat() { @@ -408,7 +444,7 @@ void transportProcessMessage() { (void)signerCheckTimer(); // Manage signing timeout uint8_t payloadLength = transportReceive((uint8_t *)&_msg); - (void)payloadLength; // currently not used, but good to test for CRC-ok but corrupt msgs + (void)payloadLength; // currently not used setIndication(INDICATION_RX); @@ -418,26 +454,25 @@ void transportProcessMessage() { uint8_t last = _msg.last; uint8_t destination = _msg.destination; - debug(PSTR("TSP:MSG:READ %d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d:%s\n"), + TRANSPORT_DEBUG(PSTR("TSF:MSG:READ,%d-%d-%d,s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d:%s\n"), sender, last, destination, _msg.sensor, mGetCommand(_msg), type, mGetPayloadType(_msg), mGetLength(_msg), mGetSigned(_msg), _msg.getString(_convBuf)); // verify protocol version if(mGetVersion(_msg) != PROTOCOL_VERSION) { setIndication(INDICATION_ERR_VERSION); - debug(PSTR("!TSP:MSG:PVER mismatch\n")); // protocol version + TRANSPORT_DEBUG(PSTR("!TSF:MSG:PVER,%d!=%d\n"), mGetVersion(_msg),PROTOCOL_VERSION); // protocol version mismatch return; } - // Reject massages that do not pass verification + // Reject messages that do not pass verification if (!signerVerifyMsg(_msg)) { setIndication(INDICATION_ERR_SIGN); - debug(PSTR("!TSP:MSG:SIGN verify fail\n")); + TRANSPORT_DEBUG(PSTR("!TSF:MSG:SIGN VERIFY FAIL\n")); return; } - + // Is message addressed to this node? if (destination == _nc.nodeId) { - // This message is addressed to this node // prevent buffer overflow by limiting max. possible message length (5 bits=31 bytes max) to MAX_PAYLOAD (25 bytes) mSetLength(_msg, min(mGetLength(_msg),MAX_PAYLOAD)); // null terminate data @@ -459,7 +494,7 @@ void transportProcessMessage() { _msgTmp.sender = _nc.nodeId; _msgTmp.destination = sender; // send ACK - debug(PSTR("TSP:MSG:ACK msg\n")); + TRANSPORT_DEBUG(PSTR("TSF:MSG:ACK REQ\n")); // ACK requested // use transportSendRoute since ACK reply is not internal, i.e. if !transportOK do not reply transportSendRoute(_msgTmp); } @@ -479,32 +514,37 @@ void transportProcessMessage() { return; // no further processing required } if (type == I_FIND_PARENT_RESPONSE) { - #if !defined(MY_GATEWAY_FEATURE) - // Reply to a I_FIND_PARENT message. Check if the distance is shorter than we already have. - uint8_t distance = _msg.getByte(); - debug(PSTR("TSP:MSG:FPAR RES (ID=%d, dist=%d)\n"), sender, distance); - if (isValidDistance(distance)) { - // Distance to gateway is one more for us w.r.t. parent - distance++; - // update settings if distance shorter or preferred parent found - if (((isValidDistance(distance) && distance < _nc.distance) || (!_autoFindParent && sender == MY_PARENT_NODE_ID)) && !_transportSM.preferredParentFound) { - // Found a neighbor closer to GW than previously found - if (!_autoFindParent && sender == MY_PARENT_NODE_ID) { - _transportSM.preferredParentFound = true; - debug(PSTR("TSP:MSG:FPAR (PPAR FOUND)\n")); // preferred parent found + #if !defined(MY_GATEWAY_FEATURE) && !defined(MY_PARENT_NODE_IS_STATIC) + if (_transportSM.findingParentNode) { // only process if find parent active + // Reply to a I_FIND_PARENT message. Check if the distance is shorter than we already have. + uint8_t distance = _msg.getByte(); + TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR RES,ID=%d,D=%d\n"), sender, distance); // find parent response + if (isValidDistance(distance)) { + // Distance to gateway is one more for us w.r.t. parent + distance++; + // update settings if distance shorter or preferred parent found + if (((isValidDistance(distance) && distance < _nc.distance) || (!_autoFindParent && sender == MY_PARENT_NODE_ID)) && !_transportSM.preferredParentFound) { + // Found a neighbor closer to GW than previously found + if (!_autoFindParent && sender == MY_PARENT_NODE_ID) { + _transportSM.preferredParentFound = true; + TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR PREF FOUND\n")); // find parent, preferred parent found + } + _nc.distance = distance; + _nc.parentNodeId = sender; + TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR OK,ID=%d,D=%d\n"), _nc.parentNodeId, _nc.distance); } - _nc.distance = distance; - _nc.parentNodeId = sender; - debug(PSTR("TSP:MSG:PAR OK (ID=%d, dist=%d)\n"), _nc.parentNodeId, _nc.distance); } } + else { + TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR INACTIVE\n")); // find parent response received, but inactive + } return; #endif } #endif // general if (type == I_PING) { - debug(PSTR("TSP:MSG:PINGED (ID=%d, hops=%d)\n"), sender, _msg.getByte()); + TRANSPORT_DEBUG(PSTR("TSF:MSG:PINGED,ID=%d,HP=%d\n"), sender, _msg.getByte()); // node pinged transportRouteMessage(build(_msgTmp, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_PONG, false).set((uint8_t)0x01)); return; // no further processing required } @@ -512,7 +552,7 @@ void transportProcessMessage() { if (_transportSM.pingActive) { _transportSM.pingActive = false; _transportSM.pingResponse = _msg.getByte(); - debug(PSTR("TSP:MSG:PONG RECV (hops=%d)\n"), _transportSM.pingResponse); + TRANSPORT_DEBUG(PSTR("TSF:MSG:PONG RECV,HP=%d\n"), _transportSM.pingResponse); // pong received } return; // no further processing required } @@ -528,40 +568,42 @@ void transportProcessMessage() { #endif } } + else { + TRANSPORT_DEBUG(PSTR("TSF:MSG:ACK\n")); // received message is ACK, no internal processing, handover to msg callback + } #if defined(MY_GATEWAY_FEATURE) // Hand over message to controller gatewayTransportSend(_msg); - #else - // Call incoming message callback if available - if (receive) { - receive(_msg); - } #endif + // Call incoming message callback if available + if (receive) { + receive(_msg); + } return; } else if (destination == BROADCAST_ADDRESS) { - // broadcast - debug(PSTR("TSP:MSG:BC\n")); + TRANSPORT_DEBUG(PSTR("TSF:MSG:BC\n")); // broadcast msg if (command == C_INTERNAL) { - if (isTransportOK()) { + if (isTransportReady()) { // only reply if node is fully operational if (type == I_FIND_PARENT) { #if defined(MY_REPEATER_FEATURE) if (sender != _nc.parentNodeId) { // no circular reference - debug(PSTR("TSP:MSG:FPAR REQ (sender=%d)\n"), sender); // FPR: find parent request + TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR REQ,ID=%d\n"), sender); // FPR: find parent request // node is in our range, update routing table - important if node has new repeater as parent hwWriteConfig(EEPROM_ROUTES_ADDRESS + sender, sender); // check if uplink functional - node can only be parent node if link to GW functional // this also prevents circular references in case GW ooo if(transportCheckUplink(false)){ - #if defined(MY_REPEATER_FEATURE) - _transport_lastUplinkCheck = hwMillis(); - #endif - debug(PSTR("TSP:MSG:GWL OK\n")); // GW uplink ok + _transportSM.lastUplinkCheck = hwMillis(); + TRANSPORT_DEBUG(PSTR("TSF:MSG:GWL OK\n")); // GW uplink ok // delay minimizes collisions delay(hwMillis() & 0x3ff); transportRouteMessage(build(_msgTmp, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(_nc.distance)); } + else { + TRANSPORT_DEBUG(PSTR("!TSF:MSG:GWL FAIL\n")); // GW uplink fail, do not respond to parent request + } } #endif @@ -580,8 +622,8 @@ void transportProcessMessage() { // controlled BC relay #if defined(MY_REPEATER_FEATURE) // controlled BC repeating: forward only if message received from parent and sender not self to prevent circular fwds - if(last == _nc.parentNodeId && sender != _nc.nodeId && isTransportOK()){ - debug(PSTR("TSP:MSG:FWD BC MSG\n")); // forward BC msg + if(last == _nc.parentNodeId && sender != _nc.nodeId && isTransportReady()){ + TRANSPORT_DEBUG(PSTR("TSF:MSG:FWD BC MSG\n")); // controlled broadcast msg forwarding transportRouteMessage(_msg); } #endif @@ -593,10 +635,10 @@ void transportProcessMessage() { } else { - // msg not no us and not BC, relay msg + // msg not to us and not BC, relay msg #if defined(MY_REPEATER_FEATURE) - if (isTransportOK()) { - debug(PSTR("TSP:MSG:REL MSG\n")); // relay msg + if (isTransportReady()) { + TRANSPORT_DEBUG(PSTR("TSF:MSG:REL MSG\n")); // relay msg // update routing table if message not received from parent if (last != _nc.parentNodeId) { hwWriteConfig(EEPROM_ROUTES_ADDRESS + sender, last); @@ -605,7 +647,7 @@ void transportProcessMessage() { if (type == I_PING || type == I_PONG) { uint8_t hopsCnt = _msg.getByte(); if (hopsCnt != MAX_HOPS) { - debug(PSTR("TSP:MSG:REL PxNG (hops=%d)\n"), hopsCnt); + TRANSPORT_DEBUG(PSTR("TSF:MSG:REL PxNG,HP=%d\n"), hopsCnt); _msg.set((uint8_t)(hopsCnt + 1)); } } @@ -614,24 +656,28 @@ void transportProcessMessage() { transportRouteMessage(_msg); } #else - debug(PSTR("!TSM:MSG:REL MSG, but not a repeater\n")); + TRANSPORT_DEBUG(PSTR("!TSF:MSG:REL MSG,NORP\n")); // message relaying request, but not a repeater #endif } } +void transportInvokeSanityCheck() { + if (!transportSanityCheck()) { + TRANSPORT_DEBUG(PSTR("!TSF:SANCHK:FAIL\n")); // sanity check fail + transportSwitchSM(stFailure); + return; + } + else { + TRANSPORT_DEBUG(PSTR("TSF:SANCHK:OK\n")); // sanity check ok + } +} + inline void transportProcessFIFO() { if (_transportSM.transportActive) { #if defined(MY_TRANSPORT_SANITY_CHECK) || defined(MY_REPEATER_FEATURE) - if (hwMillis() > (_transport_lastSanityCheck + MY_TRANSPORT_SANITY_CHECK_INTERVAL)) { - _transport_lastSanityCheck = hwMillis(); - if (!transportSanityCheck()) { - debug(PSTR("!TSP:SANCHK:FAIL\n")); // sanity check fail - transportSwitchSM(stFailure); - return; - } - else { - debug(PSTR("TSP:SANCHK:OK\n")); // sanity check ok - } + if (hwMillis() - _transportSM.lastSanityCheck > MY_TRANSPORT_SANITY_CHECK_INTERVAL) { + _transportSM.lastSanityCheck = hwMillis(); + transportInvokeSanityCheck(); } #endif } @@ -645,7 +691,7 @@ inline void transportProcessFIFO() { transportProcessMessage(); } #if defined(MY_OTA_FIRMWARE_FEATURE) - if (isTransportOK()) { + if (isTransportReady()) { // only process if transport ok firmwareOTAUpdateRequest(); } @@ -659,7 +705,7 @@ bool transportSendWrite(uint8_t to, MyMessage &message) { // sign message if required if (!signerSignMsg(message)) { - debug(PSTR("!TSP:MSG:SIGN fail\n")); + TRANSPORT_DEBUG(PSTR("!TSF:MSG:SIGN FAIL\n")); setIndication(INDICATION_ERR_SIGN); return false; } @@ -671,10 +717,11 @@ bool transportSendWrite(uint8_t to, MyMessage &message) { setIndication(INDICATION_TX); bool ok = transportSend(to, &message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length)); - debug(PSTR("%sTSP:MSG:SEND %d-%d-%d-%d s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d,ft=%d,st=%s:%s\n"), + TRANSPORT_DEBUG(PSTR("%sTSF:MSG:SEND,%d-%d-%d-%d,s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d,ft=%d,st=%s:%s\n"), (ok || to == BROADCAST_ADDRESS ? "" : "!"),message.sender,message.last, to, message.destination, message.sensor, mGetCommand(message), message.type, - mGetPayloadType(message), mGetLength(message), mGetSigned(message), _transportSM.failedUplinkTransmissions, to==BROADCAST_ADDRESS ? "bc" : (ok ? "ok":"fail"), message.getString(_convBuf)); + mGetPayloadType(message), mGetLength(message), mGetSigned(message), _transportSM.failedUplinkTransmissions, to==BROADCAST_ADDRESS ? "bc" : (ok ? "OK":"NACK"), message.getString(_convBuf)); return (ok || to==BROADCAST_ADDRESS); } +// EOF MyTransport.cpp \ No newline at end of file diff --git a/core/MyTransport.h b/core/MyTransport.h index c4800e9c1..ad038a58d 100644 --- a/core/MyTransport.h +++ b/core/MyTransport.h @@ -20,8 +20,126 @@ /** * @file MyTransport.h * + * @defgroup MyTransportgrp MyTransport + * @ingroup internals + * @{ + * + * Transport-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE + * - [!] Exclamation mark is prepended in case of error + * - SYSTEM: + * - TSM: messages emitted by the transport state machine + * - TSF: messages emitted by transport support functions + * - SUB SYSTEMS: + * - Transport state machine (TSM) + * - TSM:INIT from stInit Initialize transport and radio + * - TSM:FPAR from stParent Find parent + * - TSM:ID from stID Check/request node ID, if dynamic node ID set + * - TSM:UPL from stUplink Verify uplink connection by pinging GW + * - TSM:READY from stReady Transport is ready and fully operational + * - TSM:FAILURE from stFailure Failure in transport link or transport HW + * - Transport support function (TSF) + * - TSF:CHKUPL from @ref transportCheckUplink(..), checks connection to GW + * - TSF:ASID from @ref transportAssignNodeID(..), assigns node ID + * - TSF:PING from @ref transportPingNode(..), pings a node + * - TSF:CRT from @ref transportClearRoutingTable(..), clears routing table stored in EEPROM + * - TSF:MSG from @ref transportProcessMessage(..), processes incoming message + * - TSF:SANCHK from @ref transportInvokeSanityCheck(..), calls transport-specific sanity check + * - TSF:ROUTE from @ref transportRouteMessage(..), sends message + * - TSF:SEND from @ref transportSendRoute(..), sends message if transport is ready (exposed) + * + * TSM state stInit log status / errors + * - TSM:INIT Transition to stInit state + * - TSM:INIT:STATID,ID=x Node ID x is static + * - TSM:INIT:TSP OK Transport device configured and fully operational + * - TSM:INIT:GW MODE Node is set up as GW, thus omitting ID and findParent states + * - !TSM:INIT:TSP FAIL Transport device initialization failed + * + * TSM state stParent log status / errors + * - TSM:FPAR Transition to stParent state + * - TSM:FPAR:STATP=x Static parent x set, skip finding parent + * - TSM:FPAR:OK Parent node identified + * - !TSM:FPAR:NO REPLY No potential parents replied to find parent request, retry + * - !TSM:FPAR:FAIL Finding parent failed, go to failure state + * + * TSM state stID log status / errors + * - TSM:ID Transition to stID state + * - TSM:ID:OK,ID=x Node ID x is valid + * - TSM:ID:REQ Request node ID from controller + * - !TSM:ID:FAIL,ID=x ID verification failed, ID x invalid + * + * TSM state stUplink log status / errors + * - TSM:UPL Transition to stUplink state + * - TSM:UPL:OK Uplink OK, GW returned ping + * - !TSM:UPL:FAIL Uplink check failed, i.e. GW could not be pinged + * + * TSM state stReady log status / errors + * - TSM:READY Transition to stReady, i.e. transport is ready and fully operational + * - !TSM:READY:UPL FAIL,SNP Too many failed uplink transmissions, search new parent + * - !TSM:READY:UPL FAIL,STATP Too many failed uplink transmissions, no SNP, static parent enforced + * + * TSM state stFailure information / status + * - TSM:FAILURE Transition to stFailure state + * - TSM:FAILURE:PDT Power-down transport + * - TSM:FAILURE:RE-INIT Attempt to re-initialize transport + * + * TSF information / status + * - TSF:CHKUPL:OK Uplink OK + * - TSF:CHKUPL:OK,FCTRL Uplink OK, flood control prevents pinging GW in too short intervals + * - TSF:CHKUPL:DGWC,O=x,N=y Checking uplink revealed a changed network topology, old distance x, new distance y + * - TSF:CHKUPL:FAIL No reply received when checking uplink + * - TSF:ASID:OK,ID=x Node ID x assigned + * - TSF:PING:SEND,TO=x Send ping to destination x + * - TSF:MSG:ACK REQ ACK message requested + * - TSF:MSG:ACK ACK message, do not proceed but forward to callback + * - TSF:MSG:FPAR RES,ID=x,D=y Response to find parent received from node x with distance y to GW + * - TSF:MSG:FPAR PREF FOUND Preferred parent found + * - TSF:MSG:FPAR OK,ID=x,D=y Find parent reponse from node x is valid, distance y to GW + * - TSF:MSG:FPAR INACTIVE Find parent response received, but no find parent request active, skip response + * - TSF:MSG:FPAR REQ,ID=x Find parent request from node x + * - TSF:MSG:PINGED,ID=x,HP=y Node pinged by node x with y hops + * - TSF:MSG:PONG RECV,HP=x Pinged node replied with x hops + * - TSF:MSG:BC Broadcast message received + * - TSF:MSG:GWL OK Link to GW ok + * - TSF:MSG:FWD BC MSG Controlled broadcast message forwarding + * - TSF:MSG:REL MSG Relay message + * - TSF:MSG:REL PxNG,HP=x Relay PING/PONG message, increment hop counter x + * - TSF:SANCHK:OK Sanity check passed. This ensures radio functionality and automatically attempts to re-initialize in case of failure + * - TSF:CRT:OK Clearing routing table successful + * + * Incoming / outgoing messages + * + * See here for more detail on the format and definitons. + * + * Receiving a message + * - TSF:MSG:READ,sender-last-destination,s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d:%s + * Sending a message + * - [!]TSF:MSG:SEND,sender-last-next-destination,s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d,ft=%d,st=%s:%s + * + * - Message fields: + * - s=sensor ID + * - c=command + * - t=msg type + * - pt=payload type + * - l=length + * - ft=failed uplink transmission counter + * - sg=signing flag + * + * TSF errors + * - !TSF:ASID:FAIL,ID=x Assigned ID x is invalid, e.g. 0 (GATEWAY) + * - !TSF:ROUTE:FPAR ACTIVE Finding parent active, message not sent + * - !TSF:ROUTE:DST x UNKNOWN Routing for destination x unkown, send message to parent + * - !TSF:SEND:TNR Transport not ready, message cannot be sent + * - !TSF:MSG:PVER,x!=y Message protocol version mismatch + * - !TSF:MSG:SIGN VERIFY FAIL Signing verficiation failed + * - !TSF:MSG:REL MSG,NORP Node received a message for relaying, but node is not a repeater, message skipped + * - !TSF:MSG:SIGN FAIL Signing message failed + * - !TSF:MSG:GWL FAIL GW uplink failed + * - !TSF:SANCHK:FAIL Sanity check failed, attempt to re-intialize radio + * * @brief API declaration for MyTransport + * */ + #ifndef MyTransport_h #define MyTransport_h @@ -52,7 +170,7 @@ * * This structure stores SM state definitions */ -struct State { +struct transportState { void(*Transition)(); //!< state transition function void(*Update)(); //!< state update function }; @@ -63,16 +181,21 @@ struct State { * This structure stores transport status and SM variables */ typedef struct { - State* currentState; //!< pointer to current fsm state + transportState* currentState; //!< pointer to current fsm state uint32_t stateEnter; //!< state enter timepoint + uint32_t lastUplinkCheck; //!< last uplink check, required to prevent GW flooding + uint32_t lastSanityCheck; //!< last sanity check + // 8 bits bool findingParentNode : 1; //!< flag finding parent node is active bool preferredParentFound : 1; //!< flag preferred parent found bool uplinkOk : 1; //!< flag uplink ok bool pingActive : 1; //!< flag ping active bool transportActive : 1; //!< flag transport active uint8_t reserved : 3; //!< reserved + // 8 bits uint8_t retries : 4; //!< retries / state re-enter uint8_t failedUplinkTransmissions : 4; //!< counter failed uplink transmissions + // 8 bits uint8_t pingResponse; //!< stores hops received in I_PONG } __attribute__((packed)) transportSM; @@ -106,11 +229,11 @@ void stUplinkTransition(); /** * @brief Set transport OK */ -void stOKTransition(); +void stReadyTransition(); /** * @brief Monitor transport link */ -void stOKUpdate(); +void stReadyUpdate(); /** * @brief Transport failure and power down radio */ @@ -123,7 +246,7 @@ void stFailureUpdate(); * @brief Switch SM state * @param newState New state to switch SM to */ -void transportSwitchSM(State& newState); +void transportSwitchSM(transportState& newState); /** * @brief Update SM state */ @@ -133,7 +256,10 @@ void transportUpdateSM(); * @return ms in current state */ uint32_t transportTimeInState(); - +/** +* @brief Call transport driver sanity check +*/ +void transportInvokeSanityCheck(); /** * @brief Process all pending messages in RX FIFO */ @@ -145,8 +271,9 @@ void transportProcessMessage(); /** * @brief Assign node ID * @param newNodeId New node ID +* @return true if node ID valid and successfully assigned */ -void transportAssignNodeID(uint8_t newNodeId); +bool transportAssignNodeID(uint8_t newNodeId); /** * @brief Wait and process messages for a defined amount of time until specified message received * @param ms Time to wait and process incoming messages in ms @@ -164,7 +291,7 @@ uint8_t transportPingNode(uint8_t targetId); /** * @brief Send and route message according to destination * -* This function is used in MyTransport and omits the transport state check, i.e. message can be sent even if transport is !OK +* This function is used in MyTransport and omits the transport state check, i.e. message can be sent even if transport is not ready * * @param message * @return true if message sent successfully @@ -201,10 +328,15 @@ void transportInitialize(); */ void transportProcess(); /** -* @brief Verify transport status +* @brief Flag transport ready * @return true if transport is initialize and ready */ -bool isTransportOK(); +bool isTransportReady(); +/** +* @brief Flag searching parent ongoing +* @return true if transport is searching for parent +*/ +bool isTransportSearchingParent(); /** * @brief Clear routing table */ From ea99e4735d7b6a179dd1c531441ce9f92dccb3f0 Mon Sep 17 00:00:00 2001 From: Brenda Wallace Date: Sun, 31 Jul 2016 16:43:58 +1200 Subject: [PATCH 014/167] Added MY_CONTROLLER_URL_ADDRESS to keywords Signed-off-by: Brenda Wallace --- keywords.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/keywords.txt b/keywords.txt index 09acb9978..da92188c5 100644 --- a/keywords.txt +++ b/keywords.txt @@ -100,6 +100,7 @@ MY_USE_UDP LITERAL1 MY_IP_RENEWAL_INTERVAL LITERAL1 MY_MAC_ADDRESS LITERAL1 MY_CONTROLLER_IP_ADDRESS LITERAL1 +MY_CONTROLLER_URL_ADDRESS LITERAL1 MY_GATEWAY_MAX_CLIENTS LITERAL1 MY_GATEWAY_MAX_SEND_LENGTH LITERAL1 MY_GATEWAY_MAX_RECEIVE_LENGTH LITERAL1 From ba6fae75968a281018bd7814662a1e29ae0b762d Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Sun, 31 Jul 2016 15:25:55 +0200 Subject: [PATCH 015/167] Fix #449, Fix #507 --- core/MyGatewayTransportMQTTClient.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/MyGatewayTransportMQTTClient.cpp b/core/MyGatewayTransportMQTTClient.cpp index f6c36e7d1..ea8138e54 100644 --- a/core/MyGatewayTransportMQTTClient.cpp +++ b/core/MyGatewayTransportMQTTClient.cpp @@ -146,6 +146,8 @@ bool reconnectMQTT() { #endif )) { debug(PSTR("MQTT connected\n")); + if (presentation) + presentation(); // Once connected, publish an announcement... //_MQTT_client.publish("outTopic","hello world"); // ... and resubscribe From 26f20b0e3be9acefeaf42398eebfe5836a2a1c20 Mon Sep 17 00:00:00 2001 From: tekka007 Date: Sat, 30 Jul 2016 17:37:41 +0200 Subject: [PATCH 016/167] Fix compatibility issue with nRF clones, update documentation --- MyConfig.h | 8 -- core/MyTransport.cpp | 8 -- core/MyTransport.h | 185 +++++++++++++++++++++--------------------- drivers/RF24/RF24.cpp | 20 ++--- 4 files changed, 100 insertions(+), 121 deletions(-) diff --git a/MyConfig.h b/MyConfig.h index 2a9c5da74..b362561e6 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -483,14 +483,6 @@ #define MY_RF24_ADDR_WIDTH 5 #endif -/** - * @def MY_RF24_SANITY_CHECK - * @brief RF24 sanity check to verify functional RF module - * - * This reads back and compares configuration registers. Disable if using non-P modules - */ -#define MY_RF24_SANITY_CHECK - // Enable SOFTSPI for NRF24L01, useful for the W5100 Ethernet module //#define MY_SOFTSPI diff --git a/core/MyTransport.cpp b/core/MyTransport.cpp index eb80ad7ff..6b14b2341 100644 --- a/core/MyTransport.cpp +++ b/core/MyTransport.cpp @@ -19,14 +19,6 @@ #include "MyTransport.h" -// debug -#if defined(MY_DEBUG) - #define TRANSPORT_DEBUG(x,...) debug(x, ##__VA_ARGS__) -#else - #define TRANSPORT_DEBUG(x,...) -#endif - - // SM: transitions and update states static transportState stInit = { stInitTransition, NULL }; static transportState stParent = { stParentTransition, stParentUpdate }; diff --git a/core/MyTransport.h b/core/MyTransport.h index ad038a58d..0b5a5c7c5 100644 --- a/core/MyTransport.h +++ b/core/MyTransport.h @@ -26,115 +26,105 @@ * * Transport-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE * - [!] Exclamation mark is prepended in case of error - * - SYSTEM: - * - TSM: messages emitted by the transport state machine - * - TSF: messages emitted by transport support functions + * - SYSTEM: + * - TSM: messages emitted by the transport state machine + * - TSF: messages emitted by transport support functions * - SUB SYSTEMS: - * - Transport state machine (TSM) + * - Transport state machine (TSM) * - TSM:INIT from stInit Initialize transport and radio * - TSM:FPAR from stParent Find parent * - TSM:ID from stID Check/request node ID, if dynamic node ID set * - TSM:UPL from stUplink Verify uplink connection by pinging GW * - TSM:READY from stReady Transport is ready and fully operational * - TSM:FAILURE from stFailure Failure in transport link or transport HW - * - Transport support function (TSF) - * - TSF:CHKUPL from @ref transportCheckUplink(..), checks connection to GW - * - TSF:ASID from @ref transportAssignNodeID(..), assigns node ID - * - TSF:PING from @ref transportPingNode(..), pings a node - * - TSF:CRT from @ref transportClearRoutingTable(..), clears routing table stored in EEPROM - * - TSF:MSG from @ref transportProcessMessage(..), processes incoming message - * - TSF:SANCHK from @ref transportInvokeSanityCheck(..), calls transport-specific sanity check - * - TSF:ROUTE from @ref transportRouteMessage(..), sends message - * - TSF:SEND from @ref transportSendRoute(..), sends message if transport is ready (exposed) + * - Transport support function (TSF) + * - TSF:CHKUPL from @ref transportCheckUplink(), checks connection to GW + * - TSF:ASID from @ref transportAssignNodeID(), assigns node ID + * - TSF:PING from @ref transportPingNode(), pings a node + * - TSF:CRT from @ref transportClearRoutingTable(), clears routing table stored in EEPROM + * - TSF:MSG from @ref transportProcessMessage(), processes incoming message + * - TSF:SANCHK from @ref transportInvokeSanityCheck(), calls transport-specific sanity check + * - TSF:ROUTE from @ref transportRouteMessage(), sends message + * - TSF:SEND from @ref transportSendRoute(), sends message if transport is ready (exposed) * - * TSM state stInit log status / errors - * - TSM:INIT Transition to stInit state - * - TSM:INIT:STATID,ID=x Node ID x is static - * - TSM:INIT:TSP OK Transport device configured and fully operational - * - TSM:INIT:GW MODE Node is set up as GW, thus omitting ID and findParent states - * - !TSM:INIT:TSP FAIL Transport device initialization failed + * Transport debug log messages: * - * TSM state stParent log status / errors - * - TSM:FPAR Transition to stParent state - * - TSM:FPAR:STATP=x Static parent x set, skip finding parent - * - TSM:FPAR:OK Parent node identified - * - !TSM:FPAR:NO REPLY No potential parents replied to find parent request, retry - * - !TSM:FPAR:FAIL Finding parent failed, go to failure state + * |E| SYS | SUB | Message | Comment + * |-|------|-----------|-----------------------|--------------------------------------------------------------------- + * | | TSM | INIT | | Transition to stInit state + * | | TSM | INIT | STATID,ID=%%d | Node ID is static + * | | TSM | INIT | TSP OK | Transport device configured and fully operational + * | | TSM | INIT | GW MODE | Node is set up as GW, thus omitting ID and findParent states + * |!| TSM | INIT | TSP FAIL | Transport device initialization failed + * | | TSM | FPAR | | Transition to stParent state + * | | TSM | FPAR | STATP=%%d | Static parent set, skip finding parent + * | | TSM | FPAR | OK | Parent node identified + * |!| TSM | FPAR | NO REPLY | No potential parents replied to find parent request + * |!| TSM | FPAR | FAIL | Finding parent failed + * | | TSM | ID | | Transition to stID state + * | | TSM | ID | OK,ID=%%d | Node ID is valid + * | | TSM | ID | REQ | Request node ID from controller + * |!| TSM | ID | FAIL,ID=%%d | ID verification failed, ID invalid + * | | TSM | UPL | | Transition to stUplink state + * | | TSM | UPL | OK | Uplink OK, GW returned ping + * |!| TSM | UPL | FAIL | Uplink check failed, i.e. GW could not be pinged + * | | TSM | READY | | Transition to stReady, i.e. transport is ready and fully operational + * |!| TSM | READY | UPL FAIL,SNP | Too many failed uplink transmissions, search new parent + * |!| TSM | READY | FAIL,STATP | Too many failed uplink transmissions, static parent enforced + * | | TSM | FAILURE | | Transition to stFailure state + * | | TSM | FAILURE | PDT | Power-down transport + * | | TSM | FAILURE | RE-INIT | Attempt to re-initialize transport + * | | TSF | CHKUPL | OK | Uplink OK + * | | TSF | CHKUPL | OK,FCTRL | Uplink OK, flood control prevents pinging GW in too short intervals + * | | TSF | CHKUPL | DGWC,O=%%d,N=%%d | Uplink check revealed changed network topology, old distance (O), new distance (N) + * | | TSF | CHKUPL | FAIL | No reply received when checking uplink + * | | TSF | ASID | OK,ID=%%d | Node ID assigned + * |!| TSF | ASID | FAIL,ID=%%d | Assigned ID is invalid + * | | TSF | PING | SEND,TO=%%d | Send ping to destination (TO) + * | | TSF | MSG | ACK REQ | ACK message requested + * | | TSF | MSG | ACK | ACK message, do not proceed but forward to callback + * | | TSF | MSG | FPAR RES,ID=%%d,D=%%d | Response to find parent received from node (ID) with distance (D) to GW + * | | TSF | MSG | FPAR PREF FOUND | Preferred parent found, i.e. parent defined via MY_PARENT_NODE_ID + * | | TSF | MSG | FPAR OK,ID=%%d,D=%%d | Find parent response from node (ID) is valid, distance (D) to GW + * | | TSF | MSG | FPAR INACTIVE | Find parent response received, but no find parent request active, skip response + * | | TSF | MSG | FPAR REQ,ID=%%d | Find parent request from node (ID) + * | | TSF | MSG | PINGED,ID=%%d,HP=%%d | Node pinged by node (ID) with (HP) hops + * | | TSF | MSG | PONG RECV,HP=%%d | Pinged node replied with (HP) hops + * | | TSF | MSG | BC | Broadcast message received + * | | TSF | MSG | GWL OK | Link to GW ok + * | | TSF | MSG | FWD BC MSG | Controlled broadcast message forwarding + * | | TSF | MSG | REL MSG | Relay message + * | | TSF | MSG | REL PxNG,HP=%%d | Relay PING/PONG message, increment hop counter (HP) + * |!| TSF | MSG | PVER,%%d!=%%d | Message protocol version mismatch + * |!| TSF | MSG | SIGN VERIFY FAIL | Signing verification failed + * |!| TSF | MSG | REL MSG,NORP | Node received a message for relaying, but node is not a repeater, message skipped + * |!| TSF | MSG | SIGN FAIL | Signing message failed + * |!| TSF | MSG | GWL FAIL | GW uplink failed + * | | TSF | SANCHK | OK | Sanity check passed + * |!| TSF | SANCHK | FAIL | Sanity check failed, attempt to re-initialize radio + * | | TSF | CRT | OK | Clearing routing table successful + * |!| TSF | ROUTE | FPAR ACTIVE | Finding parent active, message not sent + * |!| TSF | ROUTE | DST %%d UNKNOWN | Routing for destination (DST) unknown, send message to parent + * |!| TSF | SEND | TNR | Transport not ready, message cannot be sent * - * TSM state stID log status / errors - * - TSM:ID Transition to stID state - * - TSM:ID:OK,ID=x Node ID x is valid - * - TSM:ID:REQ Request node ID from controller - * - !TSM:ID:FAIL,ID=x ID verification failed, ID x invalid - * - * TSM state stUplink log status / errors - * - TSM:UPL Transition to stUplink state - * - TSM:UPL:OK Uplink OK, GW returned ping - * - !TSM:UPL:FAIL Uplink check failed, i.e. GW could not be pinged - * - * TSM state stReady log status / errors - * - TSM:READY Transition to stReady, i.e. transport is ready and fully operational - * - !TSM:READY:UPL FAIL,SNP Too many failed uplink transmissions, search new parent - * - !TSM:READY:UPL FAIL,STATP Too many failed uplink transmissions, no SNP, static parent enforced - * - * TSM state stFailure information / status - * - TSM:FAILURE Transition to stFailure state - * - TSM:FAILURE:PDT Power-down transport - * - TSM:FAILURE:RE-INIT Attempt to re-initialize transport - * - * TSF information / status - * - TSF:CHKUPL:OK Uplink OK - * - TSF:CHKUPL:OK,FCTRL Uplink OK, flood control prevents pinging GW in too short intervals - * - TSF:CHKUPL:DGWC,O=x,N=y Checking uplink revealed a changed network topology, old distance x, new distance y - * - TSF:CHKUPL:FAIL No reply received when checking uplink - * - TSF:ASID:OK,ID=x Node ID x assigned - * - TSF:PING:SEND,TO=x Send ping to destination x - * - TSF:MSG:ACK REQ ACK message requested - * - TSF:MSG:ACK ACK message, do not proceed but forward to callback - * - TSF:MSG:FPAR RES,ID=x,D=y Response to find parent received from node x with distance y to GW - * - TSF:MSG:FPAR PREF FOUND Preferred parent found - * - TSF:MSG:FPAR OK,ID=x,D=y Find parent reponse from node x is valid, distance y to GW - * - TSF:MSG:FPAR INACTIVE Find parent response received, but no find parent request active, skip response - * - TSF:MSG:FPAR REQ,ID=x Find parent request from node x - * - TSF:MSG:PINGED,ID=x,HP=y Node pinged by node x with y hops - * - TSF:MSG:PONG RECV,HP=x Pinged node replied with x hops - * - TSF:MSG:BC Broadcast message received - * - TSF:MSG:GWL OK Link to GW ok - * - TSF:MSG:FWD BC MSG Controlled broadcast message forwarding - * - TSF:MSG:REL MSG Relay message - * - TSF:MSG:REL PxNG,HP=x Relay PING/PONG message, increment hop counter x - * - TSF:SANCHK:OK Sanity check passed. This ensures radio functionality and automatically attempts to re-initialize in case of failure - * - TSF:CRT:OK Clearing routing table successful - * - * Incoming / outgoing messages + * Incoming / outgoing messages: * * See here for more detail on the format and definitons. * * Receiving a message - * - TSF:MSG:READ,sender-last-destination,s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d:%s + * - TSF:MSG:READ,sender-last-destination,s=%%d,c=%%d,t=%%d,pt=%%d,l=%%d,sg=%%d:%%s + * * Sending a message - * - [!]TSF:MSG:SEND,sender-last-next-destination,s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d,ft=%d,st=%s:%s + * - [!]TSF:MSG:SEND,sender-last-next-destination,s=%%d,c=%%d,t=%%d,pt=%%d,l=%%d,sg=%%d,ft=%%d,st=%%s:%%s * - * - Message fields: - * - s=sensor ID - * - c=command - * - t=msg type - * - pt=payload type - * - l=length - * - ft=failed uplink transmission counter - * - sg=signing flag - * - * TSF errors - * - !TSF:ASID:FAIL,ID=x Assigned ID x is invalid, e.g. 0 (GATEWAY) - * - !TSF:ROUTE:FPAR ACTIVE Finding parent active, message not sent - * - !TSF:ROUTE:DST x UNKNOWN Routing for destination x unkown, send message to parent - * - !TSF:SEND:TNR Transport not ready, message cannot be sent - * - !TSF:MSG:PVER,x!=y Message protocol version mismatch - * - !TSF:MSG:SIGN VERIFY FAIL Signing verficiation failed - * - !TSF:MSG:REL MSG,NORP Node received a message for relaying, but node is not a repeater, message skipped - * - !TSF:MSG:SIGN FAIL Signing message failed - * - !TSF:MSG:GWL FAIL GW uplink failed - * - !TSF:SANCHK:FAIL Sanity check failed, attempt to re-intialize radio + * Message fields: + * - s=sensor ID + * - c=command + * - t=msg type + * - pt=payload type + * - l=length + * - ft=failed uplink transmission counter + * - sg=signing flag * * @brief API declaration for MyTransport * @@ -145,6 +135,13 @@ #include "MySensorsCore.h" + // debug +#if defined(MY_DEBUG) + #define TRANSPORT_DEBUG(x,...) debug(x, ##__VA_ARGS__) //!< debug +#else + #define TRANSPORT_DEBUG(x,...) //!< debug NULL +#endif + #if defined(MY_REPEATER_FEATURE) #define TRANSMISSION_FAILURES 10 //!< search for a new parent node after this many transmission failures, higher threshold for repeating nodes #else @@ -350,7 +347,7 @@ uint32_t transportGetHeartbeat(); /** * @brief Initialize transport HW -* @return true if initalization successful +* @return true if initialization successful */ bool transportInit(); /** diff --git a/drivers/RF24/RF24.cpp b/drivers/RF24/RF24.cpp index 9af162fdb..511379039 100644 --- a/drivers/RF24/RF24.cpp +++ b/drivers/RF24/RF24.cpp @@ -134,7 +134,7 @@ LOCAL void RF24_setStatus(uint8_t status) { RF24_writeByteRegister(RF24_STATUS, status); } LOCAL void RF24_enableFeatures(void) { - RF24_writeByteRegister(ACTIVATE, 0x73); + RF24_RAW_writeByteRegister(ACTIVATE, 0x73); } LOCAL void RF24_openWritingPipe(uint8_t recipient) { @@ -247,7 +247,7 @@ LOCAL uint8_t RF24_getNodeID(void) { } LOCAL bool RF24_sanityCheck(void) { - // detect HW defect ot interrupted SPI line, CE disconnect cannot be detected + // detect HW defect, configuration errors or interrupted SPI line, CE disconnect cannot be detected bool status = RF24_readByteRegister(RF_SETUP) == MY_RF24_RF_SETUP; status &= RF24_readByteRegister(RF_CH) == MY_RF24_CHANNEL; return status; @@ -273,18 +273,16 @@ LOCAL bool RF24_initialize(void) { RF24_setChannel(MY_RF24_CHANNEL); // set data rate and pa level RF24_setRFSetup(MY_RF24_RF_SETUP); - // sanity check - #if defined(MY_RF24_SANITY_CHECK) - if (!RF24_sanityCheck()) { - RF24_DEBUG(PSTR("RF24:Sanity check failed: configuration mismatch! Check wiring, replace module or non-P version\n")); - return false; - } - #endif - // toggle features (necessary on some clones) + // toggle features (necessary on some clones and non-P versions) RF24_enableFeatures(); // enable ACK payload and dynamic payload RF24_setFeature(MY_RF24_FEATURE); - // enable broadcasting pipe + // sanity check (this function is P/non-P independent) + if (!RF24_sanityCheck()) { + RF24_DEBUG(PSTR("!RF24:Sanity check failed: configuration mismatch! Check wiring or replace module\n")); + return false; + } + // enable broadcasting pipe RF24_setPipe(_BV(ERX_P0 + BROADCAST_PIPE)); // disable AA on all pipes, activate when node pipe set RF24_setAutoACK(0x00); From ce61b286d5627ac0b6c1b8d15465b99c9e993b78 Mon Sep 17 00:00:00 2001 From: tekka007 Date: Fri, 22 Jul 2016 21:48:09 +0200 Subject: [PATCH 017/167] Cleanup debug messages in MySensorsCore --- MySensors.h | 6 +- core/MySensorsCore.cpp | 25 +++---- core/MySensorsCore.h | 143 ++++++++++++++++++++++++++++++++++------- 3 files changed, 134 insertions(+), 40 deletions(-) diff --git a/MySensors.h b/MySensors.h index 189990e24..aa5241c4a 100644 --- a/MySensors.h +++ b/MySensors.h @@ -43,13 +43,13 @@ #if defined(MY_GATEWAY_SERIAL) || defined(MY_GATEWAY_W5100) || defined(MY_GATEWAY_ENC28J60) || defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_MQTT_CLIENT) #define MY_GATEWAY_FEATURE #define MY_IS_GATEWAY (true) - #define MY_NODE_TYPE "gateway" + #define MY_NODE_TYPE "GW" #elif defined(MY_REPEATER_FEATURE) #define MY_IS_GATEWAY (false) - #define MY_NODE_TYPE "repeater" + #define MY_NODE_TYPE "REPEATER" #else #define MY_IS_GATEWAY (false) - #define MY_NODE_TYPE "sensor" + #define MY_NODE_TYPE "NODE" #endif // Enable radio "feature" if one of the radio types was enabled diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index bbe1566ed..0c6b220e1 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -65,16 +65,17 @@ void _infiniteLoop() { } void _begin() { + #if !defined(MY_DISABLED_SERIAL) hwInit(); #endif + debug(PSTR("MCO:BGN:INIT " MY_NODE_TYPE ",CP=" MY_CAPABILITIES ",VER=" MYSENSORS_LIBRARY_VERSION "\n")); + // Call before() in sketch (if it exists) if (before) before(); - debug(PSTR("Starting " MY_NODE_TYPE " (" MY_CAPABILITIES ", " MYSENSORS_LIBRARY_VERSION ")\n")); - #if defined(MY_LEDS_BLINKING_FEATURE) ledsInit(); #endif @@ -82,8 +83,8 @@ void _begin() { signerInit(); // Read latest received controller configuration from EEPROM + // Note: _cc.isMetric is bool, hence empty EEPROM (=0xFF) evaluates to true (default) hwReadConfigBlock((void*)&_cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig)); - // isMetric is bool, hence empty EEPROM (=0xFF) evaluates to true #if defined(MY_OTA_FIRMWARE_FEATURE) // Read firmware config from EEPROM, i.e. type, version, CRC, blocks @@ -119,7 +120,7 @@ void _begin() { // Disable pullup pinMode(MY_NODE_UNLOCK_PIN, INPUT); setIndication(INDICATION_ERR_LOCKED); - debug(PSTR("Node is unlocked.\n")); + debug(PSTR("MCO:BGN:NODE UNLOCKED\n")); } else { // Disable pullup pinMode(MY_NODE_UNLOCK_PIN, INPUT); @@ -139,7 +140,7 @@ void _begin() { // initialize the transport driver if (!gatewayTransportInit()) { setIndication(INDICATION_ERR_INIT_GWTRANSPORT); - debug(PSTR("Transport driver init fail\n")); + debug(PSTR("!MCO:BGN:TSP FAIL\n")); // Nothing more we can do _infiniteLoop(); } @@ -157,13 +158,13 @@ void _begin() { setup(); } - debug(PSTR("Init complete, id=%d, parent=%d, distance=%d, registration=%d\n"), _nc.nodeId, _nc.parentNodeId, _nc.distance, _nodeRegistered); + debug(PSTR("MCO:BGN:INIT OK,ID=%d,PAR=%d,DIS=%d,REG=%d\n"), _nc.nodeId, _nc.parentNodeId, _nc.distance, _nodeRegistered); } void _registerNode() { #if defined (MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE) - debug(PSTR("Request registration...\n")); // registration request + debug(PSTR("MCO:REG:REQ\n")); // registration request setIndication(INDICATION_REQ_REGISTRATION); _nodeRegistered = MY_REGISTRATION_DEFAULT; uint8_t counter = MY_REGISTRATION_RETRIES; @@ -174,7 +175,7 @@ void _registerNode() { #else _nodeRegistered = true; - debug(PSTR("No registration required\n")); + debug(PSTR("MCO:REG:NOT NEEDED\n")); #endif } @@ -260,7 +261,7 @@ bool send(MyMessage &message, bool enableAck) { return _sendRoute(message); } else { - debug(PSTR("NODE:!REG\n")); + debug(PSTR("!MCO:SND:NODE NOT REG\n")); // node not registered return false; } #else @@ -314,7 +315,7 @@ bool _processInternalMessages() { #if defined (MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE) _nodeRegistered = _msg.getBool(); setIndication(INDICATION_GOT_REGISTRATION); - debug(PSTR("Node registration=%d\n"), _nodeRegistered); + debug(PSTR("MCO:PIM:NODE REG=%d\n"), _nodeRegistered); // node registration #endif } else if (type == I_CONFIG) { @@ -354,7 +355,7 @@ bool _processInternalMessages() { for (uint8_t cnt = 0; cnt != 255; cnt++) { uint8_t route = hwReadConfig(EEPROM_ROUTES_ADDRESS + cnt); if (route != BROADCAST_ADDRESS) { - debug(PSTR("ID: %d via %d\n"), cnt, route); + debug(PSTR("MCO:PIM:ROUTE N=%d,R=%d\n"), cnt, route); uint8_t OutBuf[2] = { cnt,route }; _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set(OutBuf, 2)); wait(200); @@ -546,7 +547,7 @@ void nodeLock(const char* str) { hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, 0); while (1) { setIndication(INDICATION_ERR_LOCKED); - debug(PSTR("Node is locked. Ground pin %d and reset to unlock.\n"), MY_NODE_UNLOCK_PIN); + debug(PSTR("MCO:NLK:NODE LOCKED. TO UNLOCK, GND PIN %d AND RESET\n"), MY_NODE_UNLOCK_PIN); #if defined(ARDUINO_ARCH_ESP8266) yield(); #endif diff --git a/core/MySensorsCore.h b/core/MySensorsCore.h index cde376566..1141d6f87 100644 --- a/core/MySensorsCore.h +++ b/core/MySensorsCore.h @@ -17,6 +17,43 @@ * version 2 as published by the Free Software Foundation. */ + /** + * @file MySensorsCore.h + * + * @defgroup MySensorsCoregrp MySensorsCore + * @ingroup internals + * @{ + * + * MySensorsCore-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE + * - [!] Exclamation mark is prepended in case of error + * - SYSTEM: + * - MCO messages emitted by MySensorsCore + * - SUB SYSTEMS: + * - MCO:BGN from @ref _begin() + * - MCO:REG from @ref _registerNode() + * - MCO:SND from @ref send() + * - MCO:PIM from @ref _processInternalMessages() + * - MCO:NLK from @ref nodeLock() + * + * MySensorsCore debug log messages: + * + * |E| SYS | SUB | Message | Comment + * |-|------|-------|-------------------------------------------|---------------------------------------------------------------------------- + * | | MCO | BGN | INIT %%s,CP=%%s,LIB=%%s | Core initialization, capabilities (CP), library version (VER) + * | | MCO | BGN | INIT OK,ID=%%d,PAR=%%d,DIS=%%d,REG=%%d | Core initialized, parent ID (PAR), distance to GW (DIS), registration (REG) + * | | MCO | BGN | NODE UNLOCKED | Node successfully unlocked (see signing chapter) + * |!| MCO | BGN | TSP FAIL | Transport initialization failed + * | | MCO | REG | REQ | Registration request + * | | MCO | REG | NOT NEEDED | No registration needed (i.e. GW) + * |!| MCO | SND | NODE NOT REG | Node is not registered, cannot send message + * | | MCO | PIM | NODE REG=%%d | Registration response received, registration status (REG) + * | | MCO | PIM | ROUTE N=%%d,R=%%d | Routing table, messages to node (N) are routed via node (R) + * | | MCO | NLK | NODE LOCKED. UNLOCK: GND PIN %%d AND RESET| Node locked during booting, see signing chapter for additional information + * + * + * @brief API declaration for MySensorsCore + */ + #ifndef MySensorsCore_h #define MySensorsCore_h @@ -28,17 +65,16 @@ #include #include -#ifdef MY_DEBUG - #define debug(x,...) hwDebugPrint(x, ##__VA_ARGS__) -#else - #define debug(x,...) -#endif - #define GATEWAY_ADDRESS ((uint8_t)0) //!< Node ID for GW sketch #define NODE_SENSOR_ID 0xFF //!< Node child is always created/presented when a node is started #define MY_CORE_VERSION ((uint8_t)2) //!< core version #define MY_CORE_MIN_VERSION ((uint8_t)2) //!< min core version required for compatibility +#ifdef MY_DEBUG + #define debug(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug +#else + #define debug(x,...) //!< debug NULL +#endif /** * @brief Node configuration @@ -46,9 +82,9 @@ * This structure stores node-related configurations */ struct NodeConfig { - uint8_t nodeId; //!< Current node id - uint8_t parentNodeId; //!< Where this node sends its messages - uint8_t distance; //!< This nodes distance to sensor net gateway (number of hops) + uint8_t nodeId; //!< Current node id + uint8_t parentNodeId; //!< Where this node sends its messages + uint8_t distance; //!< This nodes distance to sensor net gateway (number of hops) }; /** @@ -57,10 +93,17 @@ struct NodeConfig { * This structure stores controllerrelated configurations */ struct ControllerConfig { - uint8_t isMetric; //!< Flag indicating if metric or imperial measurements are used + uint8_t isMetric; //!< Flag indicating if metric or imperial measurements are used }; +extern NodeConfig _nc; //!< Node config +extern MyMessage _msg; //!< Buffer for incoming messages +extern MyMessage _msgTmp; //!< Buffer for temporary messages (acks and nonces among others) +#ifdef MY_DEBUG + extern char _convBuf[MAX_PAYLOAD * 2 + 1]; +#endif +// **** public functions ******** /** * Return this nodes id. @@ -138,8 +181,6 @@ void request(uint8_t childSensorId, uint8_t variableType, uint8_t destination=GA */ void requestTime(); - - /** * Returns the most recent node configuration received from controller */ @@ -192,6 +233,11 @@ bool wait(unsigned long ms, uint8_t cmd, uint8_t msgtype); * @return -1 if timer woke it up, -2 if not possible (e.g. ongoing FW update) */ int8_t sleep(unsigned long ms); +/** +* Same as sleep(), send heartbeat upon wakeup and process incoming messages +* @param ms Number of milliseconds to sleep. +* @return -1 if timer woke it up, -2 if not possible (e.g. ongoing FW update) +*/ int8_t smartSleep(unsigned long ms); /** @@ -204,6 +250,13 @@ int8_t smartSleep(unsigned long ms); * @return Interrupt number wake up was triggered by pin change, -1 if timer woke it up, -2 if not possible (e.g. ongoing FW update) */ int8_t sleep(uint8_t interrupt, uint8_t mode, unsigned long ms=0); +/** +* Same as sleep(), send heartbeat upon wakeup and process incoming messages +* @param interrupt Interrupt that should trigger the wakeup +* @param mode RISING, FALLING, CHANGE +* @param ms Number of milliseconds to sleep. +* @return -1 if timer woke it up, -2 if not possible (e.g. ongoing FW update) +*/ int8_t smartSleep(uint8_t interrupt, uint8_t mode, unsigned long ms=0); /** @@ -218,6 +271,15 @@ int8_t smartSleep(uint8_t interrupt, uint8_t mode, unsigned long ms=0); * @return Interrupt number wake up was triggered by pin change, -1 if timer woke it up, -2 if not possible (e.g. ongoing FW update) */ int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms=0); +/** +* Same as sleep(), send heartbeat upon wakeup and process incoming messages +* @param interrupt1 First interrupt that should trigger the wakeup +* @param mode1 Mode for first interrupt (RISING, FALLING, CHANGE) +* @param interrupt2 Second interrupt that should trigger the wakeup +* @param mode2 Mode for second interrupt (RISING, FALLING, CHANGE) +* @param ms Number of milliseconds to sleep or 0 to sleep forever +* @return Interrupt number wake up was triggered by pin change, -1 if timer woke it up, -2 if not possible (e.g. ongoing FW update) +*/ int8_t smartSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms=0); #ifdef MY_NODE_LOCK_FEATURE @@ -235,31 +297,60 @@ int8_t smartSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t void nodeLock(const char* str); #endif -/****** PRIVATE ********/ +// **** private functions ******** +/** +* @brief Node initialisation +*/ void _begin(); - +/** +* @brief Main framework process +*/ void _process(void); - +/** +* @brief Processes internal messages +* @return True if received message requires further processing +*/ bool _processInternalMessages(); - +/** +* @brief Puts node to a infinite loop if unrecoverable situation detected +*/ void _infiniteLoop(); - +/** +* @brief Handles registration request +*/ void _registerNode(); - +/** +* @brief Sends message according to routing table +* @param message +* @return True if message successfully sent to next node +*/ bool _sendRoute(MyMessage &message); -extern NodeConfig _nc; -extern MyMessage _msg; // Buffer for incoming messages. -extern MyMessage _msgTmp; // Buffer for temporary messages (acks and nonces among others). -#ifdef MY_DEBUG - extern char _convBuf[MAX_PAYLOAD*2+1]; -#endif +/** +* @brief Callback for incoming messages +* @param message +*/ void receive(const MyMessage &message) __attribute__((weak)); +/** +* @brief Callback for incoming time messages +*/ void receiveTime(unsigned long) __attribute__((weak)); +/** +* @brief Node presenation +*/ void presentation() __attribute__((weak)); +/** +* @brief Called before node initialises +*/ void before() __attribute__((weak)); +/** +* @brief Called after node initialises but before main loop +*/ void setup() __attribute__((weak)); +/** +* @brief Main loop +*/ void loop() __attribute__((weak)); @@ -278,7 +369,7 @@ static inline MyMessage& build(MyMessage &msg, uint8_t sender, uint8_t destinati static inline MyMessage& buildGw(MyMessage &msg, uint8_t type) { msg.sender = GATEWAY_ADDRESS; msg.destination = GATEWAY_ADDRESS; - msg.sensor = 255; + msg.sensor = NODE_SENSOR_ID; msg.type = type; mSetCommand(msg, C_INTERNAL); mSetRequestAck(msg, false); @@ -288,3 +379,5 @@ static inline MyMessage& buildGw(MyMessage &msg, uint8_t type) { #endif + +/** @}*/ From b8e898c0adb027fbe402c6fcdbf4f14ad3f34af1 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Mon, 1 Aug 2016 22:16:50 +0200 Subject: [PATCH 018/167] Make the library.properties up-to-date (#534) --- library.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library.properties b/library.properties index 9915004d9..9d945cd2c 100644 --- a/library.properties +++ b/library.properties @@ -3,7 +3,7 @@ version=2.0.1-beta author=The MySensors Team maintainer=The MySensors Team sentence=Home Automation Framework -paragraph=Create your own wireless sensor mesh using NRF24L01+ and RFM69 radios running on Arduino or ESP8266. Over-the-air updates and MySensors support in 16+ home automation controllers. +paragraph=Create your own wireless sensor mesh using NRF24L01+ and RFM69 radios running on Arduino, SAMD and ESP8266. Allows over-the-air updates of nodes. Supported by 20+ home automation controllers. category=Communication -url=http://www.mysensors.org +url=https://www.mysensors.org architectures=avr,esp8266,samd From 37119b2a3a76bdfcca0ce1f23db757e976882c22 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Mon, 1 Aug 2016 23:59:31 +0200 Subject: [PATCH 019/167] Present locally attached sensors and node when missing radio (#532) * Present locally attached sensors and node when missing radio Fix #524 * Combining gateway and node presentation. --- core/MyGatewayTransport.cpp | 1 + core/MyGatewayTransport.h | 1 + core/MyGatewayTransportEthernet.cpp | 7 +++---- core/MyGatewayTransportMQTTClient.cpp | 7 +++++-- core/MyGatewayTransportSerial.cpp | 3 +++ core/MySensorsCore.cpp | 6 ++---- drivers/{pubsubclient => PubSubClient}/README.md | 0 7 files changed, 15 insertions(+), 10 deletions(-) rename drivers/{pubsubclient => PubSubClient}/README.md (100%) diff --git a/core/MyGatewayTransport.cpp b/core/MyGatewayTransport.cpp index a7838aa82..beb16d2e7 100644 --- a/core/MyGatewayTransport.cpp +++ b/core/MyGatewayTransport.cpp @@ -22,6 +22,7 @@ extern bool transportSendRoute(MyMessage &message); extern MyMessage _msg; + inline void gatewayTransportProcess() { if (gatewayTransportAvailable()) { _msg = gatewayTransportReceive(); diff --git a/core/MyGatewayTransport.h b/core/MyGatewayTransport.h index d34bd31ac..8df4b59d3 100644 --- a/core/MyGatewayTransport.h +++ b/core/MyGatewayTransport.h @@ -21,6 +21,7 @@ #define MyGatewayTransport_h #include "MyProtocol.h" +#include "MySensorsCore.h" // Common gateway functions diff --git a/core/MyGatewayTransportEthernet.cpp b/core/MyGatewayTransportEthernet.cpp index 3d6b0fc4f..6c930e72b 100644 --- a/core/MyGatewayTransportEthernet.cpp +++ b/core/MyGatewayTransportEthernet.cpp @@ -301,8 +301,8 @@ bool gatewayTransportAvailable() inputString[i].idx = 0; debug(PSTR("Client %d connected\n"), i); gatewayTransportSend(buildGw(_msg, I_GATEWAY_READY).set("Gateway startup complete.")); - if (presentation) - presentation(); + // Send presentation of locally attached sensors (and node if applicable) + presentNode(); } } bool connected = clients[i].connected(); @@ -335,8 +335,7 @@ bool gatewayTransportAvailable() _w5100_spi_en(false); gatewayTransportSend(buildGw(_msg, I_GATEWAY_READY).set("Gateway startup complete.")); _w5100_spi_en(true); - if (presentation) - presentation(); + presentNode(); } } if (client) { diff --git a/core/MyGatewayTransportMQTTClient.cpp b/core/MyGatewayTransportMQTTClient.cpp index ea8138e54..b6ca3779a 100644 --- a/core/MyGatewayTransportMQTTClient.cpp +++ b/core/MyGatewayTransportMQTTClient.cpp @@ -20,6 +20,7 @@ // Topic structure: MY_MQTT_PUBLISH_TOPIC_PREFIX/NODE-ID/SENSOR-ID/CMD-TYPE/ACK-FLAG/SUB-TYPE +#include "MyGatewayTransport.h" #if defined MY_CONTROLLER_IP_ADDRESS IPAddress _brokerIp(MY_CONTROLLER_IP_ADDRESS); @@ -146,8 +147,10 @@ bool reconnectMQTT() { #endif )) { debug(PSTR("MQTT connected\n")); - if (presentation) - presentation(); + + // Send presentation of locally attached sensors (and node if applicable) + presentNode(); + // Once connected, publish an announcement... //_MQTT_client.publish("outTopic","hello world"); // ... and resubscribe diff --git a/core/MyGatewayTransportSerial.cpp b/core/MyGatewayTransportSerial.cpp index e3ea5fb3e..f7c35c840 100644 --- a/core/MyGatewayTransportSerial.cpp +++ b/core/MyGatewayTransportSerial.cpp @@ -39,6 +39,9 @@ bool gatewayTransportSend(MyMessage &message) { bool gatewayTransportInit() { gatewayTransportSend(buildGw(_msg, I_GATEWAY_READY).set("Gateway startup complete.")); + // Send presentation of locally attached sensors (and node if applicable) + presentNode(); + return true; } diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 838ef124d..b31106a71 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -146,7 +146,7 @@ void _begin() { } #endif - #if defined(MY_RADIO_FEATURE) + #if !defined(MY_GATEWAY_FEATURE) presentNode(); #endif @@ -325,9 +325,7 @@ bool _processInternalMessages() { } else if (type == I_PRESENTATION) { // Re-send node presentation to controller - #if defined(MY_RADIO_FEATURE) - presentNode(); - #endif + presentNode(); } else if (type == I_HEARTBEAT) { sendHeartbeat(); diff --git a/drivers/pubsubclient/README.md b/drivers/PubSubClient/README.md similarity index 100% rename from drivers/pubsubclient/README.md rename to drivers/PubSubClient/README.md From 4695cc71ddf6142fa114ef8d47c0a84d8bffd47c Mon Sep 17 00:00:00 2001 From: Olivier Date: Tue, 2 Aug 2016 21:50:00 +0200 Subject: [PATCH 020/167] Fix Doxygen warning (#539) --- MyConfig.h | 1 + 1 file changed, 1 insertion(+) diff --git a/MyConfig.h b/MyConfig.h index b362561e6..3432dbec6 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -694,4 +694,5 @@ #define MY_REGISTRATION_CONTROLLER #define MY_DEBUG_VERBOSE_RF24 #define MY_TRANSPORT_SANITY_CHECK +#define MY_NODE_LOCK_FEATURE #endif From 99973a346eafe2fb74c46be4bdba7412d3446344 Mon Sep 17 00:00:00 2001 From: Embedded Innovation Date: Tue, 2 Aug 2016 22:20:25 +0200 Subject: [PATCH 021/167] Add nRF24 receive message buffering (#538) * Add critical section support Allows defining a code block which is executed as a critical section. Supports AVR, ESP8266 & SAMD. * Add receive message buffering When MY_RF24_IRQ_PIN is defined (and connected), a buffer will be used to retrieve & store messages received by nRF24 as fast as possible. This reduces the chance of losing messages due to a busy microcontroller. nRF24 SPI rx message transfer is running from interrupt context when MY_RF24_IRQ_PIN is defined. If this transfer takes too long, serial characters received will get lost. Therefore serial rx is enabled during SPI transfer of nRF messages. Limitations: Only AVR/SAMD & nRF24L01+ combinations can buffer rx messages. nRF24L01+ IRQ pin should be connected to AVR. Tested on W5100- & Serial-gateway. SAMD has not been tested yet! * Fix Doxygen warnings * Fix more Doxygen warnings --- MyConfig.h | 18 +++ MySensors.h | 17 ++ core/MyCapabilities.h | 8 +- core/MyHw.h | 64 +++++++- core/MyHwATMega328.h | 6 +- core/MyHwESP8266.h | 12 ++ core/MyHwSAMD.h | 24 +++ core/MyTransportNRF24.cpp | 61 +++++++- drivers/CircularBuffer/CircularBuffer.h | 196 ++++++++++++++++++++++++ drivers/RF24/RF24.cpp | 63 ++++++++ drivers/RF24/RF24.h | 18 ++- keywords.txt | 5 +- 12 files changed, 483 insertions(+), 9 deletions(-) create mode 100644 drivers/CircularBuffer/CircularBuffer.h diff --git a/MyConfig.h b/MyConfig.h index 3432dbec6..5d04238da 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -429,6 +429,22 @@ #endif #endif +/** + * @def MY_RF24_IRQ_PIN + * @brief Disable RF24 interrupt pin usage by default. Override in sketch if needed. + */ +//#define MY_RF24_IRQ_PIN + +/** + * @def MY_RX_MESSAGE_BUFFER_SIZE + * @brief Declare the amount of incoming messages that can be buffered. Requires MY_RADIO_NRF24 and MY_RF24_IRQ_PIN. Override in sketch if needed. + */ +#ifdef MY_RF24_IRQ_PIN + #ifndef MY_RX_MESSAGE_BUFFER_SIZE + #define MY_RX_MESSAGE_BUFFER_SIZE (20) + #endif +#endif + /** * @def MY_RF24_PA_LEVEL * @brief Default RF24 PA level. Override in sketch if needed. @@ -694,5 +710,7 @@ #define MY_REGISTRATION_CONTROLLER #define MY_DEBUG_VERBOSE_RF24 #define MY_TRANSPORT_SANITY_CHECK +#define MY_RF24_IRQ_PIN +#define MY_RX_MESSAGE_BUFFER_SIZE #define MY_NODE_LOCK_FEATURE #endif diff --git a/MySensors.h b/MySensors.h index aa5241c4a..8b589a8ea 100644 --- a/MySensors.h +++ b/MySensors.h @@ -255,6 +255,23 @@ #error Only one forward link driver can be activated #endif #if defined(MY_RADIO_NRF24) + #ifdef MY_RF24_IRQ_PIN + // SoftSPI does not support usingInterrupt() + #ifdef MY_SOFTSPI + #error RF24 IRQ usage cannot be used with Soft SPI + #endif + // ESP8266 does not support usingInterrupt() + #ifdef ESP8266 + #error RF24 IRQ usage cannot be used with ESP8266 + #endif + #ifndef SPI_HAS_TRANSACTION + #error RF24 IRQ usage requires transactional SPI support + #endif + #else + #ifdef MY_RX_MESSAGE_BUFFER_SIZE + #error Receive message buffering requires RF24 IRQ usage + #endif + #endif #if defined(MY_RF24_ENABLE_ENCRYPTION) #include "drivers/AES/AES.cpp" #endif diff --git a/core/MyCapabilities.h b/core/MyCapabilities.h index 2ec468d79..735ec3282 100644 --- a/core/MyCapabilities.h +++ b/core/MyCapabilities.h @@ -70,7 +70,13 @@ #define MY_CAP_SIGN "-" #endif +#if defined(MY_RX_MESSAGE_BUFFER_SIZE) + #define MY_CAP_RXBUF "Q" +#else + #define MY_CAP_RXBUF "-" +#endif + -#define MY_CAPABILITIES MY_CAP_RESET MY_CAP_RADIO MY_CAP_OTA_FW MY_CAP_TYPE MY_CAP_ARCH MY_CAP_SIGN +#define MY_CAPABILITIES MY_CAP_RESET MY_CAP_RADIO MY_CAP_OTA_FW MY_CAP_TYPE MY_CAP_ARCH MY_CAP_SIGN MY_CAP_RXBUF #endif /* MyGatewayTransportEthernet_h */ diff --git a/core/MyHw.h b/core/MyHw.h index 1224f6629..f2b29c366 100644 --- a/core/MyHw.h +++ b/core/MyHw.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 @@ -17,6 +17,12 @@ * version 2 as published by the Free Software Foundation. */ + /** + * @file MyHw.h + * + * MySensors hardware abstraction layer + */ + #ifndef MyHw_h #define MyHw_h @@ -42,11 +48,67 @@ void hwWriteConfig(int adr, uint8_t value); uint8_t hwReadConfig(int adr); */ +/** + * Sleep for a defined time, using minimum power. + * @param ms Time to sleep, in [ms]. + * @return Nonsense, please ignore. + */ int8_t hwSleep(unsigned long ms); + +/** + * Sleep for a defined time, using minimum power, or until woken by interrupt. + * @param interrupt Interrupt number, which can wake the mcu from sleep. + * @param mode Interrupt mode, as passed to attachInterrupt. + * @param ms Time to sleep, in [ms]. + * @return -1 when woken by timer, or interrupt number when woken by interrupt. + */ int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms); + +/** + * Sleep for a defined time, using minimum power, or until woken by one of the interrupts. + * @param interrupt1 Interrupt1 number, which can wake the mcu from sleep. + * @param mode1 Interrupt1 mode, as passed to attachInterrupt. + * @param interrupt2 Interrupt2 number, which can wake the mcu from sleep. + * @param mode2 Interrupt2 mode, as passed to attachInterrupt. + * @param ms Time to sleep, in [ms]. + * @return -1 when woken by timer, or interrupt number when woken by interrupt. + */ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms); + #ifdef MY_DEBUG void hwDebugPrint(const char *fmt, ... ); #endif +/** + * @def MY_CRITICAL_SECTION + * @brief Creates a block of code that is guaranteed to be executed atomically. + * Upon entering the block all interrupts are disabled, and re-enabled upon + * exiting the block from any exit path. + * A typical example that requires atomic access is a 16 (or more) bit variable + * that is shared between the main execution path and an ISR, on an 8-bit + * platform (e.g AVR): + * @code + * volatile uint16_t val = 0; + * + * void interrupHandler() + * { + * val = ~val; + * } + * + * void loop() + * { + * uint16_t copy_val; + * MY_CRITICAL_SECTION + * { + * copy_val = val; + * } + * } + * @endcode + * All code within the MY_CRITICAL_SECTION block will be protected from being + * interrupted during execution. + */ +#ifdef DOXYGEN + #define MY_CRITICAL_SECTION +#endif /* DOXYGEN */ + #endif // #ifdef MyHw_h diff --git a/core/MyHwATMega328.h b/core/MyHwATMega328.h index 8eb0060b1..157ecb1fd 100644 --- a/core/MyHwATMega328.h +++ b/core/MyHwATMega328.h @@ -27,7 +27,7 @@ #include #include #include - +#include #ifdef __cplusplus @@ -92,4 +92,8 @@ enum period_t void hwInternalSleep(unsigned long ms); +#ifndef DOXYGEN + #define MY_CRITICAL_SECTION ATOMIC_BLOCK(ATOMIC_RESTORESTATE) +#endif /* DOXYGEN */ + #endif diff --git a/core/MyHwESP8266.h b/core/MyHwESP8266.h index a9693ff5b..1495e6902 100644 --- a/core/MyHwESP8266.h +++ b/core/MyHwESP8266.h @@ -43,5 +43,17 @@ void hwWriteConfigBlock(void* buf, void* adr, size_t length); void hwWriteConfig(int adr, uint8_t value); uint8_t hwReadConfig(int adr); +/** + * Restore interrupt state. + * Helper function for MY_CRITICAL_SECTION. + */ +static __inline__ void __psRestore(const uint32_t *__s) +{ + xt_wsr_ps( *__s ); +} + +#ifndef DOXYGEN + #define MY_CRITICAL_SECTION for ( uint32_t __psSaved __attribute__((__cleanup__(__psRestore))) = xt_rsil(15), __ToDo = 1; __ToDo ; __ToDo = 0 ) +#endif /* DOXYGEN */ #endif // #ifdef ARDUINO_ARCH_ESP8266 diff --git a/core/MyHwSAMD.h b/core/MyHwSAMD.h index fcc5a9d79..dcb783c20 100644 --- a/core/MyHwSAMD.h +++ b/core/MyHwSAMD.h @@ -58,4 +58,28 @@ uint8_t hwReadConfig(int adr); #define hwWriteConfig(__adr, __value) ( __value = __value) #define hwReadConfig(__adr) (0) */ + +/** + * Disable all interrupts. + * Helper function for MY_CRITICAL_SECTION. + */ +static __inline__ uint8_t __disableIntsRetVal(void) +{ + __disable_irq(); + return 1; +} + +/** + * Restore priority mask register. + * Helper function for MY_CRITICAL_SECTION. + */ +static __inline__ void __priMaskRestore(const uint32_t *priMask) +{ + __set_PRIMASK(*priMask); +} + +#ifndef DOXYGEN + #define MY_CRITICAL_SECTION for ( uint32_t __savePriMask __attribute__((__cleanup__(__priMaskRestore))) = __get_PRIMASK(), __ToDo = __disableIntsRetVal(); __ToDo ; __ToDo = 0 ) +#endif /* DOXYGEN */ + #endif // #ifdef ARDUINO_ARCH_SAMD diff --git a/core/MyTransportNRF24.cpp b/core/MyTransportNRF24.cpp index e38ecf4ca..6d7f40737 100644 --- a/core/MyTransportNRF24.cpp +++ b/core/MyTransportNRF24.cpp @@ -20,11 +20,47 @@ #include "MyConfig.h" #include "MyTransport.h" #include "drivers/RF24/RF24.h" +#include "drivers/CircularBuffer/CircularBuffer.h" #if defined(MY_RF24_ENABLE_ENCRYPTION) #include "drivers/AES/AES.h" #endif +#ifdef MY_RF24_IRQ_PIN +typedef struct _transportQueuedMessage +{ + uint8_t m_len; // Length of the data + uint8_t m_data[MAX_MESSAGE_LENGTH]; // The raw data +} transportQueuedMessage; + +/** Buffer to store queued messages in. */ +static transportQueuedMessage transportRxQueueStorage[MY_RX_MESSAGE_BUFFER_SIZE]; +/** Circular buffer, which uses the transportRxQueueStorage and administers stored messages. */ +static CircularBuffer transportRxQueue(transportRxQueueStorage, MY_RX_MESSAGE_BUFFER_SIZE); + +static volatile uint8_t transportLostMessageCount = 0; + +static void transportRxCallback(void) +{ + // Called for each message received by radio, from interrupt context. + // This function _must_ call RF24_readMessage() to de-assert interrupt line! + if (!transportRxQueue.full()) + { + transportQueuedMessage* msg = transportRxQueue.getFront(); + msg->m_len = RF24_readMessage(msg->m_data); // Read payload & clear RX_DR + (void)transportRxQueue.pushFront(msg); + } else { + // Queue is full. Discard message. + (void)RF24_readMessage(NULL); // Read payload & clear RX_DR + // Keep track of messages lost. Max 255, prevent wrapping. + if (transportLostMessageCount < 255) + { + ++transportLostMessageCount; + } + } +} +#endif + #if defined(MY_RF24_ENABLE_ENCRYPTION) AES _aes; uint8_t _dataenc[32] = {0}; @@ -32,7 +68,6 @@ #endif bool transportInit() { - #if defined(MY_RF24_ENABLE_ENCRYPTION) hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); //set up AES-key @@ -41,6 +76,9 @@ bool transportInit() { memset(_psk, 0, 16); #endif + #ifdef MY_RF24_IRQ_PIN + RF24_registerReceiveCallback( transportRxCallback ); + #endif return RF24_initialize(); } @@ -71,8 +109,12 @@ bool transportSend(uint8_t recipient, const void* data, uint8_t len) { } bool transportAvailable() { - bool avail = RF24_isDataAvailable(); - return avail; + #ifdef MY_RF24_IRQ_PIN + (void)RF24_isDataAvailable; // Prevent 'defined but not used' warning + return !transportRxQueue.empty(); + #else + return RF24_isDataAvailable(); + #endif } bool transportSanityCheck() { @@ -80,7 +122,18 @@ bool transportSanityCheck() { } uint8_t transportReceive(void* data) { - uint8_t len = RF24_readMessage(data); + uint8_t len = 0; + #ifdef MY_RF24_IRQ_PIN + transportQueuedMessage* msg = transportRxQueue.getBack(); + if (msg) + { + len = msg->m_len; + (void)memcpy(data, msg->m_data, len); + (void)transportRxQueue.popBack(); + } + #else + len = RF24_readMessage(data); + #endif #if defined(MY_RF24_ENABLE_ENCRYPTION) // has to be adjusted, WIP! _aes.set_IV(0); diff --git a/drivers/CircularBuffer/CircularBuffer.h b/drivers/CircularBuffer/CircularBuffer.h new file mode 100644 index 000000000..c3362d9e0 --- /dev/null +++ b/drivers/CircularBuffer/CircularBuffer.h @@ -0,0 +1,196 @@ +/* + CircularBuffer - An Arduino circular buffering library for arbitrary types. + + Created by Ivo Pullens, Emmission, 2014-2016 -- www.emmission.nl + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + + /** + * @file CircularBuffer.h + * + * Circular buffering for arbitrary types. + */ + +#ifndef CircularBuffer_h +#define CircularBuffer_h + +/** + * The circular buffer class. + * Pass the datatype to be stored in the buffer as template parameter. + */ +template class CircularBuffer +{ + public: + /** + * Constructor + * @param buffer Preallocated buffer of at least size records. + * @param size Number of records available in the buffer. + */ + CircularBuffer(T* buffer, const uint8_t size ) + : m_size(size), m_buff(buffer) + { + clear(); + } + + /** + * Clear all entries in the circular buffer. + */ + void clear(void) + { + MY_CRITICAL_SECTION + { + m_front = 0; + m_fill = 0; + } + } + + /** + * Test if the circular buffer is empty. + * @return True, when empty. + */ + inline bool empty(void) const + { + bool empty; + MY_CRITICAL_SECTION + { + empty = !m_fill; + } + return empty; + } + + /** + * Test if the circular buffer is full. + * @return True, when full. + */ + inline bool full(void) const + { + bool full; + MY_CRITICAL_SECTION + { + full = m_fill == m_size; + } + return full; + } + + /** + * Return the number of records stored in the buffer. + * @return number of records. + */ + inline uint8_t available(void) const + { + MY_CRITICAL_SECTION + { + return m_fill; + } + } + + /** + * Aquire unused record on front of the buffer, for writing. + * After filling the record, it has to be pushed to actually + * add it to the buffer. + * @return Pointer to record, or NULL when buffer is full. + */ + T* getFront(void) const + { + MY_CRITICAL_SECTION + { + if (!full()) return get(m_front); + } + return static_cast(NULL); + } + + /** + * Push record to front of the buffer. + * @param record Record to push. If record was aquired previously (using getFront) its + * data will not be copied as it is already present in the buffer. + * @return True, when record was pushed successfully. + */ + bool pushFront(T* record) + { + MY_CRITICAL_SECTION + { + if (!full()) + { + T* f = get(m_front); + if (f != record) + *f = *record; + m_front = (m_front+1) % m_size; + m_fill++; + return true; + } + } + return false; + } + + /** + * Aquire record on back of the buffer, for reading. + * After reading the record, it has to be pop'ed to actually + * remove it from the buffer. + * @return Pointer to record, or NULL when buffer is empty. + */ + T* getBack(void) const + { + MY_CRITICAL_SECTION + { + if (!empty()) return get(back()); + } + return static_cast(NULL); + } + + /** + * Remove record from back of the buffer. + * @return True, when record was pop'ed successfully. + */ + bool popBack(void) + { + MY_CRITICAL_SECTION + { + if (!empty()) + { + m_fill--; + return true; + } + } + return false; + } + + protected: + /** + * Internal getter for records. + * @param idx Record index in buffer. + * @return Ptr to record. + */ + inline T * get(const uint8_t idx) const + { + return &(m_buff[idx]); + } + + /** + * Internal getter for index of last used record in buffer. + * @return Index of last record. + */ + inline uint8_t back(void) const + { + return (m_front - m_fill + m_size) % m_size; + } + + const uint8_t m_size; //!< Total number of records that can be stored in the buffer. + T* const m_buff; //!< Ptr to buffer holding all records. + volatile uint8_t m_front; //!< Index of front element (not pushed yet). + volatile uint8_t m_fill; //!< Amount of records currently pushed. +}; + +#endif // CircularBuffer_h diff --git a/drivers/RF24/RF24.cpp b/drivers/RF24/RF24.cpp index 511379039..d263c1fe3 100644 --- a/drivers/RF24/RF24.cpp +++ b/drivers/RF24/RF24.cpp @@ -25,6 +25,10 @@ LOCAL uint8_t MY_RF24_BASE_ADDR[MY_RF24_ADDR_WIDTH] = { MY_RF24_BASE_RADIO_ID }; LOCAL uint8_t MY_RF24_NODE_ADDRESS = AUTO; +#ifdef MY_RF24_IRQ_PIN + LOCAL RF24_receiveCallbackType RF24_receiveCallback = NULL; +#endif + LOCAL void RF24_csn(bool level) { digitalWrite(MY_RF24_CS_PIN, level); } @@ -86,6 +90,10 @@ LOCAL uint8_t RF24_getStatus(void) { return RF24_spiByteTransfer( NOP ); } +LOCAL uint8_t RF24_getFifoStatus(void) { + return RF24_readByteRegister(FIFO_STATUS); +} + LOCAL void RF24_setChannel(uint8_t channel) { RF24_writeByteRegister(RF_CH, channel); } @@ -253,14 +261,69 @@ LOCAL bool RF24_sanityCheck(void) { return status; } +#ifdef MY_RF24_IRQ_PIN +LOCAL void RF24_irqHandler( void ) +{ + if (RF24_receiveCallback) + { + // Will stay for a while (several 100us) in this interrupt handler. Any interrupts from serial + // rx coming in during our stay will not be handled and will cause characters to be lost. + // As a workaround we re-enable interrupts to allow nested processing of other interrupts. + // Our own handler is disconnected to prevent recursive calling of this handler. + #ifdef MY_GATEWAY_SERIAL + detachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN)); + interrupts(); + #endif + // Read FIFO until empty. + // Procedure acc. to datasheet (pg. 63): + // 1.Read payload, 2.Clear RX_DR IRQ, 3.Read FIFO_status, 4.Repeat when more data available. + // Datasheet (ch. 8.5) states, that the nRF de-asserts IRQ after reading STATUS. + + // Start checking if RX-FIFO is not empty, as we might end up here from an interrupt + // for a message we've already read. + while (!(RF24_getFifoStatus() & _BV(0))) { + RF24_receiveCallback(); // Must call RF24_readMessage(), which will clear RX_DR IRQ ! + } + // Restore our interrupt handler. + #ifdef MY_GATEWAY_SERIAL + noInterrupts(); + attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING); + #endif + } else { + // clear RX interrupt + RF24_setStatus(_BV(RX_DR)); + } +} + +LOCAL void RF24_registerReceiveCallback( RF24_receiveCallbackType cb ) +{ + MY_CRITICAL_SECTION { + RF24_receiveCallback = cb; + } +} +#endif + LOCAL bool RF24_initialize(void) { // Initialize pins pinMode(MY_RF24_CE_PIN,OUTPUT); pinMode(MY_RF24_CS_PIN,OUTPUT); + #ifdef MY_RF24_IRQ_PIN + pinMode(MY_RF24_IRQ_PIN,INPUT); + #endif // Initialize SPI _SPI.begin(); RF24_ce(LOW); RF24_csn(HIGH); + #ifdef MY_RF24_IRQ_PIN + // assure SPI can be used from interrupt context + // Note: ESP8266 & SoftSPI currently do not support interrupt usage for SPI, + // therefore it is unsafe to use MY_RF24_IRQ_PIN with ESP8266/SoftSPI! + _SPI.usingInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN)); + // attach interrupt + attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING); + #else + (void)RF24_getFifoStatus; // prevent 'defined but not used' warning + #endif // CRC and power up RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(PWR_UP) ) ; // settle >2ms diff --git a/drivers/RF24/RF24.h b/drivers/RF24/RF24.h index e0f81ba39..765a434a2 100644 --- a/drivers/RF24/RF24.h +++ b/drivers/RF24/RF24.h @@ -62,7 +62,11 @@ #endif // RF24 settings -#define MY_RF24_CONFIGURATION (uint8_t) (RF24_CRC_16 << 2) +#ifdef MY_RF24_IRQ_PIN + #define MY_RF24_CONFIGURATION (uint8_t) ((RF24_CRC_16 << 2) | (1 << MASK_TX_DS) | (1 << MASK_MAX_RT)) +#else + #define MY_RF24_CONFIGURATION (uint8_t) (RF24_CRC_16 << 2) +#endif #define MY_RF24_FEATURE (uint8_t)( _BV(EN_DPL) | _BV(EN_ACK_PAY) ) #define MY_RF24_RF_SETUP (uint8_t)( ((MY_RF24_DATARATE & 0b10 ) << 4) | ((MY_RF24_DATARATE & 0b01 ) << 3) | (MY_RF24_PA_LEVEL << 1) ) + 1 // +1 for Si24R1 @@ -222,6 +226,7 @@ LOCAL uint8_t RF24_RAW_writeByteRegister(uint8_t cmd, uint8_t value); LOCAL void RF24_flushRX(void); LOCAL void RF24_flushTX(void); LOCAL uint8_t RF24_getStatus(void); +LOCAL uint8_t RF24_getFifoStatus(void); LOCAL void RF24_openWritingPipe(uint8_t recipient); LOCAL void RF24_startListening(void); LOCAL void RF24_stopListening(void); @@ -248,4 +253,15 @@ LOCAL void RF24_setPipeLSB(uint8_t pipe, uint8_t LSB); LOCAL void RF24_setStatus(uint8_t status); LOCAL void RF24_enableFeatures(void); +#ifdef MY_RF24_IRQ_PIN + typedef void (*RF24_receiveCallbackType)(void); + /** + * Register a callback, which will be called (from interrupt context) for every message received. + * @note When a callback is registered, it _must_ retrieve the message from the nRF24 + * by calling RF24_readMessage(). Otherwise the interrupt will not get deasserted + * and message reception will stop. + */ + LOCAL void RF24_registerReceiveCallback( RF24_receiveCallbackType cb ); +#endif + #endif // __RF24_H__ \ No newline at end of file diff --git a/keywords.txt b/keywords.txt index da92188c5..808abf69c 100644 --- a/keywords.txt +++ b/keywords.txt @@ -74,6 +74,7 @@ MY_RF24_ENABLE_ENCRYPTION LITERAL1 MY_RF24_SPI_MAX_SPEED LITERAL1 MY_RF24_CE_PIN LITERAL1 MY_RF24_CS_PIN LITERAL1 +MY_RF24_IRQ_PIN LITERAL1 MY_RF24_PA_LEVEL LITERAL1 MY_RF24_CHANNEL LITERAL1 MY_RF24_DATARATE LITERAL1 @@ -126,4 +127,6 @@ MY_SMART_SLEEP_WAIT_DURATION LITERAL1 MY_NODE_LOCK_FEATURE LITERAL1 MY_NODE_UNLOCK_PIN LITERAL1 MY_NODE_LOCK_COUNTER_MAX LITERAL1 -MY_SPIFLASH_SST25TYPE LITERAL1 \ No newline at end of file +MY_SPIFLASH_SST25TYPE LITERAL1 +MY_CRITICAL_SECTION LITERAL1 +MY_RX_MESSAGE_BUFFER_SIZE LITERAL1 \ No newline at end of file From b293f47a7f06501b65d0cda86b650adcc1bb2137 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Tue, 2 Aug 2016 22:21:14 +0200 Subject: [PATCH 022/167] Fix smartsleep (#535) * Make smartSleep send heartbeat before sleeping Sending the heartbeat (and waiting) after waking up would delay processing inputs. For example, a switch could be back to the open state before the wait is over. * Fix typos in comments in smartSleep methods --- core/MySensorsCore.cpp | 54 +++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index b31106a71..aba87b1e2 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -65,7 +65,7 @@ void _infiniteLoop() { } void _begin() { - + #if !defined(MY_DISABLED_SERIAL) hwInit(); #endif @@ -73,7 +73,7 @@ void _begin() { debug(PSTR("MCO:BGN:INIT " MY_NODE_TYPE ",CP=" MY_CAPABILITIES ",VER=" MYSENSORS_LIBRARY_VERSION "\n")); // Call before() in sketch (if it exists) - if (before) + if (before) before(); #if defined(MY_LEDS_BLINKING_FEATURE) @@ -85,7 +85,7 @@ void _begin() { // Read latest received controller configuration from EEPROM // Note: _cc.isMetric is bool, hence empty EEPROM (=0xFF) evaluates to true (default) hwReadConfigBlock((void*)&_cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig)); - + #if defined(MY_OTA_FIRMWARE_FEATURE) // Read firmware config from EEPROM, i.e. type, version, CRC, blocks readFirmwareSettings(); @@ -104,7 +104,7 @@ void _begin() { } #endif - + #ifdef MY_NODE_LOCK_FEATURE // Check if node has been locked down @@ -131,7 +131,7 @@ void _begin() { hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, MY_NODE_LOCK_COUNTER_MAX); } #endif - + #if defined(MY_GATEWAY_FEATURE) #if defined(MY_INCLUSION_BUTTON_FEATURE) inclusionInit(); @@ -144,12 +144,12 @@ void _begin() { // Nothing more we can do _infiniteLoop(); } - #endif - + #endif + #if !defined(MY_GATEWAY_FEATURE) presentNode(); #endif - + // register node _registerNode(); @@ -173,7 +173,7 @@ void _registerNode() { _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REGISTRATION_REQUEST, false).set(MY_CORE_VERSION)); } while (!wait(2000, C_INTERNAL, I_REGISTRATION_RESPONSE) && counter--); - #else + #else _nodeRegistered = true; debug(PSTR("MCO:REG:NOT NEEDED\n")); #endif @@ -190,11 +190,11 @@ void presentNode() { present(NODE_SENSOR_ID, S_ARDUINO_NODE); #endif #else - + #if defined(MY_OTA_FIRMWARE_FEATURE) presentBootloaderInformation(); #endif - + // Send signing preferences for this node to the GW signerPresentation(_msgTmp, GATEWAY_ADDRESS); @@ -204,16 +204,16 @@ void presentNode() { #else present(NODE_SENSOR_ID, S_ARDUINO_NODE); #endif - + // Send a configuration exchange request to controller // Node sends parent node. Controller answers with latest node configuration _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CONFIG, false).set(_nc.parentNodeId)); // Wait configuration reply. wait(2000, C_INTERNAL, I_CONFIG); - + #endif - + if (presentation) presentation(); @@ -257,7 +257,7 @@ bool send(MyMessage &message, bool enableAck) { mSetRequestAck(message, enableAck); #if defined(MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE) - if (_nodeRegistered) { + if (_nodeRegistered) { return _sendRoute(message); } else { @@ -379,17 +379,17 @@ bool _processInternalMessages() { #endif } else return false; - } + } else { // sender is a node if (type == I_REGISTRATION_REQUEST) { #if defined(MY_GATEWAY_FEATURE) // register request are exclusively handled by GW/Controller // !!! eventually define if AUTO ACK or register request forwarded to controller - #if !defined(MY_REGISTRATION_CONTROLLER) + #if !defined(MY_REGISTRATION_CONTROLLER) // auto register if version compatible bool approveRegistration = true; - + #if defined(MY_CORE_COMPATIBILITY_CHECK) approveRegistration = (_msg.getByte() >= MY_CORE_MIN_VERSION); #endif @@ -397,7 +397,7 @@ bool _processInternalMessages() { #else return false; // processing of this request via controller #endif - #endif + #endif } else return false; } @@ -463,12 +463,11 @@ int8_t sleep(unsigned long ms) { } int8_t smartSleep(unsigned long ms) { - int8_t ret = sleep(ms); - // notifiy controller about wake up + // notify controller about going to sleep sendHeartbeat(); // listen for incoming messages wait(MY_SMART_SLEEP_WAIT_DURATION); - return ret; + return sleep(ms); } int8_t sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { @@ -496,12 +495,11 @@ int8_t sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { } int8_t smartSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { - int8_t ret = sleep(interrupt, mode, ms); - // notifiy controller about wake up + // notify controller about going to sleep sendHeartbeat(); // listen for incoming messages wait(MY_SMART_SLEEP_WAIT_DURATION); - return ret; + return sleep(interrupt, mode, ms); } int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { @@ -531,12 +529,11 @@ int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode } int8_t smartSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { - int8_t ret = sleep(interrupt1, mode1, interrupt2, mode2, ms); - // notifiy controller about wake up + // notify controller about going to sleep sendHeartbeat(); // listen for incoming messages wait(MY_SMART_SLEEP_WAIT_DURATION); - return ret; + return sleep(interrupt1, mode1, interrupt2, mode2, ms); } #ifdef MY_NODE_LOCK_FEATURE @@ -559,4 +556,3 @@ void nodeLock(const char* str) { } } #endif - From 3ba13f1c8cbb5a92071146f7e86faf0a6463484e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Mon, 1 Aug 2016 22:57:57 +0200 Subject: [PATCH 023/167] Added production SensebenderGW sketch preHwInit also added to hook into core startup before hwInit is called --- core/MySensorsCore.cpp | 5 +- core/MySensorsCore.h | 8 +- .../SensebenderGatewaySerial.ino | 253 ++++++++++++++++++ 3 files changed, 263 insertions(+), 3 deletions(-) create mode 100644 examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index aba87b1e2..0be57819e 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -66,8 +66,11 @@ void _infiniteLoop() { void _begin() { + if (preHwInit) + preHwInit(); + #if !defined(MY_DISABLED_SERIAL) - hwInit(); + hwInit(); #endif debug(PSTR("MCO:BGN:INIT " MY_NODE_TYPE ",CP=" MY_CAPABILITIES ",VER=" MYSENSORS_LIBRARY_VERSION "\n")); diff --git a/core/MySensorsCore.h b/core/MySensorsCore.h index 1141d6f87..5d52a8b80 100644 --- a/core/MySensorsCore.h +++ b/core/MySensorsCore.h @@ -65,9 +65,9 @@ #include #include -#define GATEWAY_ADDRESS ((uint8_t)0) //!< Node ID for GW sketch +#define GATEWAY_ADDRESS ((uint8_t)0) //!< Node ID for GW sketch #define NODE_SENSOR_ID 0xFF //!< Node child is always created/presented when a node is started -#define MY_CORE_VERSION ((uint8_t)2) //!< core version +#define MY_CORE_VERSION ((uint8_t)2) //!< core version #define MY_CORE_MIN_VERSION ((uint8_t)2) //!< min core version required for compatibility #ifdef MY_DEBUG @@ -345,6 +345,10 @@ void presentation() __attribute__((weak)); */ void before() __attribute__((weak)); /** +* @brief Called before any hwInitialization is done +*/ +void preHwInit() __attribute__((weak)); +/** * @brief Called after node initialises but before main loop */ void setup() __attribute__((weak)); diff --git a/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino b/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino new file mode 100644 index 000000000..11fb45ca8 --- /dev/null +++ b/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino @@ -0,0 +1,253 @@ + /** + * 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. + * + ******************************* + * + * DESCRIPTION + * The ArduinoGateway prints data received from sensors on the serial link. + * The gateway accepts input on seral which will be sent out on radio network. + * + * This GW code is designed for Sensebender GateWay / Arduino Zero + * + * Wire connections (OPTIONAL): + * - Inclusion button should be connected between digital pin 3 and GND + * - RX/TX/ERR leds need to be connected between +5V (anode) and digital pin 6/5/4 with resistor 270-330R in a series + * + * LEDs (OPTIONAL): + * - To use the feature, uncomment MY_LEDS_BLINKING_FEATURE in MyConfig.h + * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved + * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly + * - ERR (red) - fast blink on error during transmission error or recieve crc error + * + */ + +#define SKETCH_VERSION "0.1" +// Enable debug prints to serial monitor +#define MY_DEBUG + +// Enable and select radio type attached +#define MY_RADIO_NRF24 +//#define MY_RADIO_RFM69 + +// Set LOW transmit power level as default, if you have an amplified NRF-module and +// power your radio separately with a good regulator you can turn up PA level. +#define MY_RF24_PA_LEVEL RF24_PA_HIGH + +// Enable serial gateway +#define MY_GATEWAY_SERIAL + +// Define a lower baud rate for Arduino's running on 8 MHz (Arduino Pro Mini 3.3V & SenseBender) +#if F_CPU == 8000000L +#define MY_BAUD_RATE 38400 +#endif + +// Flash leds on rx/tx/err +#define MY_LEDS_BLINKING_FEATURE +// Set blinking period +#define MY_DEFAULT_LED_BLINK_PERIOD 300 + +// Inverses the behavior of leds +//#define MY_WITH_LEDS_BLINKING_INVERSE + +// Enable inclusion mode +#define MY_INCLUSION_MODE_FEATURE +// Enable Inclusion mode button on gateway +#define MY_INCLUSION_BUTTON_FEATURE + +// Inverses behavior of inclusion button (if using external pullup) +//#define MY_INCLUSION_BUTTON_EXTERNAL_PULLUP + +// Set inclusion mode duration (in seconds) +#define MY_INCLUSION_MODE_DURATION 60 +// Digital pin used for inclusion mode button +//#define MY_INCLUSION_MODE_BUTTON_PIN 3 + +// Uncomment to override default HW configurations +//#define MY_DEFAULT_ERR_LED_PIN 4 // Error led pin +//#define MY_DEFAULT_RX_LED_PIN 6 // Receive led pin +//#define MY_DEFAULT_TX_LED_PIN 5 // the PCB, on board LED + +#include +#include +#include +#include + +Sd2Card card; + +#define EEPROM_VERIFICATION_ADDRESS 0x01 + +static uint8_t num_of_leds = 5; +static uint8_t leds[] = {LED_BLUE, LED_RED, LED_GREEN, LED_YELLOW, LED_ORANGE}; + +void setup() { + // Setup locally attached sensors +} + +void presentation() { + // Present locally attached sensors +} + +void loop() { + // Send locally attached sensor data here +} + + +void preHwInit() { + + pinMode(MY_SWC1, INPUT_PULLUP); + pinMode(MY_SWC2, INPUT_PULLUP); + if (digitalRead(MY_SWC1) && digitalRead(MY_SWC2)) return; + + uint8_t tests = 0; + + for (int i=0; i< num_of_leds; i++) { + pinMode(leds[i], OUTPUT); + } + uint8_t led_state = 0; + if (digitalRead(MY_SWC1)) { + while (!Serial) { + digitalWrite(LED_BLUE, led_state); + led_state ^= 0x01; + delay(500); + } // Wait for USB to be connected, before spewing out data. + } + if (Serial) { + Serial.println("Sensebender GateWay test routine"); + Serial.print("Mysensors core version : "); + Serial.println(MYSENSORS_LIBRARY_VERSION); + Serial.print("GateWay sketch version : "); + Serial.println(SKETCH_VERSION); + Serial.println("----------------------------------"); + Serial.println(); + } + if (testSha204()) { + digitalWrite(LED_GREEN, HIGH); + tests++; + } + if (testSDCard()) { + digitalWrite(LED_YELLOW, HIGH); + tests++; + } + + if (testEEProm()) { + digitalWrite(LED_ORANGE, HIGH); + tests++; + } + if (tests == 3) { + while(1) { + for (int i=0; i SHA204 "); + atsha204_init(MY_SIGNING_ATSHA204_PIN); + ret_code = atsha204_wakeup(rx_buffer); + + if (ret_code == SHA204_SUCCESS) + { + ret_code = atsha204_getSerialNumber(rx_buffer); + if (ret_code != SHA204_SUCCESS) + { + if (Serial) Serial.println(F("Failed to obtain device serial number. Response: ")); Serial.println(ret_code, HEX); + } + else + { + if (Serial) { + Serial.print(F("Ok (serial : ")); + for (int i=0; i<9; i++) + { + if (rx_buffer[i] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[i], HEX); + } + Serial.println(")"); + } + return true; + } + } + else { + if (Serial) Serial.println(F("Failed to wakeup SHA204")); + } + return false; +} + +bool testSDCard() { + if (Serial) Serial.print("- > SD CARD "); + if (!card.init(SPI_HALF_SPEED, MY_SDCARD_CS)) { + if (Serial) Serial.println("SD CARD did not initialize!"); + } + else { + if (Serial) { + Serial.print("SD Card initialized correct! - "); + Serial.print("type detected : "); + switch(card.type()) { + case SD_CARD_TYPE_SD1: + Serial.println("SD1"); + break; + case SD_CARD_TYPE_SD2: + Serial.println("SD2"); + break; + case SD_CARD_TYPE_SDHC: + Serial.println("SDHC"); + break; + default: + Serial.println("Unknown"); + } + } + return true; + } + return false; +} + +bool testEEProm() { + uint8_t eeprom_d1, eeprom_d2; + SerialUSB.print(" -> EEPROM "); + Wire.begin(); + eeprom_d1 = i2c_eeprom_read_byte(EEPROM_VERIFICATION_ADDRESS); + delay(500); + eeprom_d1 = ~eeprom_d1; // invert the bits + i2c_eeprom_write_byte(EEPROM_VERIFICATION_ADDRESS, eeprom_d1); + delay(500); + eeprom_d2 = i2c_eeprom_read_byte(EEPROM_VERIFICATION_ADDRESS); + if (eeprom_d1 == eeprom_d2) { + SerialUSB.println("PASSED"); + i2c_eeprom_write_byte(EEPROM_VERIFICATION_ADDRESS, ~eeprom_d1); + return true; + } + SerialUSB.println("FAILED!"); + return false; +} From 88e37e3675b3fea7e1924db4e6ae5c35524f65cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Wed, 3 Aug 2016 22:48:03 +0200 Subject: [PATCH 024/167] Disabled inclusion button defines As they can be present in HW Variant files, so to minimize risk of warnings they are not enabled --- examples/GatewaySerial/GatewaySerial.ino | 4 ++-- examples/GatewayW5100/GatewayW5100.ino | 4 ++-- examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/GatewaySerial/GatewaySerial.ino b/examples/GatewaySerial/GatewaySerial.ino index e0069c0b3..4d72270fe 100644 --- a/examples/GatewaySerial/GatewaySerial.ino +++ b/examples/GatewaySerial/GatewaySerial.ino @@ -67,7 +67,7 @@ // Enable inclusion mode #define MY_INCLUSION_MODE_FEATURE // Enable Inclusion mode button on gateway -#define MY_INCLUSION_BUTTON_FEATURE +//#define MY_INCLUSION_BUTTON_FEATURE // Inverses behavior of inclusion button (if using external pullup) //#define MY_INCLUSION_BUTTON_EXTERNAL_PULLUP @@ -75,7 +75,7 @@ // Set inclusion mode duration (in seconds) #define MY_INCLUSION_MODE_DURATION 60 // Digital pin used for inclusion mode button -#define MY_INCLUSION_MODE_BUTTON_PIN 3 +//#define MY_INCLUSION_MODE_BUTTON_PIN 3 // Uncomment to override default HW configurations //#define MY_DEFAULT_ERR_LED_PIN 4 // Error led pin diff --git a/examples/GatewayW5100/GatewayW5100.ino b/examples/GatewayW5100/GatewayW5100.ino index 2af523044..5e7ca3fb1 100644 --- a/examples/GatewayW5100/GatewayW5100.ino +++ b/examples/GatewayW5100/GatewayW5100.ino @@ -98,11 +98,11 @@ // Enable inclusion mode #define MY_INCLUSION_MODE_FEATURE // Enable Inclusion mode button on gateway -#define MY_INCLUSION_BUTTON_FEATURE +//#define MY_INCLUSION_BUTTON_FEATURE // Set inclusion mode duration (in seconds) #define MY_INCLUSION_MODE_DURATION 60 // Digital pin used for inclusion mode button -#define MY_INCLUSION_MODE_BUTTON_PIN 3 +//#define MY_INCLUSION_MODE_BUTTON_PIN 3 // Uncomment to override default HW configurations //#define MY_DEFAULT_ERR_LED_PIN 7 // Error led pin diff --git a/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino b/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino index 8e98e808a..8798c3a34 100644 --- a/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino +++ b/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino @@ -123,11 +123,11 @@ // Enable inclusion mode #define MY_INCLUSION_MODE_FEATURE // Enable Inclusion mode button on gateway -#define MY_INCLUSION_BUTTON_FEATURE +//#define MY_INCLUSION_BUTTON_FEATURE // Set inclusion mode duration (in seconds) #define MY_INCLUSION_MODE_DURATION 60 // Digital pin used for inclusion mode button -#define MY_INCLUSION_MODE_BUTTON_PIN 3 +//#define MY_INCLUSION_MODE_BUTTON_PIN 3 // Uncomment to override default HW configurations //#define MY_DEFAULT_ERR_LED_PIN 16 // Error led pin From 7d84878cb0b30381e5e0a4fd53ab4c3bc14f0208 Mon Sep 17 00:00:00 2001 From: Embedded Innovation Date: Fri, 5 Aug 2016 12:18:24 +0200 Subject: [PATCH 025/167] Correctly initialize MyMessage --- core/MyMessage.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/core/MyMessage.cpp b/core/MyMessage.cpp index 117dfe34b..13f351554 100644 --- a/core/MyMessage.cpp +++ b/core/MyMessage.cpp @@ -23,12 +23,21 @@ #include -MyMessage::MyMessage() { - destination = 0; // Gateway is default destination +MyMessage::MyMessage() + : last( 0u ) + , sender( 0u ) + , destination( 0u ) // Gateway is default destination + , version_length( 0u ) + , command_ack_payload( 0u ) + , type( 0u ) + , sensor( 0u ) +{ + (void)memset(data, 0u, sizeof(data)); } -MyMessage::MyMessage(uint8_t _sensor, uint8_t _type) { - destination = 0; // Gateway is default destination +MyMessage::MyMessage(uint8_t _sensor, uint8_t _type) + : MyMessage() +{ sensor = _sensor; type = _type; } From 5d7f2fe38b62b5431db066c59764c1deecb3c9e3 Mon Sep 17 00:00:00 2001 From: Embedded Innovation Date: Fri, 5 Aug 2016 12:41:53 +0200 Subject: [PATCH 026/167] Fix delegating constructor --- core/MyMessage.cpp | 25 +++++++++++++++---------- core/MyMessage.h | 5 +++++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/core/MyMessage.cpp b/core/MyMessage.cpp index 13f351554..027b273af 100644 --- a/core/MyMessage.cpp +++ b/core/MyMessage.cpp @@ -24,22 +24,27 @@ MyMessage::MyMessage() - : last( 0u ) - , sender( 0u ) - , destination( 0u ) // Gateway is default destination - , version_length( 0u ) - , command_ack_payload( 0u ) - , type( 0u ) - , sensor( 0u ) { - (void)memset(data, 0u, sizeof(data)); + clear(); } MyMessage::MyMessage(uint8_t _sensor, uint8_t _type) - : MyMessage() { + clear(); sensor = _sensor; - type = _type; + type = _type; +} + +void MyMessage::clear() +{ + last = 0u; + sender = 0u; + destination = 0u; // Gateway is default destination + version_length = 0u; + command_ack_payload = 0u; + type = 0u; + sensor = 0u; + (void)memset(data, 0u, sizeof(data)); } bool MyMessage::isAck() const { diff --git a/core/MyMessage.h b/core/MyMessage.h index 2d37f78d6..aa84b49a6 100644 --- a/core/MyMessage.h +++ b/core/MyMessage.h @@ -282,6 +282,11 @@ class MyMessage char i2h(uint8_t i) const; + /** + * Clear message contents. + */ + void clear(); + /** * If payload is something else than P_STRING you can have the payload value converted * into string representation by supplying a buffer with the minimum size of From 6bdde5b1acf4f54c34955f1b1144f51cbbaa7ca9 Mon Sep 17 00:00:00 2001 From: Embedded Innovation Date: Fri, 5 Aug 2016 18:37:17 +0200 Subject: [PATCH 027/167] Add missing GOT_PARENT indication (#541) * Add missing GOT_PARENT indication * Fix tabs --- core/MyTransport.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/core/MyTransport.cpp b/core/MyTransport.cpp index 6b14b2341..a54c34dd7 100644 --- a/core/MyTransport.cpp +++ b/core/MyTransport.cpp @@ -94,6 +94,7 @@ void stParentTransition() { _nc.distance = 1; // assumption, CHKUPL:GWDC will update this variable _nc.parentNodeId = MY_PARENT_NODE_ID; // skipping find parent + setIndication(INDICATION_GOT_PARENT); transportSwitchSM(stID); #else _transportSM.findingParentNode = true; From c5c8c92755a78ac9a68045f640d6bb33e9e783ec Mon Sep 17 00:00:00 2001 From: tekka007 Date: Sat, 6 Aug 2016 00:14:19 +0200 Subject: [PATCH 028/167] Verify MY_PARENT_NODE_ID if parent is set static --- MySensors.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MySensors.h b/MySensors.h index 8b589a8ea..a52d1be68 100644 --- a/MySensors.h +++ b/MySensors.h @@ -286,6 +286,10 @@ #endif #endif +#if defined(MY_PARENT_NODE_IS_STATIC) && (MY_PARENT_NODE_ID == AUTO) + #error Parent is static but no parent ID defined. +#endif + // Make sure to disable child features when parent feature is disabled #if !defined(MY_RADIO_FEATURE) #undef MY_OTA_FIRMWARE_FEATURE From 6bc113208c3d53cbb603a01f5b6085f8165e6d9f Mon Sep 17 00:00:00 2001 From: tekka007 Date: Sat, 6 Aug 2016 09:13:38 +0200 Subject: [PATCH 029/167] MySensor keyword obsolete --- keywords.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/keywords.txt b/keywords.txt index 808abf69c..c38e03f45 100644 --- a/keywords.txt +++ b/keywords.txt @@ -2,7 +2,6 @@ # Datatypes (KEYWORD1) ####################################### MyMessage KEYWORD1 -MySensor KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) From 858b80b6a4f95867b6dbf1e3777ebc52bcd257d3 Mon Sep 17 00:00:00 2001 From: "Mikael Falkvidd git@mjo.se" Date: Sat, 6 Aug 2016 11:58:45 +0200 Subject: [PATCH 030/167] Use bool instead of boolean in examples In the Arduino IDE, boolean is an alias for bool. The Arduino IDE might deprecate boolean in the future, see https://github.com/arduino/Arduino/issues/4673 for details. --- examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino | 2 +- examples/MockMySensors/MockMySensors.ino | 2 +- examples/MotionSensor/MotionSensor.ino | 2 +- examples/MotionSensorRS485/MotionSensorRS485.ino | 2 +- examples/PHSensor/PHSensor.ino | 4 ++-- examples/SecretKnockSensor/SecretKnockSensor.ino | 4 ++-- examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino b/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino index 27856796d..918873058 100644 --- a/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino +++ b/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino @@ -52,7 +52,7 @@ unsigned long SEND_FREQUENCY = 20000; // Minimum time between send (in milliseconds). We don't wnat to spam the gateway. double ppwh = ((double)PULSE_FACTOR)/1000; // Pulses per watt hour -boolean pcReceived = false; +bool pcReceived = false; volatile unsigned long pulseCount = 0; volatile unsigned long lastBlink = 0; volatile unsigned long watt = 0; diff --git a/examples/MockMySensors/MockMySensors.ino b/examples/MockMySensors/MockMySensors.ino index dfed9bedc..6de46a0e5 100644 --- a/examples/MockMySensors/MockMySensors.ino +++ b/examples/MockMySensors/MockMySensors.ino @@ -86,7 +86,7 @@ // Global Vars unsigned long SLEEP_TIME = 900000; // Sleep time between reads (in milliseconds) -boolean metric = true; +bool metric = true; long randNumber; diff --git a/examples/MotionSensor/MotionSensor.ino b/examples/MotionSensor/MotionSensor.ino index 77c01dfe4..d082c4da1 100644 --- a/examples/MotionSensor/MotionSensor.ino +++ b/examples/MotionSensor/MotionSensor.ino @@ -60,7 +60,7 @@ void presentation() { void loop() { // Read digital motion value - boolean tripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH; + bool tripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH; Serial.println(tripped); send(msg.set(tripped?"1":"0")); // Send tripped value to gw diff --git a/examples/MotionSensorRS485/MotionSensorRS485.ino b/examples/MotionSensorRS485/MotionSensorRS485.ino index 9252243ea..5af08fbd7 100644 --- a/examples/MotionSensorRS485/MotionSensorRS485.ino +++ b/examples/MotionSensorRS485/MotionSensorRS485.ino @@ -79,7 +79,7 @@ void presentation() { void loop() { // Read digital motion value - boolean tripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH; + bool tripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH; Serial.println(tripped); send(msg.set(tripped?"1":"0")); // Send tripped value to gw diff --git a/examples/PHSensor/PHSensor.ino b/examples/PHSensor/PHSensor.ino index befd8ec6d..713f1c6e7 100644 --- a/examples/PHSensor/PHSensor.ino +++ b/examples/PHSensor/PHSensor.ino @@ -36,8 +36,8 @@ unsigned long SLEEP_TIME = 60000; // Sleep time between reads (in milliseconds) float lastPH; -boolean receivedConfig = false; -boolean metric = true; +bool receivedConfig = false; +bool metric = true; // Initialize PH message MyMessage msg(0, V_PH); diff --git a/examples/SecretKnockSensor/SecretKnockSensor.ino b/examples/SecretKnockSensor/SecretKnockSensor.ino index d03219705..34349d4bd 100644 --- a/examples/SecretKnockSensor/SecretKnockSensor.ino +++ b/examples/SecretKnockSensor/SecretKnockSensor.ino @@ -85,7 +85,7 @@ const int knockComplete = 1200; // Longest time to wait for a knock before we byte secretCode[maximumKnocks] = {50, 25, 25, 50, 100, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Initial setup: "Shave and a Hair Cut, two bits." int knockReadings[maximumKnocks]; // When someone knocks this array fills with the delays between knocks. int knockSensorValue = 0; // Last reading of the knock sensor. -boolean programModeActive = false; // True if we're trying to program a new knock. +bool programModeActive = false; // True if we're trying to program a new knock. bool lockStatus; @@ -242,7 +242,7 @@ void setLockState(bool state, bool doSend){ // Checks to see if our knock matches the secret. // Returns true if it's a good knock, false if it's not. -boolean validateKnock(){ +bool validateKnock(){ int i = 0; int currentKnockCount = 0; diff --git a/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino b/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino index 1c9163a14..b7ce981d3 100644 --- a/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino +++ b/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino @@ -65,7 +65,7 @@ double ppl = ((double)PULSE_FACTOR)/1000; // Pulses per liter volatile unsigned long pulseCount = 0; volatile unsigned long lastBlink = 0; volatile double flow = 0; -boolean pcReceived = false; +bool pcReceived = false; unsigned long oldPulseCount = 0; unsigned long newBlink = 0; double oldflow = 0; From d054c1c0c87d444c2e34e0e49f5e357e401ee209 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Sat, 6 Aug 2016 14:39:12 +0200 Subject: [PATCH 031/167] Update doxygen docs with new smartSleep behavior (#545) * Update doxygen docs with new smartSleep behavior * Update docs to new behavior. * Add info on how to set wait time in smartSleep. * Fix incorrect docs regarding return value of smartSleep. * Update docs for return value of all sleep methods * Clarify the return value of the sleep methods, suggested by @mfalkvidd. --- core/MySensorsCore.h | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/core/MySensorsCore.h b/core/MySensorsCore.h index 5d52a8b80..e3064778a 100644 --- a/core/MySensorsCore.h +++ b/core/MySensorsCore.h @@ -234,7 +234,8 @@ bool wait(unsigned long ms, uint8_t cmd, uint8_t msgtype); */ int8_t sleep(unsigned long ms); /** -* Same as sleep(), send heartbeat upon wakeup and process incoming messages +* Same as sleep(), send heartbeat and process incoming messages before going to sleep. +* Specify the time to wait for incoming messages by defining MY_SMART_SLEEP_WAIT_DURATION to a time (ms). * @param ms Number of milliseconds to sleep. * @return -1 if timer woke it up, -2 if not possible (e.g. ongoing FW update) */ @@ -247,15 +248,16 @@ int8_t smartSleep(unsigned long ms); * @param interrupt Interrupt that should trigger the wakeup * @param mode RISING, FALLING, CHANGE * @param ms Number of milliseconds to sleep or 0 to sleep forever - * @return Interrupt number wake up was triggered by pin change, -1 if timer woke it up, -2 if not possible (e.g. ongoing FW update) + * @return Interrupt number if wake up was triggered by pin change, -1 if wake up was triggered by timer, -2 if sleep was not possible (e.g. ongoing FW update) */ int8_t sleep(uint8_t interrupt, uint8_t mode, unsigned long ms=0); /** -* Same as sleep(), send heartbeat upon wakeup and process incoming messages +* Same as sleep(), send heartbeat and process incoming messages before going to sleep. +* Specify the time to wait for incoming messages by defining MY_SMART_SLEEP_WAIT_DURATION to a time (ms). * @param interrupt Interrupt that should trigger the wakeup * @param mode RISING, FALLING, CHANGE -* @param ms Number of milliseconds to sleep. -* @return -1 if timer woke it up, -2 if not possible (e.g. ongoing FW update) +* @param ms Number of milliseconds to sleep or 0 to sleep forever +* @return Interrupt number if wake up was triggered by pin change, -1 if wake up was triggered by timer, -2 if sleep was not possible (e.g. ongoing FW update) */ int8_t smartSleep(uint8_t interrupt, uint8_t mode, unsigned long ms=0); @@ -268,17 +270,18 @@ int8_t smartSleep(uint8_t interrupt, uint8_t mode, unsigned long ms=0); * @param interrupt2 Second interrupt that should trigger the wakeup * @param mode2 Mode for second interrupt (RISING, FALLING, CHANGE) * @param ms Number of milliseconds to sleep or 0 to sleep forever - * @return Interrupt number wake up was triggered by pin change, -1 if timer woke it up, -2 if not possible (e.g. ongoing FW update) + * @return Interrupt number if wake up was triggered by pin change, -1 if wake up was triggered by timer, -2 if sleep was not possible (e.g. ongoing FW update) */ int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms=0); /** -* Same as sleep(), send heartbeat upon wakeup and process incoming messages +* Same as sleep(), send heartbeat and process incoming messages before going to sleep. +* Specify the time to wait for incoming messages by defining MY_SMART_SLEEP_WAIT_DURATION to a time (ms). * @param interrupt1 First interrupt that should trigger the wakeup * @param mode1 Mode for first interrupt (RISING, FALLING, CHANGE) * @param interrupt2 Second interrupt that should trigger the wakeup * @param mode2 Mode for second interrupt (RISING, FALLING, CHANGE) * @param ms Number of milliseconds to sleep or 0 to sleep forever -* @return Interrupt number wake up was triggered by pin change, -1 if timer woke it up, -2 if not possible (e.g. ongoing FW update) +* @return Interrupt number if wake up was triggered by pin change, -1 if wake up was triggered by timer, -2 if sleep was not possible (e.g. ongoing FW update) */ int8_t smartSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms=0); From 35cab8c26dc98a0415455e8891cd0af453255ff0 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Sun, 21 Feb 2016 10:07:49 -0300 Subject: [PATCH 032/167] Add support for RaspberryPi --- libraries/MySensors/Makefile | 67 ++++ libraries/MySensors/MyConfig.h | 38 +++ libraries/MySensors/MySensor.h | 29 +- .../core/MyGatewayTransportEthernetLinux.cpp | 304 ++++++++++++++++++ libraries/MySensors/core/MyHwLinuxGeneric.cpp | 107 ++++++ libraries/MySensors/core/MyHwLinuxGeneric.h | 42 +++ libraries/MySensors/core/MyMainLinux.cpp | 13 + libraries/MySensors/core/MySensorCore.cpp | 5 + libraries/MySensors/core/MyTransportNRF24.cpp | 6 +- .../MySensors/examples_RPi/PiGateway.cpp | 55 ++++ 10 files changed, 661 insertions(+), 5 deletions(-) create mode 100644 libraries/MySensors/Makefile create mode 100644 libraries/MySensors/core/MyGatewayTransportEthernetLinux.cpp create mode 100644 libraries/MySensors/core/MyHwLinuxGeneric.cpp create mode 100644 libraries/MySensors/core/MyHwLinuxGeneric.h create mode 100644 libraries/MySensors/core/MyMainLinux.cpp create mode 100644 libraries/MySensors/examples_RPi/PiGateway.cpp diff --git a/libraries/MySensors/Makefile b/libraries/MySensors/Makefile new file mode 100644 index 000000000..20a46ff84 --- /dev/null +++ b/libraries/MySensors/Makefile @@ -0,0 +1,67 @@ +########################################################################## +# Configurable options # +########################################################################## +# Install Base location +PREFIX=/usr/local +# Bin Dir +BINDIR=$(PREFIX)/sbin + +########################################################################## +# Please do not change anything below this line # +########################################################################## +CXX ?= g++ + +ifeq "$(shell uname -m)" "armv6l" + ARCH=armv6zk +endif +ifeq "$(shell uname -m)" "armv7l" + ARCH=armv7-a +endif +ifdef ARCH + # The recommended compiler flags for the Raspberry Pi + CXXFLAGS+=-Ofast -mfpu=vfp -mfloat-abi=hard -march=$(ARCH) -mtune=arm1176jzf-s -DRASPBERRYPI_ARCH $(OPTFLAGS) + LDFLAGS+=-lrf24-bcm +endif + +CXXFLAGS+=-g -Wall -Wextra +CXXFLAGS+=-DLINUX_ARCH_GENERIC $(OPTFLAGS) + +# get PI Revision from cpuinfo +PIREV := $(shell cat /proc/cpuinfo | grep Revision | cut -f 2 -d ":" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$$//') +ifeq ($(PIREV),$(filter $(PIREV),a01041 a21041 0010)) + # a01041 and a21041 are PI 2 Model B with BPLUS Layout and 0010 is Pi Model B+ with BPLUS Layout + CXXFLAGS+=-D__PI_BPLUS +endif + +GATEWAY=examples_RPi/PiGateway +GATEWAY_SOURCES=examples_RPi/PiGateway.cpp $(wildcard ./utility/*.cpp) +GATEWAY_OBJECTS=$(patsubst %.cpp,%.o,$(GATEWAY_SOURCES)) +DEPS+=$(patsubst %.cpp,%.d,$(GATEWAY_SOURCES)) + +RF24H = /usr/local/include/RF24 +CINCLUDE=-I. -I./core -I$(RF24H) + +.PHONY: all clean install uninstall + +all: $(GATEWAY) + +# Basic Gateway Build +$(GATEWAY): LDFLAGS += -pthread +$(GATEWAY): $(GATEWAY_OBJECTS) + $(CXX) $(LDFLAGS) -o $@ $(GATEWAY_OBJECTS) + +# Include all .d files +-include $(DEPS) + +%.o: %.cpp + $(CXX) $(CXXFLAGS) $(CINCLUDE) -MMD -c -o $@ $< + +# The Cleaner +clean: + rm -rf build $(GATEWAY_OBJECTS) $(GATEWAY) $(DEPS) + +install: all install-gatewaybasic install-gatewayserial install-gatewayethernet install-initscripts + +install-gatewaybasic: + @echo "Installing $(GATEWAY) to $(BINDIR)" + @install -m 0755 $(GATEWAY) $(BINDIR) diff --git a/libraries/MySensors/MyConfig.h b/libraries/MySensors/MyConfig.h index ffe3978e2..d25a65b93 100644 --- a/libraries/MySensors/MyConfig.h +++ b/libraries/MySensors/MyConfig.h @@ -342,6 +342,17 @@ #define MY_RF24_CE_PIN 4 #elif defined(ARDUINO_ARCH_SAMD) #define MY_RF24_CE_PIN 27 + #elif defined(RASPBERRYPI_ARCH) + #include + #include + #ifdef __PI_BPLUS + #define MY_RF24_CE_PIN RPI_BPLUS_GPIO_J8_22 + #define MY_RF24_CS_PIN RPI_BPLUS_GPIO_J8_24 + #else + #define MY_RF24_CE_PIN RPI_V2_GPIO_P1_22 + #define MY_RF24_CS_PIN BCM2835_SPI_CS0 + #endif + #define MY_RF24_SPI_SPEED BCM2835_SPI_SPEED_8MHZ #else #define MY_RF24_CE_PIN 9 #endif @@ -509,6 +520,8 @@ //#define MY_GATEWAY_W5100 //#define MY_GATEWAY_ENC28J60 //#define MY_GATEWAY_ESP8266 +//#define MY_GATEWAY_RASPBERRYPI +//#define MY_GATEWAY_LINUX /** * @def MY_PORT @@ -546,6 +559,10 @@ // If MY_CONTROLLER_IP_ADDRESS is left un-defined, gateway acts as server allowing incoming connections. //#define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 254 +/************************************** +* Node Locking +***************************************/ + /** * @defgroup MyLockgrp MyNodeLock * @ingroup internals @@ -604,6 +621,27 @@ #endif +/************************************** +* RaspberryPi Settings +***************************************/ + +/** + * @def MY_RASPBERRYPI_TTY_NAME + * @brief Set the name of predictable tty + */ +#ifndef MY_RASPBERRYPI_TTY_NAME +#define MY_RASPBERRYPI_TTY_NAME /dev/ttyMySensorsGateway +#endif + +/** + * @def MY_RASPBERRYPI_TTY_GROUPNAME + * @brief Set the group name for the raw tty + */ +#ifndef MY_RASPBERRYPI_TTY_GROUPNAME +#define MY_RASPBERRYPI_TTY_GROUPNAME tty +#endif + + // Doxygen specific constructs, not included when built normally // This is used to enable disabled macros/definitions to be included in the documentation as well. #if DOXYGEN diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index c562a2a79..57bfd2733 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -40,7 +40,7 @@ * @def MY_NODE_TYPE * @brief Contain a string describing the class of sketch/node (gateway/repeater/sensor). */ -#if defined(MY_GATEWAY_SERIAL) || defined(MY_GATEWAY_W5100) || defined(MY_GATEWAY_ENC28J60) || defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_MQTT_CLIENT) +#if defined(MY_GATEWAY_SERIAL) || defined(MY_GATEWAY_W5100) || defined(MY_GATEWAY_ENC28J60) || defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_RASPBERRYPI) || defined(MY_GATEWAY_LINUX) || defined(MY_GATEWAY_MQTT_CLIENT) #define MY_GATEWAY_FEATURE #define MY_IS_GATEWAY (true) #define MY_NODE_TYPE "gateway" @@ -68,7 +68,19 @@ #elif defined(ARDUINO_ARCH_AVR) #include "core/MyHwATMega328.cpp" #elif defined(ARDUINO_ARCH_SAMD) - #include "core/MyHwSAMD.cpp" + #include "core/MyHwSAMD.cpp" +#elif defined(LINUX_ARCH_GENERIC) + // Remove PSTR macros from debug prints + #undef PSTR + #define PSTR(x) (x) + //#undef F + //#define F(x) (x) + #define PROGMEM + #define vsnprintf_P(...) vsnprintf( __VA_ARGS__ ) + #define snprintf_P(...) snprintf( __VA_ARGS__ ) + #define memcpy_P memcpy + #define pgm_read_dword(x) (*x) + #include "core/MyHwLinuxGeneric.cpp" #endif // LEDS @@ -208,6 +220,9 @@ // We assume that a gateway having a radio also should act as repeater #define MY_REPEATER_FEATURE #endif + #if defined(MY_GATEWAY_RASPBERRYPI) + #define MY_GATEWAY_LINUX + #endif #if defined(MY_CONTROLLER_IP_ADDRESS) #define MY_GATEWAY_CLIENT_MODE #endif @@ -217,6 +232,9 @@ #if defined(MY_GATEWAY_ESP8266) // GATEWAY - ESP8266 #include "core/MyGatewayTransportEthernet.cpp" + #elif defined(MY_GATEWAY_LINUX) + // GATEWAY - Generic Linux (RaspberryPi, BBB) + #include "core/MyGatewayTransportEthernetLinux.cpp" #elif defined(MY_GATEWAY_W5100) // GATEWAY - W5100 #include "core/MyGatewayTransportEthernet.cpp" @@ -229,6 +247,7 @@ #elif defined(MY_GATEWAY_SERIAL) // GATEWAY - SERIAL #include "core/MyGatewayTransportSerial.cpp" + #endif #endif @@ -256,7 +275,9 @@ #if defined(MY_RF24_ENABLE_ENCRYPTION) #include "drivers/AES/AES.cpp" #endif - #include "drivers/RF24/RF24.cpp" + #if !defined(RASPBERRYPI_ARCH) + #include "drivers/RF24/RF24.cpp" + #endif #include "core/MyTransportNRF24.cpp" #elif defined(MY_RS485) #include "drivers/AltSoftSerial/AltSoftSerial.cpp" @@ -295,6 +316,8 @@ #if !defined(MY_CORE_ONLY) #if defined(ARDUINO_ARCH_ESP8266) #include "core/MyMainESP8266.cpp" + #elif defined(LINUX_ARCH_GENERIC) + #include "core/MyMainLinux.cpp" #else #include "core/MyMainDefault.cpp" #endif diff --git a/libraries/MySensors/core/MyGatewayTransportEthernetLinux.cpp b/libraries/MySensors/core/MyGatewayTransportEthernetLinux.cpp new file mode 100644 index 000000000..e5228286a --- /dev/null +++ b/libraries/MySensors/core/MyGatewayTransportEthernetLinux.cpp @@ -0,0 +1,304 @@ +/** + * 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 + * Copyleft (c) 2016, Marcelo Aquino + * 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 "MyGatewayTransport.h" +#include +#include +#include +#include +#include +#include +#include +#include + +//TODO +#ifdef MY_USE_UDP + #error UDP not supported for this type of gateway +#endif + +union _addrIPv4{ + uint8_t bytes[4]; + uint32_t dword; +}; + +static int controllers[MY_GATEWAY_MAX_CLIENTS]; +static MyMessage _ethernetMsg; +static std::list ethernetMsg_q; +static pthread_mutex_t ethernetMsg_mutex = PTHREAD_MUTEX_INITIALIZER; + +// Prototypes +int open_listen(char *ip, uint16_t port); +uint32_t getAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); +void *get_in_addr(struct sockaddr *sa); +void *waiting_controllers(void* thread_arg); +void *connected_controller(void* thread_arg); + +bool gatewayTransportInit() { + long int sockfd; + pthread_t thread_id; + pthread_attr_t attr; + char *ip = NULL; + + // ignore SIGPIPE generated by send() to a disconnected client + signal(SIGPIPE, SIG_IGN); + + for (uint8_t i = 0; i < MY_GATEWAY_MAX_CLIENTS; i++) { + controllers[i] = -1; + } + +#ifdef MY_CONTROLLER_IP_ADDRESS + //TODO + return false; +#else + #ifdef MY_IP_ADDRESS + char ipstr[INET_ADDRSTRLEN]; + union _addrIPv4 addrIPv4 = getAddress(MY_IP_ADDRESS); + sprintf(ipstr, "%d.%d.%d.%d", addrIPv4.bytes[0], addrIPv4.bytes[1], + addrIPv4.bytes[2], addrIPv4.bytes[3]); + ip = ipstr; + #endif + + sockfd = open_listen(ip, MY_PORT); + if (sockfd < 0) { + return false; + } +#endif + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_create(&thread_id, &attr, &waiting_controllers, (void *)sockfd); + pthread_attr_destroy(&attr); + + return true; +} + +bool gatewayTransportSend(MyMessage &message) +{ + char *ethernetMsg = protocolFormat(message); + + for (uint8_t i = 0; i < MY_GATEWAY_MAX_CLIENTS; i++) { + if (controllers[i] == -1) + continue; + if (send(controllers[i], ethernetMsg, strlen(ethernetMsg), 0) == -1) + perror("send"); + } + return true; +} + +bool gatewayTransportAvailable() +{ + bool empty; + + pthread_mutex_lock(ðernetMsg_mutex); + empty = ethernetMsg_q.empty(); + pthread_mutex_unlock(ðernetMsg_mutex); + + return !empty; +} + +MyMessage& gatewayTransportReceive() +{ + // Return the last parsed message + pthread_mutex_lock(ðernetMsg_mutex); + _ethernetMsg = ethernetMsg_q.front(); + ethernetMsg_q.pop_front(); + pthread_mutex_unlock(ðernetMsg_mutex); + + return _ethernetMsg; +} + +int open_listen(char *address, uint16_t port) +{ + int sockfd; + struct addrinfo hints, *servinfo, *p; + int yes=1; + int rv; + char ipstr[INET_ADDRSTRLEN]; + char portstr[6]; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_INET; // IPv4 + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + + sprintf(portstr, "%d", port); + if ((rv = getaddrinfo(address, portstr, &hints, &servinfo)) != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); + return -1; + } + + // loop through all the results and bind to the first we can + for (p = servinfo; p != NULL; p = p->ai_next) { + if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { + perror("socket"); + continue; + } + + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { + perror("setsockopt"); + freeaddrinfo(servinfo); + return -1; + } + + if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { + close(sockfd); + perror("bind"); + continue; + } + + break; + } + + if (p == NULL) { + fprintf(stderr, "failed to bind\n"); + freeaddrinfo(servinfo); + return -1; + } + + if (listen(sockfd, MY_GATEWAY_MAX_CLIENTS) == -1) { + perror("listen"); + freeaddrinfo(servinfo); + return -1; + } + + struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr; + void *addr = &(ipv4->sin_addr); + inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr); + debug("Eth: Listening for connections on %s:%s\n", ipstr, portstr); + + freeaddrinfo(servinfo); + return sockfd; +} + +uint32_t getAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) +{ + union _addrIPv4 addrIPv4; + + addrIPv4.bytes[0] = first_octet; + addrIPv4.bytes[1] = second_octet; + addrIPv4.bytes[2] = third_octet; + addrIPv4.bytes[3] = fourth_octet; + + return addrIPv4.dword; +} + +void *get_in_addr(struct sockaddr *sa) +{ + if (sa->sa_family == AF_INET) { + return &(((struct sockaddr_in*)sa)->sin_addr); + } + + return &(((struct sockaddr_in6*)sa)->sin6_addr); +} + +void *waiting_controllers(void* thread_arg) +{ + long int sockfd = (long int) thread_arg; + long int new_fd; // new connection on new_fd + struct sockaddr_storage client_addr; // connector's address information + socklen_t sin_size; + char s[INET6_ADDRSTRLEN]; + pthread_t thread_id; + pthread_attr_t attr; + uint8_t i; + + while (1) { // accept() loop + sin_size = sizeof client_addr; + new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size); + if (new_fd == -1) { + perror("accept"); + continue; + } + + inet_ntop(client_addr.ss_family, + get_in_addr((struct sockaddr *)&client_addr), s, sizeof s); + debug("Eth: New connection from %s\n", s); + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_create(&thread_id, &attr, &connected_controller, (void *)new_fd); + pthread_attr_destroy(&attr); + + for (i = 0; i < MY_GATEWAY_MAX_CLIENTS; i++) { + if (controllers[i] == -1) { + controllers[i] = new_fd; + break; + } + } + if (i >= MY_GATEWAY_MAX_CLIENTS) { + // no free/disconnected spot so reject + close(new_fd); + } + } + + return NULL; +} + +void *connected_controller(void* thread_arg) +{ + long int sockfd = (long int) thread_arg; + char inputString[MY_GATEWAY_MAX_RECEIVE_LENGTH]; + char *ptr = inputString; + int nbytes = 0; + MyMessage ethernetMsg; + + while (1) { + if (recv(sockfd, ptr, 1, 0) > 0) { + if (*ptr == '\n' || *ptr == '\r') { + // String terminator + *ptr = 0; + debug("Eth: %s\n", inputString); + if (protocolParse(ethernetMsg, inputString)) { + pthread_mutex_lock(ðernetMsg_mutex); + ethernetMsg_q.push_back(ethernetMsg); + pthread_mutex_unlock(ðernetMsg_mutex); + } + + // Prepare for the next message + ptr = inputString; + nbytes = 0; + continue; + } + nbytes++; + if (nbytes == MY_GATEWAY_MAX_RECEIVE_LENGTH) { + // Incoming message too long. Throw away + debug("Eth: Message too long\n"); + ptr = inputString; + nbytes = 0; + } else { + ptr++; + } + } else { + break; + } + } + + if (nbytes == -1) + perror("recv"); + + for (uint8_t i = 0; i < MY_GATEWAY_MAX_CLIENTS; i++) { + if (controllers[i] == sockfd) { + controllers[i] = -1; + break; + } + } + + close(sockfd); + return NULL; +} diff --git a/libraries/MySensors/core/MyHwLinuxGeneric.cpp b/libraries/MySensors/core/MyHwLinuxGeneric.cpp new file mode 100644 index 000000000..35afc37ee --- /dev/null +++ b/libraries/MySensors/core/MyHwLinuxGeneric.cpp @@ -0,0 +1,107 @@ +/** + * 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 + * Copyleft (c) 2016, Marcelo Aquino + * 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 "MyHwLinuxGeneric.h" + +#include +#include +#include + +static const size_t _length = 1024; // ATMega328 has 1024 bytes +//TODO store _config to a file +static uint8_t _config[_length]; +static unsigned long millis_at_start; + +void hwInit() +{ + timeval curTime; + + for (size_t i = 0; i < _length; i++) + _config[i] = 0xFF; + + gettimeofday(&curTime, NULL); + millis_at_start = curTime.tv_sec; +} + +void hwReadConfigBlock(void* buf, void* addr, size_t length) +{ + unsigned long int offs = reinterpret_cast(addr); + + if (length && offs + length <= _length) { + memcpy(buf, _config+offs, length); + } +} + +void hwWriteConfigBlock(void* buf, void* addr, size_t length) +{ + unsigned long int offs = reinterpret_cast(addr); + + if (length && offs + length <= _length) { + memcpy(_config+offs, buf, length); + } +} + +uint8_t hwReadConfig(int addr) +{ + if (addr >= 0 && (unsigned)addr < _length) + return _config[addr]; + return 0xFF; +} + +void hwWriteConfig(int addr, uint8_t value) +{ + if (addr >= 0 && (unsigned)addr < _length) + _config[addr] = value; +} + +unsigned long hwMillis() +{ + timeval curTime; + + gettimeofday(&curTime, NULL); + return ((curTime.tv_sec - millis_at_start) * 1000) + (curTime.tv_usec / 1000); +} + +int8_t hwSleep(unsigned long ms) +{ + // TODO: Not supported! + return -2; +} + +int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) +{ + // TODO: Not supported! + return -2; +} + +int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) +{ + // TODO: Not supported! + return -2; +} + +#ifdef MY_DEBUG +void hwDebugPrint(const char *fmt, ... ) +{ + va_list arglist; + va_start(arglist, fmt); + vprintf(fmt, arglist); + va_end(arglist); +} +#endif diff --git a/libraries/MySensors/core/MyHwLinuxGeneric.h b/libraries/MySensors/core/MyHwLinuxGeneric.h new file mode 100644 index 000000000..3546e0981 --- /dev/null +++ b/libraries/MySensors/core/MyHwLinuxGeneric.h @@ -0,0 +1,42 @@ +/** + * 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 + * Copyleft (c) 2016, Marcelo Aquino + * 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 MyHwLinuxGeneric_h +#define MyHwLinuxGeneric_h + +#include "MyHw.h" +#include + +#define MY_SERIALDEVICE Serial +#define min(a,b) ((a)<(b)?(a):(b)) +#define max(a,b) ((a)>(b)?(a):(b)) + +// Define these as macros (do nothing) +#define hwDigitalWrite(__pin, __value) +#define hwWatchdogReset() +#define hwReboot() + +void hwInit(); +void hwReadConfigBlock(void* buf, void* adr, size_t length); +void hwWriteConfigBlock(void* buf, void* adr, size_t length); +void hwWriteConfig(int adr, uint8_t value); +uint8_t hwReadConfig(int adr); +unsigned long hwMillis(); + +#endif diff --git a/libraries/MySensors/core/MyMainLinux.cpp b/libraries/MySensors/core/MyMainLinux.cpp new file mode 100644 index 000000000..98982e536 --- /dev/null +++ b/libraries/MySensors/core/MyMainLinux.cpp @@ -0,0 +1,13 @@ +// Initialize library and handle sketch functions like we want to + +#include "MySensorCore.h" + +int main(void) { + _begin(); // Startup MySensors library + + for(;;) { + _process(); // Process incoming data + if (loop) loop(); // Call sketch loop + } + return 0; +} diff --git a/libraries/MySensors/core/MySensorCore.cpp b/libraries/MySensors/core/MySensorCore.cpp index f74cd13cf..23ad2f0a0 100644 --- a/libraries/MySensors/core/MySensorCore.cpp +++ b/libraries/MySensors/core/MySensorCore.cpp @@ -51,6 +51,11 @@ void _process() { #if defined(MY_RADIO_FEATURE) transportProcess(); #endif + + #if defined(LINUX_ARCH_GENERIC) + // To avoid high cpu usage + usleep(10000); // 10ms + #endif } #if defined(MY_RADIO_FEATURE) diff --git a/libraries/MySensors/core/MyTransportNRF24.cpp b/libraries/MySensors/core/MyTransportNRF24.cpp index 3d2ac1daf..67a7ca978 100644 --- a/libraries/MySensors/core/MyTransportNRF24.cpp +++ b/libraries/MySensors/core/MyTransportNRF24.cpp @@ -20,8 +20,10 @@ #include "MyConfig.h" #include "MyTransport.h" #include -#include "drivers/RF24/RF24.h" -#include "drivers/RF24/RF24_config.h" +#ifndef RASPBERRYPI_ARCH + #include "drivers/RF24/RF24.h" + #include "drivers/RF24/RF24_config.h" +#endif #if defined(MY_RF24_ENABLE_ENCRYPTION) #include "drivers/AES/AES.h" #endif diff --git a/libraries/MySensors/examples_RPi/PiGateway.cpp b/libraries/MySensors/examples_RPi/PiGateway.cpp new file mode 100644 index 000000000..16703f8d3 --- /dev/null +++ b/libraries/MySensors/examples_RPi/PiGateway.cpp @@ -0,0 +1,55 @@ +/** + * 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 + * Copyleft (c) 2016, Marcelo Aquino + * 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 + +// Enable debug prints to serial monitor +#define MY_DEBUG + +// Enables and select radio type (if attached) +#define MY_RADIO_NRF24 + +#define MY_GATEWAY_RASPBERRYPI + +// Enable MY_IP_ADDRESS here if you want to listen for incoming network +// connections on the specified IP address/hostname only +//#define MY_IP_ADDRESS 192,168,178,87 + +// The port to keep open on node server mode +#define MY_PORT 5003 + +// How many clients should be able to connect to this gateway (default 1) +#define MY_GATEWAY_MAX_CLIENTS 2 + +#include + +using namespace std; + +void setup() { +} + +void presentation() { + // Present locally attached sensors here +} + +void loop() { + // Send locally attached sensors data here +} From e7682cf006a51c117f47250d66a60b25eee9184d Mon Sep 17 00:00:00 2001 From: tekka007 Date: Mon, 8 Aug 2016 17:37:42 +0200 Subject: [PATCH 033/167] Harmonize message type names --- core/MyMessage.h | 10 +++++----- core/MySensorsCore.cpp | 2 +- core/MySigning.cpp | 10 +++++----- core/MyTransport.cpp | 8 ++++---- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/core/MyMessage.h b/core/MyMessage.h index aa84b49a6..0258b9321 100644 --- a/core/MyMessage.h +++ b/core/MyMessage.h @@ -163,13 +163,13 @@ typedef enum { /// @brief Type of internal messages (for internal messages) typedef enum { I_BATTERY_LEVEL = 0, //!< Battery level - I_TIME = 1, //!< Time + I_TIME = 1, //!< Time (request/response) I_VERSION = 2, //!< Version I_ID_REQUEST = 3, //!< ID request I_ID_RESPONSE = 4, //!< ID response I_INCLUSION_MODE = 5, //!< Inclusion mode - I_CONFIG = 6, //!< Config - I_FIND_PARENT = 7, //!< Find parent + I_CONFIG = 6, //!< Config (request/response) + I_FIND_PARENT_REQUEST = 7, //!< Find parent I_FIND_PARENT_RESPONSE = 8, //!< Find parent response I_LOG_MESSAGE = 9, //!< Log message I_CHILDREN = 10, //!< Children @@ -180,9 +180,9 @@ typedef enum { I_SIGNING_PRESENTATION = 15, //!< Provides signing related preferences (first byte is preference version) I_NONCE_REQUEST = 16, //!< Request for a nonce I_NONCE_RESPONSE = 17, //!< Payload is nonce data - I_HEARTBEAT = 18, //!< Heartbeat request + I_HEARTBEAT_REQUEST = 18, //!< Heartbeat request I_PRESENTATION = 19, //!< Presentation message - I_DISCOVER = 20, //!< Discover request + I_DISCOVER_REQUEST = 20, //!< Discover request I_DISCOVER_RESPONSE = 21, //!< Discover response I_HEARTBEAT_RESPONSE = 22, //!< Heartbeat response I_LOCKED = 23, //!< Node is locked (reason in string-payload) diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 0be57819e..9afd2d5b4 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -330,7 +330,7 @@ bool _processInternalMessages() { // Re-send node presentation to controller presentNode(); } - else if (type == I_HEARTBEAT) { + else if (type == I_HEARTBEAT_REQUEST) { sendHeartbeat(); } else if (type == I_TIME) { diff --git a/core/MySigning.cpp b/core/MySigning.cpp index a1081a435..c0013b7ec 100644 --- a/core/MySigning.cpp +++ b/core/MySigning.cpp @@ -84,11 +84,11 @@ static bool skipSign(MyMessage &msg) { SIGN_DEBUG(PSTR("Skipping security for ACK on command %d type %d\n"), mGetCommand(msg), msg.type); return true; } else if (mGetCommand(msg) == C_INTERNAL && - (msg.type == I_NONCE_REQUEST || msg.type == I_NONCE_RESPONSE || msg.type == I_SIGNING_PRESENTATION || - msg.type == I_ID_REQUEST || msg.type == I_ID_RESPONSE || - msg.type == I_FIND_PARENT || msg.type == I_FIND_PARENT_RESPONSE || - msg.type == I_HEARTBEAT || msg.type == I_HEARTBEAT_RESPONSE || - msg.type == I_PING || msg.type == I_PONG || + (msg.type == I_NONCE_REQUEST || msg.type == I_NONCE_RESPONSE || msg.type == I_SIGNING_PRESENTATION || + msg.type == I_ID_REQUEST || msg.type == I_ID_RESPONSE || + 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 )) { SIGN_DEBUG(PSTR("Skipping security for command %d type %d\n"), mGetCommand(msg), msg.type); return true; diff --git a/core/MyTransport.cpp b/core/MyTransport.cpp index a54c34dd7..63239855f 100644 --- a/core/MyTransport.cpp +++ b/core/MyTransport.cpp @@ -101,7 +101,7 @@ void stParentTransition() { _nc.distance = DISTANCE_INVALID; // Set distance to max and invalidate parent node ID _nc.parentNodeId = AUTO; // Broadcast find parent request - transportRouteMessage(build(_msgTmp, _nc.nodeId, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT, false).set("")); + transportRouteMessage(build(_msgTmp, _nc.nodeId, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_REQUEST, false).set("")); #endif } @@ -509,7 +509,7 @@ void transportProcessMessage() { if (type == I_FIND_PARENT_RESPONSE) { #if !defined(MY_GATEWAY_FEATURE) && !defined(MY_PARENT_NODE_IS_STATIC) if (_transportSM.findingParentNode) { // only process if find parent active - // Reply to a I_FIND_PARENT message. Check if the distance is shorter than we already have. + // Reply to a I_FIND_PARENT_REQUEST message. Check if the distance is shorter than we already have. uint8_t distance = _msg.getByte(); TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR RES,ID=%d,D=%d\n"), sender, distance); // find parent response if (isValidDistance(distance)) { @@ -579,7 +579,7 @@ void transportProcessMessage() { if (command == C_INTERNAL) { if (isTransportReady()) { // only reply if node is fully operational - if (type == I_FIND_PARENT) { + if (type == I_FIND_PARENT_REQUEST) { #if defined(MY_REPEATER_FEATURE) if (sender != _nc.parentNodeId) { // no circular reference TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR REQ,ID=%d\n"), sender); // FPR: find parent request @@ -603,7 +603,7 @@ void transportProcessMessage() { return; // no further processing required } } - if (type == I_DISCOVER) { + if (type == I_DISCOVER_REQUEST) { if (last == _nc.parentNodeId) { // random wait to minimize collisions delay(hwMillis() & 0x3ff); From de896e1827e8b647f7216ae27e6f7288af0a6103 Mon Sep 17 00:00:00 2001 From: tekka007 Date: Mon, 8 Aug 2016 17:48:07 +0200 Subject: [PATCH 034/167] Set protocol version in MyMessage::clear() --- core/MyMessage.cpp | 5 ++++- core/MyMessage.h | 3 +++ core/MyTransport.cpp | 3 +-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/core/MyMessage.cpp b/core/MyMessage.cpp index 027b273af..1f330de2f 100644 --- a/core/MyMessage.cpp +++ b/core/MyMessage.cpp @@ -44,7 +44,10 @@ void MyMessage::clear() command_ack_payload = 0u; type = 0u; sensor = 0u; - (void)memset(data, 0u, sizeof(data)); + (void)memset(data, 0u, sizeof(data)); + + // set message protocol version + miSetVersion(PROTOCOL_VERSION); } bool MyMessage::isAck() const { diff --git a/core/MyMessage.h b/core/MyMessage.h index aa84b49a6..6f74e5208 100644 --- a/core/MyMessage.h +++ b/core/MyMessage.h @@ -257,6 +257,9 @@ typedef enum { #define miSetLength(_length) BF_SET(version_length, _length, 3, 5) //!< Internal setter for length field #define miGetLength() ((uint8_t)BF_GET(version_length, 3, 5)) //!< Internal getter for length field +#define miSetVersion(_version) BF_SET(version_length, _version, 0, 2) //!< Internal setter for version field +#define miGetVersion() ((uint8_t)BF_GET(version_length, 0, 2)) //!< Internal getter for version field + #define miSetRequestAck(_rack) BF_SET(command_ack_payload, _rack, 3, 1) //!< Internal setter for ack-request field #define miGetRequestAck() ((bool)BF_GET(command_ack_payload, 3, 1)) //!< Internal getter for ack-request field diff --git a/core/MyTransport.cpp b/core/MyTransport.cpp index a54c34dd7..da00b61d3 100644 --- a/core/MyTransport.cpp +++ b/core/MyTransport.cpp @@ -692,8 +692,7 @@ inline void transportProcessFIFO() { } bool transportSendWrite(uint8_t to, MyMessage &message) { - // set protocol version and update last - mSetVersion(message, PROTOCOL_VERSION); + // Update last message.last = _nc.nodeId; // sign message if required From 6bc4a374ed63683b681ae0d383fa10114bfa7e4a Mon Sep 17 00:00:00 2001 From: tekka007 Date: Mon, 8 Aug 2016 19:40:00 +0200 Subject: [PATCH 035/167] Use _msgTmp when building messages --- core/MyGatewayTransport.cpp | 6 +++++- core/MyGatewayTransportEthernet.cpp | 14 ++++++++------ core/MyGatewayTransportSerial.cpp | 4 +++- core/MyInclusionMode.cpp | 5 ++++- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/core/MyGatewayTransport.cpp b/core/MyGatewayTransport.cpp index beb16d2e7..f4e98f413 100644 --- a/core/MyGatewayTransport.cpp +++ b/core/MyGatewayTransport.cpp @@ -20,7 +20,11 @@ #include "MyGatewayTransport.h" extern bool transportSendRoute(MyMessage &message); + +// global variables extern MyMessage _msg; +extern MyMessage _msgTmp; +extern NodeConfig _nc; inline void gatewayTransportProcess() { @@ -41,7 +45,7 @@ inline void gatewayTransportProcess() { if (mGetCommand(_msg) == C_INTERNAL) { if (_msg.type == I_VERSION) { // Request for version. Create the response - gatewayTransportSend(buildGw(_msg, I_VERSION).set(MYSENSORS_LIBRARY_VERSION)); + gatewayTransportSend(buildGw(_msgTmp, I_VERSION).set(MYSENSORS_LIBRARY_VERSION)); #ifdef MY_INCLUSION_MODE_FEATURE } else if (_msg.type == I_INCLUSION_MODE) { // Request to change inclusion mode diff --git a/core/MyGatewayTransportEthernet.cpp b/core/MyGatewayTransportEthernet.cpp index 6c930e72b..cef41e7be 100644 --- a/core/MyGatewayTransportEthernet.cpp +++ b/core/MyGatewayTransportEthernet.cpp @@ -19,6 +19,10 @@ #include "MyGatewayTransport.h" + // global variables +extern MyMessage _msgTmp; + + #if defined(MY_CONTROLLER_IP_ADDRESS) IPAddress _ethernetControllerIP(MY_CONTROLLER_IP_ADDRESS); #endif @@ -32,8 +36,6 @@ MyMessage _ethernetMsg; #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) -// gatewayTransportSend(buildGw(_msg, I_GATEWAY_READY).set("Gateway startup complete.")); - typedef struct { char string[MY_GATEWAY_MAX_RECEIVE_LENGTH]; @@ -113,7 +115,7 @@ bool gatewayTransportInit() { while (WiFi.status() != WL_CONNECTED) { delay(500); - MY_SERIALDEVICE.print("."); + MY_SERIALDEVICE.print(F(".")); yield(); } MY_SERIALDEVICE.print(F("IP: ")); @@ -126,7 +128,7 @@ bool gatewayTransportInit() { #else // Get IP address from DHCP if (!Ethernet.begin(_ethernetGatewayMAC)) { - MY_SERIALDEVICE.print("DHCP FAILURE..."); + MY_SERIALDEVICE.print(F("DHCP FAILURE...")); _w5100_spi_en(false); return false; } @@ -300,7 +302,7 @@ bool gatewayTransportAvailable() clients[i] = _ethernetServer.available(); inputString[i].idx = 0; debug(PSTR("Client %d connected\n"), i); - gatewayTransportSend(buildGw(_msg, I_GATEWAY_READY).set("Gateway startup complete.")); + gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete.")); // Send presentation of locally attached sensors (and node if applicable) presentNode(); } @@ -333,7 +335,7 @@ bool gatewayTransportAvailable() client = newclient; debug(PSTR("Eth: connect\n")); _w5100_spi_en(false); - gatewayTransportSend(buildGw(_msg, I_GATEWAY_READY).set("Gateway startup complete.")); + gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete.")); _w5100_spi_en(true); presentNode(); } diff --git a/core/MyGatewayTransportSerial.cpp b/core/MyGatewayTransportSerial.cpp index f7c35c840..bbad4b3c0 100644 --- a/core/MyGatewayTransportSerial.cpp +++ b/core/MyGatewayTransportSerial.cpp @@ -24,6 +24,8 @@ #include "MyMessage.h" #include "MyProtocol.h" + // global variables +extern MyMessage _msgTmp; char _serialInputString[MY_GATEWAY_MAX_RECEIVE_LENGTH]; // A buffer for incoming commands from serial interface int _serialInputPos; @@ -38,7 +40,7 @@ bool gatewayTransportSend(MyMessage &message) { } bool gatewayTransportInit() { - gatewayTransportSend(buildGw(_msg, I_GATEWAY_READY).set("Gateway startup complete.")); + gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete.")); // Send presentation of locally attached sensors (and node if applicable) presentNode(); diff --git a/core/MyInclusionMode.cpp b/core/MyInclusionMode.cpp index e55612f3b..ea2198c57 100644 --- a/core/MyInclusionMode.cpp +++ b/core/MyInclusionMode.cpp @@ -19,6 +19,9 @@ #include "MyInclusionMode.h" + // global variables +extern MyMessage _msgTmp; + unsigned long _inclusionStartTime; bool _inclusionMode; @@ -37,7 +40,7 @@ void inclusionModeSet(bool newMode) { if (newMode != _inclusionMode) { _inclusionMode = newMode; // Send back mode change to controller - gatewayTransportSend(buildGw(_msg, I_INCLUSION_MODE).set((uint8_t)(_inclusionMode?1:0))); + gatewayTransportSend(buildGw(_msgTmp, I_INCLUSION_MODE).set((uint8_t)(_inclusionMode?1:0))); if (_inclusionMode) { _inclusionStartTime = hwMillis(); } From a1a5d0d7070192e6c357da07aa559bbb8fb1d837 Mon Sep 17 00:00:00 2001 From: tekka007 Date: Tue, 9 Aug 2016 09:18:35 +0200 Subject: [PATCH 036/167] Rename macro param (_msg) to avoid confusions --- core/MyMessage.h | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/core/MyMessage.h b/core/MyMessage.h index 098d05e94..a4fe002e8 100644 --- a/core/MyMessage.h +++ b/core/MyMessage.h @@ -229,26 +229,26 @@ typedef enum { #define BF_SET(y, x, start, len) ( y= ((y) &~ BF_MASK(start, len)) | BF_PREP(x, start, len) ) //!< Insert a new bitfield value 'x' into 'y' // Getters/setters for special bit fields in header -#define mSetVersion(_msg,_version) BF_SET(_msg.version_length, _version, 0, 2) //!< Set version field -#define mGetVersion(_msg) ((uint8_t)BF_GET(_msg.version_length, 0, 2)) //!< Get version field +#define mSetVersion(_message,_version) BF_SET(_message.version_length, _version, 0, 2) //!< Set version field +#define mGetVersion(_message) ((uint8_t)BF_GET(_message.version_length, 0, 2)) //!< Get version field -#define mSetSigned(_msg,_signed) BF_SET(_msg.version_length, _signed, 2, 1) //!< Set signed field -#define mGetSigned(_msg) ((bool)BF_GET(_msg.version_length, 2, 1)) //!< Get versignedsion field +#define mSetSigned(_message,_signed) BF_SET(_message.version_length, _signed, 2, 1) //!< Set signed field +#define mGetSigned(_message) ((bool)BF_GET(_message.version_length, 2, 1)) //!< Get versignedsion field -#define mSetLength(_msg,_length) BF_SET(_msg.version_length, _length, 3, 5) //!< Set length field -#define mGetLength(_msg) ((uint8_t)BF_GET(_msg.version_length, 3, 5)) //!< Get length field +#define mSetLength(_message,_length) BF_SET(_message.version_length, _length, 3, 5) //!< Set length field +#define mGetLength(_message) ((uint8_t)BF_GET(_message.version_length, 3, 5)) //!< Get length field -#define mSetCommand(_msg,_command) BF_SET(_msg.command_ack_payload, _command, 0, 3) //!< Set command field -#define mGetCommand(_msg) ((uint8_t)BF_GET(_msg.command_ack_payload, 0, 3)) //!< Get command field +#define mSetCommand(_message,_command) BF_SET(_message.command_ack_payload, _command, 0, 3) //!< Set command field +#define mGetCommand(_message) ((uint8_t)BF_GET(_message.command_ack_payload, 0, 3)) //!< Get command field -#define mSetRequestAck(_msg,_rack) BF_SET(_msg.command_ack_payload, _rack, 3, 1) //!< Set ack-request field -#define mGetRequestAck(_msg) ((bool)BF_GET(_msg.command_ack_payload, 3, 1)) //!< Get ack-request field +#define mSetRequestAck(_message,_rack) BF_SET(_message.command_ack_payload, _rack, 3, 1) //!< Set ack-request field +#define mGetRequestAck(_message) ((bool)BF_GET(_message.command_ack_payload, 3, 1)) //!< Get ack-request field -#define mSetAck(_msg,_ackMsg) BF_SET(_msg.command_ack_payload, _ackMsg, 4, 1) //!< Set ack field -#define mGetAck(_msg) ((bool)BF_GET(_msg.command_ack_payload, 4, 1)) //!< Get ack field +#define mSetAck(_message,_ackMsg) BF_SET(_message.command_ack_payload, _ackMsg, 4, 1) //!< Set ack field +#define mGetAck(_message) ((bool)BF_GET(_message.command_ack_payload, 4, 1)) //!< Get ack field -#define mSetPayloadType(_msg, _pt) BF_SET(_msg.command_ack_payload, _pt, 5, 3) //!< Set payload type field -#define mGetPayloadType(_msg) ((uint8_t)BF_GET(_msg.command_ack_payload, 5, 3)) //!< Get payload type field +#define mSetPayloadType(_message, _pt) BF_SET(_message.command_ack_payload, _pt, 5, 3) //!< Set payload type field +#define mGetPayloadType(_message) ((uint8_t)BF_GET(_message.command_ack_payload, 5, 3)) //!< Get payload type field // internal access for special fields From e9b1ab287c7bbb28e6567fc434a01ef737bbfd55 Mon Sep 17 00:00:00 2001 From: tekka007 Date: Tue, 9 Aug 2016 18:45:10 +0200 Subject: [PATCH 037/167] Add debug output for before() and setup() --- core/MySensorsCore.cpp | 5 ++++- core/MySensorsCore.h | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 9afd2d5b4..8e5a5fad2 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -76,8 +76,10 @@ void _begin() { debug(PSTR("MCO:BGN:INIT " MY_NODE_TYPE ",CP=" MY_CAPABILITIES ",VER=" MYSENSORS_LIBRARY_VERSION "\n")); // Call before() in sketch (if it exists) - if (before) + if (before) { + debug(PSTR("MCO:BGN:BFR\n")); // before callback before(); + } #if defined(MY_LEDS_BLINKING_FEATURE) ledsInit(); @@ -158,6 +160,7 @@ void _begin() { // Call sketch setup if (setup) { + debug(PSTR("MCO:BGN:STP\n")); // setup callback setup(); } diff --git a/core/MySensorsCore.h b/core/MySensorsCore.h index e3064778a..567684034 100644 --- a/core/MySensorsCore.h +++ b/core/MySensorsCore.h @@ -40,6 +40,8 @@ * |E| SYS | SUB | Message | Comment * |-|------|-------|-------------------------------------------|---------------------------------------------------------------------------- * | | MCO | BGN | INIT %%s,CP=%%s,LIB=%%s | Core initialization, capabilities (CP), library version (VER) + * | | MCO | BGN | BFR | Callback before() + * | | MCO | BGN | STP | Callback setup() * | | MCO | BGN | INIT OK,ID=%%d,PAR=%%d,DIS=%%d,REG=%%d | Core initialized, parent ID (PAR), distance to GW (DIS), registration (REG) * | | MCO | BGN | NODE UNLOCKED | Node successfully unlocked (see signing chapter) * |!| MCO | BGN | TSP FAIL | Transport initialization failed From 94348cec1ad8976e203ddb6d49484281e60e6116 Mon Sep 17 00:00:00 2001 From: tekka007 Date: Wed, 10 Aug 2016 12:08:44 +0200 Subject: [PATCH 038/167] Limit payload size to MAX_PAYLOAD_SIZE --- core/MyMessage.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/MyMessage.cpp b/core/MyMessage.cpp index 1f330de2f..a0ee9d007 100644 --- a/core/MyMessage.cpp +++ b/core/MyMessage.cpp @@ -210,9 +210,10 @@ MyMessage& MyMessage::setDestination(uint8_t _destination) { // Set payload MyMessage& MyMessage::set(void* value, uint8_t length) { + uint8_t payloadLength = value == NULL ? 0 : min(length, MAX_PAYLOAD); + miSetLength(payloadLength); miSetPayloadType(P_CUSTOM); - miSetLength(length); - memcpy(data, value, min(length, MAX_PAYLOAD)); + memcpy(data, value, payloadLength); return *this; } From 9441b30d30a39689ba508be921a058237fb52e65 Mon Sep 17 00:00:00 2001 From: tekka007 Date: Fri, 12 Aug 2016 16:21:54 +0200 Subject: [PATCH 039/167] Remove duplicate va_end() --- core/MyHwATMega328.cpp | 7 +++---- core/MyHwATMega328.h | 2 ++ core/MyHwESP8266.cpp | 7 +++---- core/MyHwESP8266.h | 2 ++ core/MyHwSAMD.cpp | 7 +++---- core/MyHwSAMD.h | 1 + 6 files changed, 14 insertions(+), 12 deletions(-) diff --git a/core/MyHwATMega328.cpp b/core/MyHwATMega328.cpp index 349e77540..100d7ed96 100644 --- a/core/MyHwATMega328.cpp +++ b/core/MyHwATMega328.cpp @@ -198,22 +198,21 @@ uint16_t hwFreeMem() { #ifdef MY_DEBUG void hwDebugPrint(const char *fmt, ... ) { - char fmtBuffer[300]; + char fmtBuffer[MY_DEBUG_BUFFER_SIZE]; #ifdef MY_GATEWAY_FEATURE // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) - snprintf_P(fmtBuffer, 299, PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); + snprintf_P(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); MY_SERIALDEVICE.print(fmtBuffer); #endif va_list args; va_start (args, fmt ); - va_end (args); #ifdef MY_GATEWAY_FEATURE // Truncate message if this is gateway node vsnprintf_P(fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, fmt, args); fmtBuffer[MY_GATEWAY_MAX_SEND_LENGTH-1] = '\n'; fmtBuffer[MY_GATEWAY_MAX_SEND_LENGTH] = '\0'; #else - vsnprintf_P(fmtBuffer, 299, fmt, args); + vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args); #endif va_end (args); MY_SERIALDEVICE.print(fmtBuffer); diff --git a/core/MyHwATMega328.h b/core/MyHwATMega328.h index 157ecb1fd..8d6c1025d 100644 --- a/core/MyHwATMega328.h +++ b/core/MyHwATMega328.h @@ -35,6 +35,8 @@ #endif #define MY_SERIALDEVICE Serial +#define MY_DEBUG_BUFFER_SIZE 300 + #if defined __AVR_ATmega328P__ #ifndef sleep_bod_disable #define sleep_bod_disable() \ diff --git a/core/MyHwESP8266.cpp b/core/MyHwESP8266.cpp index 1e501565f..3c1010550 100644 --- a/core/MyHwESP8266.cpp +++ b/core/MyHwESP8266.cpp @@ -132,22 +132,21 @@ uint16_t hwFreeMem() { #ifdef MY_DEBUG void hwDebugPrint(const char *fmt, ... ) { - char fmtBuffer[300]; + char fmtBuffer[MY_DEBUG_BUFFER_SIZE]; #ifdef MY_GATEWAY_FEATURE // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) - snprintf_P(fmtBuffer, 299, PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); + snprintf_P(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); MY_SERIALDEVICE.print(fmtBuffer); #endif va_list args; va_start (args, fmt ); - va_end (args); #ifdef MY_GATEWAY_FEATURE // Truncate message if this is gateway node vsnprintf_P(fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, fmt, args); fmtBuffer[MY_GATEWAY_MAX_SEND_LENGTH-1] = '\n'; fmtBuffer[MY_GATEWAY_MAX_SEND_LENGTH] = '\0'; #else - vsnprintf_P(fmtBuffer, 299, fmt, args); + vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args); #endif va_end (args); MY_SERIALDEVICE.print(fmtBuffer); diff --git a/core/MyHwESP8266.h b/core/MyHwESP8266.h index 1495e6902..ffbcb6906 100644 --- a/core/MyHwESP8266.h +++ b/core/MyHwESP8266.h @@ -26,6 +26,8 @@ #endif #define MY_SERIALDEVICE Serial +#define MY_DEBUG_BUFFER_SIZE 300 + #define min(a,b) ((a)<(b)?(a):(b)) #define max(a,b) ((a)>(b)?(a):(b)) diff --git a/core/MyHwSAMD.cpp b/core/MyHwSAMD.cpp index 264da9c17..2d8550137 100644 --- a/core/MyHwSAMD.cpp +++ b/core/MyHwSAMD.cpp @@ -156,22 +156,21 @@ uint16_t hwFreeMem() { #ifdef MY_DEBUG void hwDebugPrint(const char *fmt, ... ) { if (MY_SERIALDEVICE) { - char fmtBuffer[300]; + char fmtBuffer[MY_DEBUG_BUFFER_SIZE]; #ifdef MY_GATEWAY_FEATURE // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) - snprintf(fmtBuffer, 299, PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); + snprintf(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); MY_SERIALDEVICE.print(fmtBuffer); #endif va_list args; va_start (args, fmt ); - va_end (args); #ifdef MY_GATEWAY_FEATURE // Truncate message if this is gateway node vsnprintf(fmtBuffer, 60, fmt, args); fmtBuffer[59] = '\n'; fmtBuffer[60] = '\0'; #else - vsnprintf(fmtBuffer, 299, fmt, args); + vsnprintf(fmtBuffer, sizeof(fmtBuffer), fmt, args); #endif va_end (args); MY_SERIALDEVICE.print(fmtBuffer); diff --git a/core/MyHwSAMD.h b/core/MyHwSAMD.h index dcb783c20..dce2dbacc 100644 --- a/core/MyHwSAMD.h +++ b/core/MyHwSAMD.h @@ -50,6 +50,7 @@ void hwWriteConfig(int adr, uint8_t value); uint8_t hwReadConfig(int adr); #define MY_SERIALDEVICE SerialUSB +#define MY_DEBUG_BUFFER_SIZE 300 /* From cc08240e5da7cfd3f7b5e18f2ec9659346fade43 Mon Sep 17 00:00:00 2001 From: tekka007 Date: Fri, 12 Aug 2016 21:15:12 +0200 Subject: [PATCH 040/167] Update FW OTA logs and doxygenize lib --- core/MyOTAFirmwareUpdate.cpp | 35 ++++++----- core/MyOTAFirmwareUpdate.h | 110 ++++++++++++++++++++++++----------- 2 files changed, 96 insertions(+), 49 deletions(-) diff --git a/core/MyOTAFirmwareUpdate.cpp b/core/MyOTAFirmwareUpdate.cpp index 73f7488b3..e30cf97a0 100644 --- a/core/MyOTAFirmwareUpdate.cpp +++ b/core/MyOTAFirmwareUpdate.cpp @@ -19,6 +19,12 @@ #include "MyOTAFirmwareUpdate.h" +// global variables +extern MyMessage _msg; +extern MyMessage _msgTmp; +extern NodeConfig _nc; + +// local variables SPIFlash _flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID); NodeFirmwareConfig _fc; bool _fwUpdateOngoing; @@ -26,16 +32,16 @@ unsigned long _fwLastRequestTime; uint16_t _fwBlock; uint8_t _fwRetry; -inline void readFirmwareSettings() { +void readFirmwareSettings() { hwReadConfigBlock((void*)&_fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); } -inline void firmwareOTAUpdateRequest() { +void firmwareOTAUpdateRequest() { unsigned long enter = hwMillis(); if (_fwUpdateOngoing && (enter - _fwLastRequestTime > MY_OTA_RETRY_DELAY)) { if (!_fwRetry) { setIndication(INDICATION_ERR_FW_TIMEOUT); - debug(PSTR("fw upd fail\n")); + OTA_DEBUG(PSTR("!OTA:FRQ:FW UPD FAIL\n")); // fw update failed // Give up. We have requested MY_OTA_RETRY times without any packet in return. _fwUpdateOngoing = false; return; @@ -47,24 +53,24 @@ inline void firmwareOTAUpdateRequest() { firmwareRequest.type = _fc.type; firmwareRequest.version = _fc.version; firmwareRequest.block = (_fwBlock - 1); - debug(PSTR("req FW: T=%02X, V=%02X, B=%04X\n"),_fc.type,_fc.version,_fwBlock - 1); + OTA_DEBUG(PSTR("OTA:FRQ:FW REQ,T=%04X,V=%04X,B=%04X\n"),_fc.type,_fc.version,_fwBlock - 1); // request FW update block _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_REQUEST, false).set(&firmwareRequest,sizeof(RequestFWBlock))); } } -inline bool firmwareOTAUpdateProcess() { +bool firmwareOTAUpdateProcess() { if (_msg.type == ST_FIRMWARE_CONFIG_RESPONSE) { NodeFirmwareConfig *firmwareConfigResponse = (NodeFirmwareConfig *)_msg.data; // compare with current node configuration, if they differ, start fw fetch process if (memcmp(&_fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig))) { setIndication(INDICATION_FW_UPDATE_START); - debug(PSTR("fw update\n")); + OTA_DEBUG(PSTR("OTA:FWP:UPDATE\n")); // FW update initiated // copy new FW config memcpy(&_fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig)); // Init flash if (!_flash.initialize()) { setIndication(INDICATION_ERR_FW_FLASH_INIT); - debug(PSTR("flash init fail\n")); + OTA_DEBUG(PSTR("!OTA:FWP:FLASH INIT FAIL\n")); // failed to initialise flash _fwUpdateOngoing = false; } else { // erase lower 32K -> max flash size for ATMEGA328 @@ -79,12 +85,12 @@ inline bool firmwareOTAUpdateProcess() { } return true; } - debug(PSTR("fw update skipped\n")); + OTA_DEBUG(PSTR("OTA:FWP:UPDATE SKIPPED\n")); // FW update skipped, no newer version available } else if (_msg.type == ST_FIRMWARE_RESPONSE) { if (_fwUpdateOngoing) { // Save block to flash setIndication(INDICATION_FW_UPDATE_RX); - debug(PSTR("fw block %d\n"), _fwBlock); + OTA_DEBUG(PSTR("OTA:FWP:RECV B=%04X\n"), _fwBlock); // received FW block // extract FW block ReplyFWBlock *firmwareResponse = (ReplyFWBlock *)_msg.data; // write to flash @@ -94,9 +100,10 @@ inline bool firmwareOTAUpdateProcess() { _fwBlock--; if (!_fwBlock) { // We're finished! Do a checksum and reboot. + OTA_DEBUG(PSTR("OTA:FWP:FW END\n")); // received FW block _fwUpdateOngoing = false; if (transportIsValidFirmware()) { - debug(PSTR("fw checksum ok\n")); + OTA_DEBUG(PSTR("OTA:FWP:CRC OK\n")); // FW checksum ok // All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it) uint16_t fwsize = FIRMWARE_BLOCK_SIZE * _fc.blocks; uint8_t OTAbuffer[10] = {'F','L','X','I','M','G',':',(uint8_t)(fwsize >> 8),(uint8_t)(fwsize & 0xff),':'}; @@ -106,21 +113,21 @@ inline bool firmwareOTAUpdateProcess() { hwReboot(); } else { setIndication(INDICATION_ERR_FW_CHECKSUM); - debug(PSTR("fw checksum fail\n")); + OTA_DEBUG(PSTR("!OTA:FWP:CRC FAIL\n")); } } // reset flags _fwRetry = MY_OTA_RETRY+1; _fwLastRequestTime = 0; } else { - debug(PSTR("No fw update ongoing\n")); + OTA_DEBUG(PSTR("!OTA:FWP:NO UPDATE\n")); } return true; } return false; } -inline void presentBootloaderInformation(){ +void presentBootloaderInformation(){ RequestFirmwareConfig *reqFWConfig = (RequestFirmwareConfig *)_msgTmp.data; mSetLength(_msgTmp, sizeof(RequestFirmwareConfig)); mSetCommand(_msgTmp, C_STREAM); @@ -133,7 +140,7 @@ inline void presentBootloaderInformation(){ _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_CONFIG_REQUEST, false)); } // do a crc16 on the whole received firmware -inline bool transportIsValidFirmware() { +bool transportIsValidFirmware() { // init crc uint16_t crc = ~0; for (uint16_t i = 0; i < _fc.blocks * FIRMWARE_BLOCK_SIZE; ++i) { diff --git a/core/MyOTAFirmwareUpdate.h b/core/MyOTAFirmwareUpdate.h index 3c3921d44..7153eac3e 100644 --- a/core/MyOTAFirmwareUpdate.h +++ b/core/MyOTAFirmwareUpdate.h @@ -17,57 +17,95 @@ * version 2 as published by the Free Software Foundation. */ + /** + * @file MyOTAFirmwareUpdate.h + * + * @defgroup MyOTAFirmwaregrp MyOTAFirmwareUpdate + * @ingroup internals + * @{ + * + * MyOTAFirmwareUpdate-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE + * - [!] Exclamation mark is prepended in case of error or warning + * - SYSTEM: + * - OTA messages emitted by MyOTAFirmwareUpdate + * - SUB SYSTEMS: + * - OTA:FRQ from @ref firmwareOTAUpdateRequest() + * - OTA:FWP from @ref firmwareOTAUpdateProcess() + * + * MyOTAFirmwareUpdate debug log messages: + * + * |E| SYS | SUB | Message | Comment + * |-|------|-------|-------------------------------------------|---------------------------------------------------------------------------- + * | | OTA | FWP | UPDATE | FW update initiated + * |!| 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 | FW END | FW received, proceed to CRC verification + * | | OTA | FWP | CRC OK | FW CRC verification OK + * |!| OTA | FWP | CRC FAIL | FW CRC verification failed + * | | OTA | FRQ | FW REQ,T=%04X,V=%04X,B=%04X | Request FW update, FW type (T), version (V), block (B) + * |!| OTA | FRQ | FW UPD FAIL | FW update failed + * + * + * @brief API declaration for MyOTAFirmwareUpdate + */ + + #ifndef MyOTAFirmwareUpdate_h #define MyOTAFirmwareUpdate_h #include "MySensorsCore.h" -// Size of each firmware block -#define FIRMWARE_BLOCK_SIZE 16 -// Number of times a firmware block should be requested before giving up -#define FIRMWARE_MAX_REQUESTS 5 -// Number of times to request a fw block before giving up -#define MY_OTA_RETRY 5 -// Number of millisecons before re-request a fw block -#define MY_OTA_RETRY_DELAY 500 -// Start offset for firmware in flash (DualOptiboot wants to keeps a signature first) -#define FIRMWARE_START_OFFSET 10 -// Bootloader version -#define MY_OTA_BOOTLOADER_MAJOR_VERSION 3 -#define MY_OTA_BOOTLOADER_MINOR_VERSION 0 -#define MY_OTA_BOOTLOADER_VERSION (MY_OTA_BOOTLOADER_MINOR_VERSION * 256 + MY_OTA_BOOTLOADER_MAJOR_VERSION) +#define FIRMWARE_BLOCK_SIZE (16) //!< Size of each firmware block +#define FIRMWARE_MAX_REQUESTS (5) //!< Number of times a firmware block should be requested before giving up +#define MY_OTA_RETRY (5) //!< Number of times to request a fw block before giving up +#define MY_OTA_RETRY_DELAY (500) //!< Number of milliseconds before re-requesting a FW block +#define FIRMWARE_START_OFFSET (10) //!< Start offset for firmware in flash (DualOptiboot wants to keeps a signature first) + +#define MY_OTA_BOOTLOADER_MAJOR_VERSION (3) //!< Bootloader version major +#define MY_OTA_BOOTLOADER_MINOR_VERSION (0) //!< Bootloader version minor +#define MY_OTA_BOOTLOADER_VERSION (MY_OTA_BOOTLOADER_MINOR_VERSION * 256 + MY_OTA_BOOTLOADER_MAJOR_VERSION) //!< Bootloader version +#define OTA_DEBUG(x,...) debug(x, ##__VA_ARGS__) //!< debug -/// @brief FW config structure, stored in eeprom +/** +* @brief FW config structure, stored in eeprom +*/ typedef struct { - uint16_t type; //!< Type of config - uint16_t version; //!< Version of config - uint16_t blocks; //!< Number of blocks - uint16_t crc; //!< CRC of block data + uint16_t type; //!< Type of config + uint16_t version; //!< Version of config + uint16_t blocks; //!< Number of blocks + uint16_t crc; //!< CRC of block data } __attribute__((packed)) NodeFirmwareConfig; -/// @brief FW config request structure +/** +* @brief FW config request structure +*/ typedef struct { - uint16_t type; //!< Type of config - uint16_t version; //!< Version of config - uint16_t blocks; //!< Number of blocks - uint16_t crc; //!< CRC of block data - uint16_t BLVersion; //!< Bootloader version + uint16_t type; //!< Type of config + uint16_t version; //!< Version of config + uint16_t blocks; //!< Number of blocks + uint16_t crc; //!< CRC of block data + uint16_t BLVersion; //!< Bootloader version } __attribute__((packed)) RequestFirmwareConfig; -/// @brief FW block request structure +/** +* @brief FW block request structure +*/ typedef struct { - uint16_t type; //!< Type of config - uint16_t version; //!< Version of config - uint16_t block; //!< Block index + uint16_t type; //!< Type of config + uint16_t version; //!< Version of config + uint16_t block; //!< Block index } __attribute__((packed)) RequestFWBlock; -/// @brief FW block reply structure +/** +* @brief FW block reply structure +*/ typedef struct { - uint16_t type; //!< Type of config - uint16_t version; //!< Version of config - uint16_t block; //!< Block index - uint8_t data[FIRMWARE_BLOCK_SIZE]; //!< Block data + uint16_t type; //!< Type of config + uint16_t version; //!< Version of config + uint16_t block; //!< Block index + uint8_t data[FIRMWARE_BLOCK_SIZE]; //!< Block data } __attribute__((packed)) ReplyFWBlock; @@ -98,4 +136,6 @@ bool transportIsValidFirmware(); */ void presentBootloaderInformation(); -#endif \ No newline at end of file +#endif + +/** @}*/ \ No newline at end of file From 9dcb06cdc55c160543e16b190242c0947193855c Mon Sep 17 00:00:00 2001 From: tekka007 Date: Sat, 13 Aug 2016 10:40:15 +0200 Subject: [PATCH 041/167] Reorganize RX message buffering checks - fix doxygen warning --- MyConfig.h | 15 +++++++++------ MySensors.h | 17 ----------------- core/MySensorsCore.h | 2 +- core/MyTransport.h | 12 ++++++++++++ core/MyTransportNRF24.cpp | 11 +++++------ drivers/RF24/RF24.cpp | 8 ++++---- drivers/RF24/RF24.h | 30 +++++++++++++++++++++++++----- keywords.txt | 1 + 8 files changed, 57 insertions(+), 39 deletions(-) diff --git a/MyConfig.h b/MyConfig.h index 5d04238da..9582a1da4 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -430,16 +430,18 @@ #endif /** - * @def MY_RF24_IRQ_PIN - * @brief Disable RF24 interrupt pin usage by default. Override in sketch if needed. - */ -//#define MY_RF24_IRQ_PIN +* @def MY_RX_MESSAGE_BUFFER_FEATURE +* @brief This enabled the receiving buffer feature. +* +* This feature is currently not supported for RFM69 and RS485, for RF24 MY_RF24_IRQ_PIN has to be defined. +*/ +//#define MY_RX_MESSAGE_BUFFER_FEATURE /** * @def MY_RX_MESSAGE_BUFFER_SIZE - * @brief Declare the amount of incoming messages that can be buffered. Requires MY_RADIO_NRF24 and MY_RF24_IRQ_PIN. Override in sketch if needed. + * @brief Declare the amount of incoming messages that can be buffered. */ -#ifdef MY_RF24_IRQ_PIN +#ifdef MY_RX_MESSAGE_BUFFER_FEATURE #ifndef MY_RX_MESSAGE_BUFFER_SIZE #define MY_RX_MESSAGE_BUFFER_SIZE (20) #endif @@ -711,6 +713,7 @@ #define MY_DEBUG_VERBOSE_RF24 #define MY_TRANSPORT_SANITY_CHECK #define MY_RF24_IRQ_PIN +#define MY_RX_MESSAGE_BUFFER_FEATURE #define MY_RX_MESSAGE_BUFFER_SIZE #define MY_NODE_LOCK_FEATURE #endif diff --git a/MySensors.h b/MySensors.h index a52d1be68..70bc9361c 100644 --- a/MySensors.h +++ b/MySensors.h @@ -255,23 +255,6 @@ #error Only one forward link driver can be activated #endif #if defined(MY_RADIO_NRF24) - #ifdef MY_RF24_IRQ_PIN - // SoftSPI does not support usingInterrupt() - #ifdef MY_SOFTSPI - #error RF24 IRQ usage cannot be used with Soft SPI - #endif - // ESP8266 does not support usingInterrupt() - #ifdef ESP8266 - #error RF24 IRQ usage cannot be used with ESP8266 - #endif - #ifndef SPI_HAS_TRANSACTION - #error RF24 IRQ usage requires transactional SPI support - #endif - #else - #ifdef MY_RX_MESSAGE_BUFFER_SIZE - #error Receive message buffering requires RF24 IRQ usage - #endif - #endif #if defined(MY_RF24_ENABLE_ENCRYPTION) #include "drivers/AES/AES.cpp" #endif diff --git a/core/MySensorsCore.h b/core/MySensorsCore.h index 567684034..d9dafa69b 100644 --- a/core/MySensorsCore.h +++ b/core/MySensorsCore.h @@ -33,7 +33,7 @@ * - MCO:REG from @ref _registerNode() * - MCO:SND from @ref send() * - MCO:PIM from @ref _processInternalMessages() - * - MCO:NLK from @ref nodeLock() + * - MCO:NLK from nodeLock() * * MySensorsCore debug log messages: * diff --git a/core/MyTransport.h b/core/MyTransport.h index 0b5a5c7c5..2267bee3b 100644 --- a/core/MyTransport.h +++ b/core/MyTransport.h @@ -147,6 +147,18 @@ #else #define TRANSMISSION_FAILURES 5 //!< search for a new parent node after this many transmission failures, lower threshold for non-repeating nodes #endif + +#if defined(MY_RX_MESSAGE_BUFFER_FEATURE) + #if defined(MY_RADIO_RFM69) + #error Receive message buffering not supported for RFM69! + #endif + #if defined(MY_RS485) + #error Receive message buffering not supported for RS485! + #endif +#elif !defined(MY_RX_MESSAGE_BUFFER_FEATURE) && defined(MY_RX_MESSAGE_BUFFER_SIZE) + #error Receive message buffering requires message buffering feature enabled! +#endif + #define TIMEOUT_FAILURE_STATE 10000 //!< duration failure state #define STATE_TIMEOUT 2000 //!< general state timeout #define STATE_RETRIES 3 //!< retries before switching to FAILURE diff --git a/core/MyTransportNRF24.cpp b/core/MyTransportNRF24.cpp index 6d7f40737..ffa0889d2 100644 --- a/core/MyTransportNRF24.cpp +++ b/core/MyTransportNRF24.cpp @@ -26,7 +26,7 @@ #include "drivers/AES/AES.h" #endif -#ifdef MY_RF24_IRQ_PIN +#if defined(MY_RX_MESSAGE_BUFFER_FEATURE) typedef struct _transportQueuedMessage { uint8_t m_len; // Length of the data @@ -76,7 +76,7 @@ bool transportInit() { memset(_psk, 0, 16); #endif - #ifdef MY_RF24_IRQ_PIN + #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) RF24_registerReceiveCallback( transportRxCallback ); #endif return RF24_initialize(); @@ -109,7 +109,7 @@ bool transportSend(uint8_t recipient, const void* data, uint8_t len) { } bool transportAvailable() { - #ifdef MY_RF24_IRQ_PIN + #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) (void)RF24_isDataAvailable; // Prevent 'defined but not used' warning return !transportRxQueue.empty(); #else @@ -123,10 +123,9 @@ bool transportSanityCheck() { uint8_t transportReceive(void* data) { uint8_t len = 0; - #ifdef MY_RF24_IRQ_PIN + #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) transportQueuedMessage* msg = transportRxQueue.getBack(); - if (msg) - { + if (msg) { len = msg->m_len; (void)memcpy(data, msg->m_data, len); (void)transportRxQueue.popBack(); diff --git a/drivers/RF24/RF24.cpp b/drivers/RF24/RF24.cpp index d263c1fe3..ea30f21d2 100644 --- a/drivers/RF24/RF24.cpp +++ b/drivers/RF24/RF24.cpp @@ -25,7 +25,7 @@ LOCAL uint8_t MY_RF24_BASE_ADDR[MY_RF24_ADDR_WIDTH] = { MY_RF24_BASE_RADIO_ID }; LOCAL uint8_t MY_RF24_NODE_ADDRESS = AUTO; -#ifdef MY_RF24_IRQ_PIN +#if defined(MY_RX_MESSAGE_BUFFER_FEATURE) LOCAL RF24_receiveCallbackType RF24_receiveCallback = NULL; #endif @@ -261,7 +261,7 @@ LOCAL bool RF24_sanityCheck(void) { return status; } -#ifdef MY_RF24_IRQ_PIN +#if defined(MY_RX_MESSAGE_BUFFER_FEATURE) LOCAL void RF24_irqHandler( void ) { if (RF24_receiveCallback) @@ -307,14 +307,14 @@ LOCAL bool RF24_initialize(void) { // Initialize pins pinMode(MY_RF24_CE_PIN,OUTPUT); pinMode(MY_RF24_CS_PIN,OUTPUT); - #ifdef MY_RF24_IRQ_PIN + #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) pinMode(MY_RF24_IRQ_PIN,INPUT); #endif // Initialize SPI _SPI.begin(); RF24_ce(LOW); RF24_csn(HIGH); - #ifdef MY_RF24_IRQ_PIN + #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) // assure SPI can be used from interrupt context // Note: ESP8266 & SoftSPI currently do not support interrupt usage for SPI, // therefore it is unsafe to use MY_RF24_IRQ_PIN with ESP8266/SoftSPI! diff --git a/drivers/RF24/RF24.h b/drivers/RF24/RF24.h index 765a434a2..77a4cf299 100644 --- a/drivers/RF24/RF24.h +++ b/drivers/RF24/RF24.h @@ -36,9 +36,6 @@ #if defined (ARDUINO) && !defined (__arm__) && !defined (_SPI) #if defined(MY_SOFTSPI) SoftSPI _SPI; - #elif defined(ARDUINO_ARCH_SAMD) - #include - #define _SPI SPI1 #else #include #define _SPI SPI @@ -61,8 +58,31 @@ #endif #endif +// verify RF24 IRQ defs +#if defined(MY_RX_MESSAGE_BUFFER_FEATURE) + #if !defined(MY_RF24_IRQ_PIN) + #error Message buffering feature requires MY_RF24_IRQ_PIN to be defined! + #endif + // SoftSPI does not support usingInterrupt() + #ifdef MY_SOFTSPI + #error RF24 IRQ usage cannot be used with Soft SPI + #endif + // ESP8266 does not support usingInterrupt() + #ifdef ARDUINO_ARCH_ESP8266 + #error RF24 IRQ usage cannot be used with ESP8266 + #endif + #ifndef SPI_HAS_TRANSACTION + #error RF24 IRQ usage requires transactional SPI support + #endif +#else + #ifdef MY_RX_MESSAGE_BUFFER_SIZE + #error Receive message buffering requires RF24 IRQ usage + #endif +#endif + + // RF24 settings -#ifdef MY_RF24_IRQ_PIN +#if defined(MY_RX_MESSAGE_BUFFER_FEATURE) #define MY_RF24_CONFIGURATION (uint8_t) ((RF24_CRC_16 << 2) | (1 << MASK_TX_DS) | (1 << MASK_MAX_RT)) #else #define MY_RF24_CONFIGURATION (uint8_t) (RF24_CRC_16 << 2) @@ -253,7 +273,7 @@ LOCAL void RF24_setPipeLSB(uint8_t pipe, uint8_t LSB); LOCAL void RF24_setStatus(uint8_t status); LOCAL void RF24_enableFeatures(void); -#ifdef MY_RF24_IRQ_PIN +#if defined(MY_RX_MESSAGE_BUFFER_FEATURE) typedef void (*RF24_receiveCallbackType)(void); /** * Register a callback, which will be called (from interrupt context) for every message received. diff --git a/keywords.txt b/keywords.txt index c38e03f45..77a25406e 100644 --- a/keywords.txt +++ b/keywords.txt @@ -74,6 +74,7 @@ MY_RF24_SPI_MAX_SPEED LITERAL1 MY_RF24_CE_PIN LITERAL1 MY_RF24_CS_PIN LITERAL1 MY_RF24_IRQ_PIN LITERAL1 +MY_RX_MESSAGE_BUFFER_FEATURE LITERAL1 MY_RF24_PA_LEVEL LITERAL1 MY_RF24_CHANNEL LITERAL1 MY_RF24_DATARATE LITERAL1 From ce2e2006c634c2bd2b2ea0e88ad2628dc042b2ad Mon Sep 17 00:00:00 2001 From: tekka007 Date: Sat, 13 Aug 2016 22:25:20 +0200 Subject: [PATCH 042/167] Minor updates --- drivers/RF24/RF24.cpp | 38 ++++++++++++++++++-------------------- drivers/RF24/RF24.h | 3 ++- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/drivers/RF24/RF24.cpp b/drivers/RF24/RF24.cpp index ea30f21d2..bd84c5609 100644 --- a/drivers/RF24/RF24.cpp +++ b/drivers/RF24/RF24.cpp @@ -66,7 +66,7 @@ LOCAL uint8_t RF24_spiByteTransfer(uint8_t cmd) { } LOCAL uint8_t RF24_RAW_readByteRegister(uint8_t cmd) { - uint8_t value = RF24_spiMultiByteTransfer( cmd, NULL, 1, true); + const uint8_t value = RF24_spiMultiByteTransfer( cmd, NULL, 1, true); RF24_DEBUG(PSTR("RF24:read register, reg=%d, value=%d\n"), cmd & (R_REGISTER ^ 0xFF), value); return value; } @@ -90,7 +90,7 @@ LOCAL uint8_t RF24_getStatus(void) { return RF24_spiByteTransfer( NOP ); } -LOCAL uint8_t RF24_getFifoStatus(void) { +LOCAL uint8_t RF24_getFIFOStatus(void) { return RF24_readByteRegister(FIFO_STATUS); } @@ -138,6 +138,10 @@ LOCAL void RF24_setPipeLSB(uint8_t pipe, uint8_t LSB) { RF24_writeByteRegister(pipe, LSB); } +LOCAL uint8_t RF24_getObserveTX(void) { + return RF24_readByteRegister(OBSERVE_TX); +} + LOCAL void RF24_setStatus(uint8_t status) { RF24_writeByteRegister(RF24_STATUS, status); } @@ -187,9 +191,8 @@ LOCAL bool RF24_sendMessage( uint8_t recipient, const void* buf, uint8_t len ) { // flush TX FIFO RF24_flushTX(); // this command is affected in clones (e.g. Si24R1): flipped NoACK bit when using W_TX_PAYLOAD_NO_ACK / W_TX_PAYLOAD - // RF24_spiMultiByteTransfer( recipient==BROADCAST_ADDRESS ? W_TX_PAYLOAD_NO_ACK : W_TX_PAYLOAD, (uint8_t*)buf, len, false ); - // we are safe by disabling AutoACK on the broadcasting pipe - RF24_spiMultiByteTransfer( W_TX_PAYLOAD, (uint8_t*)buf, len, false ); + // AutoACK is disabled on the broadcasting pipe - NO_ACK prevents resending + RF24_spiMultiByteTransfer(recipient == BROADCAST_ADDRESS ? W_TX_PAYLOAD_NO_ACK : W_TX_PAYLOAD, (uint8_t*)buf, len, false ); // go, TX starts after ~10us RF24_ce(HIGH); // timeout counter to detect HW issues @@ -207,10 +210,9 @@ LOCAL bool RF24_sendMessage( uint8_t recipient, const void* buf, uint8_t len ) { RF24_DEBUG(PSTR("RF24:MAX_RT\n")); RF24_flushTX(); } - RF24_startListening(); - // true if message sent and not timeout - return (status & _BV(TX_DS) && timeout); + // true if message sent + return ( status & _BV(TX_DS) ); } LOCAL uint8_t RF24_getDynamicPayloadSize(void) { @@ -224,15 +226,13 @@ LOCAL uint8_t RF24_getDynamicPayloadSize(void) { return result; } - LOCAL bool RF24_isDataAvailable() { - uint8_t status = RF24_getStatus(); - return (((status >> RX_P_NO) & 0b0111) <= 5); + return ( !(RF24_getFIFOStatus() & _BV(0)) ); } LOCAL uint8_t RF24_readMessage( void* buf) { - uint8_t len = RF24_getDynamicPayloadSize(); + const uint8_t len = RF24_getDynamicPayloadSize(); RF24_DEBUG(PSTR("RF24:read message, len=%d\n"), len); RF24_spiMultiByteTransfer( R_RX_PAYLOAD , (uint8_t*)buf, len, true ); // clear RX interrupt @@ -256,9 +256,7 @@ LOCAL uint8_t RF24_getNodeID(void) { LOCAL bool RF24_sanityCheck(void) { // detect HW defect, configuration errors or interrupted SPI line, CE disconnect cannot be detected - bool status = RF24_readByteRegister(RF_SETUP) == MY_RF24_RF_SETUP; - status &= RF24_readByteRegister(RF_CH) == MY_RF24_CHANNEL; - return status; + return (RF24_readByteRegister(RF_SETUP) == MY_RF24_RF_SETUP) & (RF24_readByteRegister(RF_CH) == MY_RF24_CHANNEL); } #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) @@ -281,7 +279,7 @@ LOCAL void RF24_irqHandler( void ) // Start checking if RX-FIFO is not empty, as we might end up here from an interrupt // for a message we've already read. - while (!(RF24_getFifoStatus() & _BV(0))) { + while (RF24_isDataAvailable()) { RF24_receiveCallback(); // Must call RF24_readMessage(), which will clear RX_DR IRQ ! } // Restore our interrupt handler. @@ -295,8 +293,7 @@ LOCAL void RF24_irqHandler( void ) } } -LOCAL void RF24_registerReceiveCallback( RF24_receiveCallbackType cb ) -{ +LOCAL void RF24_registerReceiveCallback( RF24_receiveCallbackType cb ) { MY_CRITICAL_SECTION { RF24_receiveCallback = cb; } @@ -304,6 +301,9 @@ LOCAL void RF24_registerReceiveCallback( RF24_receiveCallbackType cb ) #endif LOCAL bool RF24_initialize(void) { + // prevent warning + (void)RF24_getObserveTX; + // Initialize pins pinMode(MY_RF24_CE_PIN,OUTPUT); pinMode(MY_RF24_CS_PIN,OUTPUT); @@ -321,8 +321,6 @@ LOCAL bool RF24_initialize(void) { _SPI.usingInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN)); // attach interrupt attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING); - #else - (void)RF24_getFifoStatus; // prevent 'defined but not used' warning #endif // CRC and power up RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(PWR_UP) ) ; diff --git a/drivers/RF24/RF24.h b/drivers/RF24/RF24.h index 77a4cf299..4f1718ff0 100644 --- a/drivers/RF24/RF24.h +++ b/drivers/RF24/RF24.h @@ -246,7 +246,7 @@ LOCAL uint8_t RF24_RAW_writeByteRegister(uint8_t cmd, uint8_t value); LOCAL void RF24_flushRX(void); LOCAL void RF24_flushTX(void); LOCAL uint8_t RF24_getStatus(void); -LOCAL uint8_t RF24_getFifoStatus(void); +LOCAL uint8_t RF24_getFIFOStatus(void); LOCAL void RF24_openWritingPipe(uint8_t recipient); LOCAL void RF24_startListening(void); LOCAL void RF24_stopListening(void); @@ -270,6 +270,7 @@ LOCAL void RF24_setDynamicPayload(uint8_t pipe); LOCAL void RF24_setRFConfiguration(uint8_t configuration); LOCAL void RF24_setPipeAddress(uint8_t pipe, uint8_t* address, uint8_t width); LOCAL void RF24_setPipeLSB(uint8_t pipe, uint8_t LSB); +LOCAL uint8_t RF24_getObserveTX(void); LOCAL void RF24_setStatus(uint8_t status); LOCAL void RF24_enableFeatures(void); From 0a8fbe5816c4a1d82c6508359e5d1f01eac6b6ed Mon Sep 17 00:00:00 2001 From: Olivier Date: Sun, 14 Aug 2016 14:46:05 +0200 Subject: [PATCH 043/167] Remove SPI.h and EEPROM.h includes (#555) * Remove duplicate includes * Reorder SPI.h include --- drivers/RF24/RF24.h | 2 +- examples/AirQualitySensor/AirQualitySensor.ino | 1 - examples/BatteryPoweredSensor/BatteryPoweredSensor.ino | 1 - examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino | 1 - examples/CO2Sensor/CO2Sensor.ino | 1 - examples/ClearEepromConfig/ClearEepromConfig.ino | 1 - examples/DimmableLEDActuator/DimmableLEDActuator.ino | 1 - examples/DimmableLight/DimmableLight.ino | 1 - examples/DustSensor/DustSensor.ino | 1 - examples/DustSensorDSM/DustSensorDSM.ino | 1 - examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino | 1 - examples/GatewayESP8266/GatewayESP8266.ino | 2 -- examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino | 2 -- examples/GatewayESP8266OTA/GatewayESP8266OTA.ino | 2 -- examples/GatewaySerial/GatewaySerial.ino | 1 - examples/GatewaySerialRS485/GatewaySerialRS485.ino | 1 - examples/GatewayW5100/GatewayW5100.ino | 1 - examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino | 1 - examples/LightSensor/LightSensor.ino | 1 - examples/MockMySensors/MockMySensors.ino | 1 - examples/MotionSensor/MotionSensor.ino | 1 - examples/MotionSensorRS485/MotionSensorRS485.ino | 1 - examples/PHSensor/PHSensor.ino | 1 - examples/PingPongSensor/PingPongSensor.ino | 1 - examples/RelayActuator/RelayActuator.ino | 1 - examples/RepeaterNode/RepeaterNode.ino | 1 - examples/SecretKnockSensor/SecretKnockSensor.ino | 1 - examples/SecureActuator/SecureActuator.ino | 1 - examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino | 1 - examples/SoilMoistSensor/SoilMoistSensor.ino | 1 - examples/UVSensor/UVSensor.ino | 1 - examples/VibrationSensor/VibrationSensor.ino | 1 - examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino | 1 - .../hard_signing_no_whitelisting_full_debug.ino | 1 - .../hard_signing_whitelisting_full_debug.ino | 1 - .../hard_signing_whitelisting_full_debug_nodelock.ino | 1 - .../hard_signing_whitelisting_full_debug_nrf24_rsa.ino | 1 - .../hard_signing_whitelisting_full_debug_rfm69_rsa.ino | 1 - .../soft_signing_no_whitelisting_full_debug.ino | 1 - .../soft_signing_whitelisting_full_debug.ino | 1 - 40 files changed, 1 insertion(+), 43 deletions(-) diff --git a/drivers/RF24/RF24.h b/drivers/RF24/RF24.h index 77a4cf299..70e609ac8 100644 --- a/drivers/RF24/RF24.h +++ b/drivers/RF24/RF24.h @@ -34,10 +34,10 @@ #define MY_RF24_SPI_DATA_MODE SPI_MODE0 #if defined (ARDUINO) && !defined (__arm__) && !defined (_SPI) + #include #if defined(MY_SOFTSPI) SoftSPI _SPI; #else - #include #define _SPI SPI #endif #else diff --git a/examples/AirQualitySensor/AirQualitySensor.ino b/examples/AirQualitySensor/AirQualitySensor.ino index f2bc01bbb..07827aa4d 100644 --- a/examples/AirQualitySensor/AirQualitySensor.ino +++ b/examples/AirQualitySensor/AirQualitySensor.ino @@ -41,7 +41,6 @@ #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include #include #define CHILD_ID_MQ 0 diff --git a/examples/BatteryPoweredSensor/BatteryPoweredSensor.ino b/examples/BatteryPoweredSensor/BatteryPoweredSensor.ino index a3e3ed1ba..9a5b74faf 100644 --- a/examples/BatteryPoweredSensor/BatteryPoweredSensor.ino +++ b/examples/BatteryPoweredSensor/BatteryPoweredSensor.ino @@ -35,7 +35,6 @@ #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include #include int BATTERY_SENSE_PIN = A0; // select the input pin for the battery sense point diff --git a/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino b/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino index 3c6c08fa6..f4d44e76a 100644 --- a/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino +++ b/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino @@ -37,7 +37,6 @@ #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include #include #define SKETCH_NAME "Binary Sensor" diff --git a/examples/CO2Sensor/CO2Sensor.ino b/examples/CO2Sensor/CO2Sensor.ino index cd6e7fc97..3ba37370d 100644 --- a/examples/CO2Sensor/CO2Sensor.ino +++ b/examples/CO2Sensor/CO2Sensor.ino @@ -45,7 +45,6 @@ #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include #include #define CHILD_ID_AIQ 0 diff --git a/examples/ClearEepromConfig/ClearEepromConfig.ino b/examples/ClearEepromConfig/ClearEepromConfig.ino index f2a7e79d3..e885917fd 100644 --- a/examples/ClearEepromConfig/ClearEepromConfig.ino +++ b/examples/ClearEepromConfig/ClearEepromConfig.ino @@ -26,7 +26,6 @@ // load core modules only #define MY_CORE_ONLY -#include #include void setup() diff --git a/examples/DimmableLEDActuator/DimmableLEDActuator.ino b/examples/DimmableLEDActuator/DimmableLEDActuator.ino index aa04a9324..332aba776 100644 --- a/examples/DimmableLEDActuator/DimmableLEDActuator.ino +++ b/examples/DimmableLEDActuator/DimmableLEDActuator.ino @@ -42,7 +42,6 @@ #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include #include #define SN "DimmableLED" diff --git a/examples/DimmableLight/DimmableLight.ino b/examples/DimmableLight/DimmableLight.ino index e834dafae..12bac2ddb 100644 --- a/examples/DimmableLight/DimmableLight.ino +++ b/examples/DimmableLight/DimmableLight.ino @@ -36,7 +36,6 @@ #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include #include #define CHILD_ID_LIGHT 1 diff --git a/examples/DustSensor/DustSensor.ino b/examples/DustSensor/DustSensor.ino index 8b4cedd1d..e6ea3b238 100644 --- a/examples/DustSensor/DustSensor.ino +++ b/examples/DustSensor/DustSensor.ino @@ -45,7 +45,6 @@ #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include #include #define CHILD_ID_DUST 0 diff --git a/examples/DustSensorDSM/DustSensorDSM.ino b/examples/DustSensorDSM/DustSensorDSM.ino index e27a37a19..665711023 100644 --- a/examples/DustSensorDSM/DustSensorDSM.ino +++ b/examples/DustSensorDSM/DustSensorDSM.ino @@ -37,7 +37,6 @@ #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include #include #define CHILD_ID_DUST_PM10 0 diff --git a/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino b/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino index 918873058..041f0b2d4 100644 --- a/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino +++ b/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino @@ -41,7 +41,6 @@ #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include #include #define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your light sensor. (Only 2 and 3 generates interrupt!) diff --git a/examples/GatewayESP8266/GatewayESP8266.ino b/examples/GatewayESP8266/GatewayESP8266.ino index 2408bea67..6582a70a0 100644 --- a/examples/GatewayESP8266/GatewayESP8266.ino +++ b/examples/GatewayESP8266/GatewayESP8266.ino @@ -65,8 +65,6 @@ * Make sure to fill in your ssid and WiFi password below for ssid & pass. */ -#include -#include // Enable debug prints to serial monitor #define MY_DEBUG diff --git a/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino b/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino index 164aa12f3..7a73594e1 100644 --- a/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino +++ b/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino @@ -57,8 +57,6 @@ * Make sure to fill in your ssid and WiFi password below for ssid & pass. */ -#include -#include // Enable debug prints to serial monitor #define MY_DEBUG diff --git a/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino b/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino index f89ccf8fa..4e7870c6c 100644 --- a/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino +++ b/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino @@ -66,8 +66,6 @@ * Make sure to fill in your ssid and WiFi password below for ssid & pass. */ -#include -#include #include // Enable debug prints to serial monitor diff --git a/examples/GatewaySerial/GatewaySerial.ino b/examples/GatewaySerial/GatewaySerial.ino index 4d72270fe..3c0b6bea7 100644 --- a/examples/GatewaySerial/GatewaySerial.ino +++ b/examples/GatewaySerial/GatewaySerial.ino @@ -82,7 +82,6 @@ //#define MY_DEFAULT_RX_LED_PIN 6 // Receive led pin //#define MY_DEFAULT_TX_LED_PIN 5 // the PCB, on board LED -#include #include void setup() { diff --git a/examples/GatewaySerialRS485/GatewaySerialRS485.ino b/examples/GatewaySerialRS485/GatewaySerialRS485.ino index 3c3ca923b..aabd1bc48 100644 --- a/examples/GatewaySerialRS485/GatewaySerialRS485.ino +++ b/examples/GatewaySerialRS485/GatewaySerialRS485.ino @@ -82,7 +82,6 @@ #define MY_DEFAULT_RX_LED_PIN 5 // Receive led pin #define MY_DEFAULT_TX_LED_PIN 6 // the PCB, on board LED -#include #include void setup() { diff --git a/examples/GatewayW5100/GatewayW5100.ino b/examples/GatewayW5100/GatewayW5100.ino index 5e7ca3fb1..2074842ba 100644 --- a/examples/GatewayW5100/GatewayW5100.ino +++ b/examples/GatewayW5100/GatewayW5100.ino @@ -109,7 +109,6 @@ //#define MY_DEFAULT_RX_LED_PIN 8 // Receive led pin //#define MY_DEFAULT_TX_LED_PIN 9 // the PCB, on board LED -#include #if defined(MY_USE_UDP) #include diff --git a/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino b/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino index 8798c3a34..bbcaa968f 100644 --- a/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino +++ b/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino @@ -57,7 +57,6 @@ * Make sure to fill in your ssid and WiFi password below for ssid & pass. */ -#include // Enable debug prints to serial monitor #define MY_DEBUG diff --git a/examples/LightSensor/LightSensor.ino b/examples/LightSensor/LightSensor.ino index 193130d7c..baa8280f1 100644 --- a/examples/LightSensor/LightSensor.ino +++ b/examples/LightSensor/LightSensor.ino @@ -33,7 +33,6 @@ #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include #include #define CHILD_ID_LIGHT 0 diff --git a/examples/MockMySensors/MockMySensors.ino b/examples/MockMySensors/MockMySensors.ino index 6de46a0e5..7b801c932 100644 --- a/examples/MockMySensors/MockMySensors.ino +++ b/examples/MockMySensors/MockMySensors.ino @@ -15,7 +15,6 @@ #define MY_NODE_ID 254 -#include #include #define RADIO_ERROR_LED_PIN 4 // Error led pin diff --git a/examples/MotionSensor/MotionSensor.ino b/examples/MotionSensor/MotionSensor.ino index d082c4da1..17bdc48a5 100644 --- a/examples/MotionSensor/MotionSensor.ino +++ b/examples/MotionSensor/MotionSensor.ino @@ -34,7 +34,6 @@ #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include #include unsigned long SLEEP_TIME = 120000; // Sleep time between reports (in milliseconds) diff --git a/examples/MotionSensorRS485/MotionSensorRS485.ino b/examples/MotionSensorRS485/MotionSensorRS485.ino index 5af08fbd7..7af76d2f9 100644 --- a/examples/MotionSensorRS485/MotionSensorRS485.ino +++ b/examples/MotionSensorRS485/MotionSensorRS485.ino @@ -53,7 +53,6 @@ // Set RS485 baud rate to use #define MY_RS485_BAUD_RATE 9600 -#include #include unsigned long SLEEP_TIME = 120000; // Sleep time between reports (in milliseconds) diff --git a/examples/PHSensor/PHSensor.ino b/examples/PHSensor/PHSensor.ino index 713f1c6e7..4eb7b8f5c 100644 --- a/examples/PHSensor/PHSensor.ino +++ b/examples/PHSensor/PHSensor.ino @@ -29,7 +29,6 @@ #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include #include #define COMPARE_PH 1 // Send PH only if changed? 1 = Yes 0 = No diff --git a/examples/PingPongSensor/PingPongSensor.ino b/examples/PingPongSensor/PingPongSensor.ino index 4a98b31bc..67249dec4 100644 --- a/examples/PingPongSensor/PingPongSensor.ino +++ b/examples/PingPongSensor/PingPongSensor.ino @@ -15,7 +15,6 @@ #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include #include #include "MYSLog.h" diff --git a/examples/RelayActuator/RelayActuator.ino b/examples/RelayActuator/RelayActuator.ino index dd26414e1..7f82c711c 100644 --- a/examples/RelayActuator/RelayActuator.ino +++ b/examples/RelayActuator/RelayActuator.ino @@ -37,7 +37,6 @@ // Enable repeater functionality for this node #define MY_REPEATER_FEATURE -#include #include #define RELAY_1 3 // Arduino Digital I/O pin number for first relay (second on pin+1 etc) diff --git a/examples/RepeaterNode/RepeaterNode.ino b/examples/RepeaterNode/RepeaterNode.ino index fae8609e6..90791f6dc 100644 --- a/examples/RepeaterNode/RepeaterNode.ino +++ b/examples/RepeaterNode/RepeaterNode.ino @@ -38,7 +38,6 @@ // Enabled repeater feature for this node #define MY_REPEATER_FEATURE -#include #include void setup() { diff --git a/examples/SecretKnockSensor/SecretKnockSensor.ino b/examples/SecretKnockSensor/SecretKnockSensor.ino index 34349d4bd..7859d2ecd 100644 --- a/examples/SecretKnockSensor/SecretKnockSensor.ino +++ b/examples/SecretKnockSensor/SecretKnockSensor.ino @@ -58,7 +58,6 @@ #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include #include diff --git a/examples/SecureActuator/SecureActuator.ino b/examples/SecureActuator/SecureActuator.ino index 80f34ea9d..b3a67f991 100644 --- a/examples/SecureActuator/SecureActuator.ino +++ b/examples/SecureActuator/SecureActuator.ino @@ -65,7 +65,6 @@ // SETTINGS FOR MY_SIGNING_ATSHA204 #define MY_SIGNING_ATSHA204_PIN 17 //!< A3 - pin where ATSHA204 is attached -#include #include diff --git a/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino b/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino index 11fb45ca8..f8443daed 100644 --- a/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino +++ b/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino @@ -82,7 +82,6 @@ //#define MY_DEFAULT_RX_LED_PIN 6 // Receive led pin //#define MY_DEFAULT_TX_LED_PIN 5 // the PCB, on board LED -#include #include #include #include diff --git a/examples/SoilMoistSensor/SoilMoistSensor.ino b/examples/SoilMoistSensor/SoilMoistSensor.ino index 9d51e0dbf..0d45d080d 100644 --- a/examples/SoilMoistSensor/SoilMoistSensor.ino +++ b/examples/SoilMoistSensor/SoilMoistSensor.ino @@ -68,7 +68,6 @@ //#define MY_RADIO_RFM69 #include // Conversion equation from resistance to % -#include #include // Setting up format for reading 3 soil sensors diff --git a/examples/UVSensor/UVSensor.ino b/examples/UVSensor/UVSensor.ino index 2b70dee2e..e22451db5 100644 --- a/examples/UVSensor/UVSensor.ino +++ b/examples/UVSensor/UVSensor.ino @@ -43,7 +43,6 @@ #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include #include #define UV_SENSOR_ANALOG_PIN 0 diff --git a/examples/VibrationSensor/VibrationSensor.ino b/examples/VibrationSensor/VibrationSensor.ino index f0609823c..eaefa5905 100644 --- a/examples/VibrationSensor/VibrationSensor.ino +++ b/examples/VibrationSensor/VibrationSensor.ino @@ -39,7 +39,6 @@ #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include #include #include diff --git a/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino b/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino index b7ce981d3..2a0710530 100644 --- a/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino +++ b/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino @@ -41,7 +41,6 @@ #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include #include #define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your sensor. (Only 2 and 3 generates interrupt!) diff --git a/tests/Arduino/sketches/hard_signing_no_whitelisting_full_debug/hard_signing_no_whitelisting_full_debug.ino b/tests/Arduino/sketches/hard_signing_no_whitelisting_full_debug/hard_signing_no_whitelisting_full_debug.ino index 39b766d06..dea5111cb 100644 --- a/tests/Arduino/sketches/hard_signing_no_whitelisting_full_debug/hard_signing_no_whitelisting_full_debug.ino +++ b/tests/Arduino/sketches/hard_signing_no_whitelisting_full_debug/hard_signing_no_whitelisting_full_debug.ino @@ -34,5 +34,4 @@ #define MY_SIGNING_ATSHA204_PIN 17 #endif -#include #include diff --git a/tests/Arduino/sketches/hard_signing_whitelisting_full_debug/hard_signing_whitelisting_full_debug.ino b/tests/Arduino/sketches/hard_signing_whitelisting_full_debug/hard_signing_whitelisting_full_debug.ino index d398e5c8b..23f0d9b82 100644 --- a/tests/Arduino/sketches/hard_signing_whitelisting_full_debug/hard_signing_whitelisting_full_debug.ino +++ b/tests/Arduino/sketches/hard_signing_whitelisting_full_debug/hard_signing_whitelisting_full_debug.ino @@ -34,5 +34,4 @@ #define MY_SIGNING_ATSHA204_PIN 17 #endif -#include #include diff --git a/tests/Arduino/sketches/hard_signing_whitelisting_full_debug_nodelock/hard_signing_whitelisting_full_debug_nodelock.ino b/tests/Arduino/sketches/hard_signing_whitelisting_full_debug_nodelock/hard_signing_whitelisting_full_debug_nodelock.ino index c6e4de66a..43ff5e971 100644 --- a/tests/Arduino/sketches/hard_signing_whitelisting_full_debug_nodelock/hard_signing_whitelisting_full_debug_nodelock.ino +++ b/tests/Arduino/sketches/hard_signing_whitelisting_full_debug_nodelock/hard_signing_whitelisting_full_debug_nodelock.ino @@ -35,5 +35,4 @@ #endif #define MY_NODE_LOCK_FEATURE -#include #include diff --git a/tests/Arduino/sketches/hard_signing_whitelisting_full_debug_nrf24_rsa/hard_signing_whitelisting_full_debug_nrf24_rsa.ino b/tests/Arduino/sketches/hard_signing_whitelisting_full_debug_nrf24_rsa/hard_signing_whitelisting_full_debug_nrf24_rsa.ino index c5027bd3c..d1263b7d0 100644 --- a/tests/Arduino/sketches/hard_signing_whitelisting_full_debug_nrf24_rsa/hard_signing_whitelisting_full_debug_nrf24_rsa.ino +++ b/tests/Arduino/sketches/hard_signing_whitelisting_full_debug_nrf24_rsa/hard_signing_whitelisting_full_debug_nrf24_rsa.ino @@ -35,5 +35,4 @@ #endif #define MY_RF24_ENABLE_ENCRYPTION -#include #include diff --git a/tests/Arduino/sketches/hard_signing_whitelisting_full_debug_rfm69_rsa/hard_signing_whitelisting_full_debug_rfm69_rsa.ino b/tests/Arduino/sketches/hard_signing_whitelisting_full_debug_rfm69_rsa/hard_signing_whitelisting_full_debug_rfm69_rsa.ino index 3ddcb5338..489f926da 100644 --- a/tests/Arduino/sketches/hard_signing_whitelisting_full_debug_rfm69_rsa/hard_signing_whitelisting_full_debug_rfm69_rsa.ino +++ b/tests/Arduino/sketches/hard_signing_whitelisting_full_debug_rfm69_rsa/hard_signing_whitelisting_full_debug_rfm69_rsa.ino @@ -35,5 +35,4 @@ #endif #define MY_RFM69_ENABLE_ENCRYPTION -#include #include diff --git a/tests/Arduino/sketches/soft_signing_no_whitelisting_full_debug/soft_signing_no_whitelisting_full_debug.ino b/tests/Arduino/sketches/soft_signing_no_whitelisting_full_debug/soft_signing_no_whitelisting_full_debug.ino index 099a56961..f922d57ef 100644 --- a/tests/Arduino/sketches/soft_signing_no_whitelisting_full_debug/soft_signing_no_whitelisting_full_debug.ino +++ b/tests/Arduino/sketches/soft_signing_no_whitelisting_full_debug/soft_signing_no_whitelisting_full_debug.ino @@ -34,5 +34,4 @@ #define MY_SIGNING_ATSHA204_PIN 17 #endif -#include #include diff --git a/tests/Arduino/sketches/soft_signing_whitelisting_full_debug/soft_signing_whitelisting_full_debug.ino b/tests/Arduino/sketches/soft_signing_whitelisting_full_debug/soft_signing_whitelisting_full_debug.ino index 707b2fd17..3790fc690 100644 --- a/tests/Arduino/sketches/soft_signing_whitelisting_full_debug/soft_signing_whitelisting_full_debug.ino +++ b/tests/Arduino/sketches/soft_signing_whitelisting_full_debug/soft_signing_whitelisting_full_debug.ino @@ -34,5 +34,4 @@ #define MY_SIGNING_ATSHA204_PIN 17 #endif -#include #include From 378112db7d33a0afa2b923cc31d1fc13449b5cfa Mon Sep 17 00:00:00 2001 From: Ivan Kravets Date: Tue, 16 Aug 2016 13:10:05 +0300 Subject: [PATCH 044/167] Update supported development platforms --- library.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/library.json b/library.json index 0bd39628c..d55c3e4a4 100644 --- a/library.json +++ b/library.json @@ -9,7 +9,11 @@ }, "version": "2.0.1-beta", "frameworks": "arduino", - "platforms": "*", + "platforms": [ + "atmelavr", + "atmelsam", + "espressif" + ], "exclude": [ "tests", "Documentation" From 4b0664be5cf8dad6be91b79008173674440c707a Mon Sep 17 00:00:00 2001 From: aaron832 Date: Mon, 22 Feb 2016 22:01:16 -0800 Subject: [PATCH 045/167] Add MQTT topic generation Add MQTT topic generation to the protocol definition file. --- .../MySensors/core/MyGatewayTransportMQTTClient.cpp | 6 +++--- libraries/MySensors/core/MyProtocolMySensors.cpp | 10 ++++++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/libraries/MySensors/core/MyGatewayTransportMQTTClient.cpp b/libraries/MySensors/core/MyGatewayTransportMQTTClient.cpp index a2c1d6c4c..4528c8e71 100644 --- a/libraries/MySensors/core/MyGatewayTransportMQTTClient.cpp +++ b/libraries/MySensors/core/MyGatewayTransportMQTTClient.cpp @@ -59,9 +59,9 @@ MyMessage _mqttMsg; bool gatewayTransportSend(MyMessage &message) { if (!_client.connected()) return false; - snprintf_P(_fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, PSTR(MY_MQTT_PUBLISH_TOPIC_PREFIX "/%d/%d/%d/%d/%d"), message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type); - debug(PSTR("Sending message on topic: %s\n"), _fmtBuffer); - return _client.publish(_fmtBuffer, message.getString(_convBuffer)); + char *mqttMsg = protocolFormatMQTT(message); + debug(PSTR("Sending message on topic: %s\n"), mqttMsg); + return _client.publish(mqttMsg, message.getString(_convBuffer)); } diff --git a/libraries/MySensors/core/MyProtocolMySensors.cpp b/libraries/MySensors/core/MyProtocolMySensors.cpp index f9ffe12b9..109f7494e 100644 --- a/libraries/MySensors/core/MyProtocolMySensors.cpp +++ b/libraries/MySensors/core/MyProtocolMySensors.cpp @@ -100,6 +100,16 @@ char * protocolFormat(MyMessage &message) { return _fmtBuffer; } +char * protocolFormatMQTTTopic(const char* prefix, MyMessage &message) { + snprintf_P(_fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, PSTR("%s/%d/%d/%d/%d/%d"), prefix, message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type); + return _fmtBuffer; +} + +char * protocolFormatMQTTSubscribe(const char* prefix) { + snprintf_P(_fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, PSTR("%s/+/+/+/+/+"), prefix); + return _fmtBuffer; +} + uint8_t protocolH2i(char c) { uint8_t i = 0; if (c <= '9') From b50a651e5ef55e7edbafffc986571b9ad8baf5a9 Mon Sep 17 00:00:00 2001 From: aaron832 Date: Mon, 22 Feb 2016 22:04:38 -0800 Subject: [PATCH 046/167] Reform definition logic Reform definition logic to allow MY_GATEWAY_MQTT_CLIENT along side MY_GATEWAY_FEATURE as there was some redundancy. Add some specific exclusions for Linux implementation of MQTT. --- libraries/MySensors/MySensor.h | 65 ++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/libraries/MySensors/MySensor.h b/libraries/MySensors/MySensor.h index 57bfd2733..e073a46d0 100644 --- a/libraries/MySensors/MySensor.h +++ b/libraries/MySensors/MySensor.h @@ -181,34 +181,7 @@ #endif #endif - - -// GATEWAY - TRANSPORT -#if defined(MY_GATEWAY_MQTT_CLIENT) - #if defined(MY_RADIO_FEATURE) - // We assume that a gateway having a radio also should act as repeater - #define MY_REPEATER_FEATURE - #endif - // GATEWAY - COMMON FUNCTIONS - // We only support MQTT Client using W5100 and ESP8266 at the moment - #if !(defined(MY_CONTROLLER_URL_ADDRESS) || defined(MY_CONTROLLER_IP_ADDRESS)) - #error You must specify MY_CONTROLLER_IP_ADDRESS or MY_CONTROLLER_URL_ADDRESS - #endif - - #if !defined(MY_MQTT_PUBLISH_TOPIC_PREFIX) - #error You must specify a topic publish prefix MY_MQTT_PUBLISH_TOPIC_PREFIX for this MQTT client - #endif - #if !defined(MY_MQTT_SUBSCRIBE_TOPIC_PREFIX) - #error You must specify a topic subscribe prefix MY_MQTT_SUBSCRIBE_TOPIC_PREFIX for this MQTT client - #endif - #if !defined(MY_MQTT_CLIENT_ID) - #error You must define a unique MY_MQTT_CLIENT_ID for this MQTT client - #endif - - #include "drivers/pubsubclient/src/PubSubClient.cpp" - #include "core/MyGatewayTransport.cpp" - #include "core/MyGatewayTransportMQTTClient.cpp" -#elif defined(MY_GATEWAY_FEATURE) +#if defined(MY_GATEWAY_FEATURE) // GATEWAY - COMMON FUNCTIONS #include "core/MyGatewayTransport.cpp" @@ -231,13 +204,23 @@ #endif #if defined(MY_GATEWAY_ESP8266) // GATEWAY - ESP8266 - #include "core/MyGatewayTransportEthernet.cpp" + #if defined(MY_GATEWAY_MQTT_CLIENT) + #include "drivers/pubsubclient/src/PubSubClient.cpp" + #include "core/MyGatewayTransportMQTTClient.cpp" + #else + #include "core/MyGatewayTransportEthernet.cpp" + #endif #elif defined(MY_GATEWAY_LINUX) // GATEWAY - Generic Linux (RaspberryPi, BBB) #include "core/MyGatewayTransportEthernetLinux.cpp" #elif defined(MY_GATEWAY_W5100) // GATEWAY - W5100 - #include "core/MyGatewayTransportEthernet.cpp" + #if defined(MY_GATEWAY_MQTT_CLIENT) + #include "drivers/pubsubclient/src/PubSubClient.cpp" + #include "core/MyGatewayTransportMQTTClient.cpp" + #else + #include "core/MyGatewayTransportEthernet.cpp" + #endif #elif defined(MY_GATEWAY_ENC28J60) // GATEWAY - ENC28J60 #if defined(MY_USE_UDP) @@ -251,6 +234,28 @@ #endif #endif +// GATEWAY - MQTT +#if defined(MY_GATEWAY_MQTT_CLIENT) && !defined(MY_GATEWAY_LINUX) + // GATEWAY - COMMON FUNCTIONS + // We only support MQTT Client using W5100, ESP8266 or Linux/RasperryPi at the moment + #if !(defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_W5100) || defined(MY_GATEWAY_LINUX)) + #error We only support MQTT Client using W5100, ESP8266 or Linux/RasperryPi at the moment + #endif + + #if !(defined(MY_CONTROLLER_URL_ADDRESS) || defined(MY_CONTROLLER_IP_ADDRESS)) + #error You must specify MY_CONTROLLER_IP_ADDRESS or MY_CONTROLLER_URL_ADDRESS + #endif + + #if !defined(MY_MQTT_PUBLISH_TOPIC_PREFIX) + #error You must specify a topic publish prefix MY_MQTT_PUBLISH_TOPIC_PREFIX for this MQTT client + #endif + #if !defined(MY_MQTT_SUBSCRIBE_TOPIC_PREFIX) + #error You must specify a topic subscribe prefix MY_MQTT_SUBSCRIBE_TOPIC_PREFIX for this MQTT client + #endif + #if !defined(MY_MQTT_CLIENT_ID) + #error You must define a unique MY_MQTT_CLIENT_ID for this MQTT client + #endif +#endif // RADIO #if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) || defined(MY_RS485) From b880a745fe4f3d922a82fabdb94e14964078e6fe Mon Sep 17 00:00:00 2001 From: aaron832 Date: Mon, 22 Feb 2016 22:06:42 -0800 Subject: [PATCH 047/167] Initial implementation of MQTT Initial implementation of MQTT alongside ethernet gateway. --- libraries/MySensors/Makefile | 21 +- .../core/MyGatewayTransportEthernetLinux.cpp | 218 ++++++++++++++++++ .../MySensors/examples_RPi/PiGateway.cpp | 13 ++ 3 files changed, 249 insertions(+), 3 deletions(-) diff --git a/libraries/MySensors/Makefile b/libraries/MySensors/Makefile index 20a46ff84..03e671df6 100644 --- a/libraries/MySensors/Makefile +++ b/libraries/MySensors/Makefile @@ -33,7 +33,9 @@ ifeq ($(PIREV),$(filter $(PIREV),a01041 a21041 0010)) CXXFLAGS+=-D__PI_BPLUS endif +COMPILER_FLAGS=examples_RPi/compiler_flags GATEWAY=examples_RPi/PiGateway +GATEWAYMQTT=examples_RPi/PiGatewayMQTT GATEWAY_SOURCES=examples_RPi/PiGateway.cpp $(wildcard ./utility/*.cpp) GATEWAY_OBJECTS=$(patsubst %.cpp,%.o,$(GATEWAY_SOURCES)) DEPS+=$(patsubst %.cpp,%.d,$(GATEWAY_SOURCES)) @@ -41,24 +43,37 @@ DEPS+=$(patsubst %.cpp,%.d,$(GATEWAY_SOURCES)) RF24H = /usr/local/include/RF24 CINCLUDE=-I. -I./core -I$(RF24H) -.PHONY: all clean install uninstall +.PHONY: all gateway gatewaymqtt clean install uninstall force all: $(GATEWAY) +mqtt: $(GATEWAYMQTT) + +$(COMPILER_FLAGS): force + echo '$(CXXFLAGS)' | cmp -s - $@ || echo '$(CXXFLAGS)' > $@ + +$(GATEWAY_OBJECTS): $(COMPILER_FLAGS) + # Basic Gateway Build $(GATEWAY): LDFLAGS += -pthread $(GATEWAY): $(GATEWAY_OBJECTS) $(CXX) $(LDFLAGS) -o $@ $(GATEWAY_OBJECTS) + +# MQTT Gateway Build +$(GATEWAYMQTT): CXXFLAGS += -DMY_GATEWAY_MQTT_CLIENT +$(GATEWAYMQTT): LDFLAGS += -pthread -lmosquitto +$(GATEWAYMQTT): $(GATEWAY_OBJECTS) + $(CXX) $(LDFLAGS) -o $@ $(GATEWAY_OBJECTS) # Include all .d files -include $(DEPS) - + %.o: %.cpp $(CXX) $(CXXFLAGS) $(CINCLUDE) -MMD -c -o $@ $< # The Cleaner clean: - rm -rf build $(GATEWAY_OBJECTS) $(GATEWAY) $(DEPS) + rm -rf build $(GATEWAY_OBJECTS) $(GATEWAY) $(GATEWAYMQTT) $(DEPS) $(COMPILER_FLAGS) install: all install-gatewaybasic install-gatewayserial install-gatewayethernet install-initscripts diff --git a/libraries/MySensors/core/MyGatewayTransportEthernetLinux.cpp b/libraries/MySensors/core/MyGatewayTransportEthernetLinux.cpp index e5228286a..4eadf49f9 100644 --- a/libraries/MySensors/core/MyGatewayTransportEthernetLinux.cpp +++ b/libraries/MySensors/core/MyGatewayTransportEthernetLinux.cpp @@ -27,6 +27,26 @@ #include #include +#ifdef MY_GATEWAY_MQTT_CLIENT + #include + + #ifndef MQTT_IP + #define MQTT_IP "127.0.0.1" + #endif + #ifndef MQTT_PORT + #define MQTT_PORT 1883 + #endif + #ifndef MQTT_KEEPALIVE + #define MQTT_KEEPALIVE 60 + #endif + #ifndef MY_MQTT_PUBLISH_TOPIC_PREFIX + #define MY_MQTT_PUBLISH_TOPIC_PREFIX "mygateway1-out" + #endif + #ifndef MY_MQTT_SUBSCRIBE_TOPIC_PREFIX + #define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX "mygateway1-in" + #endif +#endif + //TODO #ifdef MY_USE_UDP #error UDP not supported for this type of gateway @@ -49,10 +69,19 @@ void *get_in_addr(struct sockaddr *sa); void *waiting_controllers(void* thread_arg); void *connected_controller(void* thread_arg); +#ifdef MY_GATEWAY_MQTT_CLIENT +void *mqtt_thread(void *); +void parsemqtt_and_send(char *topic, const char *payload); +struct mosquitto *mosq; +#endif + bool gatewayTransportInit() { long int sockfd; pthread_t thread_id; pthread_attr_t attr; +#ifdef MY_GATEWAY_MQTT_CLIENT + pthread_attr_t mqtt_attr; +#endif char *ip = NULL; // ignore SIGPIPE generated by send() to a disconnected client @@ -84,6 +113,14 @@ bool gatewayTransportInit() { pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_create(&thread_id, &attr, &waiting_controllers, (void *)sockfd); pthread_attr_destroy(&attr); + +#ifdef MY_GATEWAY_MQTT_CLIENT + /* mqtt thread */ + pthread_attr_init(&mqtt_attr); + pthread_attr_setdetachstate(&mqtt_attr, PTHREAD_CREATE_DETACHED); + pthread_create(&thread_id, &mqtt_attr, &mqtt_thread, NULL); + pthread_attr_destroy(&mqtt_attr); +#endif return true; } @@ -98,6 +135,13 @@ bool gatewayTransportSend(MyMessage &message) if (send(controllers[i], ethernetMsg, strlen(ethernetMsg), 0) == -1) perror("send"); } + +#ifdef MY_GATEWAY_MQTT_CLIENT + char *mqttMsg = protocolFormatMQTTTopic(MY_MQTT_PUBLISH_TOPIC_PREFIX, message); + //connection, message id, topic, bytes, data, QOS, retain + mosquitto_publish(mosq, NULL, mqttMsg, strlen(message.getString(_convBuffer)), message.getString(_convBuffer), 0, false); +#endif + return true; } @@ -302,3 +346,177 @@ void *connected_controller(void* thread_arg) close(sockfd); return NULL; } + +#ifdef MY_GATEWAY_MQTT_CLIENT +void mqtt_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message) +{ + (void)mosq; + (void)userdata; + + if(message->payloadlen){ + printf("Got a MQTT message %s %s\n", message->topic, (char*)message->payload); + + std::string strpayload((char *)message->payload); + strpayload = strpayload.substr(0,(int)message->payloadlen); + + parsemqtt_and_send(message->topic, strpayload.c_str()); + }else{ + printf("%s (null)\n", message->topic); + } + fflush(stdout); +} + +void mqtt_connect_callback(struct mosquitto *mosq, void *userdata, int result) +{ + (void)mosq; + (void)userdata; + + if(!result){ + printf("Connected!\n"); + /* Subscribe to broker information topics on successful connect. */ + //connection, message id, topic, qos + mosquitto_subscribe(mosq, NULL, protocolFormatMQTTSubscribe(MY_MQTT_SUBSCRIBE_TOPIC_PREFIX), 0); + }else{ + fprintf(stderr, "Connect failed\n"); + } +} + +void mqtt_subscribe_callback(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos) +{ + (void)mosq; + (void)userdata; + + int i; + + printf("Subscribed (mid: %d): %d", mid, granted_qos[0]); + for(i=1; i using namespace std; From e9a50586ff6aeaecb5d01a0f54804f41725363e9 Mon Sep 17 00:00:00 2001 From: aaron832 Date: Tue, 23 Feb 2016 11:39:08 -0800 Subject: [PATCH 048/167] Move MQTT to message parsing Move MQTT to message parsing into MyProtocolMySensor.cpp to be common amongst all MQTT client implementations. --- .../core/MyGatewayTransportEthernetLinux.cpp | 122 ++++-------------- .../core/MyGatewayTransportMQTTClient.cpp | 65 +--------- .../MySensors/core/MyProtocolMySensors.cpp | 67 ++++++++++ 3 files changed, 96 insertions(+), 158 deletions(-) diff --git a/libraries/MySensors/core/MyGatewayTransportEthernetLinux.cpp b/libraries/MySensors/core/MyGatewayTransportEthernetLinux.cpp index 4eadf49f9..c5d1091ea 100644 --- a/libraries/MySensors/core/MyGatewayTransportEthernetLinux.cpp +++ b/libraries/MySensors/core/MyGatewayTransportEthernetLinux.cpp @@ -71,7 +71,6 @@ void *connected_controller(void* thread_arg); #ifdef MY_GATEWAY_MQTT_CLIENT void *mqtt_thread(void *); -void parsemqtt_and_send(char *topic, const char *payload); struct mosquitto *mosq; #endif @@ -355,15 +354,35 @@ void mqtt_message_callback(struct mosquitto *mosq, void *userdata, const struct if(message->payloadlen){ printf("Got a MQTT message %s %s\n", message->topic, (char*)message->payload); - - std::string strpayload((char *)message->payload); - strpayload = strpayload.substr(0,(int)message->payloadlen); - - parsemqtt_and_send(message->topic, strpayload.c_str()); }else{ - printf("%s (null)\n", message->topic); + printf("Got a MQTT message %s (null)\n", message->topic); + } + + MyMessage msg; + protocolMQTTParse(msg, message->topic, (uint8_t*)message->payload, message->payloadlen); + + if(msg.destination != 0 && msg.sensor != 0 && msg.type != 255) + { + ethernetMsg_q.push_back(msg); + + // Forward the data to Ethernet + // Likely this is a duplicate from a C_SET that we received and published + // in msg_callback. Not much we can do to avoid the duplicate as there is + // no way to tell if we performed the publish that is triggering this callback. + char *ethernetMsg = protocolFormat(msg); + + for (uint8_t i = 0; i < MY_GATEWAY_MAX_CLIENTS; i++) { + if (controllers[i] == -1) + continue; + if (send(controllers[i], ethernetMsg, strlen(ethernetMsg), 0) == -1) + perror("send"); + } + } + else + { + printf("Recieved a bad MQTT message: '%s':'%s'\n destination:%i, sensor:%i, type:%i\n", + message->topic, (char*)message->payload, msg.destination, msg.sensor, msg.type); } - fflush(stdout); } void mqtt_connect_callback(struct mosquitto *mosq, void *userdata, int result) @@ -432,91 +451,4 @@ void *mqtt_thread(void *) return NULL; } -void parsemqtt_and_send(char *topic, const char *payload) -{ - //Buffer for parsemqtt_and_send. Do not want to re-create it every time we get a message - MyMessage msg; - char *str, *p; - - char* topic_copy = strdup(topic); - - - // TODO: Check if we should send ack or not. - int i = 0; - for (str = strtok_r(topic_copy,"/",&p) ; str && i<4 ; str = strtok_r(NULL,"/",&p)) - { - // Example: /mySensors/105/4/V_LIGHT - // 0: mySensors - Prefix - // 1: 105 - node - // 2: 4 - sensor - // 3: V_LIGHT - type - if (i == 0) { - //TODO: Add warning when we receive a message from an unexpected broker prefix. - //if (strcmp_P(str,broker)!=0) { //look for MQTT_BROKER_PREFIX - // return; //Message not for us or malformatted! - //} - } else if (i==1) { - printf("Destination parse %s\n", str); - msg.destination = atoi(str); //NodeID - } else if (i==2) { - msg.sensor = atoi(str); //SensorID - } else if (i==3) { - unsigned char match=255; //SensorType - - //Support for numeric types - if ( atoi(str)!=0 || (str[0]=='0' && str[1] =='\0') ) { - match=atoi(str); - } - - /* - //Check through all the data type string attary to find a match. - //? Not sure if there is any need to be checking for other types like sensor and internal - //? as those don't seem like they should be outside settable thought MQTT. - for (uint8_t j=0; match == 255 && j Date: Sun, 6 Mar 2016 20:37:02 -0800 Subject: [PATCH 049/167] Use iostream for min, max functions Use iostream for min, max functions as well as for reading / writing to file. --- libraries/MySensors/core/MyHwLinuxGeneric.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/MySensors/core/MyHwLinuxGeneric.h b/libraries/MySensors/core/MyHwLinuxGeneric.h index 3546e0981..cec3b6cb4 100644 --- a/libraries/MySensors/core/MyHwLinuxGeneric.h +++ b/libraries/MySensors/core/MyHwLinuxGeneric.h @@ -22,16 +22,17 @@ #include "MyHw.h" #include +#include #define MY_SERIALDEVICE Serial -#define min(a,b) ((a)<(b)?(a):(b)) -#define max(a,b) ((a)>(b)?(a):(b)) // Define these as macros (do nothing) #define hwDigitalWrite(__pin, __value) #define hwWatchdogReset() #define hwReboot() +using namespace std; + void hwInit(); void hwReadConfigBlock(void* buf, void* adr, size_t length); void hwWriteConfigBlock(void* buf, void* adr, size_t length); From 79c263291b47225477eebb90ad0b4118b5ca5175 Mon Sep 17 00:00:00 2001 From: aaron832 Date: Sun, 6 Mar 2016 20:56:06 -0800 Subject: [PATCH 050/167] Save eeprom config data to file hwWriteConfig and hwReadConfig now use hwWriteConfigBlock and hwReadConfigBlock calls for simplicity. --- libraries/MySensors/core/MyHwLinuxGeneric.cpp | 74 ++++++++++++++++--- 1 file changed, 65 insertions(+), 9 deletions(-) diff --git a/libraries/MySensors/core/MyHwLinuxGeneric.cpp b/libraries/MySensors/core/MyHwLinuxGeneric.cpp index 35afc37ee..9aa504dab 100644 --- a/libraries/MySensors/core/MyHwLinuxGeneric.cpp +++ b/libraries/MySensors/core/MyHwLinuxGeneric.cpp @@ -22,18 +22,62 @@ #include #include #include +#include +#include +static const char* CONFIG_FILE = "/etc/MySensorGateway.cfg"; static const size_t _length = 1024; // ATMega328 has 1024 bytes -//TODO store _config to a file static uint8_t _config[_length]; static unsigned long millis_at_start; +bool CheckConfigFile() { + struct stat fileInfo; + + if(stat(CONFIG_FILE, &fileInfo) != 0) + { + //File does not exist. Create it. + debug("Config file %s does not exist, creating new config file.\n", CONFIG_FILE); + ofstream myFile(CONFIG_FILE, ios::out | ios::binary); + if(!myFile) + { + debug("Unable to create config file %s.\n", CONFIG_FILE); + return false; + } + myFile.write((const char*)_config, _length); + myFile.close(); + } + else if(fileInfo.st_size != _length) + { + debug("Config file %s is not the correct size of %i. Please remove the file and a new one will be created.\n", CONFIG_FILE, _length); + return false; + } + else + { + //Read config into local memory. + ifstream myFile(CONFIG_FILE, ios::in | ios::binary); + if(!myFile) + { + debug("Unable to open config to file %s for reading.\n", CONFIG_FILE); + return false; + } + myFile.read((char*)_config, _length); + myFile.close(); + } + + return true; +} + void hwInit() { timeval curTime; for (size_t i = 0; i < _length; i++) _config[i] = 0xFF; + + if (!CheckConfigFile()) + { + exit(1); + } gettimeofday(&curTime, NULL); millis_at_start = curTime.tv_sec; @@ -51,23 +95,35 @@ void hwReadConfigBlock(void* buf, void* addr, size_t length) void hwWriteConfigBlock(void* buf, void* addr, size_t length) { unsigned long int offs = reinterpret_cast(addr); - + if (length && offs + length <= _length) { memcpy(_config+offs, buf, length); + + ofstream myFile(CONFIG_FILE, ios::out | ios::binary); + if(!myFile) + { + debug("Unable to write config to file %s.\n", CONFIG_FILE); + return; + } + myFile.write((const char*)buf+offs, _length); + myFile.close(); } } -uint8_t hwReadConfig(int addr) +uint8_t hwReadConfig(int adr) { - if (addr >= 0 && (unsigned)addr < _length) - return _config[addr]; - return 0xFF; + uint8_t value = 0xFF; + hwReadConfigBlock(&value, reinterpret_cast(adr), 1); + return value; } -void hwWriteConfig(int addr, uint8_t value) +void hwWriteConfig(int adr, uint8_t value) { - if (addr >= 0 && (unsigned)addr < _length) - _config[addr] = value; + uint8_t curr = hwReadConfig(adr); + if (curr != value) + { + hwWriteConfigBlock(&value, reinterpret_cast(adr), 1); + } } unsigned long hwMillis() From 6b756335d0d57a7f6150e86cfb65c6bff805cf4a Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Mon, 8 Aug 2016 01:46:15 -0300 Subject: [PATCH 051/167] Refactor RaspberryPi port --- Makefile | 63 +++++ MyConfig.h | 25 +- MySensors.h | 69 ++---- configure | 322 ++++++++++++++++++++++++++ core/MyGatewayTransportEthernet.cpp | 79 ++++--- core/MyGatewayTransportMQTTClient.cpp | 101 +------- core/MyHwATMega328.h | 8 +- core/MyHwESP8266.h | 8 +- core/MyHwLinuxGeneric.cpp | 190 +++++++++++++++ core/MyHwLinuxGeneric.h | 75 ++++++ core/MyMainLinux.cpp | 39 ++++ core/MyMessage.cpp | 4 + core/MyMessage.h | 1 - core/MyProtocolMySensors.cpp | 69 +++--- core/MySensorsCore.cpp | 12 +- core/MyTransport.cpp | 4 +- core/MyTransportNRF24.cpp | 8 +- core/MyTransportRS485.cpp | 5 - drivers/Linux/Arduino.h | 212 +++++++++++++++++ drivers/Linux/Client.h | 46 ++++ drivers/Linux/EthernetClient.cpp | 253 ++++++++++++++++++++ drivers/Linux/EthernetClient.h | 80 +++++++ drivers/Linux/EthernetServer.cpp | 241 +++++++++++++++++++ drivers/Linux/EthernetServer.h | 64 +++++ drivers/Linux/IPAddress.cpp | 105 +++++++++ drivers/Linux/IPAddress.h | 87 +++++++ drivers/Linux/Server.h | 28 +++ drivers/Linux/Stream.h | 15 ++ drivers/RF24/RF24_RPi.cpp | 210 +++++++++++++++++ examples_RPi/MySGateway.cpp | 93 ++++++++ initscripts/mysgateway.systemd | 9 + initscripts/mysgateway.sysvinit | 159 +++++++++++++ 32 files changed, 2460 insertions(+), 224 deletions(-) create mode 100644 Makefile create mode 100755 configure create mode 100644 core/MyHwLinuxGeneric.cpp create mode 100644 core/MyHwLinuxGeneric.h create mode 100644 core/MyMainLinux.cpp create mode 100644 drivers/Linux/Arduino.h create mode 100644 drivers/Linux/Client.h create mode 100644 drivers/Linux/EthernetClient.cpp create mode 100644 drivers/Linux/EthernetClient.h create mode 100644 drivers/Linux/EthernetServer.cpp create mode 100644 drivers/Linux/EthernetServer.h create mode 100644 drivers/Linux/IPAddress.cpp create mode 100644 drivers/Linux/IPAddress.h create mode 100644 drivers/Linux/Server.h create mode 100644 drivers/Linux/Stream.h create mode 100644 drivers/RF24/RF24_RPi.cpp create mode 100644 examples_RPi/MySGateway.cpp create mode 100644 initscripts/mysgateway.systemd create mode 100644 initscripts/mysgateway.sysvinit diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..825d83ded --- /dev/null +++ b/Makefile @@ -0,0 +1,63 @@ +############################################################################# +# +# Makefile for MySensors +# +# Description: +# ------------ +# use make all and make install to install the gateway +# + +CONFIG_FILE=Makefile.inc + +include $(CONFIG_FILE) + +GATEWAY=examples_RPi/MySGateway +GATEWAY_SOURCES=examples_RPi/MySGateway.cpp +GATEWAY_OBJECTS=$(patsubst %.cpp,%.o,$(GATEWAY_SOURCES)) +DEPS+=$(patsubst %.cpp,%.d,$(GATEWAY_SOURCES)) + +CINCLUDE=-I. -I./core -I./drivers/Linux -I$(RF24H_LIB_DIR) + +.PHONY: all gateway cleanconfig clean install uninstall force + +all: $(GATEWAY) + +# Gateway Build +$(GATEWAY): $(GATEWAY_OBJECTS) + $(CXX) $(LDFLAGS) -o $@ $(GATEWAY_OBJECTS) + +# Include all .d files +-include $(DEPS) + +%.o: %.cpp + $(CXX) $(CXXFLAGS) $(CINCLUDE) -MMD -c -o $@ $< + +# clear configuration files +cleanconfig: + @echo "[Cleaning configuration]" + rm -rf $(CONFIG_FILE) + +# clear build files +clean: + @echo "[Cleaning]" + rm -rf build $(GATEWAY_OBJECTS) $(GATEWAY) $(DEPS) + +$(CONFIG_FILE): + @echo "[Running configure]" + @./configure --no-clean + +install: all install-gateway install-initscripts + +install-gateway: + @echo "Installing $(GATEWAY) to $(GATEWAY_DIR)" + @install -m 0755 $(GATEWAY) $(GATEWAY_DIR) + +install-initscripts: + if [[ `systemctl` =~ -\.mount ]]; then \ + install -m0644 initscripts/mysgateway.systemd /etc/systemd/system/mysgateway.service && \ + sed -i -e "s|%gateway_dir%|${GATEWAY_DIR}|g" /etc/systemd/system/mysgateway.service && \ + systemctl daemon-reload; \ + elif [[ -f /etc/init.d/cron && ! -h /etc/init.d/cron ]]; then \ + install -m0755 initscripts/mysgateway.sysvinit /etc/init.d/mysgateway && \ + sed -i -e "s|%gateway_dir%|${GATEWAY_DIR}|g" /etc/init.d/mysgateway; \ + fi diff --git a/MyConfig.h b/MyConfig.h index cb775cead..5d4cec8bf 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -413,7 +413,7 @@ #elif defined(RASPBERRYPI_ARCH) #include #include - #ifdef __PI_BPLUS + #ifdef __RPI_BPLUS #define MY_RF24_CE_PIN RPI_BPLUS_GPIO_J8_22 #define MY_RF24_CS_PIN RPI_BPLUS_GPIO_J8_24 #else @@ -716,25 +716,34 @@ #endif /************************************** -* RaspberryPi Settings +* Linux Settings ***************************************/ /** - * @def MY_RASPBERRYPI_TTY_NAME + * @def MY_LINUX_TTY_NAME * @brief Set the name of predictable tty */ -#ifndef MY_RASPBERRYPI_TTY_NAME -#define MY_RASPBERRYPI_TTY_NAME /dev/ttyMySensorsGateway +#ifndef MY_LINUX_TTY_NAME +#define MY_LINUX_TTY_NAME "/dev/ttyMySensorsGateway" #endif /** - * @def MY_RASPBERRYPI_TTY_GROUPNAME + * @def MY_LINUX_TTY_GROUPNAME * @brief Set the group name for the raw tty */ -#ifndef MY_RASPBERRYPI_TTY_GROUPNAME -#define MY_RASPBERRYPI_TTY_GROUPNAME tty +#ifndef MY_LINUX_TTY_GROUPNAME +#define MY_LINUX_TTY_GROUPNAME tty #endif +/** + * @def MY_LINUX_CONFIG_FILE + * @brief Set the filepath for the gateway config file + * + * For now the configuration file is only used to store the emulated eeprom state + */ + #ifndef MY_LINUX_CONFIG_FILE + #define MY_LINUX_CONFIG_FILE "/etc/MySensorGateway.cfg" + #endif // Doxygen specific constructs, not included when built normally // This is used to enable disabled macros/definitions to be included in the documentation as well. diff --git a/MySensors.h b/MySensors.h index d849874a2..05d145f45 100644 --- a/MySensors.h +++ b/MySensors.h @@ -52,6 +52,10 @@ #define MY_NODE_TYPE "NODE" #endif +#if defined(MY_GATEWAY_RASPBERRYPI) + #define MY_GATEWAY_LINUX +#endif + // Enable radio "feature" if one of the radio types was enabled #if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) || defined(MY_RS485) #define MY_RADIO_FEATURE @@ -68,7 +72,7 @@ #elif defined(ARDUINO_ARCH_AVR) #include "core/MyHwATMega328.cpp" #elif defined(ARDUINO_ARCH_SAMD) - #include "core/MyHwSAMD.cpp" + #include "core/MyHwSAMD.cpp" #elif defined(LINUX_ARCH_GENERIC) // Remove PSTR macros from debug prints #undef PSTR @@ -80,6 +84,7 @@ #define snprintf_P(...) snprintf( __VA_ARGS__ ) #define memcpy_P memcpy #define pgm_read_dword(x) (*x) + #define pgm_read_byte_near(x) (*x) #include "core/MyHwLinuxGeneric.cpp" #endif @@ -197,7 +202,7 @@ #define MY_REPEATER_FEATURE #endif // GATEWAY - COMMON FUNCTIONS - // We only support MQTT Client using W5100 and ESP8266 at the moment + // We support MQTT Client using W5100, ESP8266 and Linux #if !(defined(MY_CONTROLLER_URL_ADDRESS) || defined(MY_CONTROLLER_IP_ADDRESS)) #error You must specify MY_CONTROLLER_IP_ADDRESS or MY_CONTROLLER_URL_ADDRESS #endif @@ -208,18 +213,25 @@ #if !defined(MY_MQTT_SUBSCRIBE_TOPIC_PREFIX) #error You must specify a topic subscribe prefix MY_MQTT_SUBSCRIBE_TOPIC_PREFIX for this MQTT client #endif - #if !defined(MY_MQTT_CLIENT_ID) + + #if !defined(MY_MQTT_CLIENT_ID) #error You must define a unique MY_MQTT_CLIENT_ID for this MQTT client #endif - #include "drivers/PubSubClient/PubSubClient.cpp" #include "core/MyGatewayTransport.cpp" + #include "core/MyProtocolMySensors.cpp" + + #if defined(MY_GATEWAY_LINUX) + #include "drivers/Linux/EthernetClient.cpp" + #include "drivers/Linux/EthernetServer.cpp" + #include "drivers/Linux/IPAddress.cpp" + #endif + #include "drivers/PubSubClient/PubSubClient.cpp" #include "core/MyGatewayTransportMQTTClient.cpp" #elif defined(MY_GATEWAY_FEATURE) // GATEWAY - COMMON FUNCTIONS #include "core/MyGatewayTransport.cpp" - // We currently only support one protocol at the moment, enable it. #include "core/MyProtocolMySensors.cpp" // GATEWAY - CONFIGURATION @@ -227,9 +239,6 @@ // We assume that a gateway having a radio also should act as repeater #define MY_REPEATER_FEATURE #endif - #if defined(MY_GATEWAY_RASPBERRYPI) - #define MY_GATEWAY_LINUX - #endif #if defined(MY_CONTROLLER_IP_ADDRESS) #define MY_GATEWAY_CLIENT_MODE #endif @@ -238,23 +247,16 @@ #endif #if defined(MY_GATEWAY_ESP8266) // GATEWAY - ESP8266 - #if defined(MY_GATEWAY_MQTT_CLIENT) - #include "drivers/pubsubclient/src/PubSubClient.cpp" - #include "core/MyGatewayTransportMQTTClient.cpp" - #else - #include "core/MyGatewayTransportEthernet.cpp" - #endif + #include "core/MyGatewayTransportEthernet.cpp" #elif defined(MY_GATEWAY_LINUX) - // GATEWAY - Generic Linux (RaspberryPi, BBB) - #include "core/MyGatewayTransportEthernetLinux.cpp" + // GATEWAY - Generic Linux (RaspberryPi, BBB, ...) + #include "drivers/Linux/EthernetClient.cpp" + #include "drivers/Linux/EthernetServer.cpp" + #include "drivers/Linux/IPAddress.cpp" + #include "core/MyGatewayTransportEthernet.cpp" #elif defined(MY_GATEWAY_W5100) // GATEWAY - W5100 - #if defined(MY_GATEWAY_MQTT_CLIENT) - #include "drivers/pubsubclient/src/PubSubClient.cpp" - #include "core/MyGatewayTransportMQTTClient.cpp" - #else - #include "core/MyGatewayTransportEthernet.cpp" - #endif + #include "core/MyGatewayTransportEthernet.cpp" #elif defined(MY_GATEWAY_ENC28J60) // GATEWAY - ENC28J60 #if defined(MY_USE_UDP) @@ -264,32 +266,9 @@ #elif defined(MY_GATEWAY_SERIAL) // GATEWAY - SERIAL #include "core/MyGatewayTransportSerial.cpp" - #endif #endif -// GATEWAY - MQTT -#if defined(MY_GATEWAY_MQTT_CLIENT) && !defined(MY_GATEWAY_LINUX) - // GATEWAY - COMMON FUNCTIONS - // We only support MQTT Client using W5100, ESP8266 or Linux/RasperryPi at the moment - #if !(defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_W5100) || defined(MY_GATEWAY_LINUX)) - #error We only support MQTT Client using W5100, ESP8266 or Linux/RasperryPi at the moment - #endif - - #if !(defined(MY_CONTROLLER_URL_ADDRESS) || defined(MY_CONTROLLER_IP_ADDRESS)) - #error You must specify MY_CONTROLLER_IP_ADDRESS or MY_CONTROLLER_URL_ADDRESS - #endif - - #if !defined(MY_MQTT_PUBLISH_TOPIC_PREFIX) - #error You must specify a topic publish prefix MY_MQTT_PUBLISH_TOPIC_PREFIX for this MQTT client - #endif - #if !defined(MY_MQTT_SUBSCRIBE_TOPIC_PREFIX) - #error You must specify a topic subscribe prefix MY_MQTT_SUBSCRIBE_TOPIC_PREFIX for this MQTT client - #endif - #if !defined(MY_MQTT_CLIENT_ID) - #error You must define a unique MY_MQTT_CLIENT_ID for this MQTT client - #endif -#endif // RADIO #if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) || defined(MY_RS485) diff --git a/configure b/configure new file mode 100755 index 000000000..ad46759c4 --- /dev/null +++ b/configure @@ -0,0 +1,322 @@ +#!/bin/bash +# This version is heavily based on the work of mz-fuzzy (https://github.com/mz-fuzzy) +# adapted to work with MySensors project. +# Original work: https://github.com/TMRh20/RF24/blob/master/configure + +function help { +cat < CPU defining/optimizing flags to be used. [configure autodetected] + --extra-cxxflags= Extra C flags passed to C/C++ compilation. [] + --extra-ldflags= Extra C flags passed to linking. [] + --libname= Library name. [rf24] + --cxx_compiler= C++ compiler [arm-linux-gnueabihf-g++][g++] + --no-clean Don't clean previous build artifacts. + --rf24h-lib-dir RF24 library files directory. + +Installation options: + --prefix= Installation prefix path. [/usr/local] + --gateway-dir= Gateway files installation directory. [PREFIX/bin] + +MySensors options: + --my-debug Enables debug. + --my-gateway-type=[ethernet|mqtt] + Gateway type, default to ethernet. + --my-config-file= Config file path. [/etc/MySensorGateway.cfg] + --my-rf24-enable Enables RF24 radio. + --my-rf24-channel=<0-125> RF channel for the sensor net, 0-125. + --my-rf24-pa-level=[RF24_PA_MAX|RF24_PA_LOW] + RF24 PA level. + --my-controller-url-address= + Controller or MQTT broker url. + --my-controller-ip-address= + Controller or MQTT broker ip. + Use commas instead of points. Example: 127,0,0,1 + --my-port Controller or MQTT broker port. + --my-mqtt-client-id= MQTT client id. + --my-mqtt-publish-topic-prefix= + MQTT publish topic prefix. + --my-mqtt-subscribe-topic-prefix= + MQTT subscribe topic prefix. + --my-rf24-irq-pin Pin number connected to nRF24L01 IRQ pin. + --my-rx-message-buffer-size Buffer size for incoming messages when using rf24 interrupts. + Default set to 20. +EOF +} + +function die { + echo "[ERROR] $1" + exit $2 +} + +function detect_rpi_revision { + # get PI Revision from cpuinfo + local pirev=$(eval "cat /proc/cpuinfo 2>/dev/null | grep Revision | cut -f 2 -d ':' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$$//'") + echo ${pirev} +} + +function detect_machine { + local cpu=$(eval "uname -m 2>/dev/null") + local machine=$(eval "cat /sys/firmware/devicetree/base/model 2>/dev/null") + local hardware=$(eval "grep sunxi_platform /sys/class/sunxi_info/sys_info 2>/dev/null | sed 's/^.*: \(.*\)$/\1/'") + if [ -z "$hardware" ]; then + local hardware=$(eval "grep Hardware /proc/cpuinfo 2>/dev/null | sed 's/^.*: \(.*\)$/\1/'") + fi + local soc="unknown" + local tp="unknown" + local rev="unknown" + + if [ -z "$cpu" ]; then + cpu="unknown" + fi + + case $hardware in + BCM2708) + soc="BCM2835" + if [[ $machine == "Raspberry"* ]]; then + tp="RPi" + rev=($(detect_rpi_revision)) + fi + ;; + BCM2709) + soc="BCM2836" + if [[ $machine == "Raspberry"* ]]; then + rev=($(detect_rpi_revision)) + if [[ $rev == "a02082" || $rev == "a22082" ]]; then + tp="RPi3" + else + tp="Rpi2" + fi + fi + ;; + sun4i|Sun4iw1p1) + soc="A10" + ;; + sun5i|Sun4iw2p1) + soc="A13" + ;; + Sun4iw2p2) + soc="A12" + ;; + Sun4iw2p3) + soc="A10s" + ;; + sun6i|Sun8iw1p1) + soc="A31" + ;; + Sun8iw1p2) + soc="A31s" + ;; + sun7i|Sun8iw2p1) + soc="A20" + if [[ $machine == "Banana Pi"* ]]; then + tp="BananaPi" + elif [[ $machine == "Banana Pro"* ]]; then + tp="BananaPro" + fi + ;; + sun8i|Sun8iw7p1) + soc="H3" + ;; + Sun8iw3p1) + soc="A23" + ;; + Sun8iw5p1) + soc="A33" + ;; + Sun8iw6p1) + soc="A83t" + ;; + sun9i|Sun9iw1p1) + soc="A80" + ;; + Sun9iw1p2) + soc="A80t" + ;; + sun50i|Sun50iw1p1) + soc="A64" + ;; + 'Generic AM33XX'*) + soc="AM33XX" + ;; + *) + soc="unknown" + esac + echo "${soc} ${tp} ${cpu} ${rev}" +} + +function gcc_cpu_flags { + local soc=$1 + case $soc in + BCM2835) + flags="-march=armv6zk -mtune=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard -DRASPBERRYPI_ARCH" + ;; + BCM2836) + flags="-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard -DRASPBERRYPI_ARCH" + ;; + AM33XX) + flags="-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard" + ;; + A10) + flags="-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard" + ;; + A13) + flags="-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard" + ;; + A20) + 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="" + esac + echo ${flags} +} + +params="OS SOC CPUFLAGS CXXFLAGS LDFLAGS PREFIX CXX RF24H_LIB_DIR GATEWAY_DIR" + +for opt do + if [ "$opt" = "-h" ] || [ "$opt" = "--help" ]; then + help + exit 0 + fi + optarg="${opt#*=}" + case "$opt" in + --os=*) + OS="$optarg" + ;; + --soc=*) + SOC="$optarg" + ;; + --cpu-flags=*) + CPUFLAGS="$optarg" + ;; + --extra-cxxflags=*) + CXXFLAGS="$optarg" + ;; + --extra-ldflags=*) + LDFLAGS="$optarg" + ;; + --cxx_compiler=*) + CXX="$optarg" + ;; + --no-clean*) + NO_CLEAN="1" + ;; + --prefix=*) + PREFIX="$optarg" + ;; + --rf24h-lib-dir=*) + RF24H_LIB_DIR="$optarg" + ;; + --gateway-dir=*) + GATEWAY_DIR="$optarg" + ;; + --my-debug*) + CXXFLAGS="-DMY_DEBUG $CXXFLAGS" + ;; + --my-gateway-type=*) + if [[ ${optarg} == "mqtt" ]]; then + LDFLAGS="-lmosquitto $LDFLAGS" + CXXFLAGS="-DMY_GATEWAY_MQTT_CLIENT $CXXFLAGS" + fi + ;; + --my-config-file=*) + CXXFLAGS="-DMY_CONFIG_FILE=${optarg} $CXXFLAGS" + ;; + --my-rf24-enable*) + CXXFLAGS="-DMY_RADIO_NRF24 $CXXFLAGS" + ;; + --my-rf24-channel=*) + CXXFLAGS="-DMY_RF24_CHANNEL=${optarg} $CXXFLAGS" + ;; + --my-rf24-pa-level=*) + CXXFLAGS="-DMY_RF24_PA_LEVEL=${optarg} $CXXFLAGS" + ;; + --my-controller-url-address=*) + CXXFLAGS="-DMY_CONTROLLER_URL_ADDRESS=${optarg} $CXXFLAGS" + ;; + --my-controller-ip-address=*) + CXXFLAGS="-DMY_CONTROLLER_IP_ADDRESS=${optarg} $CXXFLAGS" + ;; + --my-port=*) + CXXFLAGS="-DMY_PORT=${optarg} $CXXFLAGS" + ;; + --my-mqtt-client-id=*) + CXXFLAGS="-DMY_MQTT_CLIENT_ID=${optarg} $CXXFLAGS" + ;; + --my-mqtt-publish-topic-prefix=*) + CXXFLAGS="-DMY_MQTT_PUBLISH_TOPIC_PREFIX=${optarg} $CXXFLAGS" + ;; + --my-mqtt-subscribe-topic-prefix=*) + CXXFLAGS="-DMY_MQTT_SUBSCRIBE_TOPIC_PREFIX=${optarg} $CXXFLAGS" + ;; + --my-rf24-irq-pin=*) + CXXFLAGS="-DMY_RF24_IRQ_PIN=${optarg} $CXXFLAGS" + ;; + --my-rx-message-buffer-size=*) + CXXFLAGS="-DMY_RX_MESSAGE_BUFFER_SIZE=${optarg} $CXXFLAGS" + ;; + *) + echo "[WARNING] Unknown option detected:$opt, ignored" + ;; + esac +done + +PREFIX=${PREFIX:-/usr/local} +RF24H_LIB_DIR=${PREFIX}/include/RF24 +GATEWAY_DIR=${GATEWAY_DIR:-${PREFIX}/bin} +CXX=${CXX:-g++} + +if [ -z "${SOC}" ]; then + echo "[SECTION] Detecting target machine." + info=($(detect_machine)) + SOC=${info[0]} + TYPE=${info[1]} + CPU=${info[2]} + REV=${info[3]} + echo "[OK] machine detected: SoC=${SOC}, Type=${TYPE}, CPU=${CPU}, REV=${REV}." +fi + +if [ -z "${CPUFLAGS}" ]; then + CPUFLAGS=$(gcc_cpu_flags $SOC) +fi + +CXXFLAGS="$CPUFLAGS -Ofast -g -Wall -Wextra -DLINUX_ARCH_GENERIC $CXXFLAGS" + +if [[ $TYPE == "RPi2" || $TYPE == "RPi3" || $REV == "0010" ]]; then + CXXFLAGS+="-D__RPI_BPLUS" +fi + +LDFLAGS="-pthread -lrf24-bcm $LDFLAGS" + +echo "[SECTION] Saving configuration." +echo -n "" > Makefile.inc +for param in ${params}; do + if [[ ${!param} ]]; then + echo "${param}=${!param}" >> Makefile.inc + fi +done + +if [ -z "${NO_CLEAN}" ]; then + echo "[SECTION] Cleaning previous builds." + make clean >/dev/null +fi + + +echo "[OK] Finished." diff --git a/core/MyGatewayTransportEthernet.cpp b/core/MyGatewayTransportEthernet.cpp index 6c930e72b..a8f6599eb 100644 --- a/core/MyGatewayTransportEthernet.cpp +++ b/core/MyGatewayTransportEthernet.cpp @@ -26,7 +26,7 @@ #if defined(MY_IP_ADDRESS) IPAddress _ethernetGatewayIP(MY_IP_ADDRESS); #endif -byte _ethernetGatewayMAC[] = { MY_MAC_ADDRESS }; +uint8_t _ethernetGatewayMAC[] = { MY_MAC_ADDRESS }; uint16_t _ethernetGatewayPort = MY_PORT; MyMessage _ethernetMsg; @@ -36,8 +36,8 @@ MyMessage _ethernetMsg; typedef struct { - char string[MY_GATEWAY_MAX_RECEIVE_LENGTH]; - uint8_t idx; + char string[MY_GATEWAY_MAX_RECEIVE_LENGTH]; + uint8_t idx; } inputBuffer; #if defined(MY_GATEWAY_ESP8266) @@ -50,7 +50,6 @@ typedef struct IPAddress _gatewayIp(MY_IP_GATEWAY_ADDRESS); IPAddress _subnetIp(MY_IP_SUBNET_ADDRESS); #endif - static bool clientsConnected[MY_GATEWAY_MAX_CLIENTS]; #endif #if defined(MY_USE_UDP) @@ -60,8 +59,9 @@ typedef struct #endif -#if defined(MY_GATEWAY_ESP8266) +#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX) static EthernetClient clients[MY_GATEWAY_MAX_CLIENTS]; + static bool clientsConnected[MY_GATEWAY_MAX_CLIENTS]; static inputBuffer inputString[MY_GATEWAY_MAX_CLIENTS]; #else static EthernetClient client = EthernetClient(); @@ -78,18 +78,18 @@ typedef struct #ifdef MY_W5100_SPI_EN void _w5100_spi_en(bool enable) { - if (enable) - { - // Pull up pin - pinMode(MY_W5100_SPI_EN, INPUT); - digitalWrite(MY_W5100_SPI_EN, HIGH); - } - else - { - // Ground pin - pinMode(MY_W5100_SPI_EN, OUTPUT); - digitalWrite(MY_W5100_SPI_EN, LOW); - } + if (enable) + { + // Pull up pin + pinMode(MY_W5100_SPI_EN, INPUT); + digitalWrite(MY_W5100_SPI_EN, HIGH); + } + else + { + // Ground pin + pinMode(MY_W5100_SPI_EN, OUTPUT); + digitalWrite(MY_W5100_SPI_EN, LOW); + } } #else #define _w5100_spi_en(x) @@ -119,7 +119,8 @@ bool gatewayTransportInit() { MY_SERIALDEVICE.print(F("IP: ")); MY_SERIALDEVICE.println(WiFi.localIP()); #endif - + #elif defined(MY_GATEWAY_LINUX) + // Nothing to do here #else #ifdef MY_IP_ADDRESS Ethernet.begin(_ethernetGatewayMAC, _ethernetGatewayIP); @@ -140,8 +141,12 @@ bool gatewayTransportInit() { #ifdef MY_USE_UDP _ethernetServer.begin(_ethernetGatewayPort); #else - // we have to use pointers due to the constructor of EthernetServer - _ethernetServer.begin(); + #if defined(MY_GATEWAY_LINUX) && defined(MY_IP_ADDRESS) + _ethernetServer.begin(_ethernetGatewayIP); + #else + // we have to use pointers due to the constructor of EthernetServer + _ethernetServer.begin(); + #endif #endif /* USE_UDP */ _w5100_spi_en(false); return true; @@ -152,7 +157,7 @@ bool gatewayTransportSend(MyMessage &message) bool ret = true; char *_ethernetMsg = protocolFormat(message); - setIndication(INDICATION_GW_TX); + setIndication(INDICATION_GW_TX); _w5100_spi_en(true); #if defined(MY_CONTROLLER_IP_ADDRESS) @@ -164,16 +169,16 @@ bool gatewayTransportSend(MyMessage &message) #else EthernetClient client; #if defined(MY_CONTROLLER_URL_ADDRESS) - if (client.connected() || client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) { - #else - if (client.connected() || client.connect(_ethernetControllerIP, MY_PORT)) { - #endif - client.write(_ethernetMsg, strlen(_ethernetMsg)); - } - else { - // connecting to the server failed! - ret = false; - } + if (client.connected() || client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) { + #else + if (client.connected() || client.connect(_ethernetControllerIP, MY_PORT)) { + #endif + client.write(_ethernetMsg, strlen(_ethernetMsg)); + } + else { + // connecting to the server failed! + ret = false; + } #endif #else // Send message to connected clients @@ -195,7 +200,7 @@ bool gatewayTransportSend(MyMessage &message) } -#if defined(MY_GATEWAY_ESP8266) +#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX) bool _readFromClient(uint8_t i) { while (clients[i].connected() && clients[i].available()) { char inChar = clients[i].read(); @@ -270,7 +275,7 @@ bool gatewayTransportAvailable() if (packet_size) { //debug(PSTR("UDP packet available. Size:%d\n"), packet_size); - setIndication(INDICATION_GW_RX); + setIndication(INDICATION_GW_RX); #if defined(MY_GATEWAY_ESP8266) _ethernetServer.read(inputString[0].string, MY_GATEWAY_MAX_RECEIVE_LENGTH); inputString[0].string[packet_size] = 0; @@ -285,7 +290,7 @@ bool gatewayTransportAvailable() #endif } #else - #if defined(MY_GATEWAY_ESP8266) + #if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX) // ESP8266: Go over list of clients and stop any that are no longer connected. // If the server has a new client connection it will be assigned to a free slot. bool allSlotsOccupied = true; @@ -318,7 +323,7 @@ bool gatewayTransportAvailable() // Loop over clients connect and read available data for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++) { if (_readFromClient(i)) { - setIndication(INDICATION_GW_RX); + setIndication(INDICATION_GW_RX); _w5100_spi_en(false); return true; } @@ -344,7 +349,7 @@ bool gatewayTransportAvailable() client.stop(); } else { if (_readFromClient()) { - setIndication(INDICATION_GW_RX); + setIndication(INDICATION_GW_RX); _w5100_spi_en(false); return true; } @@ -363,7 +368,7 @@ MyMessage& gatewayTransportReceive() } -#if !defined(MY_IP_ADDRESS) && !defined(MY_GATEWAY_ESP8266) +#if !defined(MY_IP_ADDRESS) && !defined(MY_GATEWAY_ESP8266) && !defined(MY_GATEWAY_LINUX) void gatewayTransportRenewIP() { /* renew/rebind IP address diff --git a/core/MyGatewayTransportMQTTClient.cpp b/core/MyGatewayTransportMQTTClient.cpp index b6ca3779a..85f5186da 100644 --- a/core/MyGatewayTransportMQTTClient.cpp +++ b/core/MyGatewayTransportMQTTClient.cpp @@ -32,8 +32,10 @@ IPAddress _gatewayIp(MY_IP_GATEWAY_ADDRESS); IPAddress _subnetIp(MY_IP_SUBNET_ADDRESS); #endif +#elif defined(MY_GATEWAY_LINUX) + // Nothing to do here #else - byte _MQTT_clientMAC[] = { MY_MAC_ADDRESS }; + uint8_t _MQTT_clientMAC[] = { MY_MAC_ADDRESS }; #endif #if defined(MY_IP_ADDRESS) @@ -46,98 +48,20 @@ static bool _MQTT_connecting = true; static bool _MQTT_available = false; static MyMessage _MQTT_msg; -uint8_t protocolH2i(char c) { - uint8_t i = 0; - if (c <= '9') - i += c - '0'; - else if (c >= 'a') - i += c - 'a' + 10; - else - i += c - 'A' + 10; - return i; -} - - bool gatewayTransportSend(MyMessage &message) { if (!_MQTT_client.connected()) return false; setIndication(INDICATION_GW_TX); - char _fmtBuffer[MY_GATEWAY_MAX_SEND_LENGTH]; - char _convBuffer[MAX_PAYLOAD * 2 + 1]; - snprintf_P(_fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, PSTR(MY_MQTT_PUBLISH_TOPIC_PREFIX "/%d/%d/%d/%d/%d"), message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type); - debug(PSTR("Sending message on topic: %s\n"), _fmtBuffer); - return _MQTT_client.publish(_fmtBuffer, message.getString(_convBuffer)); + char *topic = protocolFormatMQTTTopic(MY_MQTT_PUBLISH_TOPIC_PREFIX, message); + debug(PSTR("Sending message on topic: %s\n"), topic); + return _MQTT_client.publish(topic, message.getString(_convBuffer)); } -void incomingMQTT(char* topic, byte* payload, unsigned int length) { +void incomingMQTT(char* topic, uint8_t* payload, unsigned int length) { debug(PSTR("Message arrived on topic: %s\n"), topic); - char *str, *p; - uint8_t i = 0; - uint8_t bvalue[MAX_PAYLOAD]; - uint8_t blen = 0; - uint8_t command = 0; - for (str = strtok_r(topic, "/", &p); str && i <= 5; - str = strtok_r(NULL, "/", &p)) { - switch (i) { - case 0: { - // Topic prefix - if (strcmp(str, MY_MQTT_SUBSCRIBE_TOPIC_PREFIX) != 0) { - // Message not for us or malformed! - return; - } - break; - } - case 1: { - // Node id - _MQTT_msg.destination = atoi(str); - break; - } - case 2: { - // Sensor id - _MQTT_msg.sensor = atoi(str); - break; - } - case 3: { - // Command type - command = atoi(str); - mSetCommand(_MQTT_msg, command); - break; - } - case 4: { - // Ack flag - mSetRequestAck(_MQTT_msg, atoi(str) ? 1 : 0); - break; - } - case 5: { - // Sub type - _MQTT_msg.type = atoi(str); - // Add payload - if (command == C_STREAM) { - blen = 0; - uint8_t val; - while (*payload) { - val = protocolH2i(*payload++) << 4; - val += protocolH2i(*payload++); - bvalue[blen] = val; - blen++; - } - _MQTT_msg.set(bvalue, blen); - } - else { - char* ca; - ca = (char *)payload; - ca += length; - *ca = '\0'; - _MQTT_msg.set((const char*)payload); - } - _MQTT_available = true; - } - } - i++; - } + _MQTT_available = protocolMQTTParse(_MQTT_msg, topic, payload, length); } - bool reconnectMQTT() { debug(PSTR("Attempting MQTT connection...\n")); // Attempt to connect @@ -168,6 +92,10 @@ bool gatewayTransportConnect() { } MY_SERIALDEVICE.print("IP: "); MY_SERIALDEVICE.println(WiFi.localIP()); + #elif defined(MY_GATEWAY_LINUX) + #if defined(MY_IP_ADDRESS) + //TODO + #endif #else #ifdef MY_IP_ADDRESS Ethernet.begin(_MQTT_clientMAC, _MQTT_clientIp); @@ -215,8 +143,6 @@ bool gatewayTransportInit() { return true; } - - bool gatewayTransportAvailable() { if (_MQTT_connecting) @@ -239,6 +165,3 @@ MyMessage & gatewayTransportReceive() { _MQTT_available = false; return _MQTT_msg; } - - - diff --git a/core/MyHwATMega328.h b/core/MyHwATMega328.h index 157ecb1fd..c48623980 100644 --- a/core/MyHwATMega328.h +++ b/core/MyHwATMega328.h @@ -57,7 +57,13 @@ do { \ // Define these as macros to save valuable space #define hwDigitalWrite(__pin, __value) (digitalWrite(__pin, __value)) -#define hwInit() MY_SERIALDEVICE.begin(MY_BAUD_RATE) + +#if defined(MY_DISABLED_SERIAL) + #define hwInit() +#else + #define hwInit() MY_SERIALDEVICE.begin(MY_BAUD_RATE) +#endif + #define hwWatchdogReset() wdt_reset() #define hwReboot() wdt_enable(WDTO_15MS); while (1) #define hwMillis() millis() diff --git a/core/MyHwESP8266.h b/core/MyHwESP8266.h index 1495e6902..2c5a942a6 100644 --- a/core/MyHwESP8266.h +++ b/core/MyHwESP8266.h @@ -33,7 +33,13 @@ // Define these as macros to save valuable space #define hwDigitalWrite(__pin, __value) (digitalWrite(__pin, __value)) -#define hwInit() MY_SERIALDEVICE.begin(MY_BAUD_RATE); MY_SERIALDEVICE.setDebugOutput(true) + +#if defined(MY_DISABLED_SERIAL) + #define hwInit() +#else + #define hwInit() MY_SERIALDEVICE.begin(MY_BAUD_RATE); MY_SERIALDEVICE.setDebugOutput(true) +#endif + #define hwWatchdogReset() wdt_reset() #define hwReboot() ESP.restart(); #define hwMillis() millis() diff --git a/core/MyHwLinuxGeneric.cpp b/core/MyHwLinuxGeneric.cpp new file mode 100644 index 000000000..272fe2910 --- /dev/null +++ b/core/MyHwLinuxGeneric.cpp @@ -0,0 +1,190 @@ +/** + * 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. + */ + +#include "MyHwLinuxGeneric.h" + +#include +#include +#include +#include +#include + +static const char* CONFIG_FILE = MY_LINUX_CONFIG_FILE; +static const size_t _length = 1024; // ATMega328 has 1024 bytes +static uint8_t _config[_length]; +static unsigned long millis_at_start; + +bool CheckConfigFile() { + struct stat fileInfo; + + if(stat(CONFIG_FILE, &fileInfo) != 0) + { + //File does not exist. Create it. + debug("Config file %s does not exist, creating new config file.\n", CONFIG_FILE); + ofstream myFile(CONFIG_FILE, ios::out | ios::binary); + if(!myFile) + { + debug("Unable to create config file %s.\n", CONFIG_FILE); + return false; + } + myFile.write((const char*)_config, _length); + myFile.close(); + } + else if(fileInfo.st_size < 0 || (size_t)fileInfo.st_size != _length) + { + debug("Config file %s is not the correct size of %i. Please remove the file and a new one will be created.\n", CONFIG_FILE, _length); + return false; + } + else + { + //Read config into local memory. + ifstream myFile(CONFIG_FILE, ios::in | ios::binary); + if(!myFile) + { + debug("Unable to open config to file %s for reading.\n", CONFIG_FILE); + return false; + } + myFile.read((char*)_config, _length); + myFile.close(); + } + + return true; +} + +void hwInit() +{ + timeval curTime; + + for (size_t i = 0; i < _length; i++) + _config[i] = 0xFF; + + if (!CheckConfigFile()) + { + exit(1); + } + + gettimeofday(&curTime, NULL); + millis_at_start = curTime.tv_sec; +} + +void hwReadConfigBlock(void* buf, void* addr, size_t length) +{ + unsigned long int offs = reinterpret_cast(addr); + + if (length && offs + length <= _length) { + memcpy(buf, _config+offs, length); + } +} + +void hwWriteConfigBlock(void* buf, void* addr, size_t length) +{ + unsigned long int offs = reinterpret_cast(addr); + + if (length && offs + length <= _length) { + memcpy(_config+offs, buf, length); + + ofstream myFile(CONFIG_FILE, ios::out | ios::binary); + if(!myFile) + { + debug("Unable to write config to file %s.\n", CONFIG_FILE); + return; + } + myFile.write((const char*)buf+offs, _length); + myFile.close(); + } +} + +uint8_t hwReadConfig(int adr) +{ + uint8_t value = 0xFF; + hwReadConfigBlock(&value, reinterpret_cast(adr), 1); + return value; +} + +void hwWriteConfig(int adr, uint8_t value) +{ + uint8_t curr = hwReadConfig(adr); + if (curr != value) + { + hwWriteConfigBlock(&value, reinterpret_cast(adr), 1); + } +} + +unsigned long hwMillis() +{ + timeval curTime; + + gettimeofday(&curTime, NULL); + return ((curTime.tv_sec - millis_at_start) * 1000) + (curTime.tv_usec / 1000); +} + +// TODO: Not supported! +int8_t hwSleep(unsigned long ms) +{ + (void)ms; + + return -2; +} + +// TODO: Not supported! +int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) +{ + (void)interrupt; + (void)mode; + (void)ms; + + return -2; +} + +// TODO: 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 -2; +} + +uint16_t hwCPUVoltage() { + // TODO: Not supported! + return 0; +} + +uint16_t hwCPUFrequency() { + // TODO: Not supported! + return 0; +} + +uint16_t hwFreeMem() { + // TODO: Not supported! + return 0; +} + +#ifdef MY_DEBUG +void hwDebugPrint(const char *fmt, ... ) +{ + va_list arglist; + va_start(arglist, fmt); + vprintf(fmt, arglist); + va_end(arglist); +} +#endif diff --git a/core/MyHwLinuxGeneric.h b/core/MyHwLinuxGeneric.h new file mode 100644 index 000000000..32e840693 --- /dev/null +++ b/core/MyHwLinuxGeneric.h @@ -0,0 +1,75 @@ +/** + * 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. + */ + +#ifndef MyHwLinuxGeneric_h +#define MyHwLinuxGeneric_h + +#include "MyHw.h" +#include +#include +#include + +#define MY_SERIALDEVICE Serial + +// Define these as macros (do nothing) +#define hwDigitalWrite(__pin, __value) +#define hwWatchdogReset() +#define hwReboot() + +using namespace std; + +void hwInit(); +void hwReadConfigBlock(void* buf, void* adr, size_t length); +void hwWriteConfigBlock(void* buf, void* adr, size_t length); +void hwWriteConfig(int adr, uint8_t value); +uint8_t hwReadConfig(int adr); +unsigned long hwMillis(); + +#ifdef MY_RF24_IRQ_PIN +static pthread_mutex_t hw_mutex = PTHREAD_MUTEX_INITIALIZER; + +static __inline__ void __hwUnlock(const uint8_t *__s) { + pthread_mutex_unlock(&hw_mutex); + (void)__s; +} + +static __inline__ void __hwLock() { + pthread_mutex_lock(&hw_mutex); +} +#endif + +#if defined(__DOXYGEN__) + #define ATOMIC_BLOCK_CLEANUP +#elif defined(MY_RF24_IRQ_PIN) + #define ATOMIC_BLOCK_CLEANUP uint8_t __atomic_loop \ + __attribute__((__cleanup__( __hwUnlock ))) = 1 +#endif /* __DOXYGEN__ */ + +#if defined(__DOXYGEN__) + #define ATOMIC_BLOCK +#elif defined(MY_RF24_IRQ_PIN) + #define ATOMIC_BLOCK for ( ATOMIC_BLOCK_CLEANUP, __hwLock(); \ + __atomic_loop ; __atomic_loop = 0 ) +#endif /* __DOXYGEN__ */ + +#ifndef DOXYGEN + #define MY_CRITICAL_SECTION ATOMIC_BLOCK +#endif /* DOXYGEN */ + +#endif diff --git a/core/MyMainLinux.cpp b/core/MyMainLinux.cpp new file mode 100644 index 000000000..5ecab964d --- /dev/null +++ b/core/MyMainLinux.cpp @@ -0,0 +1,39 @@ +// Initialize library and handle sketch functions like we want to + +#include +#include +#include "MySensorsCore.h" + +volatile static int running = 1; + +/* + * handler for SIGINT signal + */ +void handle_sigint(int sig) +{ + running = 0; + + if (sig == SIGINT) { + std::cout << "Received SIGINT\n" << std::endl; + } else if (sig == SIGTERM) { + std::cout << "Received SIGTERM\n" << std::endl; + } + + #ifdef MY_RF24_IRQ_PIN + detachInterrupt(MY_RF24_IRQ_PIN); + #endif +} + +int main(void) { + /* register the signal handler */ + signal(SIGINT, handle_sigint); + signal(SIGTERM, handle_sigint); + + _begin(); // Startup MySensors library + + while (running) { + _process(); // Process incoming data + if (loop) loop(); // Call sketch loop + } + return 0; +} diff --git a/core/MyMessage.cpp b/core/MyMessage.cpp index 027b273af..1179a0b7f 100644 --- a/core/MyMessage.cpp +++ b/core/MyMessage.cpp @@ -21,7 +21,11 @@ #include "MyMessage.h" #include #include +#include +#ifndef ARDUINO + #define min(a,b) ((a)<(b)?(a):(b)) +#endif MyMessage::MyMessage() { diff --git a/core/MyMessage.h b/core/MyMessage.h index aa84b49a6..b11a7fffe 100644 --- a/core/MyMessage.h +++ b/core/MyMessage.h @@ -32,7 +32,6 @@ #ifdef __cplusplus #include -#include #include #endif diff --git a/core/MyProtocolMySensors.cpp b/core/MyProtocolMySensors.cpp index 18fdbd5b2..8c96b4279 100644 --- a/core/MyProtocolMySensors.cpp +++ b/core/MyProtocolMySensors.cpp @@ -20,6 +20,7 @@ #include "MyConfig.h" #include "MyTransport.h" #include "MyProtocol.h" +#include uint8_t protocolH2i(char c); @@ -32,7 +33,6 @@ bool protocolParse(MyMessage &message, char *inputString) { uint8_t blen = 0; int i = 0; uint8_t command = 0; - uint8_t ack = 0; // Extract command data coming on serial line for (str = strtok_r(inputString, ";", &p); // split using semicolon @@ -51,7 +51,7 @@ bool protocolParse(MyMessage &message, char *inputString) { mSetCommand(message, command); break; case 3: // Should we request ack from destination? - ack = atoi(str); + mSetRequestAck(message, atoi(str)?1:0); break; case 4: // Data type message.type = atoi(str); @@ -86,8 +86,7 @@ bool protocolParse(MyMessage &message, char *inputString) { message.sender = GATEWAY_ADDRESS; message.last = GATEWAY_ADDRESS; - mSetRequestAck(message, ack?1:0); - mSetAck(message, false); + mSetAck(message, false); if (command == C_STREAM) message.set(bvalue, blen); else @@ -110,23 +109,23 @@ char * protocolFormatMQTTSubscribe(const char* prefix) { return _fmtBuffer; } -void protocolMQTTParse(MyMessage &message, char* topic, uint8_t* payload, unsigned int length) { - //TODO: Not sure if we should copy the topic and payload into a buffer so we are not modifying original. +#ifdef MY_GATEWAY_MQTT_CLIENT +bool protocolMQTTParse(MyMessage &message, char* topic, uint8_t* payload, unsigned int length) { char *str, *p; uint8_t i = 0; uint8_t bvalue[MAX_PAYLOAD]; uint8_t blen = 0; uint8_t command = 0; + for (str = strtok_r(topic, "/", &p); str && i <= 5; str = strtok_r(NULL, "/", &p)) { switch (i) { case 0: { // Topic prefix - //TODO: Should be checking the topic prefix - //if (strcmp(str, MY_MQTT_SUBSCRIBE_TOPIC_PREFIX) != 0) { + if (strcmp(str, MY_MQTT_SUBSCRIBE_TOPIC_PREFIX) != 0) { // Message not for us or malformed! - // return; - //} + return false; + } break; } case 1: { @@ -153,29 +152,41 @@ void protocolMQTTParse(MyMessage &message, char* topic, uint8_t* payload, unsign case 5: { // Sub type message.type = atoi(str); - // Add payload - if (command == C_STREAM) { - blen = 0; - uint8_t val; - while (*payload) { - val = protocolH2i(*payload++) << 4; - val += protocolH2i(*payload++); - bvalue[blen] = val; - blen++; - } - message.set(bvalue, blen); - } else { - char* ca; - ca = (char *) payload; - ca += length; - *ca = '\0'; - message.set((const char*) payload); - } + break; } } i++; } + + if (i != 6) + return false; + + message.sender = GATEWAY_ADDRESS; + message.last = GATEWAY_ADDRESS; + mSetAck(message, false); + + // Add payload + if (command == C_STREAM) { + blen = 0; + uint8_t val; + while (*payload) { + val = protocolH2i(*payload++) << 4; + val += protocolH2i(*payload++); + bvalue[blen] = val; + blen++; + } + message.set(bvalue, blen); + } else { + char* ca; + ca = (char *) payload; + ca += length; + *ca = '\0'; + message.set((const char*) payload); + } + + return true; } +#endif uint8_t protocolH2i(char c) { uint8_t i = 0; @@ -187,5 +198,3 @@ uint8_t protocolH2i(char c) { i += c - 'A' + 10; return i; } - - diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 0be57819e..959e33b59 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -51,6 +51,10 @@ void _process() { transportProcess(); #endif + #if defined(LINUX_ARCH_GENERIC) + // To avoid high cpu usage + usleep(10000); // 10ms + #endif } void _infiniteLoop() { @@ -61,17 +65,17 @@ void _infiniteLoop() { #if defined (MY_LEDS_BLINKING_FEATURE) ledsProcess(); #endif + #if defined(LINUX_ARCH_GENERIC) + exit(1); + #endif } } void _begin() { - if (preHwInit) preHwInit(); - #if !defined(MY_DISABLED_SERIAL) - hwInit(); - #endif + hwInit(); debug(PSTR("MCO:BGN:INIT " MY_NODE_TYPE ",CP=" MY_CAPABILITIES ",VER=" MYSENSORS_LIBRARY_VERSION "\n")); diff --git a/core/MyTransport.cpp b/core/MyTransport.cpp index a54c34dd7..61925e72b 100644 --- a/core/MyTransport.cpp +++ b/core/MyTransport.cpp @@ -467,7 +467,7 @@ void transportProcessMessage() { // Is message addressed to this node? if (destination == _nc.nodeId) { // prevent buffer overflow by limiting max. possible message length (5 bits=31 bytes max) to MAX_PAYLOAD (25 bytes) - mSetLength(_msg, min(mGetLength(_msg),MAX_PAYLOAD)); + mSetLength(_msg, min(mGetLength(_msg),(uint8_t)MAX_PAYLOAD)); // null terminate data _msg.data[mGetLength(_msg)] = 0x00; @@ -717,4 +717,4 @@ bool transportSendWrite(uint8_t to, MyMessage &message) { return (ok || to==BROADCAST_ADDRESS); } -// EOF MyTransport.cpp \ No newline at end of file +// EOF MyTransport.cpp diff --git a/core/MyTransportNRF24.cpp b/core/MyTransportNRF24.cpp index 6d7f40737..fa72736ba 100644 --- a/core/MyTransportNRF24.cpp +++ b/core/MyTransportNRF24.cpp @@ -19,7 +19,13 @@ #include "MyConfig.h" #include "MyTransport.h" -#include "drivers/RF24/RF24.h" + +#ifdef RASPBERRYPI_ARCH + #include "drivers/RF24/RF24_RPi.cpp" +#else + #include "drivers/RF24/RF24.h" +#endif + #include "drivers/CircularBuffer/CircularBuffer.h" #if defined(MY_RF24_ENABLE_ENCRYPTION) diff --git a/core/MyTransportRS485.cpp b/core/MyTransportRS485.cpp index 814f721fd..285c1d1c9 100644 --- a/core/MyTransportRS485.cpp +++ b/core/MyTransportRS485.cpp @@ -57,12 +57,7 @@ #include "MyTransport.h" #include - -#if defined(ARDUINO) && ARDUINO >= 100 #include -#else -#include -#endif #include "MyTransport.h" diff --git a/drivers/Linux/Arduino.h b/drivers/Linux/Arduino.h new file mode 100644 index 000000000..7ae816294 --- /dev/null +++ b/drivers/Linux/Arduino.h @@ -0,0 +1,212 @@ +#ifndef Arduino_h +#define Arduino_h + +#include + +#ifndef LSBFIRST + #define LSBFIRST 0 +#endif + +#ifndef MSBFIRST + #define MSBFIRST 1 +#endif + +#define abs(x) ((x)>0?(x):-(x)) +#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) +#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) +#define radians(deg) ((deg)*DEG_TO_RAD) +#define degrees(rad) ((rad)*RAD_TO_DEG) +#define sq(x) ((x)*(x)) + +#define lowByte(w) ((uint8_t) ((w) & 0xff)) +#define highByte(w) ((uint8_t) ((w) >> 8)) + +#define bit(b) (1UL << (b)) + +typedef bool boolean; +typedef uint8_t byte; + +#ifdef __cplusplus + extern "C" { +#endif + +/** +* C++ version 0.4 char* style "itoa": +* Written by Lukás Chmela +* Released under GPLv3. +*/ +char *itoa(int value, char* result, int base) { + // check that the base if valid + if (base < 2 || base > 36) { *result = '\0'; return result; } + + char* ptr = result, *ptr1 = result, tmp_char; + int tmp_value; + + do { + tmp_value = value; + value /= base; + *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)]; + } while ( value ); + + // Apply negative sign + // Apply negative sign + if (tmp_value < 0) *ptr++ = '-'; + *ptr-- = '\0'; + while(ptr1 < ptr) { + tmp_char = *ptr; + *ptr--= *ptr1; + *ptr1++ = tmp_char; + } + return result; +} + +/** + * C++ version 0.4 char* style "itoa": + * Written by Lukás Chmela + * Released under GPLv3. + */ +char *ltoa(long value, char* result, int base) { + // check that the base if valid + if (base < 2 || base > 36) { *result = '\0'; return result; } + + char* ptr = result, *ptr1 = result, tmp_char; + long tmp_value; + + do { + tmp_value = value; + value /= base; + *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)]; + } while ( value ); + + // Apply negative sign + if (tmp_value < 0) *ptr++ = '-'; + *ptr-- = '\0'; + while(ptr1 < ptr) { + tmp_char = *ptr; + *ptr--= *ptr1; + *ptr1++ = tmp_char; + } + return result; +} + +char *ultoa(long num, char *str, int radix) +{ + unsigned long value; + char *sp = str; + char *sp2; + + value = num; + + /* Store sign at start of buffer for negative base-10 values */ + if (10 == radix && 0 > num) { + *sp++ = '-'; + value = -num; + } + + sp2 = sp; + + do { + char rem = value % radix; + value /= radix; + if (10 > rem) { + *sp++ = '0' + rem; + } else { + *sp++ = 'A' + rem - 10; + } + } while (0 < value); + + /* Mark end of string */ + *sp-- = 0; + + /* Reverse string contents (excluding sign) in place */ + while (sp2 < sp) { + char tmp = *sp2; + *sp2++ = *sp; + *sp-- = tmp; + } + + return str; +} + +/** + * Copyright (c) 2012, Peter A. Bigot + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of the software nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +char *utoa(int num, char *str, int radix) +{ + unsigned int value; + char *sp = str; + char *sp2; + + value = num; + + /* Store sign at start of buffer for negative base-10 values */ + if (10 == radix && 0 > num) { + *sp++ = '-'; + value = -num; + } + + sp2 = sp; + + do { + char rem = value % radix; + value /= radix; + if (10 > rem) { + *sp++ = '0' + rem; + } else { + *sp++ = 'A' + rem - 10; + } + } while (0 < value); + + /* Mark end of string */ + *sp-- = 0; + + /* Reverse string contents (excluding sign) in place */ + while (sp2 < sp) { + char tmp = *sp2; + *sp2++ = *sp; + *sp-- = tmp; + } + + return str; +} + +char *dtostrf(float f, int width, int decimals, char *result) +{ + sprintf(result,"%*.*f", width, decimals, f); + return result; +} + +#ifdef __cplusplus + } +#endif + +#endif diff --git a/drivers/Linux/Client.h b/drivers/Linux/Client.h new file mode 100644 index 000000000..0169890df --- /dev/null +++ b/drivers/Linux/Client.h @@ -0,0 +1,46 @@ +/* + Client.h - Base class that provides Client + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified by Marcelo Aquino for MySensors use +*/ + +#ifndef client_h +#define client_h +#include "Stream.h" +#include "IPAddress.h" + +class Client : public Stream { + +public: + virtual int connect(IPAddress ip, uint16_t port) = 0; + virtual int connect(const char *host, uint16_t port) = 0; + virtual size_t write(uint8_t) = 0; + virtual size_t write(const uint8_t *buf, size_t size) = 0; + virtual int available() = 0; + virtual int read() = 0; + virtual int read(uint8_t *buf, size_t size) = 0; + virtual int peek() = 0; + virtual void flush() = 0; + virtual void stop() = 0; + virtual uint8_t connected() = 0; + virtual operator bool() = 0; +protected: + uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; +}; + +#endif diff --git a/drivers/Linux/EthernetClient.cpp b/drivers/Linux/EthernetClient.cpp new file mode 100644 index 000000000..17774298b --- /dev/null +++ b/drivers/Linux/EthernetClient.cpp @@ -0,0 +1,253 @@ +/* +* 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 Arduino ethernet library, Copyright (c) 2010 Arduino LLC. All right reserved. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "EthernetClient.h" + +EthernetClient::EthernetClient() : _sock(-1) { +} + +EthernetClient::EthernetClient(int sock) : _sock(sock) { +} + +int EthernetClient::connect(const char* host, uint16_t port) { + int sockfd; + struct addrinfo hints, *servinfo, *p; + int rv; + char s[INET6_ADDRSTRLEN]; + char port_str[6]; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + sprintf(port_str, "%hu", port); + if ((rv = getaddrinfo(host, port_str, &hints, &servinfo)) != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); + return -1; + } + + // loop through all the results and connect to the first we can + for (p = servinfo; p != NULL; p = p->ai_next) { + if ((sockfd = socket(p->ai_family, p->ai_socktype, + p->ai_protocol)) == -1) { + perror("socket"); + continue; + } + + if (::connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) { + close(sockfd); + perror("connect"); + continue; + } + + break; + } + + if (p == NULL) { + fprintf(stderr, "failed to connect\n"); + return -1; + } + + _sock = sockfd; + + void *addr = &(((struct sockaddr_in*)p->ai_addr)->sin_addr); + inet_ntop(p->ai_family, addr, s, sizeof s); + ETHERNETCLIENT_DEBUG("connected to %s\n", s); + + freeaddrinfo(servinfo); // all done with this structure + + return 1; +} + +int EthernetClient::connect(IPAddress ip, uint16_t port) { + return connect(ip.toString().c_str(), port); +} + +size_t EthernetClient::write(uint8_t b) { + return write(&b, 1); +} + +size_t EthernetClient::write(const uint8_t *buf, size_t size) { + int rc = 0; + int bytes = 0; + + if (_sock == -1) { + return 0; + } + + while (size > 0) { + rc = send(_sock, buf + bytes, size, MSG_NOSIGNAL | MSG_DONTWAIT); + if (rc == -1) { + perror("send"); + close(_sock); + _sock = -1; + break; + } + bytes += rc; + size -= rc; + } + + return bytes; +} + +size_t EthernetClient::write(const char *str) { + if (str == NULL) return 0; + return write((const uint8_t *)str, strlen(str)); +} +size_t EthernetClient::write(const char *buffer, size_t size) { + return write((const uint8_t *)buffer, size); +} + +int EthernetClient::available() { + int count = 0; + + if (_sock != -1) { + ioctl(_sock, FIONREAD, &count); + return count; + } + return 0; +} + +int EthernetClient::read() { + uint8_t b; + if ( recv(_sock, &b, 1, 0) > 0 ) + { + // recv worked + return b; + } else { + // No data available + return -1; + } +} + +int EthernetClient::read(uint8_t *buf, size_t size) { + return recv(_sock, buf, size, 0); +} + +int EthernetClient::peek() { + uint8_t b; + + return recv(_sock, &b, 1, MSG_PEEK | MSG_DONTWAIT); +} + +void EthernetClient::flush() { + // There isn't much we can do here + return; +} + +void EthernetClient::stop() { + if (_sock == -1) + return; + + // attempt to close the connection gracefully (send a FIN to other side) + shutdown(_sock, SHUT_RDWR); + + timeval startTime, curTime; + gettimeofday(&startTime, NULL); + + // wait up to a second for the connection to close + uint8_t s; + do { + s = status(); + if (s == ETHERNETCLIENT_W5100_CLOSED) + break; // exit the loop + usleep(1000); + gettimeofday(&curTime, NULL); + } while (((curTime.tv_sec - startTime.tv_sec) * 1000000) + (curTime.tv_usec - startTime.tv_usec) < 1000000); + + // if it hasn't closed, close it forcefully + if (s != ETHERNETCLIENT_W5100_CLOSED) + close(_sock); + + _sock = -1; +} + +uint8_t EthernetClient::connected() { + if (_sock == -1) return 0; + + if (peek() < 0) { + if (errno == EAGAIN) { + return 1; + } + return 0; + } + return 1; +} + +uint8_t EthernetClient::status() { + if (_sock == -1) return ETHERNETCLIENT_W5100_CLOSED; + + struct tcp_info tcp_info; + int tcp_info_length = sizeof(tcp_info); + + if ( getsockopt( _sock, SOL_TCP, TCP_INFO, (void *)&tcp_info, (socklen_t *)&tcp_info_length ) == 0 ) { + switch (tcp_info.tcpi_state) { + case TCP_ESTABLISHED: + return ETHERNETCLIENT_W5100_ESTABLISHED; + case TCP_SYN_SENT: + return ETHERNETCLIENT_W5100_SYNSENT; + case TCP_SYN_RECV: + return ETHERNETCLIENT_W5100_SYNRECV; + case TCP_FIN_WAIT1: + case TCP_FIN_WAIT2: + return ETHERNETCLIENT_W5100_FIN_WAIT; + case TCP_TIME_WAIT: + return TCP_TIME_WAIT; + case TCP_CLOSE: + return ETHERNETCLIENT_W5100_CLOSED; + case TCP_CLOSE_WAIT: + return ETHERNETCLIENT_W5100_CLOSING; + case TCP_LAST_ACK: + return ETHERNETCLIENT_W5100_LAST_ACK; + case TCP_LISTEN: + return ETHERNETCLIENT_W5100_LISTEN; + case TCP_CLOSING: + return ETHERNETCLIENT_W5100_CLOSING; + } + } else { + perror("getsockopt"); + } + + return ETHERNETCLIENT_W5100_CLOSED; +} + +// the next function allows us to use the client returned by +// EthernetServer::available() as the condition in an if-statement. + +EthernetClient::operator bool() { + return _sock != -1; +} + +bool EthernetClient::operator==(const EthernetClient& rhs) { + return _sock == rhs._sock && _sock != -1 && rhs._sock != -1; +} + +uint8_t EthernetClient::getSocketNumber() { + return _sock; +} diff --git a/drivers/Linux/EthernetClient.h b/drivers/Linux/EthernetClient.h new file mode 100644 index 000000000..b2ad1b10d --- /dev/null +++ b/drivers/Linux/EthernetClient.h @@ -0,0 +1,80 @@ +/* +* 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 Arduino ethernet library, Copyright (c) 2010 Arduino LLC. All right reserved. +*/ + +#ifndef ethernetclient_h +#define ethernetclient_h + +#include "Client.h" +#include "IPAddress.h" + +// State codes from W5100 library +#define ETHERNETCLIENT_W5100_CLOSED 0x00 +#define ETHERNETCLIENT_W5100_LISTEN 0x14 +#define ETHERNETCLIENT_W5100_SYNSENT 0x15 +#define ETHERNETCLIENT_W5100_SYNRECV 0x16 +#define ETHERNETCLIENT_W5100_ESTABLISHED 0x17 +#define ETHERNETCLIENT_W5100_FIN_WAIT 0x18 +#define ETHERNETCLIENT_W5100_CLOSING 0x1A +#define ETHERNETCLIENT_W5100_TIME_WAIT 0x1B +#define ETHERNETCLIENT_W5100_CLOSE_WAIT 0x1C +#define ETHERNETCLIENT_W5100_LAST_ACK 0x1D + +// debug +#if defined(ETHERNETCLIENT_VERBOSE) + #define ETHERNETCLIENT_DEBUG(x,...) debug(x, ##__VA_ARGS__) +#else + #define ETHERNETCLIENT_DEBUG(x,...) +#endif + +class EthernetClient : public Client { + +public: + EthernetClient(); + EthernetClient(int sock); + + uint8_t status(); + virtual int connect(IPAddress ip, uint16_t port); + virtual int connect(const char *host, uint16_t port); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *buf, size_t size); + size_t write(const char *str); + size_t write(const char *buffer, size_t size); + virtual int available(); + virtual int read(); + virtual int read(uint8_t *buf, size_t size); + virtual int peek(); + virtual void flush(); + virtual void stop(); + virtual uint8_t connected(); + virtual operator bool(); + virtual bool operator==(const bool value) { return bool() == value; } + virtual bool operator!=(const bool value) { return bool() != value; } + virtual bool operator==(const EthernetClient&); + virtual bool operator!=(const EthernetClient& rhs) { return !this->operator==(rhs); }; + uint8_t getSocketNumber(); + + friend class EthernetServer; + +private: + int _sock; +}; + +#endif diff --git a/drivers/Linux/EthernetServer.cpp b/drivers/Linux/EthernetServer.cpp new file mode 100644 index 000000000..506eb15dc --- /dev/null +++ b/drivers/Linux/EthernetServer.cpp @@ -0,0 +1,241 @@ +/* +* 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 Arduino ethernet library, Copyright (c) 2010 Arduino LLC. All right reserved. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include "EthernetServer.h" + +struct server_vars { + uint16_t port; + struct IPAddress address; + std::list *new_clients; + std::vector *clients; +}; + +static pthread_mutex_t new_clients_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER; + +void *incoming_connections(void *); + +EthernetServer::EthernetServer(uint16_t port) : port(port) +{ + clients.reserve(MY_GATEWAY_MAX_CLIENTS); +} + +void EthernetServer::begin() +{ + begin(IPAddress(0,0,0,0)); +} + +void EthernetServer::begin(IPAddress address) +{ + pthread_t thread_id; + pthread_attr_t detached_attr; + + struct server_vars *vars = new struct server_vars; + vars->port = port; + vars->address = address; + vars->new_clients = &new_clients; + vars->clients = &clients; + + pthread_attr_init(&detached_attr); + pthread_attr_setdetachstate(&detached_attr, PTHREAD_CREATE_DETACHED); + pthread_create(&thread_id, &detached_attr, &incoming_connections, vars); +} + +void EthernetServer::beginPacket(IPAddress address, uint16_t port) +{ + //TODO: UDP + (void)address; + (void)port; +} + +int EthernetServer::parsePacket() +{ + //TODO: UDP + + return 0; +} + +bool EthernetServer::hasClient() +{ + bool empty; + + pthread_mutex_lock(&new_clients_mutex); + empty = new_clients.empty(); + pthread_mutex_unlock(&new_clients_mutex); + + return !empty; +} + +EthernetClient EthernetServer::available() +{ + int sock; + + pthread_mutex_lock(&new_clients_mutex); + if (new_clients.empty()) { + sock = -1; + } else { + sock = new_clients.front(); + new_clients.pop_front(); + } + pthread_mutex_unlock(&new_clients_mutex); + + return EthernetClient(sock); +} + +size_t EthernetServer::write(uint8_t b) +{ + return write(&b, 1); +} + +size_t EthernetServer::write(const uint8_t *buffer, size_t size) +{ + size_t n = 0; + size_t i = 0; + + pthread_mutex_lock(&clients_mutex); + while (i < clients.size()) { + EthernetClient client(clients[i]); + if (client.connected()) { + n += client.write(buffer, size); + i++; + } else { + clients[i] = clients.back(); + clients.pop_back(); + } + } + pthread_mutex_unlock(&clients_mutex); + + return n; +} + +size_t EthernetServer::write(const char *str) { + if (str == NULL) return 0; + return write((const uint8_t *)str, strlen(str)); +} +size_t EthernetServer::write(const char *buffer, size_t size) { + return write((const uint8_t *)buffer, size); +} + +void *incoming_connections(void* thread_arg) +{ + struct server_vars *vars = (struct server_vars*) thread_arg; + int sockfd, new_fd; + struct addrinfo hints, *servinfo, *p; + struct sockaddr_storage client_addr; + socklen_t sin_size; + int yes=1; + int rv; + char ipstr[INET_ADDRSTRLEN]; + char portstr[6]; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; + + sprintf(portstr, "%d", vars->port); + if ((rv = getaddrinfo(vars->address.toString().c_str(), portstr, &hints, &servinfo)) != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); + return NULL; + } + + // loop through all the results and bind to the first we can + for (p = servinfo; p != NULL; p = p->ai_next) { + if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { + perror("socket"); + continue; + } + + if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { + perror("setsockopt"); + freeaddrinfo(servinfo); + return NULL; + } + + if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { + close(sockfd); + perror("bind"); + continue; + } + + break; + } + + if (p == NULL) { + fprintf(stderr, "failed to bind\n"); + freeaddrinfo(servinfo); + return NULL; + } + + if (listen(sockfd, ETHERNETSERVER_BACKLOG) == -1) { + perror("listen"); + freeaddrinfo(servinfo); + return NULL; + } + + freeaddrinfo(servinfo); + + struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr; + void *addr = &(ipv4->sin_addr); + inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr); + ETHERNETSERVER_DEBUG("Listening for connections on %s:%s\n", ipstr, portstr); + + while (1) { // accept() loop + sin_size = sizeof client_addr; + new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size); + if (new_fd == -1) { + perror("accept"); + continue; + } + + void *addr = &(((struct sockaddr_in*)&client_addr)->sin_addr); + inet_ntop(client_addr.ss_family, addr, ipstr, sizeof ipstr); + ETHERNETSERVER_DEBUG("New connection from %s\n", ipstr); + + pthread_mutex_lock(&new_clients_mutex); + pthread_mutex_lock(&clients_mutex); + int connected_clients = vars->new_clients->size() + vars->clients->size(); + + if (connected_clients == MY_GATEWAY_MAX_CLIENTS) { + pthread_mutex_unlock(&clients_mutex); + pthread_mutex_unlock(&new_clients_mutex); + ETHERNETSERVER_DEBUG("Max number of ethernet clients reached."); + close(new_fd); + usleep(5000000); + } else { + vars->new_clients->push_back(new_fd); + vars->clients->push_back(new_fd); + pthread_mutex_unlock(&clients_mutex); + pthread_mutex_unlock(&new_clients_mutex); + } + } + + delete vars; + + return NULL; +} diff --git a/drivers/Linux/EthernetServer.h b/drivers/Linux/EthernetServer.h new file mode 100644 index 000000000..10f1a4d67 --- /dev/null +++ b/drivers/Linux/EthernetServer.h @@ -0,0 +1,64 @@ +/* +* 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 Arduino ethernet library, Copyright (c) 2010 Arduino LLC. All right reserved. +*/ + +#ifndef ethernetserver_h +#define ethernetserver_h + +#include +#include +#include "Server.h" +#include "EthernetClient.h" + +#ifndef ETHERNETSERVER_BACKLOG + #define ETHERNETSERVER_BACKLOG 10 +#endif + +// debug +#if defined(ETHERNETSERVER_VERBOSE) + #define ETHERNETSERVER_DEBUG(x,...) debug(x, ##__VA_ARGS__) +#else + #define ETHERNETSERVER_DEBUG(x,...) +#endif + +class EthernetClient; + +class EthernetServer : public Server { + +private: + uint16_t port; + std::list new_clients; + std::vector clients; + +public: + EthernetServer(uint16_t); + virtual void begin(); + void begin(IPAddress); + void beginPacket(IPAddress, uint16_t); + int parsePacket(); + bool hasClient(); + EthernetClient available(); + virtual size_t write(uint8_t); + virtual size_t write(const uint8_t *, size_t); + size_t write(const char *str); + size_t write(const char *buffer, size_t size); +}; + +#endif diff --git a/drivers/Linux/IPAddress.cpp b/drivers/Linux/IPAddress.cpp new file mode 100644 index 000000000..bec172896 --- /dev/null +++ b/drivers/Linux/IPAddress.cpp @@ -0,0 +1,105 @@ +/* + IPAddress.cpp - Base class that provides IPAddress + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + + Modified by Marcelo Aquino for MySensors use + */ + +#include +#include "IPAddress.h" + +IPAddress::IPAddress() { + _address.dword = 0; +} + +IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) { + _address.bytes[0] = first_octet; + _address.bytes[1] = second_octet; + _address.bytes[2] = third_octet; + _address.bytes[3] = fourth_octet; +} + +IPAddress::IPAddress(uint32_t address) { + _address.dword = address; +} + +IPAddress::IPAddress(const uint8_t *address) { + memcpy(_address.bytes, address, sizeof(_address.bytes)); +} + +bool IPAddress::fromString(const char *address) { + // TODO: add support for "a", "a.b", "a.b.c" formats + + uint16_t acc = 0; // Accumulator + uint8_t dots = 0; + + while (*address) + { + char c = *address++; + if (c >= '0' && c <= '9') + { + acc = acc * 10 + (c - '0'); + if (acc > 255) { + // Value out of [0..255] range + return false; + } + } + else if (c == '.') + { + if (dots == 3) { + // Too much dots (there must be 3 dots) + return false; + } + _address.bytes[dots++] = acc; + acc = 0; + } + else + { + // Invalid char + return false; + } + } + + if (dots != 3) { + // Too few dots (there must be 3 dots) + return false; + } + _address.bytes[3] = acc; + return true; +} + +IPAddress& IPAddress::operator=(const uint8_t *address) { + memcpy(_address.bytes, address, sizeof(_address.bytes)); + return *this; +} + +IPAddress& IPAddress::operator=(uint32_t address) { + _address.dword = address; + return *this; +} + +bool IPAddress::operator==(const uint8_t* addr) const { + return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0; +} + +std::string IPAddress::toString() +{ + char szRet[16]; + sprintf(szRet,"%u.%u.%u.%u", _address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3]); + return std::string(szRet); +} diff --git a/drivers/Linux/IPAddress.h b/drivers/Linux/IPAddress.h new file mode 100644 index 000000000..2fb9c6fc8 --- /dev/null +++ b/drivers/Linux/IPAddress.h @@ -0,0 +1,87 @@ +/* + IPAddress.h - Base class that provides IPAddress + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + + Modified by Marcelo Aquino for MySensors use + */ + +#ifndef IPAddress_h +#define IPAddress_h + +#include +#include + +// A class to make it easier to handle and pass around IP addresses + +// class IPAddress: public Printable { +class IPAddress { + private: + union { + uint8_t bytes[4]; // IPv4 address + uint32_t dword; + } _address; + + // Access the raw byte array containing the address. Because this returns a pointer + // to the internal structure rather than a copy of the address this function should only + // be used when you know that the usage of the returned uint8_t* will be transient and not + // stored. + uint8_t* raw_address() { + return _address.bytes; + } + + public: + // Constructors + IPAddress(); + IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); + IPAddress(uint32_t address); + IPAddress(const uint8_t *address); + + bool fromString(const char *address); + bool fromString(const std::string &address) { return fromString(address.c_str()); } + + // Overloaded cast operator to allow IPAddress objects to be used where a pointer + // to a four-byte uint8_t array is expected + operator uint32_t() const { + return _address.dword; + } + bool operator==(const IPAddress& addr) const { + return _address.dword == addr._address.dword; + } + bool operator==(uint32_t addr) const { + return _address.dword == addr; + } + bool operator==(const uint8_t* addr) const; + + // Overloaded index operator to allow getting and setting individual octets of the address + uint8_t operator[](int index) const { + return _address.bytes[index]; + } + uint8_t& operator[](int index) { + return _address.bytes[index]; + } + + // Overloaded copy operators to allow initialisation of IPAddress objects from other types + IPAddress& operator=(const uint8_t *address); + IPAddress& operator=(uint32_t address); + + std::string toString(); + + friend class Client; +}; + +#endif diff --git a/drivers/Linux/Server.h b/drivers/Linux/Server.h new file mode 100644 index 000000000..d1b40461b --- /dev/null +++ b/drivers/Linux/Server.h @@ -0,0 +1,28 @@ +/* + Server.h - Base class that provides Server + Copyright (c) 2011 Adrian McEwen. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef server_h +#define server_h + +class Server { + public: + virtual void begin() =0; +}; + +#endif diff --git a/drivers/Linux/Stream.h b/drivers/Linux/Stream.h new file mode 100644 index 000000000..0241f6aae --- /dev/null +++ b/drivers/Linux/Stream.h @@ -0,0 +1,15 @@ +#ifndef Stream_h +#define Stream_h + +class Stream { + public: + virtual size_t write(uint8_t) = 0; + virtual size_t write(const uint8_t *buffer, size_t size) = 0; + + virtual int available() = 0; + virtual int read() = 0; + virtual int peek() = 0; + virtual void flush() = 0; +}; + +#endif diff --git a/drivers/RF24/RF24_RPi.cpp b/drivers/RF24/RF24_RPi.cpp new file mode 100644 index 000000000..3b1a091dc --- /dev/null +++ b/drivers/RF24/RF24_RPi.cpp @@ -0,0 +1,210 @@ +/** + * 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 Olivier Mauti work(RF24.h), copyright (C) 2016 Olivier Mauti + */ + +#include "RF24.h" + +// pipes +#define BROADCAST_PIPE 1 +#define NODE_PIPE 2 + +// debug +#if defined(MY_DEBUG_VERBOSE_RF24) + #define RF24_DEBUG(x,...) debug(x, ##__VA_ARGS__) +#else + #define RF24_DEBUG(x,...) +#endif + +#ifdef MY_RF24_IRQ_PIN + typedef void (*RF24_receiveCallbackType)(void); + + void (* RF24_receiveCallback)(void) = NULL; + + static pthread_mutex_t rf24_mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + +static uint8_t MY_RF24_BASE_ADDR[MY_RF24_ADDR_WIDTH] = { MY_RF24_BASE_RADIO_ID }; +static uint8_t MY_RF24_NODE_ADDRESS = AUTO; + +RF24 _rf24(MY_RF24_CE_PIN, MY_RF24_CS_PIN); + +static void RF24_startListening(void) { + RF24_DEBUG(PSTR("start listening\n")); + + _rf24.startListening(); +} + +static void RF24_powerDown(void) { +#ifdef MY_RF24_IRQ_PIN + pthread_mutex_lock(&rf24_mutex); +#endif + _rf24.powerDown(); +#ifdef MY_RF24_IRQ_PIN + pthread_mutex_unlock(&rf24_mutex); +#endif +} + +static bool RF24_sendMessage( uint8_t recipient, const void* buf, uint8_t len ) { +#ifdef MY_RF24_IRQ_PIN + pthread_mutex_lock(&rf24_mutex); +#endif + // Make sure radio has powered up + _rf24.powerUp(); + _rf24.stopListening(); + + RF24_DEBUG(PSTR("send message to %d, len=%d\n"), recipient,len); + + MY_RF24_BASE_ADDR[0] = recipient; + _rf24.openWritingPipe(MY_RF24_BASE_ADDR); + bool ok = _rf24.write(buf, len, recipient == BROADCAST_ADDRESS); + _rf24.startListening(); +#ifdef MY_RF24_IRQ_PIN + pthread_mutex_unlock(&rf24_mutex); +#endif + return ok; +} + +static bool RF24_isDataAvailable() { +#ifdef MY_RF24_IRQ_PIN + pthread_mutex_lock(&rf24_mutex); +#endif + uint8_t pipe_num = 255; + _rf24.available(&pipe_num); +#ifdef MY_RF24_IRQ_PIN + pthread_mutex_unlock(&rf24_mutex); +#endif + return (pipe_num <= 5); +} + +static uint8_t RF24_readMessage( void* buf) { +#ifdef MY_RF24_IRQ_PIN + pthread_mutex_lock(&rf24_mutex); +#endif + uint8_t len = _rf24.getDynamicPayloadSize(); + _rf24.read(buf, len); +#ifdef MY_RF24_IRQ_PIN + pthread_mutex_unlock(&rf24_mutex); +#endif + return len; +} + +static void RF24_setNodeAddress(uint8_t address) { +#ifdef MY_RF24_IRQ_PIN + pthread_mutex_lock(&rf24_mutex); +#endif + if (address != AUTO){ + MY_RF24_NODE_ADDRESS = address; + // enable node pipe + MY_RF24_BASE_ADDR[0] = MY_RF24_NODE_ADDRESS; + _rf24.openReadingPipe(NODE_PIPE, MY_RF24_BASE_ADDR); + // enable autoACK on node pipe + _rf24.setAutoAck(NODE_PIPE, true); + } +#ifdef MY_RF24_IRQ_PIN + pthread_mutex_unlock(&rf24_mutex); +#endif +} + +static uint8_t RF24_getNodeID(void) { + return MY_RF24_NODE_ADDRESS; +} + +bool RF24_sanityCheck(void) { + bool ok = true; +#ifdef MY_RF24_IRQ_PIN + pthread_mutex_lock(&rf24_mutex); +#endif + // detect HW defect ot interrupted SPI line, CE disconnect cannot be detected + if (_rf24.getPALevel() != MY_RF24_PA_LEVEL || _rf24.getDataRate() != MY_RF24_DATARATE || + _rf24.getChannel() != MY_RF24_CHANNEL) { + ok = false; + } +#ifdef MY_RF24_IRQ_PIN + pthread_mutex_unlock(&rf24_mutex); +#endif + return ok; +} + +#ifdef MY_RF24_IRQ_PIN +void RF24_irqHandler(void) { + if (RF24_receiveCallback) { + while (RF24_isDataAvailable()) { + RF24_receiveCallback(); + } + } else { + // clear RX interrupt + bool tx_ok,tx_fail,rx; + _rf24.whatHappened(tx_ok,tx_fail,rx); + } +} + +void RF24_registerReceiveCallback(RF24_receiveCallbackType cb) { + RF24_receiveCallback = cb; +} +#endif + +static bool RF24_initialize(void) { + // start up the radio library + _rf24.begin(); + // determine whether the hardware is an nRF24L01+ or not + if (!_rf24.isPVariant()) { + RF24_DEBUG(PSTR("radio hardware not compatible")); + return false; + } + // set CRC + _rf24.setCRCLength(RF24_CRC_16); + // set address width + _rf24.setAddressWidth(MY_RF24_ADDR_WIDTH); + // auto retransmit delay 1500us, auto retransmit count 15 + _rf24.setRetries(5, 15); + // channel + _rf24.setChannel(MY_RF24_CHANNEL); + // PA level + _rf24.setPALevel(MY_RF24_PA_LEVEL); + // data rate + _rf24.setDataRate(MY_RF24_DATARATE); + // sanity check + #if defined(MY_RF24_SANITY_CHECK) + if (!RF24_sanityCheck()) { + RF24_DEBUG(PSTR("RF24:Sanity check failed: configuration mismatch! Check wiring, replace module or non-P version\n")); + return false; + } + #endif + // enable Dynamic payload + _rf24.enableDynamicPayloads(); + // enable ACK payload + _rf24.enableAckPayload(); + // disable AA on all pipes, activate when node pipe set + _rf24.setAutoAck(false); + // all nodes listen to broadcast pipe (for FIND_PARENT_RESPONSE messages) + MY_RF24_BASE_ADDR[0] = BROADCAST_ADDRESS; + _rf24.openReadingPipe(BROADCAST_PIPE, MY_RF24_BASE_ADDR); + + //_rf24.printDetails(); + + #ifdef MY_RF24_IRQ_PIN + // Mask all interrupts except the receive interrupt + _rf24.maskIRQ(1,1,0); + + attachInterrupt(MY_RF24_IRQ_PIN, INT_EDGE_FALLING, RF24_irqHandler); + #endif + + return true; +} diff --git a/examples_RPi/MySGateway.cpp b/examples_RPi/MySGateway.cpp new file mode 100644 index 000000000..014d12a60 --- /dev/null +++ b/examples_RPi/MySGateway.cpp @@ -0,0 +1,93 @@ +/** + * 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 + * Copyleft (c) 2016, Marcelo Aquino + * 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 + +// Enable debug prints to monitor +#ifndef MY_DEBUG + #define MY_DEBUG +#endif + +// Config file +#ifndef MY_LINUX_CONFIG_FILE + #define MY_LINUX_CONFIG_FILE "/etc/MySensorGateway.cfg" +#endif + +// Enables and select radio type (if attached) +#ifndef MY_RADIO_NRF24 + #define MY_RADIO_NRF24 +#endif + +#define MY_GATEWAY_RASPBERRYPI + +// How many clients should be able to connect to this gateway (default 1) +#define MY_GATEWAY_MAX_CLIENTS 2 + +#ifdef MY_GATEWAY_MQTT_CLIENT + // Set MQTT client id + #ifndef MY_MQTT_CLIENT_ID + #define MY_MQTT_CLIENT_ID "mysensors-1" + #endif + // MQTT broker ip address. + #ifndef MY_CONTROLLER_IP_ADDRESS + #define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 68 + #endif + // The MQTT broker port to to open + #ifndef MY_PORT + #define MY_PORT 1883 + #endif + + // Enable these if your MQTT broker requires usenrame/password + //#define MY_MQTT_USER "username" + //#define MY_MQTT_PASSWORD "password" + + // Set this node's subscribe and publish topic prefix + #ifndef MY_MQTT_PUBLISH_TOPIC_PREFIX + #define MY_MQTT_PUBLISH_TOPIC_PREFIX "mygateway1-out" + #endif + #ifndef MY_MQTT_SUBSCRIBE_TOPIC_PREFIX + #define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX "mygateway1-in" + #endif +#else + // Enable MY_IP_ADDRESS here if you want to listen for incoming network + // connections on the specified IP address/hostname only + //#define MY_IP_ADDRESS 192,168,178,87 + + // The port to keep open on node server mode + #ifndef MY_PORT + #define MY_PORT 5003 + #endif +#endif + +#include + +using namespace std; + +void setup() { +} + +void presentation() { + // Present locally attached sensors here +} + +void loop() { + // Send locally attached sensors data here +} diff --git a/initscripts/mysgateway.systemd b/initscripts/mysgateway.systemd new file mode 100644 index 000000000..9763c6677 --- /dev/null +++ b/initscripts/mysgateway.systemd @@ -0,0 +1,9 @@ +[Unit] +Description=MySensors Gateway daemon +Requires=network.target + +[Service] +ExecStart=%gateway_dir%/MySGateway + +[Install] +WantedBy=multi-user.target diff --git a/initscripts/mysgateway.sysvinit b/initscripts/mysgateway.sysvinit new file mode 100644 index 000000000..df01c6cd9 --- /dev/null +++ b/initscripts/mysgateway.sysvinit @@ -0,0 +1,159 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: MySGateway +# Required-Start: $remote_fs $syslog +# Required-Stop: $remote_fs $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: MySensors Gateway +# Description: This file should be used to construct scripts to be +# placed in /etc/init.d. +### END INIT INFO + +# Author: Foo Bar +# +# Please remove the "Author" lines above and replace them +# with your own name if you copy and modify this script. + +# Do NOT "set -e" + +# PATH should only include /usr/* if it runs after the mountnfs.sh script +PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin +DESC="MySensors Gateway" +NAME=MySGateway +DAEMON=%gateway_dir%/$NAME +DAEMON_ARGS="-d" +PIDFILE=/var/run/$NAME.pid +SCRIPTNAME=/etc/init.d/$NAME + +# Exit if the package is not installed +[ -x "$DAEMON" ] || exit 0 + +# Read configuration variable file if it is present +[ -r /etc/default/$NAME ] && . /etc/default/$NAME + +# Load the VERBOSE setting and other rcS variables +. /lib/init/vars.sh + +# Define LSB log_* functions. +# Depend on lsb-base (>= 3.2-14) to ensure that this file is present +# and status_of_proc is working. +. /lib/lsb/init-functions + +# +# Function that starts the daemon/service +# +do_start() +{ + # Return + # 0 if daemon has been started + # 1 if daemon was already running + # 2 if daemon could not be started + start-stop-daemon --start --quiet --exec $DAEMON --test > /dev/null \ + || return 1 + start-stop-daemon --start --quiet --exec $DAEMON -- \ + $DAEMON_ARGS \ + || return 2 + # Add code here, if necessary, that waits for the process to be ready + # to handle requests from services started subsequently which depend + # on this one. As a last resort, sleep for some time. +} + +# +# Function that stops the daemon/service +# +do_stop() +{ + # Return + # 0 if daemon has been stopped + # 1 if daemon was already stopped + # 2 if daemon could not be stopped + # other if a failure occurred + start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --name $NAME + RETVAL="$?" + [ "$RETVAL" = 2 ] && return 2 + # Wait for children to finish too if this is a daemon that forks + # and if the daemon is only ever run from this initscript. + # If the above conditions are not satisfied then add some other code + # that waits for the process to drop all resources that could be + # needed by services started subsequently. A last resort is to + # sleep for some time. + start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON + [ "$?" = 2 ] && return 2 + # Many daemons don't delete their pidfiles when they exit. + rm -f $PIDFILE + return "$RETVAL" +} + +# +# Function that sends a SIGHUP to the daemon/service +# +do_reload() { + # + # If the daemon can reload its configuration without + # restarting (for example, when it is sent a SIGHUP), + # then implement that here. + # + start-stop-daemon --stop --signal 1 --quiet --name $NAME + return 0 +} + +case "$1" in + start) + [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" + do_start + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + stop) + [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" + do_stop + case "$?" in + 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; + 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; + esac + ;; + status) + status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? + ;; + #reload|force-reload) + # + # If do_reload() is not implemented then leave this commented out + # and leave 'force-reload' as an alias for 'restart'. + # + #log_daemon_msg "Reloading $DESC" "$NAME" + #do_reload + #log_end_msg $? + #;; + restart|force-reload) + # + # If the "reload" option is implemented then remove the + # 'force-reload' alias + # + log_daemon_msg "Restarting $DESC" "$NAME" + do_stop + case "$?" in + 0|1) + do_start + case "$?" in + 0) log_end_msg 0 ;; + 1) log_end_msg 1 ;; # Old process is still running + *) log_end_msg 1 ;; # Failed to start + esac + ;; + *) + # Failed to stop + log_end_msg 1 + ;; + esac + ;; + *) + #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 + echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 + exit 3 + ;; +esac + +: From 43e5a7ddf96c26e66c073c8d2a2f37cf347d50c8 Mon Sep 17 00:00:00 2001 From: Konst Kolesnichenko Date: Mon, 1 Aug 2016 22:49:53 +0300 Subject: [PATCH 052/167] Fixed build error --- drivers/Linux/EthernetClient.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/Linux/EthernetClient.cpp b/drivers/Linux/EthernetClient.cpp index 17774298b..c6a938940 100644 --- a/drivers/Linux/EthernetClient.cpp +++ b/drivers/Linux/EthernetClient.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include "EthernetClient.h" EthernetClient::EthernetClient() : _sock(-1) { From 899f992d112b4adcb46227deaf41498d397819b9 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Mon, 8 Aug 2016 19:37:08 -0300 Subject: [PATCH 053/167] Fix Doxygen preprocessor variable * Fix build error when not using RF24 interrupt pin --- core/MyHwLinuxGeneric.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/core/MyHwLinuxGeneric.h b/core/MyHwLinuxGeneric.h index 32e840693..cb01c7883 100644 --- a/core/MyHwLinuxGeneric.h +++ b/core/MyHwLinuxGeneric.h @@ -54,19 +54,23 @@ static __inline__ void __hwLock() { } #endif -#if defined(__DOXYGEN__) +#if defined(DOXYGEN) #define ATOMIC_BLOCK_CLEANUP #elif defined(MY_RF24_IRQ_PIN) #define ATOMIC_BLOCK_CLEANUP uint8_t __atomic_loop \ __attribute__((__cleanup__( __hwUnlock ))) = 1 -#endif /* __DOXYGEN__ */ +#else + #define ATOMIC_BLOCK_CLEANUP +#endif /* DOXYGEN */ -#if defined(__DOXYGEN__) +#if defined(DOXYGEN) #define ATOMIC_BLOCK #elif defined(MY_RF24_IRQ_PIN) #define ATOMIC_BLOCK for ( ATOMIC_BLOCK_CLEANUP, __hwLock(); \ __atomic_loop ; __atomic_loop = 0 ) -#endif /* __DOXYGEN__ */ +#else + #define ATOMIC_BLOCK +#endif /* DOXYGEN */ #ifndef DOXYGEN #define MY_CRITICAL_SECTION ATOMIC_BLOCK From 9132e7a42ad53fcf47bd43336bf633c36610bf1a Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Fri, 12 Aug 2016 12:42:49 -0300 Subject: [PATCH 054/167] Exit immediately when receiving a signal --- core/MyMainLinux.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/core/MyMainLinux.cpp b/core/MyMainLinux.cpp index 5ecab964d..5798cecf0 100644 --- a/core/MyMainLinux.cpp +++ b/core/MyMainLinux.cpp @@ -1,18 +1,15 @@ // Initialize library and handle sketch functions like we want to #include -#include +#include +#include #include "MySensorsCore.h" -volatile static int running = 1; - /* * handler for SIGINT signal */ void handle_sigint(int sig) { - running = 0; - if (sig == SIGINT) { std::cout << "Received SIGINT\n" << std::endl; } else if (sig == SIGTERM) { @@ -22,6 +19,8 @@ void handle_sigint(int sig) #ifdef MY_RF24_IRQ_PIN detachInterrupt(MY_RF24_IRQ_PIN); #endif + + exit(0); } int main(void) { @@ -31,7 +30,7 @@ int main(void) { _begin(); // Startup MySensors library - while (running) { + for (;;) { _process(); // Process incoming data if (loop) loop(); // Call sketch loop } From c4b2a809aa7289fb4b8927a470245753208f5f8e Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Fri, 12 Aug 2016 12:53:14 -0300 Subject: [PATCH 055/167] Move init system detection to configure --- Makefile | 16 ++++++++-------- configure | 22 +++++++++++++++++----- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 825d83ded..3f74aded2 100644 --- a/Makefile +++ b/Makefile @@ -53,11 +53,11 @@ install-gateway: @install -m 0755 $(GATEWAY) $(GATEWAY_DIR) install-initscripts: - if [[ `systemctl` =~ -\.mount ]]; then \ - install -m0644 initscripts/mysgateway.systemd /etc/systemd/system/mysgateway.service && \ - sed -i -e "s|%gateway_dir%|${GATEWAY_DIR}|g" /etc/systemd/system/mysgateway.service && \ - systemctl daemon-reload; \ - elif [[ -f /etc/init.d/cron && ! -h /etc/init.d/cron ]]; then \ - install -m0755 initscripts/mysgateway.sysvinit /etc/init.d/mysgateway && \ - sed -i -e "s|%gateway_dir%|${GATEWAY_DIR}|g" /etc/init.d/mysgateway; \ - fi +ifeq ($(INIT_SYSTEM), systemd) + install -m0644 initscripts/mysgateway.systemd /etc/systemd/system/mysgateway.service + @sed -i -e "s|%gateway_dir%|${GATEWAY_DIR}|g" /etc/systemd/system/mysgateway.service + systemctl daemon-reload +else ifeq ($(INIT_SYSTEM), sysvinit) + install -m0755 initscripts/mysgateway.sysvinit /etc/init.d/mysgateway + @sed -i -e "s|%gateway_dir%|${GATEWAY_DIR}|g" /etc/init.d/mysgateway +endif diff --git a/configure b/configure index ad46759c4..d686549a7 100755 --- a/configure +++ b/configure @@ -45,15 +45,17 @@ MySensors options: --my-controller-ip-address= Controller or MQTT broker ip. Use commas instead of points. Example: 127,0,0,1 - --my-port Controller or MQTT broker port. + --my-port= Controller or MQTT broker port. --my-mqtt-client-id= MQTT client id. --my-mqtt-publish-topic-prefix= MQTT publish topic prefix. --my-mqtt-subscribe-topic-prefix= MQTT subscribe topic prefix. - --my-rf24-irq-pin Pin number connected to nRF24L01 IRQ pin. - --my-rx-message-buffer-size Buffer size for incoming messages when using rf24 interrupts. - Default set to 20. + --my-rf24-irq-pin= Pin number connected to nRF24L01 IRQ pin. + For RaspberryPi use BCM numbering. + --my-rx-message-buffer-size= + Buffer size for incoming messages when using rf24 interrupts. + Default is 20. EOF } @@ -188,7 +190,7 @@ function gcc_cpu_flags { echo ${flags} } -params="OS SOC CPUFLAGS CXXFLAGS LDFLAGS PREFIX CXX RF24H_LIB_DIR GATEWAY_DIR" +params="OS SOC CPUFLAGS CXXFLAGS LDFLAGS PREFIX CXX RF24H_LIB_DIR GATEWAY_DIR INIT_SYSTEM" for opt do if [ "$opt" = "-h" ] || [ "$opt" = "--help" ]; then @@ -305,6 +307,16 @@ fi LDFLAGS="-pthread -lrf24-bcm $LDFLAGS" +if [ -x /usr/bin/systemctl ] || [ -x /bin/systemctl ]; then + INIT_SYSTEM=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" +else + echo "[FAILED] unknown init system" +fi + echo "[SECTION] Saving configuration." echo -n "" > Makefile.inc for param in ${params}; do From 768b70e882683addd3ba8c8fc5fe1ea980bdd19c Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Fri, 12 Aug 2016 15:10:19 -0300 Subject: [PATCH 056/167] Fix conflicts with arduino macros and stdlib --- core/MyHwLinuxGeneric.cpp | 1 + core/MyHwLinuxGeneric.h | 9 +++------ core/MyMessage.cpp | 10 +++------- drivers/Linux/Arduino.h | 35 +++++++++++++++++++++++++---------- examples_RPi/MySGateway.cpp | 2 -- 5 files changed, 32 insertions(+), 25 deletions(-) diff --git a/core/MyHwLinuxGeneric.cpp b/core/MyHwLinuxGeneric.cpp index 272fe2910..e288bd664 100644 --- a/core/MyHwLinuxGeneric.cpp +++ b/core/MyHwLinuxGeneric.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include diff --git a/core/MyHwLinuxGeneric.h b/core/MyHwLinuxGeneric.h index cb01c7883..c44d9123d 100644 --- a/core/MyHwLinuxGeneric.h +++ b/core/MyHwLinuxGeneric.h @@ -21,8 +21,7 @@ #define MyHwLinuxGeneric_h #include "MyHw.h" -#include -#include +#include #include #define MY_SERIALDEVICE Serial @@ -32,8 +31,6 @@ #define hwWatchdogReset() #define hwReboot() -using namespace std; - void hwInit(); void hwReadConfigBlock(void* buf, void* adr, size_t length); void hwWriteConfigBlock(void* buf, void* adr, size_t length); @@ -73,7 +70,7 @@ static __inline__ void __hwLock() { #endif /* DOXYGEN */ #ifndef DOXYGEN - #define MY_CRITICAL_SECTION ATOMIC_BLOCK -#endif /* DOXYGEN */ + #define MY_CRITICAL_SECTION ATOMIC_BLOCK +#endif /* DOXYGEN */ #endif diff --git a/core/MyMessage.cpp b/core/MyMessage.cpp index fc945ed27..d95977ef7 100644 --- a/core/MyMessage.cpp +++ b/core/MyMessage.cpp @@ -23,10 +23,6 @@ #include #include -#ifndef ARDUINO - #define min(a,b) ((a)<(b)?(a):(b)) -#endif - MyMessage::MyMessage() { clear(); @@ -121,7 +117,7 @@ char* MyMessage::getString(char *buffer) const { } else if (payloadType == P_ULONG32) { ultoa(ulValue, buffer, 10); } else if (payloadType == P_FLOAT32) { - dtostrf(fValue,2,min(fPrecision, 8),buffer); + dtostrf(fValue,2,min(fPrecision, (uint8_t)8),buffer); } else if (payloadType == P_CUSTOM) { return getCustomString(buffer); } @@ -216,12 +212,12 @@ MyMessage& MyMessage::setDestination(uint8_t _destination) { MyMessage& MyMessage::set(void* value, uint8_t length) { miSetPayloadType(P_CUSTOM); miSetLength(length); - memcpy(data, value, min(length, MAX_PAYLOAD)); + memcpy(data, value, min(length, (uint8_t)MAX_PAYLOAD)); return *this; } MyMessage& MyMessage::set(const char* value) { - uint8_t length = value == NULL ? 0 : min(strlen(value), MAX_PAYLOAD); + uint8_t length = value == NULL ? 0 : min(strlen(value), (size_t)MAX_PAYLOAD); miSetLength(length); miSetPayloadType(P_STRING); if (length) { diff --git a/drivers/Linux/Arduino.h b/drivers/Linux/Arduino.h index 7ae816294..e352dd1b0 100644 --- a/drivers/Linux/Arduino.h +++ b/drivers/Linux/Arduino.h @@ -3,17 +3,31 @@ #include -#ifndef LSBFIRST - #define LSBFIRST 0 +#ifdef __cplusplus + #include + + using namespace std; + + extern "C" { #endif -#ifndef MSBFIRST - #define MSBFIRST 1 +void yield(void); + +#define PI 3.1415926535897932384626433832795 +#define HALF_PI 1.5707963267948966192313216916398 +#define TWO_PI 6.283185307179586476925286766559 +#define DEG_TO_RAD 0.017453292519943295769236907684886 +#define RAD_TO_DEG 57.295779513082320876798154814105 +#define EULER 2.718281828459045235360287471352 + +#ifndef __cplusplus + #define min(a,b) ((a)<(b)?(a):(b)) + #define max(a,b) ((a)>(b)?(a):(b)) + #define abs(x) ((x)>0?(x):-(x)) + #define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) #endif -#define abs(x) ((x)>0?(x):-(x)) #define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) -#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) #define radians(deg) ((deg)*DEG_TO_RAD) #define degrees(rad) ((rad)*RAD_TO_DEG) #define sq(x) ((x)*(x)) @@ -21,15 +35,16 @@ #define lowByte(w) ((uint8_t) ((w) & 0xff)) #define highByte(w) ((uint8_t) ((w) >> 8)) +#define bitRead(value, bit) (((value) >> (bit)) & 0x01) +#define bitSet(value, bit) ((value) |= (1UL << (bit))) +#define bitClear(value, bit) ((value) &= ~(1UL << (bit))) +#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit)) + #define bit(b) (1UL << (b)) typedef bool boolean; typedef uint8_t byte; -#ifdef __cplusplus - extern "C" { -#endif - /** * C++ version 0.4 char* style "itoa": * Written by Lukás Chmela diff --git a/examples_RPi/MySGateway.cpp b/examples_RPi/MySGateway.cpp index 014d12a60..dc61f853e 100644 --- a/examples_RPi/MySGateway.cpp +++ b/examples_RPi/MySGateway.cpp @@ -79,8 +79,6 @@ #include -using namespace std; - void setup() { } From dad6732f3801960a6c3d43b0b509be47ce1ba3bb Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Sat, 13 Aug 2016 04:45:08 -0300 Subject: [PATCH 057/167] Include .h instead of .cpp when possible * Move implementation code from Arduino.h --- Makefile | 2 +- MySensors.h | 12 +- core/MyGatewayTransportEthernet.cpp | 2 + drivers/Linux/Arduino.h | 180 +--------------------------- drivers/Linux/EthernetClient.cpp | 43 +++---- drivers/Linux/EthernetClient.h | 44 +++---- drivers/Linux/EthernetServer.cpp | 50 ++++---- drivers/Linux/EthernetServer.h | 49 ++++---- drivers/Linux/IPAddress.cpp | 39 +++--- drivers/Linux/IPAddress.h | 38 +++--- drivers/Linux/utility.cpp | 177 +++++++++++++++++++++++++++ 11 files changed, 329 insertions(+), 307 deletions(-) create mode 100644 drivers/Linux/utility.cpp diff --git a/Makefile b/Makefile index 3f74aded2..b5ba3a8d8 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ CONFIG_FILE=Makefile.inc include $(CONFIG_FILE) GATEWAY=examples_RPi/MySGateway -GATEWAY_SOURCES=examples_RPi/MySGateway.cpp +GATEWAY_SOURCES=$(wildcard drivers/Linux/*.cpp) examples_RPi/MySGateway.cpp GATEWAY_OBJECTS=$(patsubst %.cpp,%.o,$(GATEWAY_SOURCES)) DEPS+=$(patsubst %.cpp,%.d,$(GATEWAY_SOURCES)) diff --git a/MySensors.h b/MySensors.h index 05d145f45..b2f689019 100644 --- a/MySensors.h +++ b/MySensors.h @@ -222,9 +222,9 @@ #include "core/MyProtocolMySensors.cpp" #if defined(MY_GATEWAY_LINUX) - #include "drivers/Linux/EthernetClient.cpp" - #include "drivers/Linux/EthernetServer.cpp" - #include "drivers/Linux/IPAddress.cpp" + #include "drivers/Linux/EthernetClient.h" + #include "drivers/Linux/EthernetServer.h" + #include "drivers/Linux/IPAddress.h" #endif #include "drivers/PubSubClient/PubSubClient.cpp" #include "core/MyGatewayTransportMQTTClient.cpp" @@ -250,9 +250,9 @@ #include "core/MyGatewayTransportEthernet.cpp" #elif defined(MY_GATEWAY_LINUX) // GATEWAY - Generic Linux (RaspberryPi, BBB, ...) - #include "drivers/Linux/EthernetClient.cpp" - #include "drivers/Linux/EthernetServer.cpp" - #include "drivers/Linux/IPAddress.cpp" + #include "drivers/Linux/EthernetClient.h" + #include "drivers/Linux/EthernetServer.h" + #include "drivers/Linux/IPAddress.h" #include "core/MyGatewayTransportEthernet.cpp" #elif defined(MY_GATEWAY_W5100) // GATEWAY - W5100 diff --git a/core/MyGatewayTransportEthernet.cpp b/core/MyGatewayTransportEthernet.cpp index f97459318..ee8b7a86a 100644 --- a/core/MyGatewayTransportEthernet.cpp +++ b/core/MyGatewayTransportEthernet.cpp @@ -56,6 +56,8 @@ typedef struct #if defined(MY_USE_UDP) EthernetUDP _ethernetServer; +#elif defined(MY_GATEWAY_LINUX) + EthernetServer _ethernetServer(_ethernetGatewayPort, MY_GATEWAY_MAX_CLIENTS); #else EthernetServer _ethernetServer(_ethernetGatewayPort); #endif diff --git a/drivers/Linux/Arduino.h b/drivers/Linux/Arduino.h index e352dd1b0..39f0f6e22 100644 --- a/drivers/Linux/Arduino.h +++ b/drivers/Linux/Arduino.h @@ -2,6 +2,7 @@ #define Arduino_h #include +#include #ifdef __cplusplus #include @@ -45,180 +46,11 @@ void yield(void); typedef bool boolean; typedef uint8_t byte; -/** -* C++ version 0.4 char* style "itoa": -* Written by Lukás Chmela -* Released under GPLv3. -*/ -char *itoa(int value, char* result, int base) { - // check that the base if valid - if (base < 2 || base > 36) { *result = '\0'; return result; } - - char* ptr = result, *ptr1 = result, tmp_char; - int tmp_value; - - do { - tmp_value = value; - value /= base; - *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)]; - } while ( value ); - - // Apply negative sign - // Apply negative sign - if (tmp_value < 0) *ptr++ = '-'; - *ptr-- = '\0'; - while(ptr1 < ptr) { - tmp_char = *ptr; - *ptr--= *ptr1; - *ptr1++ = tmp_char; - } - return result; -} - -/** - * C++ version 0.4 char* style "itoa": - * Written by Lukás Chmela - * Released under GPLv3. - */ -char *ltoa(long value, char* result, int base) { - // check that the base if valid - if (base < 2 || base > 36) { *result = '\0'; return result; } - - char* ptr = result, *ptr1 = result, tmp_char; - long tmp_value; - - do { - tmp_value = value; - value /= base; - *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)]; - } while ( value ); - - // Apply negative sign - if (tmp_value < 0) *ptr++ = '-'; - *ptr-- = '\0'; - while(ptr1 < ptr) { - tmp_char = *ptr; - *ptr--= *ptr1; - *ptr1++ = tmp_char; - } - return result; -} - -char *ultoa(long num, char *str, int radix) -{ - unsigned long value; - char *sp = str; - char *sp2; - - value = num; - - /* Store sign at start of buffer for negative base-10 values */ - if (10 == radix && 0 > num) { - *sp++ = '-'; - value = -num; - } - - sp2 = sp; - - do { - char rem = value % radix; - value /= radix; - if (10 > rem) { - *sp++ = '0' + rem; - } else { - *sp++ = 'A' + rem - 10; - } - } while (0 < value); - - /* Mark end of string */ - *sp-- = 0; - - /* Reverse string contents (excluding sign) in place */ - while (sp2 < sp) { - char tmp = *sp2; - *sp2++ = *sp; - *sp-- = tmp; - } - - return str; -} - -/** - * Copyright (c) 2012, Peter A. Bigot - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of the software nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -char *utoa(int num, char *str, int radix) -{ - unsigned int value; - char *sp = str; - char *sp2; - - value = num; - - /* Store sign at start of buffer for negative base-10 values */ - if (10 == radix && 0 > num) { - *sp++ = '-'; - value = -num; - } - - sp2 = sp; - - do { - char rem = value % radix; - value /= radix; - if (10 > rem) { - *sp++ = '0' + rem; - } else { - *sp++ = 'A' + rem - 10; - } - } while (0 < value); - - /* Mark end of string */ - *sp-- = 0; - - /* Reverse string contents (excluding sign) in place */ - while (sp2 < sp) { - char tmp = *sp2; - *sp2++ = *sp; - *sp-- = tmp; - } - - return str; -} - -char *dtostrf(float f, int width, int decimals, char *result) -{ - sprintf(result,"%*.*f", width, decimals, f); - return result; -} +char *itoa(int value, char* result, int base); +char *ltoa(long value, char* result, int base); +char *ultoa(long num, char *str, int radix); +char *utoa(int num, char *str, int radix); +char *dtostrf(float f, int width, int decimals, char *result); #ifdef __cplusplus } diff --git a/drivers/Linux/EthernetClient.cpp b/drivers/Linux/EthernetClient.cpp index c6a938940..5e8084831 100644 --- a/drivers/Linux/EthernetClient.cpp +++ b/drivers/Linux/EthernetClient.cpp @@ -1,24 +1,25 @@ /* -* 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 Arduino ethernet library, Copyright (c) 2010 Arduino LLC. All right reserved. -*/ - + * 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 Arduino ethernet library, Copyright (c) 2010 Arduino LLC. All right reserved. + */ + +#include #include #include #include @@ -249,6 +250,6 @@ bool EthernetClient::operator==(const EthernetClient& rhs) { return _sock == rhs._sock && _sock != -1 && rhs._sock != -1; } -uint8_t EthernetClient::getSocketNumber() { +int EthernetClient::getSocketNumber() { return _sock; } diff --git a/drivers/Linux/EthernetClient.h b/drivers/Linux/EthernetClient.h index b2ad1b10d..062743613 100644 --- a/drivers/Linux/EthernetClient.h +++ b/drivers/Linux/EthernetClient.h @@ -1,26 +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 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 Arduino ethernet library, Copyright (c) 2010 Arduino LLC. All right reserved. -*/ + * 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 Arduino ethernet library, Copyright (c) 2010 Arduino LLC. All right reserved. + */ -#ifndef ethernetclient_h -#define ethernetclient_h +#ifndef EthernetClient_h +#define EthernetClient_h #include "Client.h" #include "IPAddress.h" @@ -69,7 +69,7 @@ class EthernetClient : public Client { virtual bool operator!=(const bool value) { return bool() != value; } virtual bool operator==(const EthernetClient&); virtual bool operator!=(const EthernetClient& rhs) { return !this->operator==(rhs); }; - uint8_t getSocketNumber(); + int getSocketNumber(); friend class EthernetServer; diff --git a/drivers/Linux/EthernetServer.cpp b/drivers/Linux/EthernetServer.cpp index 506eb15dc..be82704f4 100644 --- a/drivers/Linux/EthernetServer.cpp +++ b/drivers/Linux/EthernetServer.cpp @@ -1,24 +1,25 @@ /* -* 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 Arduino ethernet library, Copyright (c) 2010 Arduino LLC. All right reserved. -*/ - + * 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 Arduino ethernet library, Copyright (c) 2010 Arduino LLC. All right reserved. + */ + +#include #include #include #include @@ -33,6 +34,7 @@ struct server_vars { struct IPAddress address; std::list *new_clients; std::vector *clients; + uint16_t max_clients; }; static pthread_mutex_t new_clients_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -40,9 +42,9 @@ static pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER; void *incoming_connections(void *); -EthernetServer::EthernetServer(uint16_t port) : port(port) +EthernetServer::EthernetServer(uint16_t port, uint16_t max_clients) : port(port), max_clients(max_clients) { - clients.reserve(MY_GATEWAY_MAX_CLIENTS); + clients.reserve(max_clients); } void EthernetServer::begin() @@ -60,6 +62,7 @@ void EthernetServer::begin(IPAddress address) vars->address = address; vars->new_clients = &new_clients; vars->clients = &clients; + vars->max_clients = max_clients; pthread_attr_init(&detached_attr); pthread_attr_setdetachstate(&detached_attr, PTHREAD_CREATE_DETACHED); @@ -137,6 +140,7 @@ size_t EthernetServer::write(const char *str) { if (str == NULL) return 0; return write((const uint8_t *)str, strlen(str)); } + size_t EthernetServer::write(const char *buffer, size_t size) { return write((const uint8_t *)buffer, size); } @@ -221,7 +225,7 @@ void *incoming_connections(void* thread_arg) pthread_mutex_lock(&clients_mutex); int connected_clients = vars->new_clients->size() + vars->clients->size(); - if (connected_clients == MY_GATEWAY_MAX_CLIENTS) { + if (connected_clients == vars->max_clients) { pthread_mutex_unlock(&clients_mutex); pthread_mutex_unlock(&new_clients_mutex); ETHERNETSERVER_DEBUG("Max number of ethernet clients reached."); diff --git a/drivers/Linux/EthernetServer.h b/drivers/Linux/EthernetServer.h index 10f1a4d67..2127829a7 100644 --- a/drivers/Linux/EthernetServer.h +++ b/drivers/Linux/EthernetServer.h @@ -1,26 +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 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 Arduino ethernet library, Copyright (c) 2010 Arduino LLC. All right reserved. -*/ + * 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 Arduino ethernet library, Copyright (c) 2010 Arduino LLC. All right reserved. + */ -#ifndef ethernetserver_h -#define ethernetserver_h +#ifndef EthernetServer_h +#define EthernetServer_h #include #include @@ -31,6 +31,10 @@ #define ETHERNETSERVER_BACKLOG 10 #endif +#ifndef ETHERNETSERVER_MAX_CLIENTS + #define ETHERNETSERVER_MAX_CLIENTS ETHERNETSERVER_BACKLOG +#endif + // debug #if defined(ETHERNETSERVER_VERBOSE) #define ETHERNETSERVER_DEBUG(x,...) debug(x, ##__VA_ARGS__) @@ -46,9 +50,10 @@ class EthernetServer : public Server { uint16_t port; std::list new_clients; std::vector clients; + uint16_t max_clients; public: - EthernetServer(uint16_t); + EthernetServer(uint16_t port, uint16_t max_clients = ETHERNETSERVER_MAX_CLIENTS); virtual void begin(); void begin(IPAddress); void beginPacket(IPAddress, uint16_t); diff --git a/drivers/Linux/IPAddress.cpp b/drivers/Linux/IPAddress.cpp index bec172896..dd67b59bc 100644 --- a/drivers/Linux/IPAddress.cpp +++ b/drivers/Linux/IPAddress.cpp @@ -1,25 +1,26 @@ /* - IPAddress.cpp - Base class that provides IPAddress - Copyright (c) 2011 Adrian McEwen. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - - Modified by Marcelo Aquino for MySensors use + * IPAddress.cpp - Base class that provides IPAddress + * Copyright (c) 2011 Adrian McEwen. All right reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * + * Modified by Marcelo Aquino for MySensors use */ +#include #include #include "IPAddress.h" diff --git a/drivers/Linux/IPAddress.h b/drivers/Linux/IPAddress.h index 2fb9c6fc8..f4b05c05e 100644 --- a/drivers/Linux/IPAddress.h +++ b/drivers/Linux/IPAddress.h @@ -1,23 +1,23 @@ /* - IPAddress.h - Base class that provides IPAddress - Copyright (c) 2011 Adrian McEwen. All right reserved. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - - - Modified by Marcelo Aquino for MySensors use + * IPAddress.h - Base class that provides IPAddress + * Copyright (c) 2011 Adrian McEwen. All right reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * + * Modified by Marcelo Aquino for MySensors use */ #ifndef IPAddress_h diff --git a/drivers/Linux/utility.cpp b/drivers/Linux/utility.cpp new file mode 100644 index 000000000..aa3690576 --- /dev/null +++ b/drivers/Linux/utility.cpp @@ -0,0 +1,177 @@ +#include +#include "Arduino.h" + +/** +* C++ version 0.4 char* style "itoa": +* Written by Lukás Chmela +* Released under GPLv3. +*/ +char *itoa(int value, char* result, int base) { + // check that the base if valid + if (base < 2 || base > 36) { *result = '\0'; return result; } + + char* ptr = result, *ptr1 = result, tmp_char; + int tmp_value; + + do { + tmp_value = value; + value /= base; + *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)]; + } while ( value ); + + // Apply negative sign + // Apply negative sign + if (tmp_value < 0) *ptr++ = '-'; + *ptr-- = '\0'; + while(ptr1 < ptr) { + tmp_char = *ptr; + *ptr--= *ptr1; + *ptr1++ = tmp_char; + } + return result; +} + +/** + * C++ version 0.4 char* style "itoa": + * Written by Lukás Chmela + * Released under GPLv3. + */ +char *ltoa(long value, char* result, int base) { + // check that the base if valid + if (base < 2 || base > 36) { *result = '\0'; return result; } + + char* ptr = result, *ptr1 = result, tmp_char; + long tmp_value; + + do { + tmp_value = value; + value /= base; + *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)]; + } while ( value ); + + // Apply negative sign + if (tmp_value < 0) *ptr++ = '-'; + *ptr-- = '\0'; + while(ptr1 < ptr) { + tmp_char = *ptr; + *ptr--= *ptr1; + *ptr1++ = tmp_char; + } + return result; +} + +char *ultoa(long num, char *str, int radix) +{ + unsigned long value; + char *sp = str; + char *sp2; + + value = num; + + /* Store sign at start of buffer for negative base-10 values */ + if (10 == radix && 0 > num) { + *sp++ = '-'; + value = -num; + } + + sp2 = sp; + + do { + char rem = value % radix; + value /= radix; + if (10 > rem) { + *sp++ = '0' + rem; + } else { + *sp++ = 'A' + rem - 10; + } + } while (0 < value); + + /* Mark end of string */ + *sp-- = 0; + + /* Reverse string contents (excluding sign) in place */ + while (sp2 < sp) { + char tmp = *sp2; + *sp2++ = *sp; + *sp-- = tmp; + } + + return str; +} + +/** + * Copyright (c) 2012, Peter A. Bigot + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of the software nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +char *utoa(int num, char *str, int radix) +{ + unsigned int value; + char *sp = str; + char *sp2; + + value = num; + + /* Store sign at start of buffer for negative base-10 values */ + if (10 == radix && 0 > num) { + *sp++ = '-'; + value = -num; + } + + sp2 = sp; + + do { + char rem = value % radix; + value /= radix; + if (10 > rem) { + *sp++ = '0' + rem; + } else { + *sp++ = 'A' + rem - 10; + } + } while (0 < value); + + /* Mark end of string */ + *sp-- = 0; + + /* Reverse string contents (excluding sign) in place */ + while (sp2 < sp) { + char tmp = *sp2; + *sp2++ = *sp; + *sp-- = tmp; + } + + return str; +} + +char *dtostrf(float f, int width, int decimals, char *result) +{ + sprintf(result,"%*.*f", width, decimals, f); + return result; +} From 490037d2851002ad0ce00dafcdc872fcd1a6d086 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Mon, 15 Aug 2016 12:13:18 -0300 Subject: [PATCH 058/167] Use non-blocking socket for EthernetServer * Non-blocking socket To simplify the class design and better mimics the Arduino version * Doxygenize EthernetServer class --- drivers/Linux/EthernetServer.cpp | 251 ++++++++++++++----------------- drivers/Linux/EthernetServer.h | 94 +++++++++--- drivers/Linux/Server.h | 2 + 3 files changed, 188 insertions(+), 159 deletions(-) diff --git a/drivers/Linux/EthernetServer.cpp b/drivers/Linux/EthernetServer.cpp index be82704f4..0537bb60f 100644 --- a/drivers/Linux/EthernetServer.cpp +++ b/drivers/Linux/EthernetServer.cpp @@ -23,25 +23,14 @@ #include #include #include -#include #include #include #include +#include +#include +#include "EthernetClient.h" #include "EthernetServer.h" -struct server_vars { - uint16_t port; - struct IPAddress address; - std::list *new_clients; - std::vector *clients; - uint16_t max_clients; -}; - -static pthread_mutex_t new_clients_mutex = PTHREAD_MUTEX_INITIALIZER; -static pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER; - -void *incoming_connections(void *); - EthernetServer::EthernetServer(uint16_t port, uint16_t max_clients) : port(port), max_clients(max_clients) { clients.reserve(max_clients); @@ -54,104 +43,7 @@ void EthernetServer::begin() void EthernetServer::begin(IPAddress address) { - pthread_t thread_id; - pthread_attr_t detached_attr; - - struct server_vars *vars = new struct server_vars; - vars->port = port; - vars->address = address; - vars->new_clients = &new_clients; - vars->clients = &clients; - vars->max_clients = max_clients; - - pthread_attr_init(&detached_attr); - pthread_attr_setdetachstate(&detached_attr, PTHREAD_CREATE_DETACHED); - pthread_create(&thread_id, &detached_attr, &incoming_connections, vars); -} - -void EthernetServer::beginPacket(IPAddress address, uint16_t port) -{ - //TODO: UDP - (void)address; - (void)port; -} - -int EthernetServer::parsePacket() -{ - //TODO: UDP - - return 0; -} - -bool EthernetServer::hasClient() -{ - bool empty; - - pthread_mutex_lock(&new_clients_mutex); - empty = new_clients.empty(); - pthread_mutex_unlock(&new_clients_mutex); - - return !empty; -} - -EthernetClient EthernetServer::available() -{ - int sock; - - pthread_mutex_lock(&new_clients_mutex); - if (new_clients.empty()) { - sock = -1; - } else { - sock = new_clients.front(); - new_clients.pop_front(); - } - pthread_mutex_unlock(&new_clients_mutex); - - return EthernetClient(sock); -} - -size_t EthernetServer::write(uint8_t b) -{ - return write(&b, 1); -} - -size_t EthernetServer::write(const uint8_t *buffer, size_t size) -{ - size_t n = 0; - size_t i = 0; - - pthread_mutex_lock(&clients_mutex); - while (i < clients.size()) { - EthernetClient client(clients[i]); - if (client.connected()) { - n += client.write(buffer, size); - i++; - } else { - clients[i] = clients.back(); - clients.pop_back(); - } - } - pthread_mutex_unlock(&clients_mutex); - - return n; -} - -size_t EthernetServer::write(const char *str) { - if (str == NULL) return 0; - return write((const uint8_t *)str, strlen(str)); -} - -size_t EthernetServer::write(const char *buffer, size_t size) { - return write((const uint8_t *)buffer, size); -} - -void *incoming_connections(void* thread_arg) -{ - struct server_vars *vars = (struct server_vars*) thread_arg; - int sockfd, new_fd; struct addrinfo hints, *servinfo, *p; - struct sockaddr_storage client_addr; - socklen_t sin_size; int yes=1; int rv; char ipstr[INET_ADDRSTRLEN]; @@ -162,10 +54,10 @@ void *incoming_connections(void* thread_arg) hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; - sprintf(portstr, "%d", vars->port); - if ((rv = getaddrinfo(vars->address.toString().c_str(), portstr, &hints, &servinfo)) != 0) { + sprintf(portstr, "%d", port); + if ((rv = getaddrinfo(address.toString().c_str(), portstr, &hints, &servinfo)) != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); - return NULL; + return; } // loop through all the results and bind to the first we can @@ -178,7 +70,7 @@ void *incoming_connections(void* thread_arg) if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { perror("setsockopt"); freeaddrinfo(servinfo); - return NULL; + return; } if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { @@ -193,53 +85,130 @@ void *incoming_connections(void* thread_arg) if (p == NULL) { fprintf(stderr, "failed to bind\n"); freeaddrinfo(servinfo); - return NULL; + return; } if (listen(sockfd, ETHERNETSERVER_BACKLOG) == -1) { perror("listen"); freeaddrinfo(servinfo); - return NULL; + return; } freeaddrinfo(servinfo); + fcntl(sockfd, F_SETFL, O_NONBLOCK); + struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr; void *addr = &(ipv4->sin_addr); inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr); ETHERNETSERVER_DEBUG("Listening for connections on %s:%s\n", ipstr, portstr); +} - while (1) { // accept() loop - sin_size = sizeof client_addr; - new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size); - if (new_fd == -1) { - perror("accept"); - continue; +bool EthernetServer::hasClient() +{ + _accept(); + + return !new_clients.empty(); +} + +EthernetClient EthernetServer::available() +{ + if (new_clients.empty()) { + return EthernetClient(); + } else { + int sock = new_clients.front(); + new_clients.pop_front(); + return EthernetClient(sock); + } +} + +size_t EthernetServer::write(uint8_t b) +{ + return write(&b, 1); +} + +size_t EthernetServer::write(const uint8_t *buffer, size_t size) +{ + size_t n = 0; + size_t i = 0; + + while (i < clients.size()) { + EthernetClient client(clients[i]); + if (client.connected()) { + n += client.write(buffer, size); + i++; + } else if (!client.available()) { + client.stop(); + clients[i] = clients.back(); + clients.pop_back(); + ETHERNETSERVER_DEBUG("Client disconnected."); } + } + + return n; +} + +size_t EthernetServer::write(const char *str) +{ + if (str == NULL) return 0; + return write((const uint8_t *)str, strlen(str)); +} - void *addr = &(((struct sockaddr_in*)&client_addr)->sin_addr); - inet_ntop(client_addr.ss_family, addr, ipstr, sizeof ipstr); - ETHERNETSERVER_DEBUG("New connection from %s\n", ipstr); +size_t EthernetServer::write(const char *buffer, size_t size) +{ + return write((const uint8_t *)buffer, size); +} - pthread_mutex_lock(&new_clients_mutex); - pthread_mutex_lock(&clients_mutex); - int connected_clients = vars->new_clients->size() + vars->clients->size(); +void EthernetServer::_accept() +{ + int new_fd; + socklen_t sin_size; + struct sockaddr_storage client_addr; + char ipstr[INET_ADDRSTRLEN]; - if (connected_clients == vars->max_clients) { - pthread_mutex_unlock(&clients_mutex); - pthread_mutex_unlock(&new_clients_mutex); + if (new_clients.size() + clients.size() == max_clients) { + // no free slots, search for a dead client + bool no_free_slots = true; + for (size_t i = 0; i < clients.size();) { + EthernetClient client(clients[i]); + if (client.connected() || client.available()) { + i++; + } else { + clients[i] = clients.back(); + clients.pop_back(); + no_free_slots = false; + break; + } + } + if (no_free_slots) { + for (std::list::iterator it = new_clients.begin(); it != new_clients.end(); ++it) { + EthernetClient client(*it); + if (!client.connected() && !client.available()) { + new_clients.erase(it); + no_free_slots = false; + break; + } + } + } + if (no_free_slots) { ETHERNETSERVER_DEBUG("Max number of ethernet clients reached."); - close(new_fd); - usleep(5000000); - } else { - vars->new_clients->push_back(new_fd); - vars->clients->push_back(new_fd); - pthread_mutex_unlock(&clients_mutex); - pthread_mutex_unlock(&new_clients_mutex); + return; + } + } + + sin_size = sizeof client_addr; + new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size); + if (new_fd == -1) { + if (errno != EAGAIN && errno != EWOULDBLOCK) { + perror("accept"); } + return; } - delete vars; + new_clients.push_back(new_fd); + clients.push_back(new_fd); - return NULL; + void *addr = &(((struct sockaddr_in*)&client_addr)->sin_addr); + inet_ntop(client_addr.ss_family, addr, ipstr, sizeof ipstr); + ETHERNETSERVER_DEBUG("New connection from %s\n", ipstr); } diff --git a/drivers/Linux/EthernetServer.h b/drivers/Linux/EthernetServer.h index 2127829a7..8bb4c6dd7 100644 --- a/drivers/Linux/EthernetServer.h +++ b/drivers/Linux/EthernetServer.h @@ -25,44 +25,102 @@ #include #include #include "Server.h" -#include "EthernetClient.h" +#include "IPAddress.h" -#ifndef ETHERNETSERVER_BACKLOG - #define ETHERNETSERVER_BACKLOG 10 -#endif - -#ifndef ETHERNETSERVER_MAX_CLIENTS - #define ETHERNETSERVER_MAX_CLIENTS ETHERNETSERVER_BACKLOG +#ifdef ETHERNETSERVER_MAX_CLIENTS + #define ETHERNETSERVER_BACKLOG ETHERNETSERVER_MAX_CLIENTS //!< Maximum length to which the queue of pending connections may grow. +#else + #define ETHERNETSERVER_MAX_CLIENTS 10 //!< Default value for max_clients. + #define ETHERNETSERVER_BACKLOG 10 //!< Maximum length to which the queue of pending connections may grow. #endif // debug #if defined(ETHERNETSERVER_VERBOSE) - #define ETHERNETSERVER_DEBUG(x,...) debug(x, ##__VA_ARGS__) + #define ETHERNETSERVER_DEBUG(x,...) printf(x, ##__VA_ARGS__) //!< debug #else - #define ETHERNETSERVER_DEBUG(x,...) + #define ETHERNETSERVER_DEBUG(x,...) //!< debug NULL #endif class EthernetClient; +/** + * @brief EthernetServer class + */ class EthernetServer : public Server { private: - uint16_t port; - std::list new_clients; - std::vector clients; - uint16_t max_clients; + 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. + * + * @param port number for the socket addresses. + * @param max_clients The maximum number allowed for connected clients. + */ EthernetServer(uint16_t port, uint16_t max_clients = ETHERNETSERVER_MAX_CLIENTS); + /** + * @brief Listen for inbound connection request. + * + */ virtual void begin(); - void begin(IPAddress); - void beginPacket(IPAddress, uint16_t); - int parsePacket(); + /** + * @brief Listen on the specified ip for inbound connection request. + * + * @param addr IP address to bind to. + */ + void begin(IPAddress addr); + /** + * @brief Verifies if a new client has connected. + * + * @return @c true if a new client has connected, else @c false. + */ bool hasClient(); + /** + * @brief Get the new connected client. + * + * @return client class object if a new client has connected else -1. + */ EthernetClient available(); - virtual size_t write(uint8_t); - virtual size_t write(const uint8_t *, size_t); + /** + * @brief Write a byte to all clients. + * + * @param b byte to send. + * @return 0 if FAILURE or 1 if SUCCESS. + */ + virtual size_t write(uint8_t b); + /** + * @brief Write at most 'size' bytes to all clients. + * + * @param buffer to read from. + * @param size of the buffer. + * @return 0 if FAILURE else number of bytes sent. + */ + virtual size_t write(const uint8_t *buffer, size_t size); + /** + * @brief Write a null-terminated string to all clients. + * + * @param str String to write. + * @return 0 if FAILURE else number of characters sent. + */ size_t write(const char *str); + /** + * @brief Write at most 'size' characters to all clients. + * + * @param buffer to read from. + * @param size of the buffer. + * @return 0 if FAILURE else the number of characters sent. + */ size_t write(const char *buffer, size_t size); }; diff --git a/drivers/Linux/Server.h b/drivers/Linux/Server.h index d1b40461b..7910e8386 100644 --- a/drivers/Linux/Server.h +++ b/drivers/Linux/Server.h @@ -20,9 +20,11 @@ #ifndef server_h #define server_h +#if !DOXYGEN class Server { public: virtual void begin() =0; }; +#endif #endif From 211afb17c43ebf8e90639d44af7c7891b78f3dfa Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Mon, 15 Aug 2016 18:47:09 -0300 Subject: [PATCH 059/167] Doxygenize Linux drivers --- drivers/Linux/Client.h | 3 + drivers/Linux/EthernetClient.cpp | 34 ++++---- drivers/Linux/EthernetClient.h | 140 ++++++++++++++++++++++++++++--- drivers/Linux/IPAddress.h | 106 ++++++++++++++++++----- drivers/Linux/Stream.h | 2 + 5 files changed, 237 insertions(+), 48 deletions(-) diff --git a/drivers/Linux/Client.h b/drivers/Linux/Client.h index 0169890df..067b57dd9 100644 --- a/drivers/Linux/Client.h +++ b/drivers/Linux/Client.h @@ -24,6 +24,7 @@ #include "Stream.h" #include "IPAddress.h" +#if !DOXYGEN class Client : public Stream { public: @@ -39,8 +40,10 @@ class Client : public Stream { virtual void stop() = 0; virtual uint8_t connected() = 0; virtual operator bool() = 0; + protected: uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; }; +#endif #endif diff --git a/drivers/Linux/EthernetClient.cpp b/drivers/Linux/EthernetClient.cpp index 5e8084831..387fcaa74 100644 --- a/drivers/Linux/EthernetClient.cpp +++ b/drivers/Linux/EthernetClient.cpp @@ -190,18 +190,6 @@ void EthernetClient::stop() { _sock = -1; } -uint8_t EthernetClient::connected() { - if (_sock == -1) return 0; - - if (peek() < 0) { - if (errno == EAGAIN) { - return 1; - } - return 0; - } - return 1; -} - uint8_t EthernetClient::status() { if (_sock == -1) return ETHERNETCLIENT_W5100_CLOSED; @@ -232,13 +220,27 @@ uint8_t EthernetClient::status() { case TCP_CLOSING: return ETHERNETCLIENT_W5100_CLOSING; } - } else { - perror("getsockopt"); } return ETHERNETCLIENT_W5100_CLOSED; } +uint8_t EthernetClient::connected() { + if (_sock == -1) return 0; + + if (peek() < 0) { + if (errno == EAGAIN) { + return 1; + } + return 0; + } + return 1; +} + +int EthernetClient::getSocketNumber() { + return _sock; +} + // the next function allows us to use the client returned by // EthernetServer::available() as the condition in an if-statement. @@ -249,7 +251,3 @@ EthernetClient::operator bool() { bool EthernetClient::operator==(const EthernetClient& rhs) { return _sock == rhs._sock && _sock != -1 && rhs._sock != -1; } - -int EthernetClient::getSocketNumber() { - return _sock; -} diff --git a/drivers/Linux/EthernetClient.h b/drivers/Linux/EthernetClient.h index 062743613..f21f5d3ea 100644 --- a/drivers/Linux/EthernetClient.h +++ b/drivers/Linux/EthernetClient.h @@ -39,42 +39,160 @@ // debug #if defined(ETHERNETCLIENT_VERBOSE) - #define ETHERNETCLIENT_DEBUG(x,...) debug(x, ##__VA_ARGS__) + #define ETHERNETCLIENT_DEBUG(x,...) debug(x, ##__VA_ARGS__) //!< debug #else - #define ETHERNETCLIENT_DEBUG(x,...) + #define ETHERNETCLIENT_DEBUG(x,...) //!< debug NULL #endif +/** + * EthernetClient class + */ class EthernetClient : public Client { +private: + int _sock; + public: + /** + * @brief EthernetClient constructor. + */ EthernetClient(); + /** + * @brief EthernetClient constructor. + * + * @param sock Network socket. + */ EthernetClient(int sock); - - uint8_t status(); - virtual int connect(IPAddress ip, uint16_t port); + /** + * @brief Initiate a connection with host:port. + * + * @param host host name to resolve or a stringified dotted IP address. + * @param port to connect to. + * @return 1 if SUCCESS or -1 if FAILURE. + */ virtual int connect(const char *host, uint16_t port); - virtual size_t write(uint8_t); + /** + * @brief Initiate a connection with ip:port. + * + * @param ip to connect to. + * @param port to connect to. + * @return 1 if SUCCESS or -1 if FAILURE. + */ + virtual int connect(IPAddress ip, uint16_t port); + /** + * @brief Write a byte. + * + * @param b byte to write. + * @return 0 if FAILURE or 1 if SUCCESS. + */ + virtual size_t write(uint8_t b); + /** + * @brief Write at most 'size' bytes. + * + * @param buf Buffer to read from. + * @param size of the buffer. + * @return 0 if FAILURE or the number of bytes sent. + */ virtual size_t write(const uint8_t *buf, size_t size); + /** + * @brief Write a null-terminated string. + * + * @param str String to write. + * @return 0 if FAILURE or number of characters sent. + */ size_t write(const char *str); + /** + * @brief Write at most 'size' characters. + * + * @param buffer to read from. + * @param size of the buffer. + * @return 0 if FAILURE or the number of characters sent. + */ size_t write(const char *buffer, size_t size); + /** + * @brief Checks if new data is available. + * + * @return number of bytes available. + */ virtual int available(); + /** + * @brief Read a byte. + * + * @return 0 if FAILURE or 1 if SUCCESS. + * @note This function will block (until data becomes available or timeout is reached). + */ virtual int read(); + /** + * @brief Read a number of bytes and store in a buffer. + * + * @return -1 if FAILURE or number of read bytes. + * @note This function will block (until data becomes available or timeout is reached). + */ virtual int read(uint8_t *buf, size_t size); + /** + * @brief Check if new data are available. + * + * @return 0 if no data, else number of bytes available. + */ virtual int peek(); + /** + * @brief Flushes the network buffers. + * + * Empty function due to the way TCP works. + */ virtual void flush(); + /** + * @brief Close the connection gracefully. + * + * Send a FIN and wait 1s for a response. If no response close it forcefully. + */ virtual void stop(); + /** + * @brief Connection status. + * + * @return state according to W5100 library codes. + */ + uint8_t status(); + /** + * @brief Checks whether the socket is alive. + * + * @return 0 if disconnected or 1 if connected. + */ virtual uint8_t connected(); + /** + * @brief Get the internal socket file descriptor. + * + * @return an integer, that is the socket number. + */ + int getSocketNumber(); + /** + * @brief Overloaded cast operators. + * + * Allow EthernetClient objects to be used where a bool is expected. + */ virtual operator bool(); + /** + * @brief Overloaded cast operators. + * + */ virtual bool operator==(const bool value) { return bool() == value; } + /** + * @brief Overloaded cast operators. + * + */ virtual bool operator!=(const bool value) { return bool() != value; } - virtual bool operator==(const EthernetClient&); + /** + * @brief Overloaded cast operators. + * + */ + virtual bool operator==(const EthernetClient& rhs); + /** + * @brief Overloaded cast operators. + * + */ virtual bool operator!=(const EthernetClient& rhs) { return !this->operator==(rhs); }; - int getSocketNumber(); friend class EthernetServer; - -private: - int _sock; }; #endif diff --git a/drivers/Linux/IPAddress.h b/drivers/Linux/IPAddress.h index f4b05c05e..c8e336c81 100644 --- a/drivers/Linux/IPAddress.h +++ b/drivers/Linux/IPAddress.h @@ -26,59 +26,127 @@ #include #include -// A class to make it easier to handle and pass around IP addresses - -// class IPAddress: public Printable { +/** + * @brief A class to make it easier to handle and pass around IP addresses + */ class IPAddress { private: union { - uint8_t bytes[4]; // IPv4 address - uint32_t dword; + uint8_t bytes[4]; //!< IPv4 address as an array + uint32_t dword; //!< IPv4 address in 32 bits format } _address; - // Access the raw byte array containing the address. Because this returns a pointer - // to the internal structure rather than a copy of the address this function should only - // be used when you know that the usage of the returned uint8_t* will be transient and not - // stored. + /** + * @brief Access the raw byte array containing the address. + * + * Because this returns a pointer to the internal structure rather than a copy of the address + * this function should only be used when you know that the usage of the returned uint8_t* will + * be transient and not stored. + * + * @return pointer to the internal structure. + */ uint8_t* raw_address() { return _address.bytes; } public: - // Constructors + /** + * @brief IPAddress constructor. + */ IPAddress(); + /** + * @brief IPAddress constructor. + * + * @param first_octet first octet of the IPv4 address. + * @param second_octet second octet of the IPv4 address. + * @param third_octet third octet of the IPv4 address. + * @param fourth_octet fourth octet of the IPv4 address. + */ IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); + /** + * @brief IPAddress constructor. + * + * @param address to be set from a 32 bits integer. + */ IPAddress(uint32_t address); + /** + * @brief IPAddress constructor. + * + * @param address to be set from a byte array. + */ IPAddress(const uint8_t *address); - + /** + * @brief Set the IP from a array of characters. + * + * @param address to be set. + */ bool fromString(const char *address); + /** + * @brief Set the IP from a string class type. + * + * @param address to be set. + */ bool fromString(const std::string &address) { return fromString(address.c_str()); } - - // Overloaded cast operator to allow IPAddress objects to be used where a pointer - // to a four-byte uint8_t array is expected + /** + * @brief Overloaded cast operator + * + * Allow IPAddress objects to be used where a pointer to a four-byte uint8_t array is expected + */ operator uint32_t() const { return _address.dword; } + /** + * @brief Overloaded cast operator + * + */ bool operator==(const IPAddress& addr) const { return _address.dword == addr._address.dword; } + /** + * @brief Overloaded cast operator + * + */ bool operator==(uint32_t addr) const { return _address.dword == addr; } + /** + * @brief Overloaded cast operator + * + */ bool operator==(const uint8_t* addr) const; - - // Overloaded index operator to allow getting and setting individual octets of the address + /** + * @brief Overloaded index operator. + * + * Allow getting and setting individual octets of the address. + * + */ uint8_t operator[](int index) const { return _address.bytes[index]; } + /** + * @brief Overloaded index operator + * + */ uint8_t& operator[](int index) { return _address.bytes[index]; } - - // Overloaded copy operators to allow initialisation of IPAddress objects from other types + /** + * @brief Overloaded copy operators. + * + * Allow initialisation of IPAddress objects from byte array. + */ IPAddress& operator=(const uint8_t *address); + /** + * @brief Overloaded copy operator. + * + * Allow initialisation of IPAddress objects from a 32 bits integer. + */ IPAddress& operator=(uint32_t address); - + /** + * @brief Convert the IP address to a string. + * + * @return A stringified IP address + */ std::string toString(); friend class Client; diff --git a/drivers/Linux/Stream.h b/drivers/Linux/Stream.h index 0241f6aae..226543b92 100644 --- a/drivers/Linux/Stream.h +++ b/drivers/Linux/Stream.h @@ -1,6 +1,7 @@ #ifndef Stream_h #define Stream_h +#if !DOXYGEN class Stream { public: virtual size_t write(uint8_t) = 0; @@ -11,5 +12,6 @@ class Stream { virtual int peek() = 0; virtual void flush() = 0; }; +#endif #endif From dab1906c56815c0934c5b0e6505a9ca3b6adec59 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Tue, 16 Aug 2016 14:44:48 -0300 Subject: [PATCH 060/167] Remove leftover files from Rpi port --- libraries/MySensors/Makefile | 82 ---- .../core/MyGatewayTransportEthernetLinux.cpp | 454 ------------------ libraries/MySensors/core/MyHwLinuxGeneric.cpp | 163 ------- libraries/MySensors/core/MyHwLinuxGeneric.h | 43 -- libraries/MySensors/core/MyMainLinux.cpp | 13 - .../MySensors/examples_RPi/PiGateway.cpp | 68 --- 6 files changed, 823 deletions(-) delete mode 100644 libraries/MySensors/Makefile delete mode 100644 libraries/MySensors/core/MyGatewayTransportEthernetLinux.cpp delete mode 100644 libraries/MySensors/core/MyHwLinuxGeneric.cpp delete mode 100644 libraries/MySensors/core/MyHwLinuxGeneric.h delete mode 100644 libraries/MySensors/core/MyMainLinux.cpp delete mode 100644 libraries/MySensors/examples_RPi/PiGateway.cpp diff --git a/libraries/MySensors/Makefile b/libraries/MySensors/Makefile deleted file mode 100644 index 03e671df6..000000000 --- a/libraries/MySensors/Makefile +++ /dev/null @@ -1,82 +0,0 @@ -########################################################################## -# Configurable options # -########################################################################## -# Install Base location -PREFIX=/usr/local -# Bin Dir -BINDIR=$(PREFIX)/sbin - -########################################################################## -# Please do not change anything below this line # -########################################################################## -CXX ?= g++ - -ifeq "$(shell uname -m)" "armv6l" - ARCH=armv6zk -endif -ifeq "$(shell uname -m)" "armv7l" - ARCH=armv7-a -endif -ifdef ARCH - # The recommended compiler flags for the Raspberry Pi - CXXFLAGS+=-Ofast -mfpu=vfp -mfloat-abi=hard -march=$(ARCH) -mtune=arm1176jzf-s -DRASPBERRYPI_ARCH $(OPTFLAGS) - LDFLAGS+=-lrf24-bcm -endif - -CXXFLAGS+=-g -Wall -Wextra -CXXFLAGS+=-DLINUX_ARCH_GENERIC $(OPTFLAGS) - -# get PI Revision from cpuinfo -PIREV := $(shell cat /proc/cpuinfo | grep Revision | cut -f 2 -d ":" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$$//') -ifeq ($(PIREV),$(filter $(PIREV),a01041 a21041 0010)) - # a01041 and a21041 are PI 2 Model B with BPLUS Layout and 0010 is Pi Model B+ with BPLUS Layout - CXXFLAGS+=-D__PI_BPLUS -endif - -COMPILER_FLAGS=examples_RPi/compiler_flags -GATEWAY=examples_RPi/PiGateway -GATEWAYMQTT=examples_RPi/PiGatewayMQTT -GATEWAY_SOURCES=examples_RPi/PiGateway.cpp $(wildcard ./utility/*.cpp) -GATEWAY_OBJECTS=$(patsubst %.cpp,%.o,$(GATEWAY_SOURCES)) -DEPS+=$(patsubst %.cpp,%.d,$(GATEWAY_SOURCES)) - -RF24H = /usr/local/include/RF24 -CINCLUDE=-I. -I./core -I$(RF24H) - -.PHONY: all gateway gatewaymqtt clean install uninstall force - -all: $(GATEWAY) - -mqtt: $(GATEWAYMQTT) - -$(COMPILER_FLAGS): force - echo '$(CXXFLAGS)' | cmp -s - $@ || echo '$(CXXFLAGS)' > $@ - -$(GATEWAY_OBJECTS): $(COMPILER_FLAGS) - -# Basic Gateway Build -$(GATEWAY): LDFLAGS += -pthread -$(GATEWAY): $(GATEWAY_OBJECTS) - $(CXX) $(LDFLAGS) -o $@ $(GATEWAY_OBJECTS) - -# MQTT Gateway Build -$(GATEWAYMQTT): CXXFLAGS += -DMY_GATEWAY_MQTT_CLIENT -$(GATEWAYMQTT): LDFLAGS += -pthread -lmosquitto -$(GATEWAYMQTT): $(GATEWAY_OBJECTS) - $(CXX) $(LDFLAGS) -o $@ $(GATEWAY_OBJECTS) - -# Include all .d files --include $(DEPS) - -%.o: %.cpp - $(CXX) $(CXXFLAGS) $(CINCLUDE) -MMD -c -o $@ $< - -# The Cleaner -clean: - rm -rf build $(GATEWAY_OBJECTS) $(GATEWAY) $(GATEWAYMQTT) $(DEPS) $(COMPILER_FLAGS) - -install: all install-gatewaybasic install-gatewayserial install-gatewayethernet install-initscripts - -install-gatewaybasic: - @echo "Installing $(GATEWAY) to $(BINDIR)" - @install -m 0755 $(GATEWAY) $(BINDIR) diff --git a/libraries/MySensors/core/MyGatewayTransportEthernetLinux.cpp b/libraries/MySensors/core/MyGatewayTransportEthernetLinux.cpp deleted file mode 100644 index c5d1091ea..000000000 --- a/libraries/MySensors/core/MyGatewayTransportEthernetLinux.cpp +++ /dev/null @@ -1,454 +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 - * Copyleft (c) 2016, Marcelo Aquino - * 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 "MyGatewayTransport.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef MY_GATEWAY_MQTT_CLIENT - #include - - #ifndef MQTT_IP - #define MQTT_IP "127.0.0.1" - #endif - #ifndef MQTT_PORT - #define MQTT_PORT 1883 - #endif - #ifndef MQTT_KEEPALIVE - #define MQTT_KEEPALIVE 60 - #endif - #ifndef MY_MQTT_PUBLISH_TOPIC_PREFIX - #define MY_MQTT_PUBLISH_TOPIC_PREFIX "mygateway1-out" - #endif - #ifndef MY_MQTT_SUBSCRIBE_TOPIC_PREFIX - #define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX "mygateway1-in" - #endif -#endif - -//TODO -#ifdef MY_USE_UDP - #error UDP not supported for this type of gateway -#endif - -union _addrIPv4{ - uint8_t bytes[4]; - uint32_t dword; -}; - -static int controllers[MY_GATEWAY_MAX_CLIENTS]; -static MyMessage _ethernetMsg; -static std::list ethernetMsg_q; -static pthread_mutex_t ethernetMsg_mutex = PTHREAD_MUTEX_INITIALIZER; - -// Prototypes -int open_listen(char *ip, uint16_t port); -uint32_t getAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); -void *get_in_addr(struct sockaddr *sa); -void *waiting_controllers(void* thread_arg); -void *connected_controller(void* thread_arg); - -#ifdef MY_GATEWAY_MQTT_CLIENT -void *mqtt_thread(void *); -struct mosquitto *mosq; -#endif - -bool gatewayTransportInit() { - long int sockfd; - pthread_t thread_id; - pthread_attr_t attr; -#ifdef MY_GATEWAY_MQTT_CLIENT - pthread_attr_t mqtt_attr; -#endif - char *ip = NULL; - - // ignore SIGPIPE generated by send() to a disconnected client - signal(SIGPIPE, SIG_IGN); - - for (uint8_t i = 0; i < MY_GATEWAY_MAX_CLIENTS; i++) { - controllers[i] = -1; - } - -#ifdef MY_CONTROLLER_IP_ADDRESS - //TODO - return false; -#else - #ifdef MY_IP_ADDRESS - char ipstr[INET_ADDRSTRLEN]; - union _addrIPv4 addrIPv4 = getAddress(MY_IP_ADDRESS); - sprintf(ipstr, "%d.%d.%d.%d", addrIPv4.bytes[0], addrIPv4.bytes[1], - addrIPv4.bytes[2], addrIPv4.bytes[3]); - ip = ipstr; - #endif - - sockfd = open_listen(ip, MY_PORT); - if (sockfd < 0) { - return false; - } -#endif - - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_create(&thread_id, &attr, &waiting_controllers, (void *)sockfd); - pthread_attr_destroy(&attr); - -#ifdef MY_GATEWAY_MQTT_CLIENT - /* mqtt thread */ - pthread_attr_init(&mqtt_attr); - pthread_attr_setdetachstate(&mqtt_attr, PTHREAD_CREATE_DETACHED); - pthread_create(&thread_id, &mqtt_attr, &mqtt_thread, NULL); - pthread_attr_destroy(&mqtt_attr); -#endif - - return true; -} - -bool gatewayTransportSend(MyMessage &message) -{ - char *ethernetMsg = protocolFormat(message); - - for (uint8_t i = 0; i < MY_GATEWAY_MAX_CLIENTS; i++) { - if (controllers[i] == -1) - continue; - if (send(controllers[i], ethernetMsg, strlen(ethernetMsg), 0) == -1) - perror("send"); - } - -#ifdef MY_GATEWAY_MQTT_CLIENT - char *mqttMsg = protocolFormatMQTTTopic(MY_MQTT_PUBLISH_TOPIC_PREFIX, message); - //connection, message id, topic, bytes, data, QOS, retain - mosquitto_publish(mosq, NULL, mqttMsg, strlen(message.getString(_convBuffer)), message.getString(_convBuffer), 0, false); -#endif - - return true; -} - -bool gatewayTransportAvailable() -{ - bool empty; - - pthread_mutex_lock(ðernetMsg_mutex); - empty = ethernetMsg_q.empty(); - pthread_mutex_unlock(ðernetMsg_mutex); - - return !empty; -} - -MyMessage& gatewayTransportReceive() -{ - // Return the last parsed message - pthread_mutex_lock(ðernetMsg_mutex); - _ethernetMsg = ethernetMsg_q.front(); - ethernetMsg_q.pop_front(); - pthread_mutex_unlock(ðernetMsg_mutex); - - return _ethernetMsg; -} - -int open_listen(char *address, uint16_t port) -{ - int sockfd; - struct addrinfo hints, *servinfo, *p; - int yes=1; - int rv; - char ipstr[INET_ADDRSTRLEN]; - char portstr[6]; - - memset(&hints, 0, sizeof hints); - hints.ai_family = AF_INET; // IPv4 - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_PASSIVE; - - sprintf(portstr, "%d", port); - if ((rv = getaddrinfo(address, portstr, &hints, &servinfo)) != 0) { - fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); - return -1; - } - - // loop through all the results and bind to the first we can - for (p = servinfo; p != NULL; p = p->ai_next) { - if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { - perror("socket"); - continue; - } - - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { - perror("setsockopt"); - freeaddrinfo(servinfo); - return -1; - } - - if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { - close(sockfd); - perror("bind"); - continue; - } - - break; - } - - if (p == NULL) { - fprintf(stderr, "failed to bind\n"); - freeaddrinfo(servinfo); - return -1; - } - - if (listen(sockfd, MY_GATEWAY_MAX_CLIENTS) == -1) { - perror("listen"); - freeaddrinfo(servinfo); - return -1; - } - - struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr; - void *addr = &(ipv4->sin_addr); - inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr); - debug("Eth: Listening for connections on %s:%s\n", ipstr, portstr); - - freeaddrinfo(servinfo); - return sockfd; -} - -uint32_t getAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) -{ - union _addrIPv4 addrIPv4; - - addrIPv4.bytes[0] = first_octet; - addrIPv4.bytes[1] = second_octet; - addrIPv4.bytes[2] = third_octet; - addrIPv4.bytes[3] = fourth_octet; - - return addrIPv4.dword; -} - -void *get_in_addr(struct sockaddr *sa) -{ - if (sa->sa_family == AF_INET) { - return &(((struct sockaddr_in*)sa)->sin_addr); - } - - return &(((struct sockaddr_in6*)sa)->sin6_addr); -} - -void *waiting_controllers(void* thread_arg) -{ - long int sockfd = (long int) thread_arg; - long int new_fd; // new connection on new_fd - struct sockaddr_storage client_addr; // connector's address information - socklen_t sin_size; - char s[INET6_ADDRSTRLEN]; - pthread_t thread_id; - pthread_attr_t attr; - uint8_t i; - - while (1) { // accept() loop - sin_size = sizeof client_addr; - new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size); - if (new_fd == -1) { - perror("accept"); - continue; - } - - inet_ntop(client_addr.ss_family, - get_in_addr((struct sockaddr *)&client_addr), s, sizeof s); - debug("Eth: New connection from %s\n", s); - - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_create(&thread_id, &attr, &connected_controller, (void *)new_fd); - pthread_attr_destroy(&attr); - - for (i = 0; i < MY_GATEWAY_MAX_CLIENTS; i++) { - if (controllers[i] == -1) { - controllers[i] = new_fd; - break; - } - } - if (i >= MY_GATEWAY_MAX_CLIENTS) { - // no free/disconnected spot so reject - close(new_fd); - } - } - - return NULL; -} - -void *connected_controller(void* thread_arg) -{ - long int sockfd = (long int) thread_arg; - char inputString[MY_GATEWAY_MAX_RECEIVE_LENGTH]; - char *ptr = inputString; - int nbytes = 0; - MyMessage ethernetMsg; - - while (1) { - if (recv(sockfd, ptr, 1, 0) > 0) { - if (*ptr == '\n' || *ptr == '\r') { - // String terminator - *ptr = 0; - debug("Eth: %s\n", inputString); - if (protocolParse(ethernetMsg, inputString)) { - pthread_mutex_lock(ðernetMsg_mutex); - ethernetMsg_q.push_back(ethernetMsg); - pthread_mutex_unlock(ðernetMsg_mutex); - } - - // Prepare for the next message - ptr = inputString; - nbytes = 0; - continue; - } - nbytes++; - if (nbytes == MY_GATEWAY_MAX_RECEIVE_LENGTH) { - // Incoming message too long. Throw away - debug("Eth: Message too long\n"); - ptr = inputString; - nbytes = 0; - } else { - ptr++; - } - } else { - break; - } - } - - if (nbytes == -1) - perror("recv"); - - for (uint8_t i = 0; i < MY_GATEWAY_MAX_CLIENTS; i++) { - if (controllers[i] == sockfd) { - controllers[i] = -1; - break; - } - } - - close(sockfd); - return NULL; -} - -#ifdef MY_GATEWAY_MQTT_CLIENT -void mqtt_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message) -{ - (void)mosq; - (void)userdata; - - if(message->payloadlen){ - printf("Got a MQTT message %s %s\n", message->topic, (char*)message->payload); - }else{ - printf("Got a MQTT message %s (null)\n", message->topic); - } - - MyMessage msg; - protocolMQTTParse(msg, message->topic, (uint8_t*)message->payload, message->payloadlen); - - if(msg.destination != 0 && msg.sensor != 0 && msg.type != 255) - { - ethernetMsg_q.push_back(msg); - - // Forward the data to Ethernet - // Likely this is a duplicate from a C_SET that we received and published - // in msg_callback. Not much we can do to avoid the duplicate as there is - // no way to tell if we performed the publish that is triggering this callback. - char *ethernetMsg = protocolFormat(msg); - - for (uint8_t i = 0; i < MY_GATEWAY_MAX_CLIENTS; i++) { - if (controllers[i] == -1) - continue; - if (send(controllers[i], ethernetMsg, strlen(ethernetMsg), 0) == -1) - perror("send"); - } - } - else - { - printf("Recieved a bad MQTT message: '%s':'%s'\n destination:%i, sensor:%i, type:%i\n", - message->topic, (char*)message->payload, msg.destination, msg.sensor, msg.type); - } -} - -void mqtt_connect_callback(struct mosquitto *mosq, void *userdata, int result) -{ - (void)mosq; - (void)userdata; - - if(!result){ - printf("Connected!\n"); - /* Subscribe to broker information topics on successful connect. */ - //connection, message id, topic, qos - mosquitto_subscribe(mosq, NULL, protocolFormatMQTTSubscribe(MY_MQTT_SUBSCRIBE_TOPIC_PREFIX), 0); - }else{ - fprintf(stderr, "Connect failed\n"); - } -} - -void mqtt_subscribe_callback(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos) -{ - (void)mosq; - (void)userdata; - - int i; - - printf("Subscribed (mid: %d): %d", mid, granted_qos[0]); - for(i=1; i - * Copyleft (c) 2016, Marcelo Aquino - * 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 "MyHwLinuxGeneric.h" - -#include -#include -#include -#include -#include - -static const char* CONFIG_FILE = "/etc/MySensorGateway.cfg"; -static const size_t _length = 1024; // ATMega328 has 1024 bytes -static uint8_t _config[_length]; -static unsigned long millis_at_start; - -bool CheckConfigFile() { - struct stat fileInfo; - - if(stat(CONFIG_FILE, &fileInfo) != 0) - { - //File does not exist. Create it. - debug("Config file %s does not exist, creating new config file.\n", CONFIG_FILE); - ofstream myFile(CONFIG_FILE, ios::out | ios::binary); - if(!myFile) - { - debug("Unable to create config file %s.\n", CONFIG_FILE); - return false; - } - myFile.write((const char*)_config, _length); - myFile.close(); - } - else if(fileInfo.st_size != _length) - { - debug("Config file %s is not the correct size of %i. Please remove the file and a new one will be created.\n", CONFIG_FILE, _length); - return false; - } - else - { - //Read config into local memory. - ifstream myFile(CONFIG_FILE, ios::in | ios::binary); - if(!myFile) - { - debug("Unable to open config to file %s for reading.\n", CONFIG_FILE); - return false; - } - myFile.read((char*)_config, _length); - myFile.close(); - } - - return true; -} - -void hwInit() -{ - timeval curTime; - - for (size_t i = 0; i < _length; i++) - _config[i] = 0xFF; - - if (!CheckConfigFile()) - { - exit(1); - } - - gettimeofday(&curTime, NULL); - millis_at_start = curTime.tv_sec; -} - -void hwReadConfigBlock(void* buf, void* addr, size_t length) -{ - unsigned long int offs = reinterpret_cast(addr); - - if (length && offs + length <= _length) { - memcpy(buf, _config+offs, length); - } -} - -void hwWriteConfigBlock(void* buf, void* addr, size_t length) -{ - unsigned long int offs = reinterpret_cast(addr); - - if (length && offs + length <= _length) { - memcpy(_config+offs, buf, length); - - ofstream myFile(CONFIG_FILE, ios::out | ios::binary); - if(!myFile) - { - debug("Unable to write config to file %s.\n", CONFIG_FILE); - return; - } - myFile.write((const char*)buf+offs, _length); - myFile.close(); - } -} - -uint8_t hwReadConfig(int adr) -{ - uint8_t value = 0xFF; - hwReadConfigBlock(&value, reinterpret_cast(adr), 1); - return value; -} - -void hwWriteConfig(int adr, uint8_t value) -{ - uint8_t curr = hwReadConfig(adr); - if (curr != value) - { - hwWriteConfigBlock(&value, reinterpret_cast(adr), 1); - } -} - -unsigned long hwMillis() -{ - timeval curTime; - - gettimeofday(&curTime, NULL); - return ((curTime.tv_sec - millis_at_start) * 1000) + (curTime.tv_usec / 1000); -} - -int8_t hwSleep(unsigned long ms) -{ - // TODO: Not supported! - return -2; -} - -int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) -{ - // TODO: Not supported! - return -2; -} - -int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) -{ - // TODO: Not supported! - return -2; -} - -#ifdef MY_DEBUG -void hwDebugPrint(const char *fmt, ... ) -{ - va_list arglist; - va_start(arglist, fmt); - vprintf(fmt, arglist); - va_end(arglist); -} -#endif diff --git a/libraries/MySensors/core/MyHwLinuxGeneric.h b/libraries/MySensors/core/MyHwLinuxGeneric.h deleted file mode 100644 index cec3b6cb4..000000000 --- a/libraries/MySensors/core/MyHwLinuxGeneric.h +++ /dev/null @@ -1,43 +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 - * Copyleft (c) 2016, Marcelo Aquino - * 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 MyHwLinuxGeneric_h -#define MyHwLinuxGeneric_h - -#include "MyHw.h" -#include -#include - -#define MY_SERIALDEVICE Serial - -// Define these as macros (do nothing) -#define hwDigitalWrite(__pin, __value) -#define hwWatchdogReset() -#define hwReboot() - -using namespace std; - -void hwInit(); -void hwReadConfigBlock(void* buf, void* adr, size_t length); -void hwWriteConfigBlock(void* buf, void* adr, size_t length); -void hwWriteConfig(int adr, uint8_t value); -uint8_t hwReadConfig(int adr); -unsigned long hwMillis(); - -#endif diff --git a/libraries/MySensors/core/MyMainLinux.cpp b/libraries/MySensors/core/MyMainLinux.cpp deleted file mode 100644 index 98982e536..000000000 --- a/libraries/MySensors/core/MyMainLinux.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// Initialize library and handle sketch functions like we want to - -#include "MySensorCore.h" - -int main(void) { - _begin(); // Startup MySensors library - - for(;;) { - _process(); // Process incoming data - if (loop) loop(); // Call sketch loop - } - return 0; -} diff --git a/libraries/MySensors/examples_RPi/PiGateway.cpp b/libraries/MySensors/examples_RPi/PiGateway.cpp deleted file mode 100644 index 28031d379..000000000 --- a/libraries/MySensors/examples_RPi/PiGateway.cpp +++ /dev/null @@ -1,68 +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 - * Copyleft (c) 2016, Marcelo Aquino - * 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 - -// Enable debug prints to serial monitor -#define MY_DEBUG - -// Enables and select radio type (if attached) -#define MY_RADIO_NRF24 - -#define MY_GATEWAY_RASPBERRYPI - -// Enable MY_IP_ADDRESS here if you want to listen for incoming network -// connections on the specified IP address/hostname only -//#define MY_IP_ADDRESS 192,168,178,87 - -// The port to keep open on node server mode -#define MY_PORT 5003 - -// How many clients should be able to connect to this gateway (default 1) -#define MY_GATEWAY_MAX_CLIENTS 2 - -/* MQTT BUILD */ -#ifdef MY_GATEWAY_MQTT_CLIENT -//Linux MQTT Defines - Uncomment and modify as needed. Written as defaults. -//#define MQTT_IP "127.0.0.1" -//#define MQTT_PORT 1883 -//#define MQTT_KEEPALIVE 60 -// Enable these if your MQTT broker requires usenrame/password -//#define MY_MQTT_USER "username" -//#define MY_MQTT_PASSWORD "password" -//#define MY_MQTT_PUBLISH_TOPIC_PREFIX "mygateway1-out" -//#define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX "mygateway1-in" -#endif - -#include - -using namespace std; - -void setup() { -} - -void presentation() { - // Present locally attached sensors here -} - -void loop() { - // Send locally attached sensors data here -} From 14e5c9bf4c50602bdeb1f76d7a398cd08f770b28 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Tue, 16 Aug 2016 15:37:51 -0300 Subject: [PATCH 061/167] Fix RX message buffering for Rpi --- configure | 2 +- drivers/RF24/RF24_RPi.cpp | 44 ++++++++++++++++++++++++++------------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/configure b/configure index d686549a7..7507807f9 100755 --- a/configure +++ b/configure @@ -269,7 +269,7 @@ for opt do CXXFLAGS="-DMY_MQTT_SUBSCRIBE_TOPIC_PREFIX=${optarg} $CXXFLAGS" ;; --my-rf24-irq-pin=*) - CXXFLAGS="-DMY_RF24_IRQ_PIN=${optarg} $CXXFLAGS" + CXXFLAGS="-DMY_RX_MESSAGE_BUFFER_FEATURE -DMY_RF24_IRQ_PIN=${optarg} $CXXFLAGS" ;; --my-rx-message-buffer-size=*) CXXFLAGS="-DMY_RX_MESSAGE_BUFFER_SIZE=${optarg} $CXXFLAGS" diff --git a/drivers/RF24/RF24_RPi.cpp b/drivers/RF24/RF24_RPi.cpp index 3b1a091dc..f130df0df 100644 --- a/drivers/RF24/RF24_RPi.cpp +++ b/drivers/RF24/RF24_RPi.cpp @@ -21,6 +21,20 @@ #include "RF24.h" +// verify RF24 IRQ defs +#if defined(MY_RX_MESSAGE_BUFFER_FEATURE) + #if !defined(MY_RF24_IRQ_PIN) + #error Message buffering feature requires MY_RF24_IRQ_PIN to be defined! + #endif + #ifndef SPI_HAS_TRANSACTION + #error RF24 IRQ usage requires transactional SPI support + #endif +#else + #ifdef MY_RX_MESSAGE_BUFFER_SIZE + #error Receive message buffering requires RF24 IRQ usage + #endif +#endif + // pipes #define BROADCAST_PIPE 1 #define NODE_PIPE 2 @@ -32,7 +46,7 @@ #define RF24_DEBUG(x,...) #endif -#ifdef MY_RF24_IRQ_PIN +#ifdef MY_RX_MESSAGE_BUFFER_FEATURE typedef void (*RF24_receiveCallbackType)(void); void (* RF24_receiveCallback)(void) = NULL; @@ -52,17 +66,17 @@ static void RF24_startListening(void) { } static void RF24_powerDown(void) { -#ifdef MY_RF24_IRQ_PIN +#ifdef MY_RX_MESSAGE_BUFFER_FEATURE pthread_mutex_lock(&rf24_mutex); #endif _rf24.powerDown(); -#ifdef MY_RF24_IRQ_PIN +#ifdef MY_RX_MESSAGE_BUFFER_FEATURE pthread_mutex_unlock(&rf24_mutex); #endif } static bool RF24_sendMessage( uint8_t recipient, const void* buf, uint8_t len ) { -#ifdef MY_RF24_IRQ_PIN +#ifdef MY_RX_MESSAGE_BUFFER_FEATURE pthread_mutex_lock(&rf24_mutex); #endif // Make sure radio has powered up @@ -75,38 +89,38 @@ static bool RF24_sendMessage( uint8_t recipient, const void* buf, uint8_t len ) _rf24.openWritingPipe(MY_RF24_BASE_ADDR); bool ok = _rf24.write(buf, len, recipient == BROADCAST_ADDRESS); _rf24.startListening(); -#ifdef MY_RF24_IRQ_PIN +#ifdef MY_RX_MESSAGE_BUFFER_FEATURE pthread_mutex_unlock(&rf24_mutex); #endif return ok; } static bool RF24_isDataAvailable() { -#ifdef MY_RF24_IRQ_PIN +#ifdef MY_RX_MESSAGE_BUFFER_FEATURE pthread_mutex_lock(&rf24_mutex); #endif uint8_t pipe_num = 255; _rf24.available(&pipe_num); -#ifdef MY_RF24_IRQ_PIN +#ifdef MY_RX_MESSAGE_BUFFER_FEATURE pthread_mutex_unlock(&rf24_mutex); #endif return (pipe_num <= 5); } static uint8_t RF24_readMessage( void* buf) { -#ifdef MY_RF24_IRQ_PIN +#ifdef MY_RX_MESSAGE_BUFFER_FEATURE pthread_mutex_lock(&rf24_mutex); #endif uint8_t len = _rf24.getDynamicPayloadSize(); _rf24.read(buf, len); -#ifdef MY_RF24_IRQ_PIN +#ifdef MY_RX_MESSAGE_BUFFER_FEATURE pthread_mutex_unlock(&rf24_mutex); #endif return len; } static void RF24_setNodeAddress(uint8_t address) { -#ifdef MY_RF24_IRQ_PIN +#ifdef MY_RX_MESSAGE_BUFFER_FEATURE pthread_mutex_lock(&rf24_mutex); #endif if (address != AUTO){ @@ -117,7 +131,7 @@ static void RF24_setNodeAddress(uint8_t address) { // enable autoACK on node pipe _rf24.setAutoAck(NODE_PIPE, true); } -#ifdef MY_RF24_IRQ_PIN +#ifdef MY_RX_MESSAGE_BUFFER_FEATURE pthread_mutex_unlock(&rf24_mutex); #endif } @@ -128,7 +142,7 @@ static uint8_t RF24_getNodeID(void) { bool RF24_sanityCheck(void) { bool ok = true; -#ifdef MY_RF24_IRQ_PIN +#ifdef MY_RX_MESSAGE_BUFFER_FEATURE pthread_mutex_lock(&rf24_mutex); #endif // detect HW defect ot interrupted SPI line, CE disconnect cannot be detected @@ -136,13 +150,13 @@ bool RF24_sanityCheck(void) { _rf24.getChannel() != MY_RF24_CHANNEL) { ok = false; } -#ifdef MY_RF24_IRQ_PIN +#ifdef MY_RX_MESSAGE_BUFFER_FEATURE pthread_mutex_unlock(&rf24_mutex); #endif return ok; } -#ifdef MY_RF24_IRQ_PIN +#ifdef MY_RX_MESSAGE_BUFFER_FEATURE void RF24_irqHandler(void) { if (RF24_receiveCallback) { while (RF24_isDataAvailable()) { @@ -199,7 +213,7 @@ static bool RF24_initialize(void) { //_rf24.printDetails(); - #ifdef MY_RF24_IRQ_PIN + #ifdef MY_RX_MESSAGE_BUFFER_FEATURE // Mask all interrupts except the receive interrupt _rf24.maskIRQ(1,1,0); From 4d431fbebb3ddd3da366982887696d4ecc6279f7 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Tue, 16 Aug 2016 15:51:43 -0300 Subject: [PATCH 062/167] Increase default number of connected client on Rpi --- examples_RPi/MySGateway.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples_RPi/MySGateway.cpp b/examples_RPi/MySGateway.cpp index dc61f853e..8a7e9dd83 100644 --- a/examples_RPi/MySGateway.cpp +++ b/examples_RPi/MySGateway.cpp @@ -39,7 +39,7 @@ #define MY_GATEWAY_RASPBERRYPI // How many clients should be able to connect to this gateway (default 1) -#define MY_GATEWAY_MAX_CLIENTS 2 +#define MY_GATEWAY_MAX_CLIENTS 10 #ifdef MY_GATEWAY_MQTT_CLIENT // Set MQTT client id From b8d4a6a94375a582365663690de98ca7627c1078 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Wed, 17 Aug 2016 23:42:27 -0300 Subject: [PATCH 063/167] Improve build process for Linux --- Makefile | 10 +- MyConfig.h | 16 +- MySensors.h | 12 +- configure | 65 ++-- core/MySensorsCore.cpp | 4 +- core/MyTransportNRF24.cpp | 4 +- drivers/Linux/Arduino.h | 1 + .../Linux/{utility.cpp => compatibility.cpp} | 10 + drivers/RF24/{RF24_RPi.cpp => RF24_Linux.cpp} | 32 +- drivers/RF24/RF24_Linux.h | 302 ++++++++++++++++++ examples_RPi/MySGateway.cpp | 91 ------ examples_linux/mysGateway.cpp | 55 ++++ initscripts/mysgateway.systemd | 2 +- initscripts/mysgateway.sysvinit | 4 +- 14 files changed, 438 insertions(+), 170 deletions(-) rename drivers/Linux/{utility.cpp => compatibility.cpp} (95%) rename drivers/RF24/{RF24_RPi.cpp => RF24_Linux.cpp} (87%) create mode 100644 drivers/RF24/RF24_Linux.h delete mode 100644 examples_RPi/MySGateway.cpp create mode 100644 examples_linux/mysGateway.cpp diff --git a/Makefile b/Makefile index b5ba3a8d8..05067d134 100644 --- a/Makefile +++ b/Makefile @@ -11,12 +11,16 @@ CONFIG_FILE=Makefile.inc include $(CONFIG_FILE) -GATEWAY=examples_RPi/MySGateway -GATEWAY_SOURCES=$(wildcard drivers/Linux/*.cpp) examples_RPi/MySGateway.cpp +GATEWAY=examples_linux/mysGateway +GATEWAY_SOURCES=$(wildcard drivers/Linux/*.cpp) examples_linux/mysGateway.cpp GATEWAY_OBJECTS=$(patsubst %.cpp,%.o,$(GATEWAY_SOURCES)) DEPS+=$(patsubst %.cpp,%.d,$(GATEWAY_SOURCES)) -CINCLUDE=-I. -I./core -I./drivers/Linux -I$(RF24H_LIB_DIR) +CINCLUDE=-I. -I./core -I./drivers/Linux + +ifneq ($(RF24H_LIB_DIR),) +CINCLUDE+=-I$(RF24H_LIB_DIR) +endif .PHONY: all gateway cleanconfig clean install uninstall force diff --git a/MyConfig.h b/MyConfig.h index 10444f871..3834b5f5a 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -410,17 +410,8 @@ #define MY_RF24_CE_PIN 4 #elif defined(ARDUINO_ARCH_SAMD) #define MY_RF24_CE_PIN 27 - #elif defined(RASPBERRYPI_ARCH) - #include - #include - #ifdef __RPI_BPLUS - #define MY_RF24_CE_PIN RPI_BPLUS_GPIO_J8_22 - #define MY_RF24_CS_PIN RPI_BPLUS_GPIO_J8_24 - #else - #define MY_RF24_CE_PIN RPI_V2_GPIO_P1_22 - #define MY_RF24_CS_PIN BCM2835_SPI_CS0 - #endif - #define MY_RF24_SPI_SPEED BCM2835_SPI_SPEED_8MHZ + #elif defined(LINUX) + #define MY_RF24_CE_PIN 22 #else #define MY_RF24_CE_PIN 9 #endif @@ -435,6 +426,8 @@ #define MY_RF24_CS_PIN 15 #elif defined(ARDUINO_ARCH_SAMD) #define MY_RF24_CS_PIN 3 + #elif defined(LINUX) + #define MY_RF24_CS_PIN 24 #else #define MY_RF24_CS_PIN 10 #endif @@ -616,7 +609,6 @@ //#define MY_GATEWAY_W5100 //#define MY_GATEWAY_ENC28J60 //#define MY_GATEWAY_ESP8266 -//#define MY_GATEWAY_RASPBERRYPI //#define MY_GATEWAY_LINUX /** diff --git a/MySensors.h b/MySensors.h index 81b514bfc..d4c7a5a52 100644 --- a/MySensors.h +++ b/MySensors.h @@ -40,7 +40,7 @@ * @def MY_NODE_TYPE * @brief Contain a string describing the class of sketch/node (gateway/repeater/sensor). */ -#if defined(MY_GATEWAY_SERIAL) || defined(MY_GATEWAY_W5100) || defined(MY_GATEWAY_ENC28J60) || defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_RASPBERRYPI) || defined(MY_GATEWAY_LINUX) || defined(MY_GATEWAY_MQTT_CLIENT) +#if defined(MY_GATEWAY_SERIAL) || defined(MY_GATEWAY_W5100) || defined(MY_GATEWAY_ENC28J60) || defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX) || defined(MY_GATEWAY_MQTT_CLIENT) #define MY_GATEWAY_FEATURE #define MY_IS_GATEWAY (true) #define MY_NODE_TYPE "GW" @@ -52,10 +52,6 @@ #define MY_NODE_TYPE "NODE" #endif -#if defined(MY_GATEWAY_RASPBERRYPI) - #define MY_GATEWAY_LINUX -#endif - // Enable radio "feature" if one of the radio types was enabled #if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) || defined(MY_RS485) #define MY_RADIO_FEATURE @@ -73,7 +69,7 @@ #include "core/MyHwATMega328.cpp" #elif defined(ARDUINO_ARCH_SAMD) #include "core/MyHwSAMD.cpp" -#elif defined(LINUX_ARCH_GENERIC) +#elif defined(LINUX) // Remove PSTR macros from debug prints #undef PSTR #define PSTR(x) (x) @@ -288,7 +284,7 @@ #if defined(MY_RF24_ENABLE_ENCRYPTION) #include "drivers/AES/AES.cpp" #endif - #if !defined(RASPBERRYPI_ARCH) + #if !defined(LINUX) #include "drivers/RF24/RF24.cpp" #endif #include "core/MyTransportNRF24.cpp" @@ -333,7 +329,7 @@ #if !defined(MY_CORE_ONLY) #if defined(ARDUINO_ARCH_ESP8266) #include "core/MyMainESP8266.cpp" - #elif defined(LINUX_ARCH_GENERIC) + #elif defined(LINUX) #include "core/MyMainLinux.cpp" #else #include "core/MyMainDefault.cpp" diff --git a/configure b/configure index 7507807f9..7ad56292a 100755 --- a/configure +++ b/configure @@ -32,11 +32,15 @@ Installation options: --gateway-dir= Gateway files installation directory. [PREFIX/bin] MySensors options: - --my-debug Enables debug. - --my-gateway-type=[ethernet|mqtt] - Gateway type, default to ethernet. + --my-debug=[enable|disable] + Enables or disables debugging. + Default to enable. + --my-gateway=[none|ethernet|mqtt] + Gateway type, set to none to disable gateway feature. + Default to ethernet. --my-config-file= Config file path. [/etc/MySensorGateway.cfg] - --my-rf24-enable Enables RF24 radio. + --my-radio=[none|nrf24] Radio type, set to none to disable radio feature. + Default to rf24. --my-rf24-channel=<0-125> RF channel for the sensor net, 0-125. --my-rf24-pa-level=[RF24_PA_MAX|RF24_PA_LOW] RF24 PA level. @@ -45,7 +49,8 @@ MySensors options: --my-controller-ip-address= Controller or MQTT broker ip. Use commas instead of points. Example: 127,0,0,1 - --my-port= Controller or MQTT broker port. + --my-port= The port to keep open on gateway mode. + If gateway is set to mqtt, it sets the broker port. --my-mqtt-client-id= MQTT client id. --my-mqtt-publish-topic-prefix= MQTT publish topic prefix. @@ -164,10 +169,10 @@ function gcc_cpu_flags { local soc=$1 case $soc in BCM2835) - flags="-march=armv6zk -mtune=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard -DRASPBERRYPI_ARCH" + flags="-march=armv6zk -mtune=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard -DLINUX_ARCH_RASPBERRYPI" ;; BCM2836) - flags="-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard -DRASPBERRYPI_ARCH" + flags="-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard -DLINUX_ARCH_RASPBERRYPI" ;; AM33XX) flags="-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard" @@ -190,7 +195,12 @@ function gcc_cpu_flags { echo ${flags} } -params="OS SOC CPUFLAGS CXXFLAGS LDFLAGS PREFIX CXX RF24H_LIB_DIR GATEWAY_DIR INIT_SYSTEM" +# Default values +debug=enable +gateway_type=ethernet +radio_type=nrf24 + +params="OS SOC CXXFLAGS LDFLAGS PREFIX CXX RF24H_LIB_DIR GATEWAY_DIR INIT_SYSTEM" for opt do if [ "$opt" = "-h" ] || [ "$opt" = "--help" ]; then @@ -229,20 +239,17 @@ for opt do --gateway-dir=*) GATEWAY_DIR="$optarg" ;; - --my-debug*) - CXXFLAGS="-DMY_DEBUG $CXXFLAGS" + --my-debug=*) + debug=${optarg} ;; - --my-gateway-type=*) - if [[ ${optarg} == "mqtt" ]]; then - LDFLAGS="-lmosquitto $LDFLAGS" - CXXFLAGS="-DMY_GATEWAY_MQTT_CLIENT $CXXFLAGS" - fi + --my-gateway=*) + gateway_type=${optarg} ;; --my-config-file=*) CXXFLAGS="-DMY_CONFIG_FILE=${optarg} $CXXFLAGS" ;; - --my-rf24-enable*) - CXXFLAGS="-DMY_RADIO_NRF24 $CXXFLAGS" + --my-radio=*) + radio_type=${optarg} ;; --my-rf24-channel=*) CXXFLAGS="-DMY_RF24_CHANNEL=${optarg} $CXXFLAGS" @@ -281,7 +288,6 @@ for opt do done PREFIX=${PREFIX:-/usr/local} -RF24H_LIB_DIR=${PREFIX}/include/RF24 GATEWAY_DIR=${GATEWAY_DIR:-${PREFIX}/bin} CXX=${CXX:-g++} @@ -299,13 +305,30 @@ if [ -z "${CPUFLAGS}" ]; then CPUFLAGS=$(gcc_cpu_flags $SOC) fi -CXXFLAGS="$CPUFLAGS -Ofast -g -Wall -Wextra -DLINUX_ARCH_GENERIC $CXXFLAGS" +CXXFLAGS="$CPUFLAGS -Ofast -g -Wall -Wextra -DLINUX $CXXFLAGS" if [[ $TYPE == "RPi2" || $TYPE == "RPi3" || $REV == "0010" ]]; then CXXFLAGS+="-D__RPI_BPLUS" -fi +fi + +if [[ ${debug} == "enable" ]]; then + CXXFLAGS="-DMY_DEBUG $CXXFLAGS" +fi + +if [[ ${gateway_type} == "ethernet" ]]; then + CXXFLAGS="-DMY_GATEWAY_LINUX $CXXFLAGS" +elif [[ ${gateway_type} == "mqtt" ]]; then + LDFLAGS="-lmosquitto $LDFLAGS" + CXXFLAGS="-DMY_GATEWAY_MQTT_CLIENT $CXXFLAGS" +fi + +if [[ ${radio_type} == "nrf24" ]]; then + CXXFLAGS="-DMY_RADIO_NRF24 $CXXFLAGS" + LDFLAGS="-lrf24-bcm $LDFLAGS" + RF24H_LIB_DIR=${PREFIX}/include/RF24 +fi -LDFLAGS="-pthread -lrf24-bcm $LDFLAGS" +LDFLAGS="-pthread $LDFLAGS" if [ -x /usr/bin/systemctl ] || [ -x /bin/systemctl ]; then INIT_SYSTEM=systemd diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index b142fe279..2d0a9db60 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -51,7 +51,7 @@ void _process() { transportProcess(); #endif - #if defined(LINUX_ARCH_GENERIC) + #if defined(LINUX) // To avoid high cpu usage usleep(10000); // 10ms #endif @@ -65,7 +65,7 @@ void _infiniteLoop() { #if defined (MY_LEDS_BLINKING_FEATURE) ledsProcess(); #endif - #if defined(LINUX_ARCH_GENERIC) + #if defined(LINUX) exit(1); #endif } diff --git a/core/MyTransportNRF24.cpp b/core/MyTransportNRF24.cpp index 6dce160e9..ce3900815 100644 --- a/core/MyTransportNRF24.cpp +++ b/core/MyTransportNRF24.cpp @@ -20,8 +20,8 @@ #include "MyConfig.h" #include "MyTransport.h" -#ifdef RASPBERRYPI_ARCH - #include "drivers/RF24/RF24_RPi.cpp" +#ifdef LINUX_ARCH_RASPBERRYPI + #include "drivers/RF24/RF24_Linux.cpp" #else #include "drivers/RF24/RF24.h" #endif diff --git a/drivers/Linux/Arduino.h b/drivers/Linux/Arduino.h index 39f0f6e22..e928b0463 100644 --- a/drivers/Linux/Arduino.h +++ b/drivers/Linux/Arduino.h @@ -51,6 +51,7 @@ char *ltoa(long value, char* result, int base); char *ultoa(long num, char *str, int radix); char *utoa(int num, char *str, int radix); char *dtostrf(float f, int width, int decimals, char *result); +void delay(unsigned int millis); #ifdef __cplusplus } diff --git a/drivers/Linux/utility.cpp b/drivers/Linux/compatibility.cpp similarity index 95% rename from drivers/Linux/utility.cpp rename to drivers/Linux/compatibility.cpp index aa3690576..5c1e5fe98 100644 --- a/drivers/Linux/utility.cpp +++ b/drivers/Linux/compatibility.cpp @@ -1,4 +1,5 @@ #include +#include #include "Arduino.h" /** @@ -175,3 +176,12 @@ char *dtostrf(float f, int width, int decimals, char *result) sprintf(result,"%*.*f", width, decimals, f); return result; } + +void delay(unsigned int millis) +{ + struct timespec sleeper; + + sleeper.tv_sec = (time_t)(millis / 1000); + sleeper.tv_nsec = (long)(millis % 1000) * 1000000; + nanosleep(&sleeper, NULL); +} diff --git a/drivers/RF24/RF24_RPi.cpp b/drivers/RF24/RF24_Linux.cpp similarity index 87% rename from drivers/RF24/RF24_RPi.cpp rename to drivers/RF24/RF24_Linux.cpp index f130df0df..9b4c25a8d 100644 --- a/drivers/RF24/RF24_RPi.cpp +++ b/drivers/RF24/RF24_Linux.cpp @@ -16,35 +16,11 @@ * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * - * Based on Olivier Mauti work(RF24.h), copyright (C) 2016 Olivier Mauti + * This is a wrapper for maniacbug's RF24 library, copyright (C) 2011 J. Coliz */ -#include "RF24.h" - -// verify RF24 IRQ defs -#if defined(MY_RX_MESSAGE_BUFFER_FEATURE) - #if !defined(MY_RF24_IRQ_PIN) - #error Message buffering feature requires MY_RF24_IRQ_PIN to be defined! - #endif - #ifndef SPI_HAS_TRANSACTION - #error RF24 IRQ usage requires transactional SPI support - #endif -#else - #ifdef MY_RX_MESSAGE_BUFFER_SIZE - #error Receive message buffering requires RF24 IRQ usage - #endif -#endif - -// pipes -#define BROADCAST_PIPE 1 -#define NODE_PIPE 2 - -// debug -#if defined(MY_DEBUG_VERBOSE_RF24) - #define RF24_DEBUG(x,...) debug(x, ##__VA_ARGS__) -#else - #define RF24_DEBUG(x,...) -#endif +#include +#include "RF24_Linux.h" #ifdef MY_RX_MESSAGE_BUFFER_FEATURE typedef void (*RF24_receiveCallbackType)(void); @@ -57,7 +33,7 @@ static uint8_t MY_RF24_BASE_ADDR[MY_RF24_ADDR_WIDTH] = { MY_RF24_BASE_RADIO_ID }; static uint8_t MY_RF24_NODE_ADDRESS = AUTO; -RF24 _rf24(MY_RF24_CE_PIN, MY_RF24_CS_PIN); +RF24 _rf24(RF24_CE_PIN, RF24_CS_PIN, MY_RF24_SPI_MAX_SPEED); static void RF24_startListening(void) { RF24_DEBUG(PSTR("start listening\n")); diff --git a/drivers/RF24/RF24_Linux.h b/drivers/RF24/RF24_Linux.h new file mode 100644 index 000000000..d1e00ac91 --- /dev/null +++ b/drivers/RF24/RF24_Linux.h @@ -0,0 +1,302 @@ +/** + * 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. + * + */ + +#ifndef __RF24_LINUX_H__ +#define __RF24_LINUX_H__ + +// SPI settings +#if !defined(MY_RF24_SPI_MAX_SPEED) + #define MY_RF24_SPI_MAX_SPEED BCM2835_SPI_SPEED_8MHZ +#endif + +// verify RF24 IRQ defs +#if defined(MY_RX_MESSAGE_BUFFER_FEATURE) + #if !defined(MY_RF24_IRQ_PIN) + #error Message buffering feature requires MY_RF24_IRQ_PIN to be defined! + #endif + #ifndef SPI_HAS_TRANSACTION + #error RF24 IRQ usage requires transactional SPI support + #endif +#else + #ifdef MY_RX_MESSAGE_BUFFER_SIZE + #error Receive message buffering requires RF24 IRQ usage + #endif +#endif + +// pipes +#define BROADCAST_PIPE 1 +#define NODE_PIPE 2 + +// debug +#if defined(MY_DEBUG_VERBOSE_RF24) + #define RF24_DEBUG(x,...) debug(x, ##__VA_ARGS__) +#else + #define RF24_DEBUG(x,...) +#endif + +#ifdef LINUX_ARCH_RASPBERRYPI + // CE pin + #ifdef MY_RF24_CE_PIN + #ifdef __RPI_BPLUS + #if MY_RF24_CE_PIN == 3 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_03 + #elif MY_RF24_CE_PIN == 5 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_05 + #elif MY_RF24_CE_PIN == 7 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_07 + #elif MY_RF24_CE_PIN == 8 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_08 + #elif MY_RF24_CE_PIN == 10 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_10 + #elif MY_RF24_CE_PIN == 11 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_11 + #elif MY_RF24_CE_PIN == 12 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_12 + #elif MY_RF24_CE_PIN == 13 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_13 + #elif MY_RF24_CE_PIN == 15 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_15 + #elif MY_RF24_CE_PIN == 16 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_16 + #elif MY_RF24_CE_PIN == 18 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_18 + #elif MY_RF24_CE_PIN == 19 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_19 + #elif MY_RF24_CE_PIN == 21 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_21 + #elif MY_RF24_CE_PIN == 22 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_22 + #elif MY_RF24_CE_PIN == 23 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_23 + #elif MY_RF24_CE_PIN == 24 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_24 + #elif MY_RF24_CE_PIN == 26 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_26 + #elif MY_RF24_CE_PIN == 29 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_29 + #elif MY_RF24_CE_PIN == 31 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_31 + #elif MY_RF24_CE_PIN == 32 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_32 + #elif MY_RF24_CE_PIN == 33 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_33 + #elif MY_RF24_CE_PIN == 35 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_35 + #elif MY_RF24_CE_PIN == 36 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_36 + #elif MY_RF24_CE_PIN == 37 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_37 + #elif MY_RF24_CE_PIN == 38 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_38 + #elif MY_RF24_CE_PIN == 40 + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_40 + #else + #error invalid value for MY_RF24_CE_PIN + #endif + #else + #if MY_RF24_CE_PIN == 3 + #define RF24_CE_PIN RPI_V2_GPIO_P1_03 + #elif MY_RF24_CE_PIN == 5 + #define RF24_CE_PIN RPI_V2_GPIO_P1_05 + #elif MY_RF24_CE_PIN == 7 + #define RF24_CE_PIN RPI_V2_GPIO_P1_07 + #elif MY_RF24_CE_PIN == 8 + #define RF24_CE_PIN RPI_V2_GPIO_P1_08 + #elif MY_RF24_CE_PIN == 10 + #define RF24_CE_PIN RPI_V2_GPIO_P1_10 + #elif MY_RF24_CE_PIN == 11 + #define RF24_CE_PIN RPI_V2_GPIO_P1_11 + #elif MY_RF24_CE_PIN == 12 + #define RF24_CE_PIN RPI_V2_GPIO_P1_12 + #elif MY_RF24_CE_PIN == 13 + #define RF24_CE_PIN RPI_V2_GPIO_P1_13 + #elif MY_RF24_CE_PIN == 15 + #define RF24_CE_PIN RPI_V2_GPIO_P1_15 + #elif MY_RF24_CE_PIN == 16 + #define RF24_CE_PIN RPI_V2_GPIO_P1_16 + #elif MY_RF24_CE_PIN == 18 + #define RF24_CE_PIN RPI_V2_GPIO_P1_18 + #elif MY_RF24_CE_PIN == 19 + #define RF24_CE_PIN RPI_V2_GPIO_P1_19 + #elif MY_RF24_CE_PIN == 21 + #define RF24_CE_PIN RPI_V2_GPIO_P1_21 + #elif MY_RF24_CE_PIN == 22 + #define RF24_CE_PIN RPI_V2_GPIO_P1_22 + #elif MY_RF24_CE_PIN == 23 + #define RF24_CE_PIN RPI_V2_GPIO_P1_23 + #elif MY_RF24_CE_PIN == 24 + #define RF24_CE_PIN RPI_V2_GPIO_P1_24 + #elif MY_RF24_CE_PIN == 26 + #define RF24_CE_PIN RPI_V2_GPIO_P1_26 + #elif MY_RF24_CE_PIN == 29 + #define RF24_CE_PIN RPI_V2_GPIO_P1_29 + #elif MY_RF24_CE_PIN == 31 + #define RF24_CE_PIN RPI_V2_GPIO_P1_31 + #elif MY_RF24_CE_PIN == 32 + #define RF24_CE_PIN RPI_V2_GPIO_P1_32 + #elif MY_RF24_CE_PIN == 33 + #define RF24_CE_PIN RPI_V2_GPIO_P1_33 + #elif MY_RF24_CE_PIN == 35 + #define RF24_CE_PIN RPI_V2_GPIO_P1_35 + #elif MY_RF24_CE_PIN == 36 + #define RF24_CE_PIN RPI_V2_GPIO_P1_36 + #elif MY_RF24_CE_PIN == 37 + #define RF24_CE_PIN RPI_V2_GPIO_P1_37 + #elif MY_RF24_CE_PIN == 38 + #define RF24_CE_PIN RPI_V2_GPIO_P1_38 + #elif MY_RF24_CE_PIN == 40 + #define RF24_CE_PIN RPI_V2_GPIO_P1_40 + #else + #error invalid value for MY_RF24_CE_PIN + #endif + #endif + #else + #ifdef __RPI_BPLUS + #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_22 + #else + #define RF24_CE_PIN RPI_V2_GPIO_P1_22 + #endif + #endif + + // CS pin + #ifdef MY_RF24_CS_PIN + #ifdef __RPI_BPLUS + #if MY_RF24_CS_PIN == 3 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_03 + #elif MY_RF24_CS_PIN == 5 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_05 + #elif MY_RF24_CS_PIN == 7 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_07 + #elif MY_RF24_CS_PIN == 8 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_08 + #elif MY_RF24_CS_PIN == 10 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_10 + #elif MY_RF24_CS_PIN == 11 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_11 + #elif MY_RF24_CS_PIN == 12 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_12 + #elif MY_RF24_CS_PIN == 13 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_13 + #elif MY_RF24_CS_PIN == 15 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_15 + #elif MY_RF24_CS_PIN == 16 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_16 + #elif MY_RF24_CS_PIN == 18 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_18 + #elif MY_RF24_CS_PIN == 19 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_19 + #elif MY_RF24_CS_PIN == 21 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_21 + #elif MY_RF24_CS_PIN == 22 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_22 + #elif MY_RF24_CS_PIN == 23 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_23 + #elif MY_RF24_CS_PIN == 24 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_24 + #elif MY_RF24_CS_PIN == 26 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_26 + #elif MY_RF24_CS_PIN == 29 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_29 + #elif MY_RF24_CS_PIN == 31 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_31 + #elif MY_RF24_CS_PIN == 32 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_32 + #elif MY_RF24_CS_PIN == 33 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_33 + #elif MY_RF24_CS_PIN == 35 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_35 + #elif MY_RF24_CS_PIN == 36 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_36 + #elif MY_RF24_CS_PIN == 37 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_37 + #elif MY_RF24_CS_PIN == 38 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_38 + #elif MY_RF24_CS_PIN == 40 + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_40 + #else + #error invalid value for MY_RF24_CS_PIN + #endif + #else + #if MY_RF24_CS_PIN == 3 + #define RF24_CS_PIN RPI_V2_GPIO_P1_03 + #elif MY_RF24_CS_PIN == 5 + #define RF24_CS_PIN RPI_V2_GPIO_P1_05 + #elif MY_RF24_CS_PIN == 7 + #define RF24_CS_PIN RPI_V2_GPIO_P1_07 + #elif MY_RF24_CS_PIN == 8 + #define RF24_CS_PIN RPI_V2_GPIO_P1_08 + #elif MY_RF24_CS_PIN == 10 + #define RF24_CS_PIN RPI_V2_GPIO_P1_10 + #elif MY_RF24_CS_PIN == 11 + #define RF24_CS_PIN RPI_V2_GPIO_P1_11 + #elif MY_RF24_CS_PIN == 12 + #define RF24_CS_PIN RPI_V2_GPIO_P1_12 + #elif MY_RF24_CS_PIN == 13 + #define RF24_CS_PIN RPI_V2_GPIO_P1_13 + #elif MY_RF24_CS_PIN == 15 + #define RF24_CS_PIN RPI_V2_GPIO_P1_15 + #elif MY_RF24_CS_PIN == 16 + #define RF24_CS_PIN RPI_V2_GPIO_P1_16 + #elif MY_RF24_CS_PIN == 18 + #define RF24_CS_PIN RPI_V2_GPIO_P1_18 + #elif MY_RF24_CS_PIN == 19 + #define RF24_CS_PIN RPI_V2_GPIO_P1_19 + #elif MY_RF24_CS_PIN == 21 + #define RF24_CS_PIN RPI_V2_GPIO_P1_21 + #elif MY_RF24_CS_PIN == 22 + #define RF24_CS_PIN RPI_V2_GPIO_P1_22 + #elif MY_RF24_CS_PIN == 23 + #define RF24_CS_PIN RPI_V2_GPIO_P1_23 + #elif MY_RF24_CS_PIN == 24 + #define RF24_CS_PIN BCM2835_SPI_CS0 + #elif MY_RF24_CS_PIN == 26 + #define RF24_CS_PIN BCM2835_SPI_CS1 + #elif MY_RF24_CS_PIN == 29 + #define RF24_CS_PIN RPI_V2_GPIO_P1_29 + #elif MY_RF24_CS_PIN == 31 + #define RF24_CS_PIN RPI_V2_GPIO_P1_31 + #elif MY_RF24_CS_PIN == 32 + #define RF24_CS_PIN RPI_V2_GPIO_P1_32 + #elif MY_RF24_CS_PIN == 33 + #define RF24_CS_PIN RPI_V2_GPIO_P1_33 + #elif MY_RF24_CS_PIN == 35 + #define RF24_CS_PIN RPI_V2_GPIO_P1_35 + #elif MY_RF24_CS_PIN == 36 + #define RF24_CS_PIN RPI_V2_GPIO_P1_36 + #elif MY_RF24_CS_PIN == 37 + #define RF24_CS_PIN RPI_V2_GPIO_P1_37 + #elif MY_RF24_CS_PIN == 38 + #define RF24_CS_PIN RPI_V2_GPIO_P1_38 + #elif MY_RF24_CS_PIN == 40 + #define RF24_CS_PIN RPI_V2_GPIO_P1_40 + #else + #error invalid value for MY_RF24_CS_PIN + #endif + #endif + #else + #ifdef __RPI_BPLUS + #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_24 + #else + #define RF24_CS_PIN BCM2835_SPI_CS0 + #endif + #endif +#endif + +#endif diff --git a/examples_RPi/MySGateway.cpp b/examples_RPi/MySGateway.cpp deleted file mode 100644 index 8a7e9dd83..000000000 --- a/examples_RPi/MySGateway.cpp +++ /dev/null @@ -1,91 +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 - * Copyleft (c) 2016, Marcelo Aquino - * 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 - -// Enable debug prints to monitor -#ifndef MY_DEBUG - #define MY_DEBUG -#endif - -// Config file -#ifndef MY_LINUX_CONFIG_FILE - #define MY_LINUX_CONFIG_FILE "/etc/MySensorGateway.cfg" -#endif - -// Enables and select radio type (if attached) -#ifndef MY_RADIO_NRF24 - #define MY_RADIO_NRF24 -#endif - -#define MY_GATEWAY_RASPBERRYPI - -// How many clients should be able to connect to this gateway (default 1) -#define MY_GATEWAY_MAX_CLIENTS 10 - -#ifdef MY_GATEWAY_MQTT_CLIENT - // Set MQTT client id - #ifndef MY_MQTT_CLIENT_ID - #define MY_MQTT_CLIENT_ID "mysensors-1" - #endif - // MQTT broker ip address. - #ifndef MY_CONTROLLER_IP_ADDRESS - #define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 68 - #endif - // The MQTT broker port to to open - #ifndef MY_PORT - #define MY_PORT 1883 - #endif - - // Enable these if your MQTT broker requires usenrame/password - //#define MY_MQTT_USER "username" - //#define MY_MQTT_PASSWORD "password" - - // Set this node's subscribe and publish topic prefix - #ifndef MY_MQTT_PUBLISH_TOPIC_PREFIX - #define MY_MQTT_PUBLISH_TOPIC_PREFIX "mygateway1-out" - #endif - #ifndef MY_MQTT_SUBSCRIBE_TOPIC_PREFIX - #define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX "mygateway1-in" - #endif -#else - // Enable MY_IP_ADDRESS here if you want to listen for incoming network - // connections on the specified IP address/hostname only - //#define MY_IP_ADDRESS 192,168,178,87 - - // The port to keep open on node server mode - #ifndef MY_PORT - #define MY_PORT 5003 - #endif -#endif - -#include - -void setup() { -} - -void presentation() { - // Present locally attached sensors here -} - -void loop() { - // Send locally attached sensors data here -} diff --git a/examples_linux/mysGateway.cpp b/examples_linux/mysGateway.cpp new file mode 100644 index 000000000..b53ffccb5 --- /dev/null +++ b/examples_linux/mysGateway.cpp @@ -0,0 +1,55 @@ +/** + * 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 + * Copyleft (c) 2016, Marcelo Aquino + * 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 + +// For more options run ./configure --help + +// Config file +//#define MY_LINUX_CONFIG_FILE "/etc/MySensorGateway.cfg" + +// How many clients should be able to connect to this gateway (default 1) +#define MY_GATEWAY_MAX_CLIENTS 10 + +// MQTT options +//#define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 68 +//#define MY_PORT 1883 +//#define MY_MQTT_CLIENT_ID "mysensors-1" +//#define MY_MQTT_PUBLISH_TOPIC_PREFIX "mygateway1-out" +//#define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX "mygateway1-in" + +// Enable these if your MQTT broker requires usenrame/password +//#define MY_MQTT_USER "username" +//#define MY_MQTT_PASSWORD "password" + + +#include + +void setup() { +} + +void presentation() { + // Present locally attached sensors here +} + +void loop() { + // Send locally attached sensors data here +} diff --git a/initscripts/mysgateway.systemd b/initscripts/mysgateway.systemd index 9763c6677..5b707c6dd 100644 --- a/initscripts/mysgateway.systemd +++ b/initscripts/mysgateway.systemd @@ -3,7 +3,7 @@ Description=MySensors Gateway daemon Requires=network.target [Service] -ExecStart=%gateway_dir%/MySGateway +ExecStart=%gateway_dir%/mysGateway [Install] WantedBy=multi-user.target diff --git a/initscripts/mysgateway.sysvinit b/initscripts/mysgateway.sysvinit index df01c6cd9..34ee0c490 100644 --- a/initscripts/mysgateway.sysvinit +++ b/initscripts/mysgateway.sysvinit @@ -1,6 +1,6 @@ #! /bin/sh ### BEGIN INIT INFO -# Provides: MySGateway +# Provides: mysGateway # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 @@ -20,7 +20,7 @@ # PATH should only include /usr/* if it runs after the mountnfs.sh script PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin DESC="MySensors Gateway" -NAME=MySGateway +NAME=mysGateway DAEMON=%gateway_dir%/$NAME DAEMON_ARGS="-d" PIDFILE=/var/run/$NAME.pid From cb8c98431eaed08822452efb318a50276ee49f6f Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Fri, 19 Aug 2016 13:45:51 -0300 Subject: [PATCH 064/167] Fix compilation errors for MQTT gateway --- MyConfig.h | 16 ++++------ configure | 8 ++--- core/MyHwLinuxGeneric.cpp | 56 ++++++++++----------------------- core/MyHwLinuxGeneric.h | 18 +++++------ drivers/Linux/Arduino.h | 1 + drivers/Linux/compatibility.cpp | 17 ++++++++++ 6 files changed, 53 insertions(+), 63 deletions(-) diff --git a/MyConfig.h b/MyConfig.h index 3834b5f5a..84a5b1cbd 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -616,7 +616,11 @@ * @brief The Ethernet TCP/UDP port to open on controller or gateway. */ #ifndef MY_PORT -#define MY_PORT 5003 + #ifdef MY_GATEWAY_MQTT_CLIENT + #define MY_PORT 1883 + #else + #define MY_PORT 5003 + #endif #endif // Static ip address of gateway (if this is disabled, DHCP will be used) @@ -718,15 +722,7 @@ * @brief Set the name of predictable tty */ #ifndef MY_LINUX_TTY_NAME -#define MY_LINUX_TTY_NAME "/dev/ttyMySensorsGateway" -#endif - -/** - * @def MY_LINUX_TTY_GROUPNAME - * @brief Set the group name for the raw tty - */ -#ifndef MY_LINUX_TTY_GROUPNAME -#define MY_LINUX_TTY_GROUPNAME tty +#define MY_LINUX_TTY_NAME "/dev/ttyAMA0" #endif /** diff --git a/configure b/configure index 7ad56292a..dc3012cbb 100755 --- a/configure +++ b/configure @@ -267,13 +267,13 @@ for opt do CXXFLAGS="-DMY_PORT=${optarg} $CXXFLAGS" ;; --my-mqtt-client-id=*) - CXXFLAGS="-DMY_MQTT_CLIENT_ID=${optarg} $CXXFLAGS" + CXXFLAGS="-DMY_MQTT_CLIENT_ID=\\\"${optarg}\\\" $CXXFLAGS" ;; --my-mqtt-publish-topic-prefix=*) - CXXFLAGS="-DMY_MQTT_PUBLISH_TOPIC_PREFIX=${optarg} $CXXFLAGS" + CXXFLAGS="-DMY_MQTT_PUBLISH_TOPIC_PREFIX=\\\"${optarg}\\\" $CXXFLAGS" ;; --my-mqtt-subscribe-topic-prefix=*) - CXXFLAGS="-DMY_MQTT_SUBSCRIBE_TOPIC_PREFIX=${optarg} $CXXFLAGS" + CXXFLAGS="-DMY_MQTT_SUBSCRIBE_TOPIC_PREFIX=\\\"${optarg}\\\" $CXXFLAGS" ;; --my-rf24-irq-pin=*) CXXFLAGS="-DMY_RX_MESSAGE_BUFFER_FEATURE -DMY_RF24_IRQ_PIN=${optarg} $CXXFLAGS" @@ -319,7 +319,7 @@ if [[ ${gateway_type} == "ethernet" ]]; then CXXFLAGS="-DMY_GATEWAY_LINUX $CXXFLAGS" elif [[ ${gateway_type} == "mqtt" ]]; then LDFLAGS="-lmosquitto $LDFLAGS" - CXXFLAGS="-DMY_GATEWAY_MQTT_CLIENT $CXXFLAGS" + CXXFLAGS="-DMY_GATEWAY_LINUX -DMY_GATEWAY_MQTT_CLIENT $CXXFLAGS" fi if [[ ${radio_type} == "nrf24" ]]; then diff --git a/core/MyHwLinuxGeneric.cpp b/core/MyHwLinuxGeneric.cpp index e288bd664..ee7473169 100644 --- a/core/MyHwLinuxGeneric.cpp +++ b/core/MyHwLinuxGeneric.cpp @@ -19,7 +19,6 @@ #include "MyHwLinuxGeneric.h" -#include #include #include #include @@ -28,60 +27,47 @@ static const char* CONFIG_FILE = MY_LINUX_CONFIG_FILE; static const size_t _length = 1024; // ATMega328 has 1024 bytes -static uint8_t _config[_length]; -static unsigned long millis_at_start; +static uint8_t _config[_length]; bool CheckConfigFile() { struct stat fileInfo; - - if(stat(CONFIG_FILE, &fileInfo) != 0) - { + + if (stat(CONFIG_FILE, &fileInfo) != 0) { //File does not exist. Create it. debug("Config file %s does not exist, creating new config file.\n", CONFIG_FILE); ofstream myFile(CONFIG_FILE, ios::out | ios::binary); - if(!myFile) - { + if (!myFile) { debug("Unable to create config file %s.\n", CONFIG_FILE); return false; } myFile.write((const char*)_config, _length); myFile.close(); - } - else if(fileInfo.st_size < 0 || (size_t)fileInfo.st_size != _length) - { + } else if (fileInfo.st_size < 0 || (size_t)fileInfo.st_size != _length) { debug("Config file %s is not the correct size of %i. Please remove the file and a new one will be created.\n", CONFIG_FILE, _length); return false; - } - else - { + } else { //Read config into local memory. ifstream myFile(CONFIG_FILE, ios::in | ios::binary); - if(!myFile) - { + if (!myFile) { debug("Unable to open config to file %s for reading.\n", CONFIG_FILE); return false; } myFile.read((char*)_config, _length); myFile.close(); } - + return true; } void hwInit() { - timeval curTime; - - for (size_t i = 0; i < _length; i++) + for (size_t i = 0; i < _length; i++) { _config[i] = 0xFF; + } - if (!CheckConfigFile()) - { + if (!CheckConfigFile()) { exit(1); } - - gettimeofday(&curTime, NULL); - millis_at_start = curTime.tv_sec; } void hwReadConfigBlock(void* buf, void* addr, size_t length) @@ -101,8 +87,7 @@ void hwWriteConfigBlock(void* buf, void* addr, size_t length) memcpy(_config+offs, buf, length); ofstream myFile(CONFIG_FILE, ios::out | ios::binary); - if(!myFile) - { + if (!myFile) { debug("Unable to write config to file %s.\n", CONFIG_FILE); return; } @@ -121,21 +106,12 @@ uint8_t hwReadConfig(int adr) void hwWriteConfig(int adr, uint8_t value) { uint8_t curr = hwReadConfig(adr); - if (curr != value) - { + if (curr != value) { hwWriteConfigBlock(&value, reinterpret_cast(adr), 1); } } -unsigned long hwMillis() -{ - timeval curTime; - - gettimeofday(&curTime, NULL); - return ((curTime.tv_sec - millis_at_start) * 1000) + (curTime.tv_usec / 1000); -} - -// TODO: Not supported! +// Not supported! int8_t hwSleep(unsigned long ms) { (void)ms; @@ -143,7 +119,7 @@ int8_t hwSleep(unsigned long ms) return -2; } -// TODO: Not supported! +// Not supported! int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { (void)interrupt; @@ -153,7 +129,7 @@ int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) return -2; } -// TODO: Not supported! +// Not supported! int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { (void)interrupt1; diff --git a/core/MyHwLinuxGeneric.h b/core/MyHwLinuxGeneric.h index c44d9123d..1d763ce9b 100644 --- a/core/MyHwLinuxGeneric.h +++ b/core/MyHwLinuxGeneric.h @@ -30,25 +30,25 @@ #define hwDigitalWrite(__pin, __value) #define hwWatchdogReset() #define hwReboot() +#define hwMillis() millis() void hwInit(); void hwReadConfigBlock(void* buf, void* adr, size_t length); void hwWriteConfigBlock(void* buf, void* adr, size_t length); void hwWriteConfig(int adr, uint8_t value); uint8_t hwReadConfig(int adr); -unsigned long hwMillis(); #ifdef MY_RF24_IRQ_PIN -static pthread_mutex_t hw_mutex = PTHREAD_MUTEX_INITIALIZER; + static pthread_mutex_t hw_mutex = PTHREAD_MUTEX_INITIALIZER; -static __inline__ void __hwUnlock(const uint8_t *__s) { - pthread_mutex_unlock(&hw_mutex); - (void)__s; -} + static __inline__ void __hwUnlock(const uint8_t *__s) { + pthread_mutex_unlock(&hw_mutex); + (void)__s; + } -static __inline__ void __hwLock() { - pthread_mutex_lock(&hw_mutex); -} + static __inline__ void __hwLock() { + pthread_mutex_lock(&hw_mutex); + } #endif #if defined(DOXYGEN) diff --git a/drivers/Linux/Arduino.h b/drivers/Linux/Arduino.h index e928b0463..08e9701b8 100644 --- a/drivers/Linux/Arduino.h +++ b/drivers/Linux/Arduino.h @@ -51,6 +51,7 @@ char *ltoa(long value, char* result, int base); char *ultoa(long num, char *str, int radix); char *utoa(int num, char *str, int radix); char *dtostrf(float f, int width, int decimals, char *result); +unsigned long millis(void); void delay(unsigned int millis); #ifdef __cplusplus diff --git a/drivers/Linux/compatibility.cpp b/drivers/Linux/compatibility.cpp index 5c1e5fe98..ff76cc584 100644 --- a/drivers/Linux/compatibility.cpp +++ b/drivers/Linux/compatibility.cpp @@ -1,7 +1,11 @@ #include #include +#include #include "Arduino.h" +// For millis() +static unsigned long millis_at_start = 0; + /** * C++ version 0.4 char* style "itoa": * Written by Lukás Chmela @@ -177,6 +181,19 @@ char *dtostrf(float f, int width, int decimals, char *result) return result; } +unsigned long millis(void) +{ + timeval curTime; + + if (millis_at_start == 0) { + gettimeofday(&curTime, NULL); + millis_at_start = curTime.tv_sec; + } + + gettimeofday(&curTime, NULL); + return ((curTime.tv_sec - millis_at_start) * 1000) + (curTime.tv_usec / 1000); +} + void delay(unsigned int millis) { struct timespec sleeper; From 15b46f8023a272d6bc1c86327c44134059512772 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Fri, 19 Aug 2016 23:30:03 +0200 Subject: [PATCH 065/167] Fixes LED issues as discussed in #562 Removing MY_LED_BLINKING_FEATURE, as we now are using MY_DEFAULT_LED_xx_PIN defines to enable LED blinking feature. updated Gateway sketches to not refer to MY_LED_BLINKING_FEATURE any more fixes #562 --- MyConfig.h | 27 +++++----- MySensors.h | 48 ++--------------- core/MyIndication.cpp | 14 +++-- core/MyLeds.cpp | 14 ++++- core/MyLeds.h | 2 +- core/MySensorsCore.cpp | 6 +-- examples/GatewayESP8266/GatewayESP8266.ino | 48 ++++++++--------- .../GatewayESP8266MQTTClient.ino | 46 ++++++++-------- .../GatewayESP8266OTA/GatewayESP8266OTA.ino | 49 ++++++++--------- examples/GatewaySerial/GatewaySerial.ino | 48 ++++++++--------- .../GatewaySerialRS485/GatewaySerialRS485.ino | 46 +++++++--------- examples/GatewayW5100/GatewayW5100.ino | 40 +++++++------- .../GatewayW5100MQTTClient.ino | 52 +++++++++---------- .../SensebenderGatewaySerial.ino | 49 +++++++++-------- keywords.txt | 3 +- 15 files changed, 216 insertions(+), 276 deletions(-) diff --git a/MyConfig.h b/MyConfig.h index 9582a1da4..845d5947b 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -223,25 +223,22 @@ /********************************** * Information LEDs blinking ***********************************/ -// This feature enables LEDs blinking on message receive, transmit -// or if some error occurred. This was commonly used only in gateways, -// but now can be used in any sensor node. Also the LEDs can now be -// disabled in the gateway. - -//#define MY_LEDS_BLINKING_FEATURE +// If one of the following is defined here, or in the sketch, the pin will be used for the +// corresponding led function. +// They have to be enabled here (or in your sketch). Replace x with the pin number you have the LED on. +// +// NOTE!! that on some platforms (for example sensebender GW) the hardware variant can enable LEDs by default, +// These defaults can be overridden by defining one of these. +//#define MY_DEFAULT_ERR_LED_PIN x +//#define MY_DEFAULT_TX_LED_PIN x +//#define MY_DEFAULT_RX_LED_PIN x -// The following setting allows you to inverse the blinking feature MY_LEDS_BLINKING_FEATURE +// The following setting allows you to inverse the LED blinking // When MY_WITH_LEDS_BLINKING_INVERSE is enabled LEDSs are normally turned on and switches // off when blinking //#define MY_WITH_LEDS_BLINKING_INVERSE -// The following defines can be used to set the port pin, that the LED is connected to -// If one of the following is defined here, or in the sketch, MY_LEDS_BLINKING_FEATURE will be -// enabled by default. (Replace x with the pin number you have the LED on) -//#define MY_DEFAULT_ERR_LED_PIN x -//#define MY_DEFAULT_TX_LED_PIN x -//#define MY_DEFAULT_RX_LED_PIN x /********************************************** * Gateway inclusion button/mode configuration @@ -431,7 +428,7 @@ /** * @def MY_RX_MESSAGE_BUFFER_FEATURE -* @brief This enabled the receiving buffer feature. +* @brief This enabled the receiving buffer feature. * * This feature is currently not supported for RFM69 and RS485, for RF24 MY_RF24_IRQ_PIN has to be defined. */ @@ -439,7 +436,7 @@ /** * @def MY_RX_MESSAGE_BUFFER_SIZE - * @brief Declare the amount of incoming messages that can be buffered. + * @brief Declare the amount of incoming messages that can be buffered. */ #ifdef MY_RX_MESSAGE_BUFFER_FEATURE #ifndef MY_RX_MESSAGE_BUFFER_SIZE diff --git a/MySensors.h b/MySensors.h index 70bc9361c..c0fd42a17 100644 --- a/MySensors.h +++ b/MySensors.h @@ -84,17 +84,10 @@ #define MY_DEFAULT_RX_LED_PIN MY_HW_TX_LED_PIN #endif -// Not necessary to include blinking feature if no LED's are defined! -#if defined(MY_LEDS_BLINKING_FEATURE) && !defined(MY_DEFAULT_RX_LED_PIN) && !defined(MY_DEFAULT_TX_LED_PIN) && !defined(MY_ERR_LED_PIN) - #undef MY_LEDS_BLINKING_FEATURE -#endif - -// Enable LED BLINKING FEATURE, if there are any LEDs defined. -#if defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED) || defined(MY_DEFAULT_TX_LED_PIN) - #define MY_LEDS_BLINKING_FEATURE +#if defined(MY_LEDS_BLINKING_FEATURE) +#warning MY_LEDS_BLINKING_FEATURE is not working, define MY_DEFAULT_ERR_LED_PIN, MY_DEFAULT_TX_LED_PIN or MY_DEFAULT_RX_LED_PIN in your sketch #endif - /** * @def MY_DEFAULT_LED_BLINK_PERIOD * @brief Default LEDs blinking period in milliseconds. @@ -102,41 +95,8 @@ #ifndef MY_DEFAULT_LED_BLINK_PERIOD #define MY_DEFAULT_LED_BLINK_PERIOD 300 #endif -/** - * @def MY_DEFAULT_RX_LED_PIN - * @brief The RX LED default pin. - */ -#ifndef MY_DEFAULT_RX_LED_PIN - #if defined(ARDUINO_ARCH_ESP8266) - #define MY_DEFAULT_RX_LED_PIN 8 - #else - #define MY_DEFAULT_RX_LED_PIN 6 - #endif -#endif -/** - * @def MY_DEFAULT_TX_LED_PIN - * @brief The TX LED default pin. - */ -#ifndef MY_DEFAULT_TX_LED_PIN - #if defined(ARDUINO_ARCH_ESP8266) - #define MY_DEFAULT_TX_LED_PIN 9 - #else - #define MY_DEFAULT_TX_LED_PIN 5 - #endif -#endif -/** - * @def MY_DEFAULT_ERR_LED_PIN - * @brief The Error LED default pin. - */ -#ifndef MY_DEFAULT_ERR_LED_PIN - #if defined(ARDUINO_ARCH_ESP8266) - #define MY_DEFAULT_ERR_LED_PIN 7 - #else - #define MY_DEFAULT_ERR_LED_PIN 4 - #endif -#endif -#if defined(MY_LEDS_BLINKING_FEATURE) +#if defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) #include "core/MyLeds.cpp" #else #include "core/MyLeds.h" @@ -270,7 +230,7 @@ #endif #if defined(MY_PARENT_NODE_IS_STATIC) && (MY_PARENT_NODE_ID == AUTO) - #error Parent is static but no parent ID defined. + #error Parent is static but no parent ID defined. #endif // Make sure to disable child features when parent feature is disabled diff --git a/core/MyIndication.cpp b/core/MyIndication.cpp index 8e5e65b86..6eb5b45fe 100644 --- a/core/MyIndication.cpp +++ b/core/MyIndication.cpp @@ -18,20 +18,26 @@ */ #include "MyIndication.h" -#ifdef MY_LEDS_BLINKING_FEATURE +#if defined(MY_DEFAULT_TX_LED_PIN)|| defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) #include "MyLeds.h" #endif void setIndication( const indication_t ind ) { -#ifdef MY_LEDS_BLINKING_FEATURE +#if defined(MY_DEFAULT_TX_LED_PIN) if ((INDICATION_TX == ind) || (INDICATION_GW_TX == ind)) { ledsBlinkTx(1); - } else if ((INDICATION_RX == ind) || (INDICATION_GW_RX == ind)) + } else +#endif +#if defined(MY_DEFAULT_RX_LED_PIN) + if ((INDICATION_RX == ind) || (INDICATION_GW_RX == ind)) { ledsBlinkRx(1); - } else if (ind > INDICATION_ERR_START) + } else +#endif +#if defined(MY_DEFAULT_ERR_LED_PIN) + if (ind > INDICATION_ERR_START) { // Number of blinks indicates which error occurred. ledsBlinkErr(ind-INDICATION_ERR_START); diff --git a/core/MyLeds.cpp b/core/MyLeds.cpp index 2974c183f..33f1eedfc 100644 --- a/core/MyLeds.cpp +++ b/core/MyLeds.cpp @@ -37,10 +37,15 @@ inline void ledsInit() countErr = 0; // Setup led pins +#if defined(MY_DEFAULT_RX_LED_PIN) pinMode(MY_DEFAULT_RX_LED_PIN, OUTPUT); +#endif +#if defined(MY_DEFAULT_TX_LED_PIN) pinMode(MY_DEFAULT_TX_LED_PIN, OUTPUT); +#endif +#if defined(MY_DEFAULT_ERR_LED_PIN) pinMode(MY_DEFAULT_ERR_LED_PIN, OUTPUT); - +#endif ledsProcess(); } @@ -55,17 +60,23 @@ void ledsProcess() { // For an On/Off ratio of 4, the pattern repeated will be [on, on, on, off] // until the counter becomes 0. +#if defined(MY_DEFAULT_RX_LED_PIN) state = (countRx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF; hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, state); if (countRx) --countRx; +#endif +#if defined(MY_DEFAULT_TX_LED_PIN) state = (countTx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF; hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, state); if (countTx) --countTx; +#endif +#if defined(MY_DEFAULT_ERR_LED_PIN) state = (countErr & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF; hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, state); if (countErr) --countErr; +#endif } void ledsBlinkRx(uint8_t cnt) { @@ -79,4 +90,3 @@ void ledsBlinkTx(uint8_t cnt) { void ledsBlinkErr(uint8_t cnt) { if(!countErr) { countErr = cnt*LED_ON_OFF_RATIO; } } - diff --git a/core/MyLeds.h b/core/MyLeds.h index 18e138d17..e6f982d1d 100644 --- a/core/MyLeds.h +++ b/core/MyLeds.h @@ -29,7 +29,7 @@ #define LED_OFF 0x1 #endif -#ifdef MY_LEDS_BLINKING_FEATURE +#if defined(MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) #define ledBlinkTx(x,...) ledsBlinkTx(x) #define ledBlinkRx(x,...) ledsBlinkRx(x) #define ledBlinkErr(x,...) ledsBlinkErr(x) diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 8e5a5fad2..e66f2d473 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -35,7 +35,7 @@ void (*_timeCallback)(unsigned long); // Callback for requested time messages void _process() { hwWatchdogReset(); - #if defined (MY_LEDS_BLINKING_FEATURE) + #if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) ledsProcess(); #endif @@ -58,7 +58,7 @@ void _infiniteLoop() { #if defined(ARDUINO_ARCH_ESP8266) yield(); #endif - #if defined (MY_LEDS_BLINKING_FEATURE) + #if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) ledsProcess(); #endif } @@ -81,7 +81,7 @@ void _begin() { before(); } - #if defined(MY_LEDS_BLINKING_FEATURE) + #if defined(MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) ledsInit(); #endif diff --git a/examples/GatewayESP8266/GatewayESP8266.ino b/examples/GatewayESP8266/GatewayESP8266.ino index 6582a70a0..f4f6fd83f 100644 --- a/examples/GatewayESP8266/GatewayESP8266.ino +++ b/examples/GatewayESP8266/GatewayESP8266.ino @@ -20,34 +20,34 @@ * * REVISION HISTORY * Version 1.0 - Henrik EKblad - * Contribution by a-lurker and Anticimex, + * Contribution by a-lurker and Anticimex, * Contribution by Norbert Truchsess * Contribution by Ivo Pullens (ESP8266 support) - * + * * DESCRIPTION - * The EthernetGateway sends data received from sensors to the WiFi link. + * The EthernetGateway sends data received from sensors to the WiFi link. * The gateway also accepts input on ethernet interface, which is then sent out to the radio network. * * VERA CONFIGURATION: - * Enter "ip-number:port" in the ip-field of the Arduino GW device. This will temporarily override any serial configuration for the Vera plugin. + * Enter "ip-number:port" in the ip-field of the Arduino GW device. This will temporarily override any serial configuration for the Vera plugin. * E.g. If you want to use the defualt values in this sketch enter: 192.168.178.66:5003 * * LED purposes: - * - To use the feature, uncomment WITH_LEDS_BLINKING in MyConfig.h + * - To use the feature, uncomment any of the MY_DEFAULT_xx_LED_PINs in your sketch, only the LEDs that is defined is used. * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly - * - ERR (red) - fast blink on error during transmission error or recieve crc error - * + * - ERR (red) - fast blink on error during transmission error or recieve crc error + * * See http://www.mysensors.org/build/esp8266_gateway for wiring instructions. * nRF24L01+ ESP8266 * VCC VCC - * CE GPIO4 + * CE GPIO4 * CSN/CS GPIO15 * SCK GPIO14 * MISO GPIO12 * MOSI GPIO13 * GND GND - * + * * Not all ESP8266 modules have all pins available on their external interface. * This code has been tested on an ESP-12 module. * The ESP8266 requires a certain pin configuration to download code, and another one to run code: @@ -56,10 +56,10 @@ * - Connect CH_PD via 10K resistor to VCC * - Connect GPIO2 via 10K resistor to VCC * - Connect GPIO0 via 10K resistor to VCC, and via switch to GND ('bootload switch') - * + * * Inclusion mode button: * - Connect GPIO5 via switch to GND ('inclusion switch') - * + * * Hardware SHA204 signing is currently not supported! * * Make sure to fill in your ssid and WiFi password below for ssid & pass. @@ -67,7 +67,7 @@ // Enable debug prints to serial monitor -#define MY_DEBUG +#define MY_DEBUG // Use a bit lower baudrate for serial prints on ESP8266 than default in MyConfig.h #define MY_BAUD_RATE 9600 @@ -95,14 +95,14 @@ #define MY_IP_GATEWAY_ADDRESS 192,168,178,1 #define MY_IP_SUBNET_ADDRESS 255,255,255,0 -// The port to keep open on node server mode -#define MY_PORT 5003 +// The port to keep open on node server mode +#define MY_PORT 5003 // How many clients should be able to connect to this gateway (default 1) #define MY_GATEWAY_MAX_CLIENTS 2 -// Controller ip address. Enables client mode (default is "server" mode). -// Also enable this if MY_USE_UDP is used and you want sensor data sent somewhere. +// Controller ip address. Enables client mode (default is "server" mode). +// Also enable this if MY_USE_UDP is used and you want sensor data sent somewhere. //#define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 68 // Enable inclusion mode @@ -111,16 +111,15 @@ // Enable Inclusion mode button on gateway // #define MY_INCLUSION_BUTTON_FEATURE // Set inclusion mode duration (in seconds) -#define MY_INCLUSION_MODE_DURATION 60 +#define MY_INCLUSION_MODE_DURATION 60 // Digital pin used for inclusion mode button -#define MY_INCLUSION_MODE_BUTTON_PIN 3 +#define MY_INCLUSION_MODE_BUTTON_PIN 3 + - -// Flash leds on rx/tx/err -// #define MY_LEDS_BLINKING_FEATURE // Set blinking period // #define MY_DEFAULT_LED_BLINK_PERIOD 300 +// Flash leds on rx/tx/err // Led pins used if blinking feature is enabled above #define MY_DEFAULT_ERR_LED_PIN 16 // Error led pin #define MY_DEFAULT_RX_LED_PIN 16 // Receive led pin @@ -134,17 +133,14 @@ #include -void setup() { +void setup() { } void presentation() { - // Present locally attached sensors here + // Present locally attached sensors here } void loop() { // Send locally attached sensors data here } - - - diff --git a/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino b/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino index 7a73594e1..0b4933b16 100644 --- a/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino +++ b/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino @@ -20,26 +20,26 @@ * * REVISION HISTORY * Version 1.0 - Henrik Ekblad - * + * * DESCRIPTION * The ESP8266 MQTT gateway sends radio network (or locally attached sensors) data to your MQTT broker. * The node also listens to MY_MQTT_TOPIC_PREFIX and sends out those messages to the radio network * * LED purposes: - * - To use the feature, uncomment WITH_LEDS_BLINKING in MyConfig.h + * - To use the feature, uncomment any of the MY_DEFAULT_xx_LED_PINs in your sketch * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly - * - ERR (red) - fast blink on error during transmission error or recieve crc error - * + * - ERR (red) - fast blink on error during transmission error or recieve crc error + * * See http://www.mysensors.org/build/esp8266_gateway for wiring instructions. * nRF24L01+ ESP8266 * VCC VCC - * CE GPIO4 + * CE GPIO4 * CSN/CS GPIO15 * SCK GPIO14 * MISO GPIO12 * MOSI GPIO13 - * + * * Not all ESP8266 modules have all pins available on their external interface. * This code has been tested on an ESP-12 module. * The ESP8266 requires a certain pin configuration to download code, and another one to run code: @@ -48,10 +48,10 @@ * - Connect CH_PD via 10K resistor to VCC * - Connect GPIO2 via 10K resistor to VCC * - Connect GPIO0 via 10K resistor to VCC, and via switch to GND ('bootload switch') - * + * * Inclusion mode button: * - Connect GPIO5 via switch to GND ('inclusion switch') - * + * * Hardware SHA204 signing is currently not supported! * * Make sure to fill in your ssid and WiFi password below for ssid & pass. @@ -59,7 +59,7 @@ // Enable debug prints to serial monitor -#define MY_DEBUG +#define MY_DEBUG // Use a bit lower baudrate for serial prints on ESP8266 than default in MyConfig.h #define MY_BAUD_RATE 9600 @@ -87,7 +87,7 @@ #define MY_ESP8266_PASSWORD "MyVerySecretPassword" // Set the hostname for the WiFi Client. This is the hostname -// it will pass to the DHCP server if not static. +// it will pass to the DHCP server if not static. // #define MY_ESP8266_HOSTNAME "mqtt-sensor-gateway" // Enable MY_IP_ADDRESS here if you want a static ip address (no DHCP) @@ -98,27 +98,26 @@ #define MY_IP_SUBNET_ADDRESS 255,255,255,0 -// MQTT broker ip address. +// MQTT broker ip address. #define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 68 -// The MQTT broker port to to open -#define MY_PORT 1883 +// The MQTT broker port to to open +#define MY_PORT 1883 /* -// Flash leds on rx/tx/err -#define MY_LEDS_BLINKING_FEATURE -// Set blinking period -#define MY_DEFAULT_LED_BLINK_PERIOD 300 - // Enable inclusion mode #define MY_INCLUSION_MODE_FEATURE // Enable Inclusion mode button on gateway #define MY_INCLUSION_BUTTON_FEATURE // Set inclusion mode duration (in seconds) -#define MY_INCLUSION_MODE_DURATION 60 +#define MY_INCLUSION_MODE_DURATION 60 // Digital pin used for inclusion mode button -#define MY_INCLUSION_MODE_BUTTON_PIN 3 +#define MY_INCLUSION_MODE_BUTTON_PIN 3 + +// Set blinking period +#define MY_DEFAULT_LED_BLINK_PERIOD 300 +// Flash leds on rx/tx/err #define MY_DEFAULT_ERR_LED_PIN 16 // Error led pin #define MY_DEFAULT_RX_LED_PIN 16 // Receive led pin #define MY_DEFAULT_TX_LED_PIN 16 // the PCB, on board LED @@ -127,17 +126,14 @@ #include #include -void setup() { +void setup() { } void presentation() { - // Present locally attached sensors here + // Present locally attached sensors here } void loop() { // Send locally attech sensors data here } - - - diff --git a/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino b/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino index 4e7870c6c..353a5f2e2 100644 --- a/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino +++ b/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino @@ -21,34 +21,34 @@ * REVISION HISTORY * Version 1.0 - Henrik EKblad * Contribution by tekka, - * Contribution by a-lurker and Anticimex, + * Contribution by a-lurker and Anticimex, * Contribution by Norbert Truchsess * Contribution by Ivo Pullens (ESP8266 support) - * + * * DESCRIPTION - * The EthernetGateway sends data received from sensors to the WiFi link. + * The EthernetGateway sends data received from sensors to the WiFi link. * The gateway also accepts input on ethernet interface, which is then sent out to the radio network. * * VERA CONFIGURATION: - * Enter "ip-number:port" in the ip-field of the Arduino GW device. This will temporarily override any serial configuration for the Vera plugin. + * Enter "ip-number:port" in the ip-field of the Arduino GW device. This will temporarily override any serial configuration for the Vera plugin. * E.g. If you want to use the defualt values in this sketch enter: 192.168.178.66:5003 * * LED purposes: * - To use the feature, uncomment WITH_LEDS_BLINKING in MyConfig.h * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly - * - ERR (red) - fast blink on error during transmission error or recieve crc error - * + * - ERR (red) - fast blink on error during transmission error or recieve crc error + * * See http://www.mysensors.org/build/esp8266_gateway for wiring instructions. * nRF24L01+ ESP8266 * VCC VCC - * CE GPIO4 + * CE GPIO4 * CSN/CS GPIO15 * SCK GPIO14 * MISO GPIO12 * MOSI GPIO13 * GND GND - * + * * Not all ESP8266 modules have all pins available on their external interface. * This code has been tested on an ESP-12 module. * The ESP8266 requires a certain pin configuration to download code, and another one to run code: @@ -57,10 +57,10 @@ * - Connect CH_PD via 10K resistor to VCC * - Connect GPIO2 via 10K resistor to VCC * - Connect GPIO0 via 10K resistor to VCC, and via switch to GND ('bootload switch') - * + * * Inclusion mode button: * - Connect GPIO5 via switch to GND ('inclusion switch') - * + * * Hardware SHA204 signing is currently not supported! * * Make sure to fill in your ssid and WiFi password below for ssid & pass. @@ -69,7 +69,7 @@ #include // Enable debug prints to serial monitor -#define MY_DEBUG +#define MY_DEBUG // Use a bit lower baudrate for serial prints on ESP8266 than default in MyConfig.h #define MY_BAUD_RATE 9600 @@ -97,14 +97,14 @@ #define MY_IP_GATEWAY_ADDRESS 192,168,178,1 #define MY_IP_SUBNET_ADDRESS 255,255,255,0 -// The port to keep open on node server mode -#define MY_PORT 5003 +// The port to keep open on node server mode +#define MY_PORT 5003 // How many clients should be able to connect to this gateway (default 1) #define MY_GATEWAY_MAX_CLIENTS 2 -// Controller ip address. Enables client mode (default is "server" mode). -// Also enable this if MY_USE_UDP is used and you want sensor data sent somewhere. +// Controller ip address. Enables client mode (default is "server" mode). +// Also enable this if MY_USE_UDP is used and you want sensor data sent somewhere. //#define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 68 // Enable inclusion mode @@ -113,16 +113,15 @@ // Enable Inclusion mode button on gateway // #define MY_INCLUSION_BUTTON_FEATURE // Set inclusion mode duration (in seconds) -#define MY_INCLUSION_MODE_DURATION 60 +#define MY_INCLUSION_MODE_DURATION 60 // Digital pin used for inclusion mode button -#define MY_INCLUSION_MODE_BUTTON_PIN 3 +#define MY_INCLUSION_MODE_BUTTON_PIN 3 + - -// Flash leds on rx/tx/err -// #define MY_LEDS_BLINKING_FEATURE // Set blinking period // #define MY_DEFAULT_LED_BLINK_PERIOD 300 +// Flash leds on rx/tx/err // Led pins used if blinking feature is enabled above #define MY_DEFAULT_ERR_LED_PIN 16 // Error led pin #define MY_DEFAULT_RX_LED_PIN 16 // Receive led pin @@ -136,8 +135,8 @@ #include -void setup() { - +void setup() { + ArduinoOTA.onStart([]() { Serial.println("ArduinoOTA start"); }); @@ -163,7 +162,7 @@ void setup() { } void presentation() { - // Present locally attached sensors here + // Present locally attached sensors here } @@ -171,7 +170,3 @@ void loop() { // Send locally attech sensors data here ArduinoOTA.handle(); } - - - - diff --git a/examples/GatewaySerial/GatewaySerial.ino b/examples/GatewaySerial/GatewaySerial.ino index 3c0b6bea7..747ba9f60 100644 --- a/examples/GatewaySerial/GatewaySerial.ino +++ b/examples/GatewaySerial/GatewaySerial.ino @@ -19,25 +19,25 @@ ******************************* * * DESCRIPTION - * The ArduinoGateway prints data received from sensors on the serial link. + * The ArduinoGateway prints data received from sensors on the serial link. * The gateway accepts input on seral which will be sent out on radio network. * * The GW code is designed for Arduino Nano 328p / 16MHz * * Wire connections (OPTIONAL): - * - Inclusion button should be connected between digital pin 3 and GND + * - Inclusion button should be connected between digital pin 3 and GND * - RX/TX/ERR leds need to be connected between +5V (anode) and digital pin 6/5/4 with resistor 270-330R in a series * * LEDs (OPTIONAL): - * - To use the feature, uncomment MY_LEDS_BLINKING_FEATURE in MyConfig.h + * - To use the feature, uncomment any of the MY_DEFAULT_xx_LED_PINs * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly - * - ERR (red) - fast blink on error during transmission error or recieve crc error - * + * - ERR (red) - fast blink on error during transmission error or recieve crc error + * */ // Enable debug prints to serial monitor -#define MY_DEBUG +#define MY_DEBUG // Enable and select radio type attached @@ -45,7 +45,7 @@ //#define MY_RADIO_RFM69 // Set LOW transmit power level as default, if you have an amplified NRF-module and -// power your radio separately with a good regulator you can turn up PA level. +// power your radio separately with a good regulator you can turn up PA level. #define MY_RF24_PA_LEVEL RF24_PA_LOW // Enable serial gateway @@ -56,14 +56,6 @@ #define MY_BAUD_RATE 38400 #endif -// Flash leds on rx/tx/err -#define MY_LEDS_BLINKING_FEATURE -// Set blinking period -#define MY_DEFAULT_LED_BLINK_PERIOD 300 - -// Inverses the behavior of leds -//#define MY_WITH_LEDS_BLINKING_INVERSE - // Enable inclusion mode #define MY_INCLUSION_MODE_FEATURE // Enable Inclusion mode button on gateway @@ -73,30 +65,32 @@ //#define MY_INCLUSION_BUTTON_EXTERNAL_PULLUP // Set inclusion mode duration (in seconds) -#define MY_INCLUSION_MODE_DURATION 60 +#define MY_INCLUSION_MODE_DURATION 60 // Digital pin used for inclusion mode button -//#define MY_INCLUSION_MODE_BUTTON_PIN 3 +//#define MY_INCLUSION_MODE_BUTTON_PIN 3 + +// Set blinking period +#define MY_DEFAULT_LED_BLINK_PERIOD 300 +// Inverses the behavior of leds +//#define MY_WITH_LEDS_BLINKING_INVERSE + +// Flash leds on rx/tx/err // Uncomment to override default HW configurations //#define MY_DEFAULT_ERR_LED_PIN 4 // Error led pin //#define MY_DEFAULT_RX_LED_PIN 6 // Receive led pin //#define MY_DEFAULT_TX_LED_PIN 5 // the PCB, on board LED -#include +#include -void setup() { +void setup() { // Setup locally attached sensors } void presentation() { - // Present locally attached sensors + // Present locally attached sensors } -void loop() { - // Send locally attached sensor data here +void loop() { + // Send locally attached sensor data here } - - - - - diff --git a/examples/GatewaySerialRS485/GatewaySerialRS485.ino b/examples/GatewaySerialRS485/GatewaySerialRS485.ino index aabd1bc48..03c8996a3 100644 --- a/examples/GatewaySerialRS485/GatewaySerialRS485.ino +++ b/examples/GatewaySerialRS485/GatewaySerialRS485.ino @@ -19,23 +19,22 @@ ******************************* * * DESCRIPTION - * The RS485 Gateway prints data received from sensors on the serial link. + * The RS485 Gateway prints data received from sensors on the serial link. * The gateway accepts input on seral which will be sent out on * the RS485 link. * * Wire connections (OPTIONAL): - * - Inclusion button should be connected between digital pin 3 and GND + * - Inclusion button should be connected between digital pin 3 and GND * - RX/TX/ERR leds need to be connected between +5V (anode) and digital pin 6/5/4 with resistor 270-330R in a series * * LEDs (OPTIONAL): - * - To use the feature, uncomment MY_LEDS_BLINKING_FEATURE in MyConfig.h * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly - * - ERR (red) - fast blink on error during transmission error or recieve crc error - * - * The gateway uses AltSoftSerial to handle two serial links + * - ERR (red) - fast blink on error during transmission error or recieve crc error + * + * The gateway uses AltSoftSerial to handle two serial links * on one Arduino. Use the following pins for RS485 link - * + * * Board Transmit Receive PWM Unusable * ----- -------- ------- ------------ * Teensy 3.0 & 3.1 21 20 22 @@ -46,16 +45,16 @@ * Arduino Mega 46 48 44, 45 * Wiring-S 5 6 4 * Sanguino 13 14 12 - * + * */ // Enable debug prints to serial monitor -#define MY_DEBUG +#define MY_DEBUG // Enable RS485 transport layer #define MY_RS485 -// Define this to enables DE-pin management on defined pin +// Define this to enables DE-pin management on defined pin #define MY_RS485_DE_PIN 2 // Set RS485 baud rate to use @@ -64,39 +63,34 @@ // Enable serial gateway #define MY_GATEWAY_SERIAL -// Flash leds on rx/tx/err -#define MY_LEDS_BLINKING_FEATURE -// Set blinking period -#define MY_DEFAULT_LED_BLINK_PERIOD 300 // Enable inclusion mode #define MY_INCLUSION_MODE_FEATURE // Enable Inclusion mode button on gateway #define MY_INCLUSION_BUTTON_FEATURE // Set inclusion mode duration (in seconds) -#define MY_INCLUSION_MODE_DURATION 60 +#define MY_INCLUSION_MODE_DURATION 60 // Digital pin used for inclusion mode button -#define MY_INCLUSION_MODE_BUTTON_PIN 3 +#define MY_INCLUSION_MODE_BUTTON_PIN 3 +// Set blinking period +#define MY_DEFAULT_LED_BLINK_PERIOD 300 + +// Flash leds on rx/tx/err #define MY_DEFAULT_ERR_LED_PIN 4 // Error led pin #define MY_DEFAULT_RX_LED_PIN 5 // Receive led pin #define MY_DEFAULT_TX_LED_PIN 6 // the PCB, on board LED -#include +#include -void setup() { +void setup() { // Setup locally attached sensors } void presentation() { - // Present locally attached sensors + // Present locally attached sensors } -void loop() { - // Send locally attached sensor data here +void loop() { + // Send locally attached sensor data here } - - - - - diff --git a/examples/GatewayW5100/GatewayW5100.ino b/examples/GatewayW5100/GatewayW5100.ino index 2074842ba..0339c5203 100644 --- a/examples/GatewayW5100/GatewayW5100.ino +++ b/examples/GatewayW5100/GatewayW5100.ino @@ -42,68 +42,67 @@ */ // Enable debug prints to serial monitor -#define MY_DEBUG +#define MY_DEBUG // Enable and select radio type attached #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -// Enable gateway ethernet module type +// Enable gateway ethernet module type #define MY_GATEWAY_W5100 // W5100 Ethernet module SPI enable (optional if using a shield/module that manages SPI_EN signal) -//#define MY_W5100_SPI_EN 4 +//#define MY_W5100_SPI_EN 4 // Enable Soft SPI for NRF radio (note different radio wiring is required) -// The W5100 ethernet module seems to have a hard time co-operate with +// The W5100 ethernet module seems to have a hard time co-operate with // radio on the same spi bus. #if !defined(MY_W5100_SPI_EN) && !defined(ARDUINO_ARCH_SAMD) #define MY_SOFTSPI #define MY_SOFT_SPI_SCK_PIN 14 #define MY_SOFT_SPI_MISO_PIN 16 #define MY_SOFT_SPI_MOSI_PIN 15 -#endif +#endif // When W5100 is connected we have to move CE/CSN pins for NRF radio -#ifndef MY_RF24_CE_PIN +#ifndef MY_RF24_CE_PIN #define MY_RF24_CE_PIN 5 #endif -#ifndef MY_RF24_CS_PIN +#ifndef MY_RF24_CS_PIN #define MY_RF24_CS_PIN 6 #endif -// Enable to UDP +// Enable to UDP //#define MY_USE_UDP #define MY_IP_ADDRESS 192,168,178,66 // If this is disabled, DHCP is used to retrieve address // Renewal period if using DHCP //#define MY_IP_RENEWAL_INTERVAL 60000 // The port to keep open on node server mode / or port to contact in client mode -#define MY_PORT 5003 +#define MY_PORT 5003 + +// Controller ip address. Enables client mode (default is "server" mode). +// Also enable this if MY_USE_UDP is used and you want sensor data sent somewhere. +//#define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 254 -// Controller ip address. Enables client mode (default is "server" mode). -// Also enable this if MY_USE_UDP is used and you want sensor data sent somewhere. -//#define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 254 - // The MAC address can be anything you want but should be unique on your network. // Newer boards have a MAC address printed on the underside of the PCB, which you can (optionally) use. // Note that most of the Ardunio examples use "DEAD BEEF FEED" for the MAC address. #define MY_MAC_ADDRESS 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED -// Flash leds on rx/tx/err -#define MY_LEDS_BLINKING_FEATURE -// Set blinking period -#define MY_DEFAULT_LED_BLINK_PERIOD 300 - // Enable inclusion mode #define MY_INCLUSION_MODE_FEATURE // Enable Inclusion mode button on gateway //#define MY_INCLUSION_BUTTON_FEATURE // Set inclusion mode duration (in seconds) -#define MY_INCLUSION_MODE_DURATION 60 +#define MY_INCLUSION_MODE_DURATION 60 // Digital pin used for inclusion mode button -//#define MY_INCLUSION_MODE_BUTTON_PIN 3 +//#define MY_INCLUSION_MODE_BUTTON_PIN 3 +// Set blinking period +#define MY_DEFAULT_LED_BLINK_PERIOD 300 + +// Flash leds on rx/tx/err // Uncomment to override default HW configurations //#define MY_DEFAULT_ERR_LED_PIN 7 // Error led pin //#define MY_DEFAULT_RX_LED_PIN 8 // Receive led pin @@ -123,4 +122,3 @@ void setup() void loop() { } - diff --git a/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino b/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino index bbcaa968f..59dad451c 100644 --- a/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino +++ b/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino @@ -20,7 +20,7 @@ * * REVISION HISTORY * Version 1.0 - Henrik Ekblad - * + * * DESCRIPTION * The W5100 MQTT gateway sends radio network (or locally attached sensors) data to your MQTT broker. * The node also listens to MY_MQTT_TOPIC_PREFIX and sends out those messages to the radio network @@ -29,17 +29,17 @@ * - To use the feature, uncomment WITH_LEDS_BLINKING in MyConfig.h * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly - * - ERR (red) - fast blink on error during transmission error or recieve crc error - * + * - ERR (red) - fast blink on error during transmission error or recieve crc error + * * See http://www.mysensors.org/build/esp8266_gateway for wiring instructions. * nRF24L01+ ESP8266 * VCC VCC - * CE GPIO4 + * CE GPIO4 * CSN/CS GPIO15 * SCK GPIO14 * MISO GPIO12 * MOSI GPIO13 - * + * * Not all ESP8266 modules have all pins available on their external interface. * This code has been tested on an ESP-12 module. * The ESP8266 requires a certain pin configuration to download code, and another one to run code: @@ -48,10 +48,10 @@ * - Connect CH_PD via 10K resistor to VCC * - Connect GPIO2 via 10K resistor to VCC * - Connect GPIO0 via 10K resistor to VCC, and via switch to GND ('bootload switch') - * + * * Inclusion mode button: * - Connect GPIO5 via switch to GND ('inclusion switch') - * + * * Hardware SHA204 signing is currently not supported! * * Make sure to fill in your ssid and WiFi password below for ssid & pass. @@ -59,7 +59,7 @@ // Enable debug prints to serial monitor -#define MY_DEBUG +#define MY_DEBUG // Enables and select radio type (if attached) #define MY_RADIO_NRF24 @@ -75,23 +75,23 @@ #define MY_MQTT_CLIENT_ID "mysensors-1" // W5100 Ethernet module SPI enable (optional if using a shield/module that manages SPI_EN signal) -//#define MY_W5100_SPI_EN 4 +//#define MY_W5100_SPI_EN 4 // Enable Soft SPI for NRF radio (note different radio wiring is required) -// The W5100 ethernet module seems to have a hard time co-operate with +// The W5100 ethernet module seems to have a hard time co-operate with // radio on the same spi bus. #if !defined(MY_W5100_SPI_EN) && !defined(ARDUINO_ARCH_SAMD) #define MY_SOFTSPI #define MY_SOFT_SPI_SCK_PIN 14 #define MY_SOFT_SPI_MISO_PIN 16 #define MY_SOFT_SPI_MOSI_PIN 15 -#endif +#endif // When W5100 is connected we have to move CE/CSN pins for NRF radio -#ifndef MY_RF24_CE_PIN +#ifndef MY_RF24_CE_PIN #define MY_RF24_CE_PIN 5 #endif -#ifndef MY_RF24_CS_PIN +#ifndef MY_RF24_CS_PIN #define MY_RF24_CS_PIN 6 #endif @@ -106,28 +106,27 @@ #define MY_IP_GATEWAY_ADDRESS 192,168,178,1 #define MY_IP_SUBNET_ADDRESS 255,255,255,0 -// MQTT broker ip address or url. Define one or the other. +// MQTT broker ip address or url. Define one or the other. //#define MY_CONTROLLER_URL_ADDRESS "m20.cloudmqtt.com" #define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 68 -// The MQTT broker port to to open -#define MY_PORT 1883 +// The MQTT broker port to to open +#define MY_PORT 1883 /* -// Flash leds on rx/tx/err -#define MY_LEDS_BLINKING_FEATURE -// Set blinking period -#define MY_DEFAULT_LED_BLINK_PERIOD 300 - // Enable inclusion mode #define MY_INCLUSION_MODE_FEATURE // Enable Inclusion mode button on gateway //#define MY_INCLUSION_BUTTON_FEATURE // Set inclusion mode duration (in seconds) -#define MY_INCLUSION_MODE_DURATION 60 +#define MY_INCLUSION_MODE_DURATION 60 // Digital pin used for inclusion mode button -//#define MY_INCLUSION_MODE_BUTTON_PIN 3 +//#define MY_INCLUSION_MODE_BUTTON_PIN 3 + +// Set blinking period +#define MY_DEFAULT_LED_BLINK_PERIOD 300 +// Flash leds on rx/tx/err // Uncomment to override default HW configurations //#define MY_DEFAULT_ERR_LED_PIN 16 // Error led pin //#define MY_DEFAULT_RX_LED_PIN 16 // Receive led pin @@ -137,17 +136,14 @@ #include #include -void setup() { +void setup() { } void presentation() { - // Present locally attached sensors here + // Present locally attached sensors here } void loop() { // Send locally attached sensors data here } - - - diff --git a/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino b/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino index f8443daed..e0d6510ff 100644 --- a/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino +++ b/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino @@ -19,33 +19,33 @@ ******************************* * * DESCRIPTION - * The ArduinoGateway prints data received from sensors on the serial link. + * The ArduinoGateway prints data received from sensors on the serial link. * The gateway accepts input on seral which will be sent out on radio network. * * This GW code is designed for Sensebender GateWay / Arduino Zero * * Wire connections (OPTIONAL): - * - Inclusion button should be connected between digital pin 3 and GND + * - Inclusion button should be connected between digital pin 3 and GND * - RX/TX/ERR leds need to be connected between +5V (anode) and digital pin 6/5/4 with resistor 270-330R in a series * * LEDs (OPTIONAL): - * - To use the feature, uncomment MY_LEDS_BLINKING_FEATURE in MyConfig.h + * - To use the feature, uncomment any of the MY_DEFAULT_xx_LED_PINs * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly - * - ERR (red) - fast blink on error during transmission error or recieve crc error - * + * - ERR (red) - fast blink on error during transmission error or recieve crc error + * */ #define SKETCH_VERSION "0.1" // Enable debug prints to serial monitor -#define MY_DEBUG +#define MY_DEBUG // Enable and select radio type attached #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 // Set LOW transmit power level as default, if you have an amplified NRF-module and -// power your radio separately with a good regulator you can turn up PA level. +// power your radio separately with a good regulator you can turn up PA level. #define MY_RF24_PA_LEVEL RF24_PA_HIGH // Enable serial gateway @@ -56,14 +56,6 @@ #define MY_BAUD_RATE 38400 #endif -// Flash leds on rx/tx/err -#define MY_LEDS_BLINKING_FEATURE -// Set blinking period -#define MY_DEFAULT_LED_BLINK_PERIOD 300 - -// Inverses the behavior of leds -//#define MY_WITH_LEDS_BLINKING_INVERSE - // Enable inclusion mode #define MY_INCLUSION_MODE_FEATURE // Enable Inclusion mode button on gateway @@ -73,10 +65,17 @@ //#define MY_INCLUSION_BUTTON_EXTERNAL_PULLUP // Set inclusion mode duration (in seconds) -#define MY_INCLUSION_MODE_DURATION 60 +#define MY_INCLUSION_MODE_DURATION 60 // Digital pin used for inclusion mode button -//#define MY_INCLUSION_MODE_BUTTON_PIN 3 +//#define MY_INCLUSION_MODE_BUTTON_PIN 3 + +// Set blinking period +#define MY_DEFAULT_LED_BLINK_PERIOD 300 + +// Inverses the behavior of leds +//#define MY_WITH_LEDS_BLINKING_INVERSE +// Flash leds on rx/tx/err // Uncomment to override default HW configurations //#define MY_DEFAULT_ERR_LED_PIN 4 // Error led pin //#define MY_DEFAULT_RX_LED_PIN 6 // Receive led pin @@ -93,16 +92,16 @@ Sd2Card card; static uint8_t num_of_leds = 5; static uint8_t leds[] = {LED_BLUE, LED_RED, LED_GREEN, LED_YELLOW, LED_ORANGE}; -void setup() { +void setup() { // Setup locally attached sensors } void presentation() { - // Present locally attached sensors + // Present locally attached sensors } -void loop() { - // Send locally attached sensor data here +void loop() { + // Send locally attached sensor data here } @@ -142,7 +141,7 @@ void preHwInit() { digitalWrite(LED_YELLOW, HIGH); tests++; } - + if (testEEProm()) { digitalWrite(LED_ORANGE, HIGH); tests++; @@ -155,7 +154,7 @@ void preHwInit() { digitalWrite(leds[i], LOW); } } - } + } else { while (1) { digitalWrite(LED_RED, HIGH); @@ -164,7 +163,7 @@ void preHwInit() { delay(200); } } - + } bool testSha204(){ @@ -243,7 +242,7 @@ bool testEEProm() { delay(500); eeprom_d2 = i2c_eeprom_read_byte(EEPROM_VERIFICATION_ADDRESS); if (eeprom_d1 == eeprom_d2) { - SerialUSB.println("PASSED"); + SerialUSB.println("PASSED"); i2c_eeprom_write_byte(EEPROM_VERIFICATION_ADDRESS, ~eeprom_d1); return true; } diff --git a/keywords.txt b/keywords.txt index 77a25406e..b84d9490a 100644 --- a/keywords.txt +++ b/keywords.txt @@ -52,7 +52,6 @@ MY_PARENT_NODE_IS_STATIC LITERAL1 MY_OTA_FIRMWARE_FEATURE LITERAL1 MY_OTA_FLASH_SS LITERAL1 MY_OTA_FLASH_JDECID LITERAL1 -MY_LEDS_BLINKING_FEATURE LITERAL1 MY_WITH_LEDS_BLINKING_INVERSE LITERAL1 MY_DEFAULT_LED_BLINK_PERIOD LITERAL1 MY_WITH_LEDS_BLINKING_INVERSE LITERAL1 @@ -129,4 +128,4 @@ MY_NODE_UNLOCK_PIN LITERAL1 MY_NODE_LOCK_COUNTER_MAX LITERAL1 MY_SPIFLASH_SST25TYPE LITERAL1 MY_CRITICAL_SECTION LITERAL1 -MY_RX_MESSAGE_BUFFER_SIZE LITERAL1 \ No newline at end of file +MY_RX_MESSAGE_BUFFER_SIZE LITERAL1 From 2049bc44494c66fdc4e41f25fed314f7c62956a4 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Sat, 20 Aug 2016 07:45:56 -0300 Subject: [PATCH 066/167] Set default port to 1883 when using MQTT gateway (#565) --- MyConfig.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/MyConfig.h b/MyConfig.h index 9582a1da4..a186c6ccc 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -611,7 +611,11 @@ * @brief The Ethernet TCP/UDP port to open on controller or gateway. */ #ifndef MY_PORT -#define MY_PORT 5003 + #ifdef MY_GATEWAY_MQTT_CLIENT + #define MY_PORT 1883 + #else + #define MY_PORT 5003 + #endif #endif // Static ip address of gateway (if this is disabled, DHCP will be used) From 9304cebddf4243911395e25e5349c61765d71ad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Sun, 21 Aug 2016 01:04:49 +0200 Subject: [PATCH 067/167] Change warning to error, so people are notified (#569) * Change warning to error, so people are notified * Added doxygen for dep. MY_LEDS_BLINKING_FEATURE --- MySensors.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/MySensors.h b/MySensors.h index c0fd42a17..821af2008 100644 --- a/MySensors.h +++ b/MySensors.h @@ -85,7 +85,9 @@ #endif #if defined(MY_LEDS_BLINKING_FEATURE) -#warning MY_LEDS_BLINKING_FEATURE is not working, define MY_DEFAULT_ERR_LED_PIN, MY_DEFAULT_TX_LED_PIN or MY_DEFAULT_RX_LED_PIN in your sketch +#error MY_LEDS_BLINKING_FEATURE is now removed from MySensors core,\ + define MY_DEFAULT_ERR_LED_PIN, MY_DEFAULT_TX_LED_PIN or\ + MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs #endif /** @@ -271,4 +273,5 @@ // This is used to enable disabled macros/definitions to be included in the documentation as well. #if DOXYGEN #define MY_GATEWAY_FEATURE +#define MY_LEDS_BLINKING_FEATURE //!< \deprecated use MY_DEFAULT_RX_LED_PIN, MY_DEFAULT_TX_LED_PIN and/or MY_DEFAULT_ERR_LED_PIN instead **** DEPRECATED, DO NOT USE **** #endif From 412e41967fa61e17ace383b74da98715100ebbe5 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Sun, 21 Aug 2016 19:56:46 -0300 Subject: [PATCH 068/167] Add support for serial gateway to Rpi --- MyConfig.h | 10 +- MySensors.h | 8 +- configure | 26 +++- core/MyHwLinuxGeneric.cpp | 12 +- core/MyHwLinuxGeneric.h | 6 +- core/MySensorsCore.cpp | 4 +- core/MyTransportNRF24.cpp | 4 +- drivers/Linux/Arduino.h | 51 +++---- drivers/Linux/Client.h | 1 + drivers/Linux/EthernetClient.h | 2 +- drivers/Linux/Print.cpp | 238 +++++++++++++++++++++++++++++ drivers/Linux/Print.h | 76 ++++++++++ drivers/Linux/SerialPort.cpp | 159 ++++++++++++++++++++ drivers/Linux/SerialPort.h | 100 +++++++++++++ drivers/Linux/Server.h | 4 +- drivers/Linux/Stream.cpp | 258 ++++++++++++++++++++++++++++++++ drivers/Linux/Stream.h | 121 +++++++++++++-- drivers/Linux/compatibility.cpp | 201 ++++--------------------- drivers/Linux/noniso.cpp | 147 ++++++++++++++++++ drivers/Linux/stdlib_noniso.h | 52 +++++++ 20 files changed, 1241 insertions(+), 239 deletions(-) create mode 100644 drivers/Linux/Print.cpp create mode 100644 drivers/Linux/Print.h create mode 100644 drivers/Linux/SerialPort.cpp create mode 100644 drivers/Linux/SerialPort.h create mode 100644 drivers/Linux/Stream.cpp create mode 100644 drivers/Linux/noniso.cpp create mode 100644 drivers/Linux/stdlib_noniso.h diff --git a/MyConfig.h b/MyConfig.h index 84a5b1cbd..b8e05177b 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -410,7 +410,7 @@ #define MY_RF24_CE_PIN 4 #elif defined(ARDUINO_ARCH_SAMD) #define MY_RF24_CE_PIN 27 - #elif defined(LINUX) + #elif defined(__linux__) #define MY_RF24_CE_PIN 22 #else #define MY_RF24_CE_PIN 9 @@ -426,7 +426,7 @@ #define MY_RF24_CS_PIN 15 #elif defined(ARDUINO_ARCH_SAMD) #define MY_RF24_CS_PIN 3 - #elif defined(LINUX) + #elif defined(__linux__) #define MY_RF24_CS_PIN 24 #else #define MY_RF24_CS_PIN 10 @@ -718,11 +718,11 @@ ***************************************/ /** - * @def MY_LINUX_TTY_NAME + * @def MY_LINUX_SERIAL_PORT * @brief Set the name of predictable tty */ -#ifndef MY_LINUX_TTY_NAME -#define MY_LINUX_TTY_NAME "/dev/ttyAMA0" +#ifndef MY_LINUX_SERIAL_PORT +#define MY_LINUX_SERIAL_PORT "/dev/ttyUSB0" #endif /** diff --git a/MySensors.h b/MySensors.h index d4c7a5a52..77e36ac58 100644 --- a/MySensors.h +++ b/MySensors.h @@ -69,7 +69,7 @@ #include "core/MyHwATMega328.cpp" #elif defined(ARDUINO_ARCH_SAMD) #include "core/MyHwSAMD.cpp" -#elif defined(LINUX) +#elif defined(__linux__) // Remove PSTR macros from debug prints #undef PSTR #define PSTR(x) (x) @@ -284,7 +284,9 @@ #if defined(MY_RF24_ENABLE_ENCRYPTION) #include "drivers/AES/AES.cpp" #endif - #if !defined(LINUX) + #if defined(__linux__) + #include "drivers/RF24/RF24_Linux.cpp" + #else #include "drivers/RF24/RF24.cpp" #endif #include "core/MyTransportNRF24.cpp" @@ -329,7 +331,7 @@ #if !defined(MY_CORE_ONLY) #if defined(ARDUINO_ARCH_ESP8266) #include "core/MyMainESP8266.cpp" - #elif defined(LINUX) + #elif defined(__linux__) #include "core/MyMainLinux.cpp" #else #include "core/MyMainDefault.cpp" diff --git a/configure b/configure index dc3012cbb..8df6e9759 100755 --- a/configure +++ b/configure @@ -35,15 +35,10 @@ MySensors options: --my-debug=[enable|disable] Enables or disables debugging. Default to enable. - --my-gateway=[none|ethernet|mqtt] + --my-config-file= Config file path. [/etc/MySensorGateway.cfg] + --my-gateway=[none|ethernet|serial|mqtt] Gateway type, set to none to disable gateway feature. Default to ethernet. - --my-config-file= Config file path. [/etc/MySensorGateway.cfg] - --my-radio=[none|nrf24] Radio type, set to none to disable radio feature. - Default to rf24. - --my-rf24-channel=<0-125> RF channel for the sensor net, 0-125. - --my-rf24-pa-level=[RF24_PA_MAX|RF24_PA_LOW] - RF24 PA level. --my-controller-url-address= Controller or MQTT broker url. --my-controller-ip-address= @@ -51,11 +46,18 @@ MySensors options: Use commas instead of points. Example: 127,0,0,1 --my-port= The port to keep open on gateway mode. If gateway is set to mqtt, it sets the broker port. + --my-serial-port= Serial port. [/dev/ttyUSB0] + --my-serial-baudrate= Serial baud rate. [115200] --my-mqtt-client-id= MQTT client id. --my-mqtt-publish-topic-prefix= MQTT publish topic prefix. --my-mqtt-subscribe-topic-prefix= MQTT subscribe topic prefix. + --my-radio=[none|nrf24] Radio type, set to none to disable radio feature. + Default to rf24. + --my-rf24-channel=<0-125> RF channel for the sensor net, 0-125. + --my-rf24-pa-level=[RF24_PA_MAX|RF24_PA_LOW] + RF24 PA level. --my-rf24-irq-pin= Pin number connected to nRF24L01 IRQ pin. For RaspberryPi use BCM numbering. --my-rx-message-buffer-size= @@ -251,6 +253,12 @@ for opt do --my-radio=*) radio_type=${optarg} ;; + --my-serial-port=*) + CXXFLAGS="-DMY_LINUX_SERIAL_PORT=\\\"${optarg}\\\" $CXXFLAGS" + ;; + --my-serial-baudrate=*) + CXXFLAGS="-DMY_BAUD_RATE=${optarg} $CXXFLAGS" + ;; --my-rf24-channel=*) CXXFLAGS="-DMY_RF24_CHANNEL=${optarg} $CXXFLAGS" ;; @@ -305,7 +313,7 @@ if [ -z "${CPUFLAGS}" ]; then CPUFLAGS=$(gcc_cpu_flags $SOC) fi -CXXFLAGS="$CPUFLAGS -Ofast -g -Wall -Wextra -DLINUX $CXXFLAGS" +CXXFLAGS="$CPUFLAGS -Ofast -g -Wall -Wextra $CXXFLAGS" if [[ $TYPE == "RPi2" || $TYPE == "RPi3" || $REV == "0010" ]]; then CXXFLAGS+="-D__RPI_BPLUS" @@ -317,6 +325,8 @@ fi if [[ ${gateway_type} == "ethernet" ]]; then CXXFLAGS="-DMY_GATEWAY_LINUX $CXXFLAGS" +elif [[ ${gateway_type} == "serial" ]]; then + CXXFLAGS="-DMY_GATEWAY_SERIAL $CXXFLAGS" elif [[ ${gateway_type} == "mqtt" ]]; then LDFLAGS="-lmosquitto $LDFLAGS" CXXFLAGS="-DMY_GATEWAY_LINUX -DMY_GATEWAY_MQTT_CLIENT $CXXFLAGS" diff --git a/core/MyHwLinuxGeneric.cpp b/core/MyHwLinuxGeneric.cpp index ee7473169..bf48457ad 100644 --- a/core/MyHwLinuxGeneric.cpp +++ b/core/MyHwLinuxGeneric.cpp @@ -30,12 +30,12 @@ static const size_t _length = 1024; // ATMega328 has 1024 bytes static uint8_t _config[_length]; bool CheckConfigFile() { - struct stat fileInfo; + struct stat fileInfo; if (stat(CONFIG_FILE, &fileInfo) != 0) { //File does not exist. Create it. debug("Config file %s does not exist, creating new config file.\n", CONFIG_FILE); - ofstream myFile(CONFIG_FILE, ios::out | ios::binary); + std::ofstream myFile(CONFIG_FILE, std::ios::out | std::ios::binary); if (!myFile) { debug("Unable to create config file %s.\n", CONFIG_FILE); return false; @@ -47,7 +47,7 @@ bool CheckConfigFile() { return false; } else { //Read config into local memory. - ifstream myFile(CONFIG_FILE, ios::in | ios::binary); + std::ifstream myFile(CONFIG_FILE, std::ios::in | std::ios::binary); if (!myFile) { debug("Unable to open config to file %s for reading.\n", CONFIG_FILE); return false; @@ -68,6 +68,10 @@ void hwInit() if (!CheckConfigFile()) { exit(1); } + + #ifdef MY_GATEWAY_SERIAL + MY_SERIALDEVICE.begin(MY_BAUD_RATE); + #endif } void hwReadConfigBlock(void* buf, void* addr, size_t length) @@ -86,7 +90,7 @@ void hwWriteConfigBlock(void* buf, void* addr, size_t length) if (length && offs + length <= _length) { memcpy(_config+offs, buf, length); - ofstream myFile(CONFIG_FILE, ios::out | ios::binary); + std::ofstream myFile(CONFIG_FILE, std::ios::out | std::ios::binary); if (!myFile) { debug("Unable to write config to file %s.\n", CONFIG_FILE); return; diff --git a/core/MyHwLinuxGeneric.h b/core/MyHwLinuxGeneric.h index 1d763ce9b..0d3e49baf 100644 --- a/core/MyHwLinuxGeneric.h +++ b/core/MyHwLinuxGeneric.h @@ -20,10 +20,12 @@ #ifndef MyHwLinuxGeneric_h #define MyHwLinuxGeneric_h -#include "MyHw.h" #include #include +#include "MyHw.h" +#include "SerialPort.h" +SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PORT); #define MY_SERIALDEVICE Serial // Define these as macros (do nothing) @@ -35,8 +37,8 @@ void hwInit(); void hwReadConfigBlock(void* buf, void* adr, size_t length); void hwWriteConfigBlock(void* buf, void* adr, size_t length); -void hwWriteConfig(int adr, uint8_t value); uint8_t hwReadConfig(int adr); +void hwWriteConfig(int adr, uint8_t value); #ifdef MY_RF24_IRQ_PIN static pthread_mutex_t hw_mutex = PTHREAD_MUTEX_INITIALIZER; diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 2d0a9db60..836f81770 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -51,7 +51,7 @@ void _process() { transportProcess(); #endif - #if defined(LINUX) + #if defined(__linux__) // To avoid high cpu usage usleep(10000); // 10ms #endif @@ -65,7 +65,7 @@ void _infiniteLoop() { #if defined (MY_LEDS_BLINKING_FEATURE) ledsProcess(); #endif - #if defined(LINUX) + #if defined(__linux__) exit(1); #endif } diff --git a/core/MyTransportNRF24.cpp b/core/MyTransportNRF24.cpp index ce3900815..cdd3f2b1a 100644 --- a/core/MyTransportNRF24.cpp +++ b/core/MyTransportNRF24.cpp @@ -20,8 +20,8 @@ #include "MyConfig.h" #include "MyTransport.h" -#ifdef LINUX_ARCH_RASPBERRYPI - #include "drivers/RF24/RF24_Linux.cpp" +#ifdef __linux__ + #include "drivers/RF24/RF24_Linux.h" #else #include "drivers/RF24/RF24.h" #endif diff --git a/drivers/Linux/Arduino.h b/drivers/Linux/Arduino.h index 08e9701b8..e1dc088cb 100644 --- a/drivers/Linux/Arduino.h +++ b/drivers/Linux/Arduino.h @@ -1,18 +1,17 @@ #ifndef Arduino_h #define Arduino_h -#include +#include #include - -#ifdef __cplusplus - #include - - using namespace std; - - extern "C" { -#endif - -void yield(void); +#include +#include +#include +#include +#include +#include +#include +#include +#include "stdlib_noniso.h" #define PI 3.1415926535897932384626433832795 #define HALF_PI 1.5707963267948966192313216916398 @@ -21,17 +20,11 @@ void yield(void); #define RAD_TO_DEG 57.295779513082320876798154814105 #define EULER 2.718281828459045235360287471352 -#ifndef __cplusplus - #define min(a,b) ((a)<(b)?(a):(b)) - #define max(a,b) ((a)>(b)?(a):(b)) - #define abs(x) ((x)>0?(x):-(x)) - #define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) -#endif - #define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt))) #define radians(deg) ((deg)*DEG_TO_RAD) #define degrees(rad) ((rad)*RAD_TO_DEG) #define sq(x) ((x)*(x)) +#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) #define lowByte(w) ((uint8_t) ((w) & 0xff)) #define highByte(w) ((uint8_t) ((w) >> 8)) @@ -43,19 +36,23 @@ void yield(void); #define bit(b) (1UL << (b)) +#define GET_MACRO(_0, _1, _2, NAME, ...) NAME +#define random(...) GET_MACRO(_0, ##__VA_ARGS__, randMinMax, randMax, rand)(__VA_ARGS__) + +using std::string; +using std::min; +using std::max; +using std::abs; + typedef bool boolean; typedef uint8_t byte; +typedef string String; -char *itoa(int value, char* result, int base); -char *ltoa(long value, char* result, int base); -char *ultoa(long num, char *str, int radix); -char *utoa(int num, char *str, int radix); -char *dtostrf(float f, int width, int decimals, char *result); +void yield(void); unsigned long millis(void); void delay(unsigned int millis); - -#ifdef __cplusplus - } -#endif +void randomSeed(unsigned long seed); +long randMax(long howbig); +long randMinMax(long howsmall, long howbig); #endif diff --git a/drivers/Linux/Client.h b/drivers/Linux/Client.h index 067b57dd9..4f38ac2a5 100644 --- a/drivers/Linux/Client.h +++ b/drivers/Linux/Client.h @@ -21,6 +21,7 @@ #ifndef client_h #define client_h + #include "Stream.h" #include "IPAddress.h" diff --git a/drivers/Linux/EthernetClient.h b/drivers/Linux/EthernetClient.h index f21f5d3ea..78dc1434e 100644 --- a/drivers/Linux/EthernetClient.h +++ b/drivers/Linux/EthernetClient.h @@ -50,7 +50,7 @@ class EthernetClient : public Client { private: - int _sock; + int _sock; //!< @brief Network socket. public: /** diff --git a/drivers/Linux/Print.cpp b/drivers/Linux/Print.cpp new file mode 100644 index 000000000..306b82c8f --- /dev/null +++ b/drivers/Linux/Print.cpp @@ -0,0 +1,238 @@ +/* + Print.cpp - Base class that provides print() and println() + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 23 November 2006 by David A. Mellis + Modified December 2014 by Ivan Grokhotkov + Modified May 2015 by Michael C. Miller - esp8266 progmem support + Modified August 2016 by Marcelo Aquino for MySensors use + */ + +#include +#include +#include +#include +#include "Print.h" + +// Public Methods ////////////////////////////////////////////////////////////// + +size_t Print::write(const uint8_t *buffer, size_t size) { + size_t n = 0; + while(size--) { + n += write(*buffer++); + } + return n; +} + +size_t Print::printf(const char *format, ...) { + va_list arg; + va_start(arg, format); + char temp[64]; + char* buffer = temp; + size_t len = vsnprintf(temp, sizeof(temp), format, arg); + va_end(arg); + if (len > sizeof(temp) - 1) { + buffer = new char[len + 1]; + if (!buffer) { + return 0; + } + va_start(arg, format); + vsnprintf(buffer, len + 1, format, arg); + va_end(arg); + } + len = write((const uint8_t*) buffer, len); + if (buffer != temp) { + delete[] buffer; + } + return len; +} + +size_t Print::print(const std::string &s) { + return write(s.c_str(), s.length()); +} + +size_t Print::print(const char str[]) { + return write(str); +} + +size_t Print::print(char c) { + return write(c); +} + +size_t Print::print(unsigned char b, int base) { + return print((unsigned long) b, base); +} + +size_t Print::print(int n, int base) { + return print((long) n, base); +} + +size_t Print::print(unsigned int n, int base) { + return print((unsigned long) n, base); +} + +size_t Print::print(long n, int base) { + if(base == 0) { + return write(n); + } else if(base == 10) { + if(n < 0) { + int t = print('-'); + n = -n; + return printNumber(n, 10) + t; + } + return printNumber(n, 10); + } else { + return printNumber(n, base); + } +} + +size_t Print::print(unsigned long n, int base) { + if(base == 0) + return write(n); + else + return printNumber(n, base); +} + +size_t Print::print(double n, int digits) { + return printFloat(n, digits); +} + +size_t Print::println(void) { + return print("\r\n"); +} + +size_t Print::println(const std::string &s) { + size_t n = print(s); + n += println(); + return n; +} + +size_t Print::println(const char c[]) { + size_t n = print(c); + n += println(); + return n; +} + +size_t Print::println(char c) { + size_t n = print(c); + n += println(); + return n; +} + +size_t Print::println(unsigned char b, int base) { + size_t n = print(b, base); + n += println(); + return n; +} + +size_t Print::println(int num, int base) { + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(unsigned int num, int base) { + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(long num, int base) { + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(unsigned long num, int base) { + size_t n = print(num, base); + n += println(); + return n; +} + +size_t Print::println(double num, int digits) { + size_t n = print(num, digits); + n += println(); + return n; +} + +// Private Methods ///////////////////////////////////////////////////////////// + +size_t Print::printNumber(unsigned long n, uint8_t base) { + char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte. + char *str = &buf[sizeof(buf) - 1]; + + *str = '\0'; + + // prevent crash if called with base == 1 + if(base < 2) + base = 10; + + do { + unsigned long m = n; + n /= base; + char c = m - base * n; + *--str = c < 10 ? c + '0' : c + 'A' - 10; + } while(n); + + return write(str); +} + +size_t Print::printFloat(double number, uint8_t digits) { + size_t n = 0; + + if(std::isnan(number)) + return print("nan"); + if(std::isinf(number)) + return print("inf"); + if(number > 4294967040.0) + return print("ovf"); // constant determined empirically + if(number < -4294967040.0) + return print("ovf"); // constant determined empirically + + // Handle negative numbers + if(number < 0.0) { + n += print('-'); + number = -number; + } + + // Round correctly so that print(1.999, 2) prints as "2.00" + double rounding = 0.5; + for(uint8_t i = 0; i < digits; ++i) + rounding /= 10.0; + + number += rounding; + + // Extract the integer part of the number and print it + unsigned long int_part = (unsigned long) number; + double remainder = number - (double) int_part; + n += print(int_part); + + // Print the decimal point, but only if there are digits beyond + if(digits > 0) { + n += print("."); + } + + // Extract digits from the remainder one at a time + while(digits-- > 0) { + remainder *= 10.0; + int toPrint = int(remainder); + n += print(toPrint); + remainder -= toPrint; + } + + return n; +} diff --git a/drivers/Linux/Print.h b/drivers/Linux/Print.h new file mode 100644 index 000000000..b63e7a171 --- /dev/null +++ b/drivers/Linux/Print.h @@ -0,0 +1,76 @@ +/* + Print.h - Base class that provides print() and println() + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified August 2016 by Marcelo Aquino for MySensors use + */ + +#ifndef Print_h +#define Print_h + +#include +#include +#include + +#if !DOXYGEN +#define DEC 10 +#define HEX 16 +#define OCT 8 +#define BIN 2 + +class Print { + private: + size_t printNumber(unsigned long n, uint8_t base); + size_t printFloat(double number, uint8_t digits); + + public: + virtual size_t write(uint8_t) = 0; + size_t write(const char *str) { + if (str == NULL) + return 0; + return write((const uint8_t *) str, strlen(str)); + } + virtual size_t write(const uint8_t *buffer, size_t size); + size_t write(const char *buffer, size_t size) { + return write((const uint8_t *) buffer, size); + } + + size_t printf(const char * format, ...) __attribute__ ((format (printf, 2, 3))); + size_t print(const std::string &); + size_t print(const char[]); + size_t print(char); + size_t print(unsigned char, int = DEC); + size_t print(int, int = DEC); + size_t print(unsigned int, int = DEC); + size_t print(long, int = DEC); + size_t print(unsigned long, int = DEC); + size_t print(double, int = 2); + + size_t println(const std::string &s); + size_t println(const char[]); + size_t println(char); + size_t println(unsigned char, int = DEC); + size_t println(int, int = DEC); + size_t println(unsigned int, int = DEC); + size_t println(long, int = DEC); + size_t println(unsigned long, int = DEC); + size_t println(double, int = 2); + size_t println(void); + }; + +#endif +#endif diff --git a/drivers/Linux/SerialPort.cpp b/drivers/Linux/SerialPort.cpp new file mode 100644 index 000000000..732d102e1 --- /dev/null +++ b/drivers/Linux/SerialPort.cpp @@ -0,0 +1,159 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "SerialPort.h" + +#define SERIAL_PORT "/dev/ttyAMA0" + +SerialPort::SerialPort() +{ + SerialPort(SERIAL_PORT); +} + +SerialPort::SerialPort(const char *port) : serialPort(std::string(port)) +{} + +void SerialPort::begin(int bauds) +{ + speed_t speed; + struct termios options; + + if ((sd = open(serialPort.c_str(), O_RDWR | O_NOCTTY | O_NDELAY)) == -1) { + fprintf(stderr, "Unable to open the serial port %s - \n", serialPort.c_str()); + exit(-1); + } + + // nonblocking mode + fcntl(sd, F_SETFL, FNDELAY); + + switch (bauds) { + case 50: speed = B50 ; break ; + case 75: speed = B75 ; break ; + case 110: speed = B110 ; break ; + case 134: speed = B134 ; break ; + case 150: speed = B150 ; break ; + case 200: speed = B200 ; break ; + case 300: speed = B300 ; break ; + case 600: speed = B600 ; break ; + case 1200: speed = B1200 ; break ; + case 1800: speed = B1800 ; break ; + case 2400: speed = B2400 ; break ; + case 9600: speed = B9600 ; break ; + case 19200: speed = B19200 ; break ; + case 38400: speed = B38400 ; break ; + case 57600: speed = B57600 ; break ; + case 115200: speed = B115200 ; break ; + default: speed = B115200 ; break ; + } + + // Get the current options of the port + if (tcgetattr(sd, &options) < 0) { + perror("Couldn't get term attributes"); + exit(1); + } + + // make raw + cfmakeraw(&options); + + // Set the baud rate + cfsetispeed(&options, speed); + cfsetospeed(&options, speed); + + // turn on READ & ignore ctrl lines + options.c_cflag |= (CLOCAL | CREAD); + // 8N1 + options.c_cflag &= ~CSTOPB; + + options.c_lflag &= ~ECHOE; + + // Timer unused + options.c_cc[VTIME]=0; + // At least on character before satisfy reading + options.c_cc[VMIN]=0; + + // Set parameters + if (tcsetattr(sd, TCSANOW, &options) < 0) { + perror("Couldn't set term attributes"); + exit(1); + } + + // flush + if (tcflush(sd, TCIOFLUSH) < 0) { + perror("Couldn't flush serial"); + exit(1); + } + + usleep(10000); +} + +int SerialPort::available() +{ + int nbytes = 0; + + if (ioctl(sd, FIONREAD, &nbytes) < 0) { + fprintf(stderr, "Failed to get byte count on serial.\n"); + exit(-1); + } + return nbytes; +} + +int SerialPort::read() +{ + unsigned char c; + + ::read(sd, &c, 1); + return c; +} + +size_t SerialPort::write(uint8_t b) +{ + return ::write(sd, &b, 1); +} + +size_t SerialPort::write(const uint8_t *buffer, size_t size) +{ + return ::write(sd, buffer, size); +} + +int SerialPort::peek() +{ + FILE * f = fdopen(sd, "r+"); + int c = getc(f); + if (c == EOF) return -1; + ungetc(c, f); + return c; +} + +void SerialPort::flush() +{ + tcflush(sd, TCIFLUSH); +} + +void SerialPort::end() +{ + close(sd); +} diff --git a/drivers/Linux/SerialPort.h b/drivers/Linux/SerialPort.h new file mode 100644 index 000000000..e344c6dca --- /dev/null +++ b/drivers/Linux/SerialPort.h @@ -0,0 +1,100 @@ +/* + * 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. + */ + +#ifndef SerialPort_h +#define SerialPort_h + +#include +#include "Stream.h" + +/** + * SerialPort Class + * Class that provides the functionality of arduino Serial library + */ +class SerialPort : public Stream { + +private: + int sd; //!< @brief file descriptor number. + std::string serialPort; //!< @brief tty name. + +public: + /** + * @brief SerialPort constructor. + */ + SerialPort(); + /** + * @brief SerialPort constructor. + */ + SerialPort(const char *port); + /** + * @brief Sets the data rate in bits per second (baud) for serial data transmission. + * + * @param serialSpeed serial port speed. + */ + void begin(int serialSpeed); + /** + * @brief Get the number of bytes available. + * + * Get the numberof bytes (characters) available for reading from + * the serial port. + * + * @return number of bytes avalable to read. + */ + int available(); + /** + * @brief Reads 1 byte of incoming serial data. + * + * @return first byte of incoming serial data available. + */ + int read(); + /** + * @brief Writes a single byte to the serial port. + * + * @param b byte to write. + * @return number of bytes written. + */ + size_t write(uint8_t b); + /** + * @brief Writes binary data to the serial port. + * + * @param buffer to write. + * @param size of the buffer. + * @return number of bytes written. + */ + size_t write(const uint8_t *buffer, size_t size); + /** + * @brief + * + * Returns the next byte (character) of incoming serial data without removing it from + * the internal serial buffer. + * + * @return -1 if no data else character in the buffer. + */ + int peek(); + /** + * @brief Remove any data remaining on the serial buffer. + */ + void flush(); + /** + * @brief Disables serial communication. + */ + void end(); +}; + +#endif diff --git a/drivers/Linux/Server.h b/drivers/Linux/Server.h index 7910e8386..c637f7abe 100644 --- a/drivers/Linux/Server.h +++ b/drivers/Linux/Server.h @@ -20,8 +20,10 @@ #ifndef server_h #define server_h +#include "Print.h" + #if !DOXYGEN -class Server { +class Server : public Print { public: virtual void begin() =0; }; diff --git a/drivers/Linux/Stream.cpp b/drivers/Linux/Stream.cpp new file mode 100644 index 000000000..1817083fc --- /dev/null +++ b/drivers/Linux/Stream.cpp @@ -0,0 +1,258 @@ +/* + Stream.cpp - adds parsing methods to Stream class + Copyright (c) 2008 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Created July 2011 + parsing functions based on TextFinder library by Michael Margolis + Modified August 2016 by Marcelo Aquino for MySensors use + */ + +#include +#include + +#define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait +#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field + +// private method to read stream with timeout +int Stream::timedRead() { + int c; + _startMillis = millis(); + do { + c = read(); + if(c >= 0) + return c; + yield(); + } while(millis() - _startMillis < _timeout); + return -1; // -1 indicates timeout +} + +// private method to peek stream with timeout +int Stream::timedPeek() { + int c; + _startMillis = millis(); + do { + c = peek(); + if(c >= 0) + return c; + yield(); + } while(millis() - _startMillis < _timeout); + return -1; // -1 indicates timeout +} + +// returns peek of the next digit in the stream or -1 if timeout +// discards non-numeric characters +int Stream::peekNextDigit() { + int c; + while(1) { + c = timedPeek(); + if(c < 0) + return c; // timeout + if(c == '-') + return c; + if(c >= '0' && c <= '9') + return c; + read(); // discard non-numeric + } +} + +// Public Methods +////////////////////////////////////////////////////////////// + +void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait +{ + _timeout = timeout; +} + +// find returns true if the target string is found +bool Stream::find(const char *target) { + return findUntil(target, (char*) ""); +} + +// reads data from the stream until the target string of given length is found +// returns true if target string is found, false if timed out +bool Stream::find(const char *target, size_t length) { + return findUntil(target, length, NULL, 0); +} + +// as find but search ends if the terminator string is found +bool Stream::findUntil(const char *target, const char *terminator) { + return findUntil(target, strlen(target), terminator, strlen(terminator)); +} + +// reads data from the stream until the target string of the given length is found +// search terminated if the terminator string is found +// returns true if target string is found, false if terminated or timed out +bool Stream::findUntil(const char *target, size_t targetLen, const char *terminator, size_t termLen) { + size_t index = 0; // maximum target string length is 64k bytes! + size_t termIndex = 0; + int c; + + if(*target == 0) + return true; // return true if target is a null string + while((c = timedRead()) > 0) { + + if(c != target[index]) + index = 0; // reset index if any char does not match + + if(c == target[index]) { + //////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1); + if(++index >= targetLen) { // return true if all chars in the target match + return true; + } + } + + if(termLen > 0 && c == terminator[termIndex]) { + if(++termIndex >= termLen) + return false; // return false if terminate string found before target string + } else + termIndex = 0; + } + return false; +} + +// returns the first valid (long) integer value from the current position. +// initial characters that are not digits (or the minus sign) are skipped +// function is terminated by the first character that is not a digit. +long Stream::parseInt() { + return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout) +} + +// as above but a given skipChar is ignored +// this allows format characters (typically commas) in values to be ignored +long Stream::parseInt(char skipChar) { + boolean isNegative = false; + long value = 0; + int c; + + c = peekNextDigit(); + // ignore non numeric leading characters + if(c < 0) + return 0; // zero returned if timeout + + do { + if(c == skipChar) + ; // ignore this charactor + else if(c == '-') + isNegative = true; + else if(c >= '0' && c <= '9') // is c a digit? + value = value * 10 + c - '0'; + read(); // consume the character we got with peek + c = timedPeek(); + } while((c >= '0' && c <= '9') || c == skipChar); + + if(isNegative) + value = -value; + return value; +} + +// as parseInt but returns a floating point value +float Stream::parseFloat() { + return parseFloat(NO_SKIP_CHAR); +} + +// as above but the given skipChar is ignored +// this allows format characters (typically commas) in values to be ignored +float Stream::parseFloat(char skipChar) { + boolean isNegative = false; + boolean isFraction = false; + long value = 0; + int c; + float fraction = 1.0; + + c = peekNextDigit(); + // ignore non numeric leading characters + if(c < 0) + return 0; // zero returned if timeout + + do { + if(c == skipChar) + ; // ignore + else if(c == '-') + isNegative = true; + else if(c == '.') + isFraction = true; + else if(c >= '0' && c <= '9') { // is c a digit? + value = value * 10 + c - '0'; + if(isFraction) + fraction *= 0.1; + } + read(); // consume the character we got with peek + c = timedPeek(); + } while((c >= '0' && c <= '9') || c == '.' || c == skipChar); + + if(isNegative) + value = -value; + if(isFraction) + return value * fraction; + else + return value; +} + +// read characters from stream into buffer +// terminates if length characters have been read, or timeout (see setTimeout) +// returns the number of characters placed in the buffer +// the buffer is NOT null terminated. +// +size_t Stream::readBytes(char *buffer, size_t length) { + size_t count = 0; + while(count < length) { + int c = timedRead(); + if(c < 0) + break; + *buffer++ = (char) c; + count++; + } + return count; +} + +// as readBytes with terminator character +// terminates if length characters have been read, timeout, or if the terminator character detected +// returns the number of characters placed in the buffer (0 means no valid data found) + +size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) { + if(length < 1) + return 0; + size_t index = 0; + while(index < length) { + int c = timedRead(); + if(c < 0 || c == terminator) + break; + *buffer++ = (char) c; + index++; + } + return index; // return number of characters, not including null terminator +} + +std::string Stream::readString() { + std::string ret; + int c = timedRead(); + while(c >= 0) { + ret += (char) c; + c = timedRead(); + } + return ret; +} + +std::string Stream::readStringUntil(char terminator) { + std::string ret; + int c = timedRead(); + while(c >= 0 && c != terminator) { + ret += (char) c; + c = timedRead(); + } + return ret; +} diff --git a/drivers/Linux/Stream.h b/drivers/Linux/Stream.h index 226543b92..dff2074e5 100644 --- a/drivers/Linux/Stream.h +++ b/drivers/Linux/Stream.h @@ -1,16 +1,119 @@ +/* + Stream.h - base class for character-based streams. + Copyright (c) 2010 David A. Mellis. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + parsing functions based on TextFinder library by Michael Margolis + Modified August 2016 by Marcelo Aquino for MySensors use + */ + #ifndef Stream_h #define Stream_h +#include +#include +#include "Print.h" + +// compatability macros for testing +/* + #define getInt() parseInt() + #define getInt(skipChar) parseInt(skipchar) + #define getFloat() parseFloat() + #define getFloat(skipChar) parseFloat(skipChar) + #define getString( pre_string, post_string, buffer, length) + readBytesBetween( pre_string, terminator, buffer, length) + */ + #if !DOXYGEN -class Stream { - public: - virtual size_t write(uint8_t) = 0; - virtual size_t write(const uint8_t *buffer, size_t size) = 0; - - virtual int available() = 0; - virtual int read() = 0; - virtual int peek() = 0; - virtual void flush() = 0; +class Stream: public Print { + protected: + unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read + unsigned long _startMillis; // used for timeout measurement + int timedRead(); // private method to read stream with timeout + int timedPeek(); // private method to peek stream with timeout + int peekNextDigit(); // returns the next numeric digit in the stream or -1 if timeout + + public: + virtual int available() = 0; + virtual int read() = 0; + virtual int peek() = 0; + virtual void flush() = 0; + + Stream() { + _timeout = 1000; + } + +// parsing methods + + void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second + + bool find(const char *target); // reads data from the stream until the target string is found + bool find(uint8_t *target) { + return find((char *) target); + } + // returns true if target string is found, false if timed out (see setTimeout) + + bool find(const char *target, size_t length); // reads data from the stream until the target string of given length is found + bool find(const uint8_t *target, size_t length) { + return find((char *) target, length); + } + // returns true if target string is found, false if timed out + + bool find(char target) { return find (&target, 1); } + + bool findUntil(const char *target, const char *terminator); // as find but search ends if the terminator string is found + bool findUntil(const uint8_t *target, const char *terminator) { + return findUntil((char *) target, terminator); + } + + bool findUntil(const char *target, size_t targetLen, const char *terminate, size_t termLen); // as above but search ends if the terminate string is found + bool findUntil(const uint8_t *target, size_t targetLen, const char *terminate, size_t termLen) { + return findUntil((char *) target, targetLen, terminate, termLen); + } + + long parseInt(); // returns the first valid (long) integer value from the current position. + // initial characters that are not digits (or the minus sign) are skipped + // integer is terminated by the first character that is not a digit. + + float parseFloat(); // float version of parseInt + + virtual size_t readBytes(char *buffer, size_t length); // read chars from stream into buffer + virtual size_t readBytes(uint8_t *buffer, size_t length) { + return readBytes((char *) buffer, length); + } + // terminates if length characters have been read or timeout (see setTimeout) + // returns the number of characters placed in the buffer (0 means no valid data found) + + size_t readBytesUntil(char terminator, char *buffer, size_t length); // as readBytes with terminator character + size_t readBytesUntil(char terminator, uint8_t *buffer, size_t length) { + return readBytesUntil(terminator, (char *) buffer, length); + } + // terminates if length characters have been read, timeout, or if the terminator character detected + // returns the number of characters placed in the buffer (0 means no valid data found) + + // Arduino String functions to be added here + std::string readString(); + std::string readStringUntil(char terminator); + + protected: + long parseInt(char skipChar); // as above but the given skipChar is ignored + // as above but the given skipChar is ignored + // this allows format characters (typically commas) in values to be ignored + + float parseFloat(char skipChar); // as above but the given skipChar is ignored }; #endif diff --git a/drivers/Linux/compatibility.cpp b/drivers/Linux/compatibility.cpp index ff76cc584..a0a0eb3f9 100644 --- a/drivers/Linux/compatibility.cpp +++ b/drivers/Linux/compatibility.cpp @@ -1,185 +1,12 @@ -#include #include #include +#include #include "Arduino.h" // For millis() static unsigned long millis_at_start = 0; -/** -* C++ version 0.4 char* style "itoa": -* Written by Lukás Chmela -* Released under GPLv3. -*/ -char *itoa(int value, char* result, int base) { - // check that the base if valid - if (base < 2 || base > 36) { *result = '\0'; return result; } - - char* ptr = result, *ptr1 = result, tmp_char; - int tmp_value; - - do { - tmp_value = value; - value /= base; - *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)]; - } while ( value ); - - // Apply negative sign - // Apply negative sign - if (tmp_value < 0) *ptr++ = '-'; - *ptr-- = '\0'; - while(ptr1 < ptr) { - tmp_char = *ptr; - *ptr--= *ptr1; - *ptr1++ = tmp_char; - } - return result; -} - -/** - * C++ version 0.4 char* style "itoa": - * Written by Lukás Chmela - * Released under GPLv3. - */ -char *ltoa(long value, char* result, int base) { - // check that the base if valid - if (base < 2 || base > 36) { *result = '\0'; return result; } - - char* ptr = result, *ptr1 = result, tmp_char; - long tmp_value; - - do { - tmp_value = value; - value /= base; - *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)]; - } while ( value ); - - // Apply negative sign - if (tmp_value < 0) *ptr++ = '-'; - *ptr-- = '\0'; - while(ptr1 < ptr) { - tmp_char = *ptr; - *ptr--= *ptr1; - *ptr1++ = tmp_char; - } - return result; -} - -char *ultoa(long num, char *str, int radix) -{ - unsigned long value; - char *sp = str; - char *sp2; - - value = num; - - /* Store sign at start of buffer for negative base-10 values */ - if (10 == radix && 0 > num) { - *sp++ = '-'; - value = -num; - } - - sp2 = sp; - - do { - char rem = value % radix; - value /= radix; - if (10 > rem) { - *sp++ = '0' + rem; - } else { - *sp++ = 'A' + rem - 10; - } - } while (0 < value); - - /* Mark end of string */ - *sp-- = 0; - - /* Reverse string contents (excluding sign) in place */ - while (sp2 < sp) { - char tmp = *sp2; - *sp2++ = *sp; - *sp-- = tmp; - } - - return str; -} - -/** - * Copyright (c) 2012, Peter A. Bigot - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * * Neither the name of the software nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -char *utoa(int num, char *str, int radix) -{ - unsigned int value; - char *sp = str; - char *sp2; - - value = num; - - /* Store sign at start of buffer for negative base-10 values */ - if (10 == radix && 0 > num) { - *sp++ = '-'; - value = -num; - } - - sp2 = sp; - - do { - char rem = value % radix; - value /= radix; - if (10 > rem) { - *sp++ = '0' + rem; - } else { - *sp++ = 'A' + rem - 10; - } - } while (0 < value); - - /* Mark end of string */ - *sp-- = 0; - - /* Reverse string contents (excluding sign) in place */ - while (sp2 < sp) { - char tmp = *sp2; - *sp2++ = *sp; - *sp-- = tmp; - } - - return str; -} - -char *dtostrf(float f, int width, int decimals, char *result) -{ - sprintf(result,"%*.*f", width, decimals, f); - return result; -} +void yield(void) {} unsigned long millis(void) { @@ -202,3 +29,27 @@ void delay(unsigned int millis) sleeper.tv_nsec = (long)(millis % 1000) * 1000000; nanosleep(&sleeper, NULL); } + +void randomSeed(unsigned long seed) +{ + if (seed != 0) { + srand(seed); + } +} + +long randMax(long howbig) +{ + if (howbig == 0) { + return 0; + } + return rand() % howbig; +} + +long randMinMax(long howsmall, long howbig) +{ + if (howsmall >= howbig) { + return howsmall; + } + long diff = howbig - howsmall; + return randMax(diff) + howsmall; +} diff --git a/drivers/Linux/noniso.cpp b/drivers/Linux/noniso.cpp new file mode 100644 index 000000000..f628aa733 --- /dev/null +++ b/drivers/Linux/noniso.cpp @@ -0,0 +1,147 @@ +/* + noniso.cpp - replacements for non-ISO functions used by Arduino core + Copyright © 2016 Ivan Grokhotkov + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + Modified August 2016 by Marcelo Aquino for MySensors use +*/ + +#include +#include +#include +#include +#include +#include +#include "stdlib_noniso.h" + +char* utoa(unsigned value, char* result, int base) { + if(base < 2 || base > 16) { + *result = 0; + return result; + } + + char* out = result; + unsigned quotient = value; + + do { + const unsigned tmp = quotient / base; + *out = "0123456789abcdef"[quotient - (tmp * base)]; + ++out; + quotient = tmp; + } while(quotient); + + reverse(result, out); + *out = 0; + return result; +} + +char* itoa(int value, char* result, int base) { + if(base < 2 || base > 16) { + *result = 0; + return result; + } + + char* out = result; + int quotient = abs(value); + + do { + const int tmp = quotient / base; + *out = "0123456789abcdef"[quotient - (tmp * base)]; + ++out; + quotient = tmp; + } while(quotient); + + // Apply negative sign + if(value < 0) + *out++ = '-'; + + reverse(result, out); + *out = 0; + return result; +} + +int atoi(const char* s) { + return (int) atol(s); +} + +long atol(const char* s) { + char * tmp; + return strtol(s, &tmp, 10); +} + +double atof(const char* s) { + char * tmp; + return strtod(s, &tmp); +} + +void reverse(char* begin, char* end) { + char *is = begin; + char *ie = end - 1; + while(is < ie) { + char tmp = *ie; + *ie = *is; + *is = tmp; + ++is; + --ie; + } +} + +char* ltoa(long value, char* result, int base) { + if(base < 2 || base > 16) { + *result = 0; + return result; + } + + char* out = result; + long quotient = abs(value); + + do { + const long tmp = quotient / base; + *out = "0123456789abcdef"[quotient - (tmp * base)]; + ++out; + quotient = tmp; + } while(quotient); + + // Apply negative sign + if(value < 0) + *out++ = '-'; + + reverse(result, out); + *out = 0; + return result; +} + +char* ultoa(unsigned long value, char* result, int base) { + if(base < 2 || base > 16) { + *result = 0; + return result; + } + + char* out = result; + unsigned long quotient = value; + + do { + const unsigned long tmp = quotient / base; + *out = "0123456789abcdef"[quotient - (tmp * base)]; + ++out; + quotient = tmp; + } while(quotient); + + reverse(result, out); + *out = 0; + return result; +} + +char* dtostrf (double val, signed char width, unsigned char prec, char *s) { + sprintf(s,"%*.*f", width, prec, val); + return s; +} diff --git a/drivers/Linux/stdlib_noniso.h b/drivers/Linux/stdlib_noniso.h new file mode 100644 index 000000000..636cbf437 --- /dev/null +++ b/drivers/Linux/stdlib_noniso.h @@ -0,0 +1,52 @@ +/* + stdlib_noniso.h - nonstandard (but usefull) conversion functions + + Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. + This file is part of the esp8266 core for Arduino environment. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef STDLIB_NONISO_H +#define STDLIB_NONISO_H + +#ifdef __cplusplus +extern "C"{ +#endif + +int atoi(const char *s); + +long atol(const char* s); + +double atof(const char* s); + +char* itoa (int val, char *s, int radix); + +char* ltoa (long val, char *s, int radix); + +char* utoa (unsigned int val, char *s, int radix); + +char* ultoa (unsigned long val, char *s, int radix); + +char* dtostrf (double val, signed char width, unsigned char prec, char *s); + +void reverse(char* begin, char* end); + +#ifdef __cplusplus +} // extern "C" +#endif + + +#endif From 48e90983ac86e8055bb6e5ad8d6173aca89ba3bb Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Sun, 21 Aug 2016 23:42:44 -0300 Subject: [PATCH 069/167] Add random number initialization to MyHw layer --- core/MyHwATMega328.h | 1 + core/MyHwESP8266.h | 3 ++- core/MyHwSAMD.h | 1 + core/MySigningAtsha204Soft.cpp | 2 +- 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/core/MyHwATMega328.h b/core/MyHwATMega328.h index 8d6c1025d..0efd91118 100644 --- a/core/MyHwATMega328.h +++ b/core/MyHwATMega328.h @@ -63,6 +63,7 @@ do { \ #define hwWatchdogReset() wdt_reset() #define hwReboot() wdt_enable(WDTO_15MS); while (1) #define hwMillis() millis() +#define hwRandomNumberInit() randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)) #define hwReadConfig(__pos) (eeprom_read_byte((uint8_t*)(__pos))) #ifndef eeprom_update_byte diff --git a/core/MyHwESP8266.h b/core/MyHwESP8266.h index ffbcb6906..f021b5ba0 100644 --- a/core/MyHwESP8266.h +++ b/core/MyHwESP8266.h @@ -37,8 +37,9 @@ #define hwDigitalWrite(__pin, __value) (digitalWrite(__pin, __value)) #define hwInit() MY_SERIALDEVICE.begin(MY_BAUD_RATE); MY_SERIALDEVICE.setDebugOutput(true) #define hwWatchdogReset() wdt_reset() -#define hwReboot() ESP.restart(); +#define hwReboot() ESP.restart() #define hwMillis() millis() +#define hwRandomNumberInit() randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)) void hwReadConfigBlock(void* buf, void* adr, size_t length); void hwWriteConfigBlock(void* buf, void* adr, size_t length); diff --git a/core/MyHwSAMD.h b/core/MyHwSAMD.h index dce2dbacc..6df31621e 100644 --- a/core/MyHwSAMD.h +++ b/core/MyHwSAMD.h @@ -43,6 +43,7 @@ void hwInit(); void hwWatchdogReset(); void hwReboot(); #define hwMillis() millis() +#define hwRandomNumberInit() randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)) void hwReadConfigBlock(void* buf, void* adr, size_t length); void hwWriteConfigBlock(void* buf, void* adr, size_t length); diff --git a/core/MySigningAtsha204Soft.cpp b/core/MySigningAtsha204Soft.cpp index 400895f2f..740db9dae 100644 --- a/core/MySigningAtsha204Soft.cpp +++ b/core/MySigningAtsha204Soft.cpp @@ -92,7 +92,7 @@ static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, void signerAtsha204SoftInit(void) { // initialize pseudo-RNG - randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)); + hwRandomNumberInit(); // Set secrets hwReadConfigBlock((void*)_signing_hmac_key, (void*)EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32); hwReadConfigBlock((void*)_signing_node_serial_info, (void*)EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9); From f0c5a993d56ce9cfd679e10840b9051c94b6e4b0 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Mon, 22 Aug 2016 21:26:44 -0300 Subject: [PATCH 070/167] Fix Rpi config file corruption * Add uninstall to Makefile --- Makefile | 24 +++++++++++++++++++++++- MyConfig.h | 2 +- configure | 4 ++-- core/MyHwLinuxGeneric.cpp | 5 +++-- examples_linux/mysGateway.cpp | 2 +- 5 files changed, 30 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 05067d134..159691922 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,8 @@ CONFIG_FILE=Makefile.inc include $(CONFIG_FILE) -GATEWAY=examples_linux/mysGateway +GATEWAY_BIN=mysGateway +GATEWAY=examples_linux/$(GATEWAY_BIN) GATEWAY_SOURCES=$(wildcard drivers/Linux/*.cpp) examples_linux/mysGateway.cpp GATEWAY_OBJECTS=$(patsubst %.cpp,%.o,$(GATEWAY_SOURCES)) DEPS+=$(patsubst %.cpp,%.d,$(GATEWAY_SOURCES)) @@ -61,7 +62,28 @@ ifeq ($(INIT_SYSTEM), systemd) install -m0644 initscripts/mysgateway.systemd /etc/systemd/system/mysgateway.service @sed -i -e "s|%gateway_dir%|${GATEWAY_DIR}|g" /etc/systemd/system/mysgateway.service systemctl daemon-reload + @echo "MySensors gateway has been installed, to add to the boot run:" + @echo " sudo systemctl enable mysgateway.service" + @echo "To start the gateway run:" + @echo " sudo systemctl start mysgateway.service" else ifeq ($(INIT_SYSTEM), sysvinit) install -m0755 initscripts/mysgateway.sysvinit /etc/init.d/mysgateway @sed -i -e "s|%gateway_dir%|${GATEWAY_DIR}|g" /etc/init.d/mysgateway + @echo "MySensors gateway has been installed, to add to the boot run:" + @echo " sudo update-rc.d mysgateway defaults" + @echo "To start the gateway run:" + @echo " sudo service mysgateway start" +endif + +uninstall: +ifeq ($(INIT_SYSTEM), systemd) + @echo "Stopping daemon mysgateway (ignore errors)" + -@systemctl stop mysgateway.service + @echo "removing files" + rm /etc/systemd/system/mysgateway.service $(GATEWAY_DIR)/$(GATEWAY_BIN) +else ifeq ($(INIT_SYSTEM), sysvinit) + @echo "Stopping daemon mysgateway (ignore errors)" + -@service mysgateway stop + @echo "removing files" + rm /etc/init.d/mysgateway $(GATEWAY_DIR)/$(GATEWAY_BIN) endif diff --git a/MyConfig.h b/MyConfig.h index b8e05177b..785beda7d 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -732,7 +732,7 @@ * For now the configuration file is only used to store the emulated eeprom state */ #ifndef MY_LINUX_CONFIG_FILE - #define MY_LINUX_CONFIG_FILE "/etc/MySensorGateway.cfg" + #define MY_LINUX_CONFIG_FILE "/etc/mysensors.dat" #endif // Doxygen specific constructs, not included when built normally diff --git a/configure b/configure index 8df6e9759..242b2363f 100755 --- a/configure +++ b/configure @@ -35,7 +35,7 @@ MySensors options: --my-debug=[enable|disable] Enables or disables debugging. Default to enable. - --my-config-file= Config file path. [/etc/MySensorGateway.cfg] + --my-config-file= Config file path. [/etc/mysensors.dat] --my-gateway=[none|ethernet|serial|mqtt] Gateway type, set to none to disable gateway feature. Default to ethernet. @@ -248,7 +248,7 @@ for opt do gateway_type=${optarg} ;; --my-config-file=*) - CXXFLAGS="-DMY_CONFIG_FILE=${optarg} $CXXFLAGS" + CXXFLAGS="-DMY_LINUX_CONFIG_FILE=\\\"${optarg}\\\" $CXXFLAGS" ;; --my-radio=*) radio_type=${optarg} diff --git a/core/MyHwLinuxGeneric.cpp b/core/MyHwLinuxGeneric.cpp index bf48457ad..b11655522 100644 --- a/core/MyHwLinuxGeneric.cpp +++ b/core/MyHwLinuxGeneric.cpp @@ -90,12 +90,13 @@ void hwWriteConfigBlock(void* buf, void* addr, size_t length) if (length && offs + length <= _length) { memcpy(_config+offs, buf, length); - std::ofstream myFile(CONFIG_FILE, std::ios::out | std::ios::binary); + std::ofstream myFile(CONFIG_FILE, std::ios::out | std::ios::in | std::ios::binary); if (!myFile) { debug("Unable to write config to file %s.\n", CONFIG_FILE); return; } - myFile.write((const char*)buf+offs, _length); + myFile.seekp(offs); + myFile.write((const char*)buf, length); myFile.close(); } } diff --git a/examples_linux/mysGateway.cpp b/examples_linux/mysGateway.cpp index b53ffccb5..baec1946c 100644 --- a/examples_linux/mysGateway.cpp +++ b/examples_linux/mysGateway.cpp @@ -24,7 +24,7 @@ // For more options run ./configure --help // Config file -//#define MY_LINUX_CONFIG_FILE "/etc/MySensorGateway.cfg" +//#define MY_LINUX_CONFIG_FILE "/etc/mysensors.dat" // How many clients should be able to connect to this gateway (default 1) #define MY_GATEWAY_MAX_CLIENTS 10 From ebdaedb5145781780fa2da4fc4c2d48bb2617226 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Sun, 21 Aug 2016 23:25:11 -0300 Subject: [PATCH 071/167] Add ESP8266 Serial modes SERIAL_TX_ONLY allows to use RX (GPIO3) as a general purpose input/output SERIAL_RX_ONLY allows to use TX (GPIO1) as a general purpose input/output --- MyConfig.h | 22 ++++++++++++++++++++++ core/MyHwESP8266.h | 2 +- keywords.txt | 1 + 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/MyConfig.h b/MyConfig.h index 366a6766b..2e1d3dff3 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -643,6 +643,10 @@ // If MY_CONTROLLER_IP_ADDRESS is left un-defined, gateway acts as server allowing incoming connections. //#define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 254 +/************************************** +* Node Locking +***************************************/ + /** * @defgroup MyLockgrp MyNodeLock * @ingroup internals @@ -699,8 +703,26 @@ #endif /** @}*/ // Node lock group +/********************************** +* ESP8266 Defaults +***********************************/ + +/** + * @def MY_ESP8266_SERIAL_MODE + * @brief Serial modes: SERIAL_FULL, SERIAL_RX_ONLY, SERIAL_TX_ONLY + * + * SERIAL_FULL: Default mode. + * SERIAL_TX_ONLY: allows to use RX (GPIO3) as a general purpose input/output. + * SERIAL_RX_ONLY: allows to use TX (GPIO1) as a general purpose input/output. + */ +#ifndef MY_ESP8266_SERIAL_MODE +#define MY_ESP8266_SERIAL_MODE SERIAL_FULL #endif +/** @}*/ // ESP8266 Defaults + +#endif // MyConfig_h + // Doxygen specific constructs, not included when built normally // This is used to enable disabled macros/definitions to be included in the documentation as well. #if DOXYGEN diff --git a/core/MyHwESP8266.h b/core/MyHwESP8266.h index ffbcb6906..3bd6c00b1 100644 --- a/core/MyHwESP8266.h +++ b/core/MyHwESP8266.h @@ -35,7 +35,7 @@ // Define these as macros to save valuable space #define hwDigitalWrite(__pin, __value) (digitalWrite(__pin, __value)) -#define hwInit() MY_SERIALDEVICE.begin(MY_BAUD_RATE); MY_SERIALDEVICE.setDebugOutput(true) +#define hwInit() MY_SERIALDEVICE.begin(MY_BAUD_RATE, SERIAL_8N1, MY_ESP8266_SERIAL_MODE, 1); MY_SERIALDEVICE.setDebugOutput(true) #define hwWatchdogReset() wdt_reset() #define hwReboot() ESP.restart(); #define hwMillis() millis() diff --git a/keywords.txt b/keywords.txt index b84d9490a..5d8da56a5 100644 --- a/keywords.txt +++ b/keywords.txt @@ -107,6 +107,7 @@ MY_GATEWAY_MAX_RECEIVE_LENGTH LITERAL1 MY_ESP8266_SSID LITERAL1 MY_ESP8266_PASSWORD LITERAL1 MY_ESP8266_HOSTNAME LITERAL1 +MY_ESP8266_SERIAL_MODE LITERAL1 MY_IP_GATEWAY_ADDRESS LITERAL1 MY_IP_SUBNET_ADDRESS LITERAL1 MY_W5100_SPI_EN LITERAL1 From b4f4e28545c46f345c45003d50d74a65a58738a2 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Sat, 3 Sep 2016 00:49:36 -0300 Subject: [PATCH 072/167] Add support for PTY to RPi serial gateway --- MyConfig.h | 33 +++++++-- MySensors.h | 2 +- configure | 37 +++++----- core/MyHwLinuxGeneric.cpp | 6 ++ core/MyHwLinuxGeneric.h | 7 +- core/MyMainLinux.cpp | 4 ++ drivers/Linux/SerialPort.cpp | 126 +++++++++++++++++++++++++++------- drivers/Linux/SerialPort.h | 27 ++++++-- examples_linux/mysGateway.cpp | 10 +++ 9 files changed, 197 insertions(+), 55 deletions(-) diff --git a/MyConfig.h b/MyConfig.h index 785beda7d..dff0d6e76 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -719,21 +719,43 @@ /** * @def MY_LINUX_SERIAL_PORT - * @brief Set the name of predictable tty + * @brief Serial device port */ #ifndef MY_LINUX_SERIAL_PORT -#define MY_LINUX_SERIAL_PORT "/dev/ttyUSB0" +#define MY_LINUX_SERIAL_PORT "/dev/ttyACM0" #endif +/** + * @def MY_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 + +/** + * @def MY_LINUX_SERIAL_PTY + * @brief Symlink name for the PTY device. + */ +#ifndef MY_LINUX_SERIAL_PTY +#define MY_LINUX_SERIAL_PTY "/dev/ttyMySensorsGateway" +#endif + +/** + * @def MY_LINUX_SERIAL_GROUPNAME + * @brief Grant access to the specified system group for the serial device. + */ +//#define MY_LINUX_SERIAL_GROUPNAME "tty" + /** * @def MY_LINUX_CONFIG_FILE * @brief Set the filepath for the gateway config file * * For now the configuration file is only used to store the emulated eeprom state */ - #ifndef MY_LINUX_CONFIG_FILE - #define MY_LINUX_CONFIG_FILE "/etc/mysensors.dat" - #endif +#ifndef MY_LINUX_CONFIG_FILE +#define MY_LINUX_CONFIG_FILE "/etc/mysensors.dat" +#endif // Doxygen specific constructs, not included when built normally // This is used to enable disabled macros/definitions to be included in the documentation as well. @@ -751,4 +773,5 @@ #define MY_RX_MESSAGE_BUFFER_FEATURE #define MY_RX_MESSAGE_BUFFER_SIZE #define MY_NODE_LOCK_FEATURE +#define MY_LINUX_SERIAL_GROUPNAME #endif diff --git a/MySensors.h b/MySensors.h index 77e36ac58..2b7e82019 100644 --- a/MySensors.h +++ b/MySensors.h @@ -245,7 +245,7 @@ // GATEWAY - ESP8266 #include "core/MyGatewayTransportEthernet.cpp" #elif defined(MY_GATEWAY_LINUX) - // GATEWAY - Generic Linux (RaspberryPi, BBB, ...) + // GATEWAY - Generic Linux #include "drivers/Linux/EthernetClient.h" #include "drivers/Linux/EthernetServer.h" #include "drivers/Linux/IPAddress.h" diff --git a/configure b/configure index 242b2363f..86b73c3c5 100755 --- a/configure +++ b/configure @@ -11,12 +11,7 @@ Options: Help: -h, --help print this message -Driver options: - --driver=[SPIDEV|MRAA|RPi|LittleWire] - Driver for RF24 library. [configure autodetected] - Building options: - --os=[LINUX|DARWIN] Operating system. [configure autodetected] --soc=[BCM2835|BCM2836|AM33XX|A10|A13|A20|H3] SoC type to be used. [configure autodetected] --cpu-flags= CPU defining/optimizing flags to be used. [configure autodetected] @@ -33,12 +28,10 @@ Installation options: MySensors options: --my-debug=[enable|disable] - Enables or disables debugging. - Default to enable. + Enables or disables debugging. [enable] --my-config-file= Config file path. [/etc/mysensors.dat] --my-gateway=[none|ethernet|serial|mqtt] - Gateway type, set to none to disable gateway feature. - Default to ethernet. + Gateway type, set to none to disable gateway feature. [ethernet] --my-controller-url-address= Controller or MQTT broker url. --my-controller-ip-address= @@ -48,21 +41,25 @@ MySensors options: If gateway is set to mqtt, it sets the broker port. --my-serial-port= Serial port. [/dev/ttyUSB0] --my-serial-baudrate= Serial baud rate. [115200] + --my-serial-is-pty Set the serial port to be a pseudo terminal. Use this if you want + to connect to a controller running on the same device. + --my-serial-pty= Symlink name for the PTY device. [/dev/ttyMySensorsGateway] + --my-serial-groupname= + Grant access to the specified system group for the serial device. --my-mqtt-client-id= MQTT client id. --my-mqtt-publish-topic-prefix= MQTT publish topic prefix. --my-mqtt-subscribe-topic-prefix= MQTT subscribe topic prefix. - --my-radio=[none|nrf24] Radio type, set to none to disable radio feature. - Default to rf24. + --my-radio=[none|nrf24] Radio type, set to none to disable radio feature. [rf24] --my-rf24-channel=<0-125> RF channel for the sensor net, 0-125. --my-rf24-pa-level=[RF24_PA_MAX|RF24_PA_LOW] RF24 PA level. --my-rf24-irq-pin= Pin number connected to nRF24L01 IRQ pin. For RaspberryPi use BCM numbering. --my-rx-message-buffer-size= - Buffer size for incoming messages when using rf24 interrupts. - Default is 20. + Buffer size for incoming messages when using rf24 interrupts. [20] + EOF } @@ -202,7 +199,7 @@ debug=enable gateway_type=ethernet radio_type=nrf24 -params="OS SOC CXXFLAGS LDFLAGS PREFIX CXX RF24H_LIB_DIR GATEWAY_DIR INIT_SYSTEM" +params="SOC CXXFLAGS LDFLAGS PREFIX CXX RF24H_LIB_DIR GATEWAY_DIR INIT_SYSTEM" for opt do if [ "$opt" = "-h" ] || [ "$opt" = "--help" ]; then @@ -211,9 +208,6 @@ for opt do fi optarg="${opt#*=}" case "$opt" in - --os=*) - OS="$optarg" - ;; --soc=*) SOC="$optarg" ;; @@ -259,6 +253,15 @@ for opt do --my-serial-baudrate=*) CXXFLAGS="-DMY_BAUD_RATE=${optarg} $CXXFLAGS" ;; + --my-serial-is-pty*) + CXXFLAGS="-DMY_IS_SERIAL_PTY $CXXFLAGS" + ;; + --my-serial-pty=*) + CXXFLAGS="-DMY_LINUX_SERIAL_PTY=\\\"${optarg}\\\" $CXXFLAGS" + ;; + --my-serial-groupname=*) + CXXFLAGS="-DMY_LINUX_SERIAL_GROUPNAME=\\\"${optarg}\\\" $CXXFLAGS" + ;; --my-rf24-channel=*) CXXFLAGS="-DMY_RF24_CHANNEL=${optarg} $CXXFLAGS" ;; diff --git a/core/MyHwLinuxGeneric.cpp b/core/MyHwLinuxGeneric.cpp index b11655522..2db3102b0 100644 --- a/core/MyHwLinuxGeneric.cpp +++ b/core/MyHwLinuxGeneric.cpp @@ -71,6 +71,12 @@ 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)) { + debug("Unable to change permission for serial port device.\n"); + exit(1); + } + #endif #endif } diff --git a/core/MyHwLinuxGeneric.h b/core/MyHwLinuxGeneric.h index 0d3e49baf..eb5fee36d 100644 --- a/core/MyHwLinuxGeneric.h +++ b/core/MyHwLinuxGeneric.h @@ -25,7 +25,12 @@ #include "MyHw.h" #include "SerialPort.h" -SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PORT); +#ifdef MY_IS_SERIAL_PTY + SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PTY, true); +#else + SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PORT); +#endif + #define MY_SERIALDEVICE Serial // Define these as macros (do nothing) diff --git a/core/MyMainLinux.cpp b/core/MyMainLinux.cpp index 5798cecf0..fd044e4f0 100644 --- a/core/MyMainLinux.cpp +++ b/core/MyMainLinux.cpp @@ -20,6 +20,10 @@ void handle_sigint(int sig) detachInterrupt(MY_RF24_IRQ_PIN); #endif + #if defined(MY_GATEWAY_SERIAL) + MY_SERIALDEVICE.end(); + #endif + exit(0); } diff --git a/drivers/Linux/SerialPort.cpp b/drivers/Linux/SerialPort.cpp index 732d102e1..048db46b6 100644 --- a/drivers/Linux/SerialPort.cpp +++ b/drivers/Linux/SerialPort.cpp @@ -25,31 +25,68 @@ #include #include #include +#include +#include +#include #include "SerialPort.h" -#define SERIAL_PORT "/dev/ttyAMA0" - -SerialPort::SerialPort() +SerialPort::SerialPort(const char *port, bool isPty) : serialPort(std::string(port)), isPty(isPty) { - SerialPort(SERIAL_PORT); + sd = -1; } -SerialPort::SerialPort(const char *port) : serialPort(std::string(port)) -{} - void SerialPort::begin(int bauds) +{ + if (!open(bauds)) { + fprintf(stderr, "Failed to open serial port.\n"); + exit(1); + } +} + +bool SerialPort::open(int bauds) { speed_t speed; struct termios options; - if ((sd = open(serialPort.c_str(), O_RDWR | O_NOCTTY | O_NDELAY)) == -1) { - fprintf(stderr, "Unable to open the serial port %s - \n", serialPort.c_str()); - exit(-1); + if (isPty) { + sd = posix_openpt(O_RDWR | O_NOCTTY | O_NDELAY); + if (sd < 0) { + perror("Couldn't open a PTY"); + return false; + } + + if (grantpt(sd) != 0) { + perror("Couldn't grant permission to the PTY"); + return false; + } + + if (unlockpt(sd) != 0) { + perror("Couldn't unlock the PTY"); + return false; + } + + // Get the current options of the port + if (tcgetattr(sd, &options) < 0) { + perror("Couldn't get term attributes"); + return false; + } + + /* create a symlink with predictable name to the PTY device */ + unlink(serialPort.c_str()); // remove the symlink if it already exists + if (symlink(ptsname(sd), serialPort.c_str()) != 0) { + fprintf(stderr, "Couldn't create a symlink '%s' to PTY! (%d) %s\n", serialPort.c_str(), errno, strerror(errno)); + return false; + } + } else { + if ((sd = ::open(serialPort.c_str(), O_RDWR | O_NOCTTY | O_NDELAY)) == -1) { + fprintf(stderr, "Unable to open the serial port %s\n", serialPort.c_str()); + return false; + } + + // nonblocking mode + fcntl(sd, F_SETFL, FNDELAY); } - // nonblocking mode - fcntl(sd, F_SETFL, FNDELAY); - switch (bauds) { case 50: speed = B50 ; break ; case 75: speed = B75 ; break ; @@ -73,22 +110,20 @@ void SerialPort::begin(int bauds) // Get the current options of the port if (tcgetattr(sd, &options) < 0) { perror("Couldn't get term attributes"); - exit(1); + return false; } - // make raw - cfmakeraw(&options); + // Clear all the options + bzero(&options, sizeof(options)); // Set the baud rate cfsetispeed(&options, speed); cfsetospeed(&options, speed); - // turn on READ & ignore ctrl lines - options.c_cflag |= (CLOCAL | CREAD); - // 8N1 - options.c_cflag &= ~CSTOPB; - - options.c_lflag &= ~ECHOE; + // Configure the device : 8 bits, no parity, no control + options.c_cflag |= ( CLOCAL | CREAD | CS8); + // Ignore framing errors, parity errors and BREAK condition on input. + options.c_iflag |= ( IGNPAR | IGNBRK ); // Timer unused options.c_cc[VTIME]=0; @@ -98,16 +133,55 @@ void SerialPort::begin(int bauds) // Set parameters if (tcsetattr(sd, TCSANOW, &options) < 0) { perror("Couldn't set term attributes"); - exit(1); + return false; } // flush if (tcflush(sd, TCIOFLUSH) < 0) { perror("Couldn't flush serial"); - exit(1); + return false; } usleep(10000); + + return true; +} + +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); + if (devGrp == NULL) { + fprintf(stderr, "getgrnam: %s failed. (%d) %s\n", groupName, errno, strerror(errno)); + return false; + } + + if (isPty) { + dev = ptsname(sd); + } else { + dev = serialPort.c_str(); + } + + ret = chown(dev, -1, devGrp->gr_gid); + if (ret == -1) { + fprintf(stderr, "Could not change PTY owner! (%d) %s\n", errno, strerror(errno)); + return false; + } + + ret = chmod(dev, ttyPermissions); + if (ret != 0) { + fprintf(stderr, "Could not change PTY permissions! (%d) %s\n", errno, strerror(errno)); + return false; + } + + return true; + } + return false; } int SerialPort::available() @@ -156,4 +230,8 @@ void SerialPort::flush() void SerialPort::end() { close(sd); + + if (isPty) { + unlink(serialPort.c_str()); // remove the symlink + } } diff --git a/drivers/Linux/SerialPort.h b/drivers/Linux/SerialPort.h index e344c6dca..e0f77bb8e 100644 --- a/drivers/Linux/SerialPort.h +++ b/drivers/Linux/SerialPort.h @@ -21,6 +21,7 @@ #define SerialPort_h #include +#include #include "Stream.h" /** @@ -32,22 +33,34 @@ class SerialPort : public Stream { private: int sd; //!< @brief file descriptor number. std::string serialPort; //!< @brief tty name. + bool isPty; //!< @brief true if serial is pseudo terminal. public: /** * @brief SerialPort constructor. */ - SerialPort(); + SerialPort(const char *port, bool isPty = false); /** - * @brief SerialPort constructor. - */ - SerialPort(const char *port); + * @brief Open the serial port and set the data rate in bits per second (baud). + * + * This function will terminate the program on an error. + * + * @param bauds bits per second. + */ + void begin(int bauds); + /** + * @brief Open the serial port and set the data rate in bits per second (baud). + * + * @param bauds bits per second. + * @return @c true if no errors, else @c false. + */ + bool open(int bauds = 115200); /** - * @brief Sets the data rate in bits per second (baud) for serial data transmission. + * @brief Grant access to the specified system group for the serial device. * - * @param serialSpeed serial port speed. + * @param groupName system group name. */ - void begin(int serialSpeed); + bool setGroupPerm(const char *groupName); /** * @brief Get the number of bytes available. * diff --git a/examples_linux/mysGateway.cpp b/examples_linux/mysGateway.cpp index baec1946c..1d7c745e6 100644 --- a/examples_linux/mysGateway.cpp +++ b/examples_linux/mysGateway.cpp @@ -29,6 +29,16 @@ // How many clients should be able to connect to this gateway (default 1) #define MY_GATEWAY_MAX_CLIENTS 10 +// Serial config +// 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 +// 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 +//#define MY_LINUX_SERIAL_GROUPNAME "tty" + // MQTT options //#define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 68 //#define MY_PORT 1883 From 09103e9c042eb4c0c90b7ecba8227baaf9f78b63 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Wed, 7 Sep 2016 14:03:40 -0300 Subject: [PATCH 073/167] Add run time options to RPi gateway --- configure | 2 +- core/MyGatewayTransportSerial.cpp | 3 - core/MyHwLinuxGeneric.cpp | 24 +++++--- core/MyMainLinux.cpp | 98 ++++++++++++++++++++++++++++--- drivers/Linux/EthernetClient.cpp | 13 ++-- drivers/Linux/EthernetClient.h | 7 --- drivers/Linux/EthernetServer.cpp | 23 ++++---- drivers/Linux/EthernetServer.h | 7 --- drivers/Linux/Print.cpp | 6 +- drivers/Linux/SerialPort.cpp | 33 +++++------ drivers/Linux/log.cpp | 22 +++++++ drivers/Linux/log.h | 10 ++++ initscripts/mysgateway.sysvinit | 7 +-- 13 files changed, 178 insertions(+), 77 deletions(-) create mode 100644 drivers/Linux/log.cpp create mode 100644 drivers/Linux/log.h diff --git a/configure b/configure index 86b73c3c5..13d69fd16 100755 --- a/configure +++ b/configure @@ -28,7 +28,7 @@ Installation options: MySensors options: --my-debug=[enable|disable] - Enables or disables debugging. [enable] + Enables or disables MySensors core debugging. [enable] --my-config-file= Config file path. [/etc/mysensors.dat] --my-gateway=[none|ethernet|serial|mqtt] Gateway type, set to none to disable gateway feature. [ethernet] diff --git a/core/MyGatewayTransportSerial.cpp b/core/MyGatewayTransportSerial.cpp index bbad4b3c0..8b5120dfe 100644 --- a/core/MyGatewayTransportSerial.cpp +++ b/core/MyGatewayTransportSerial.cpp @@ -17,7 +17,6 @@ * version 2 as published by the Free Software Foundation. */ - #include "MyConfig.h" #include "MyProtocol.h" #include "MyGatewayTransport.h" @@ -31,7 +30,6 @@ char _serialInputString[MY_GATEWAY_MAX_RECEIVE_LENGTH]; // A buffer for incom int _serialInputPos; MyMessage _serialMsg; - bool gatewayTransportSend(MyMessage &message) { setIndication(INDICATION_GW_TX); MY_SERIALDEVICE.print(protocolFormat(message)); @@ -47,7 +45,6 @@ bool gatewayTransportInit() { return true; } - bool gatewayTransportAvailable() { while (MY_SERIALDEVICE.available()) { // get the new byte: diff --git a/core/MyHwLinuxGeneric.cpp b/core/MyHwLinuxGeneric.cpp index 2db3102b0..cc66f0544 100644 --- a/core/MyHwLinuxGeneric.cpp +++ b/core/MyHwLinuxGeneric.cpp @@ -24,12 +24,14 @@ #include #include #include +#include "log.h" static const char* CONFIG_FILE = MY_LINUX_CONFIG_FILE; static const size_t _length = 1024; // ATMega328 has 1024 bytes static uint8_t _config[_length]; -bool CheckConfigFile() { +bool CheckConfigFile() +{ struct stat fileInfo; if (stat(CONFIG_FILE, &fileInfo) != 0) { @@ -152,27 +154,31 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo return -2; } -uint16_t hwCPUVoltage() { +uint16_t hwCPUVoltage() +{ // TODO: Not supported! return 0; } -uint16_t hwCPUFrequency() { +uint16_t hwCPUFrequency() +{ // TODO: Not supported! return 0; } -uint16_t hwFreeMem() { +uint16_t hwFreeMem() +{ // TODO: Not supported! return 0; } #ifdef MY_DEBUG -void hwDebugPrint(const char *fmt, ... ) +void hwDebugPrint(const char *fmt, ...) { - va_list arglist; - va_start(arglist, fmt); - vprintf(fmt, arglist); - va_end(arglist); + va_list args; + + va_start(args, fmt); + mys_log_v(LOG_DEBUG, fmt, args); + va_end(args); } #endif diff --git a/core/MyMainLinux.cpp b/core/MyMainLinux.cpp index fd044e4f0..a461184c5 100644 --- a/core/MyMainLinux.cpp +++ b/core/MyMainLinux.cpp @@ -1,19 +1,23 @@ // Initialize library and handle sketch functions like we want to -#include +#include #include #include +#include +#include +#include +#include +#include "log.h" #include "MySensorsCore.h" -/* - * handler for SIGINT signal - */ void handle_sigint(int sig) { if (sig == SIGINT) { - std::cout << "Received SIGINT\n" << std::endl; + mys_log(LOG_NOTICE, "Received SIGINT\n\n"); } else if (sig == SIGTERM) { - std::cout << "Received SIGTERM\n" << std::endl; + mys_log(LOG_NOTICE, "Received SIGTERM\n\n"); + } else { + return; } #ifdef MY_RF24_IRQ_PIN @@ -27,11 +31,91 @@ void handle_sigint(int sig) exit(0); } -int main(void) { +static int daemonize(void) +{ + pid_t pid, sid; + + /* Fork off the parent process */ + pid = fork(); + if (pid < 0) { + mys_log(LOG_ERR, "fork: %s", strerror(errno)); + return -1; + } + /* If we got a good PID, then we can exit the parent process. */ + if (pid > 0) { + exit(EXIT_SUCCESS); + } + + /* At this point we are executing as the child process */ + + /* Change the file mode mask */ + umask(0); + + /* Create a new SID for the child process */ + sid = setsid(); + if (sid < 0) { + mys_log(LOG_ERR, "setsid: %s", strerror(errno)); + return -1; + } + + /* Change the current working directory. This prevents the current + directory from being locked; hence not being able to remove it. */ + if ((chdir("/")) < 0) { + mys_log(LOG_ERR, "chdir(\"/\"): %s", strerror(errno)); + return -1; + } + + freopen( "/dev/null", "r", stdin); + freopen( "/dev/null", "r", stdout); + freopen( "/dev/null", "r", stderr); + + return 0; +} + +int main(int argc, char *argv[]) +{ + int opt, log_opts, debug = 0, foreground = 1; + /* register the signal handler */ signal(SIGINT, handle_sigint); signal(SIGTERM, handle_sigint); + while ((opt = getopt(argc, argv, "hdb")) != -1) { + switch (opt) { + case 'h': + printf("Usage: mysGateway [options]\n\n" \ + "Options:\n" \ + "-h Display a short summary of all program options.\n" \ + "-d Enable debug.\n" \ + "-b Become a daemon.\n"); + exit(0); + case 'd': + debug = 1; + break; + case 'b': + foreground = 0; + break; + } + } + + log_opts = LOG_CONS; + if (foreground && isatty(STDIN_FILENO)) { + log_opts |= LOG_PERROR; + } + if (!debug) { + setlogmask(LOG_UPTO (LOG_INFO)); + } + openlog(NULL, log_opts, LOG_USER); + + if (!foreground && !debug) { + if (daemonize() != 0) { + exit(EXIT_FAILURE); + } + } + + mys_log(LOG_INFO, "Starting gateway...\n"); + mys_log(LOG_INFO, "Protocol version - %s\n", MYSENSORS_LIBRARY_VERSION); + _begin(); // Startup MySensors library for (;;) { diff --git a/drivers/Linux/EthernetClient.cpp b/drivers/Linux/EthernetClient.cpp index 387fcaa74..9a9e65b1e 100644 --- a/drivers/Linux/EthernetClient.cpp +++ b/drivers/Linux/EthernetClient.cpp @@ -29,6 +29,7 @@ #include #include #include +#include "log.h" #include "EthernetClient.h" EthernetClient::EthernetClient() : _sock(-1) { @@ -50,7 +51,7 @@ int EthernetClient::connect(const char* host, uint16_t port) { sprintf(port_str, "%hu", port); if ((rv = getaddrinfo(host, port_str, &hints, &servinfo)) != 0) { - fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); + mys_log(LOG_ERR, "getaddrinfo: %s\n", gai_strerror(rv)); return -1; } @@ -58,13 +59,13 @@ int EthernetClient::connect(const char* host, uint16_t port) { for (p = servinfo; p != NULL; p = p->ai_next) { if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { - perror("socket"); + mys_log(LOG_ERR, "socket: %s\n", strerror(errno)); continue; } if (::connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) { close(sockfd); - perror("connect"); + mys_log(LOG_ERR, "connect: %s\n", strerror(errno)); continue; } @@ -72,7 +73,7 @@ int EthernetClient::connect(const char* host, uint16_t port) { } if (p == NULL) { - fprintf(stderr, "failed to connect\n"); + mys_log(LOG_ERR, "failed to connect\n"); return -1; } @@ -80,7 +81,7 @@ int EthernetClient::connect(const char* host, uint16_t port) { void *addr = &(((struct sockaddr_in*)p->ai_addr)->sin_addr); inet_ntop(p->ai_family, addr, s, sizeof s); - ETHERNETCLIENT_DEBUG("connected to %s\n", s); + mys_log(LOG_DEBUG, "connected to %s\n", s); freeaddrinfo(servinfo); // all done with this structure @@ -106,7 +107,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); if (rc == -1) { - perror("send"); + mys_log(LOG_ERR, "send: %s\n", strerror(errno)); close(_sock); _sock = -1; break; diff --git a/drivers/Linux/EthernetClient.h b/drivers/Linux/EthernetClient.h index 78dc1434e..2cbaca9d1 100644 --- a/drivers/Linux/EthernetClient.h +++ b/drivers/Linux/EthernetClient.h @@ -37,13 +37,6 @@ #define ETHERNETCLIENT_W5100_CLOSE_WAIT 0x1C #define ETHERNETCLIENT_W5100_LAST_ACK 0x1D -// debug -#if defined(ETHERNETCLIENT_VERBOSE) - #define ETHERNETCLIENT_DEBUG(x,...) debug(x, ##__VA_ARGS__) //!< debug -#else - #define ETHERNETCLIENT_DEBUG(x,...) //!< debug NULL -#endif - /** * EthernetClient class */ diff --git a/drivers/Linux/EthernetServer.cpp b/drivers/Linux/EthernetServer.cpp index 0537bb60f..7ac89f485 100644 --- a/drivers/Linux/EthernetServer.cpp +++ b/drivers/Linux/EthernetServer.cpp @@ -28,6 +28,7 @@ #include #include #include +#include "log.h" #include "EthernetClient.h" #include "EthernetServer.h" @@ -56,26 +57,26 @@ void EthernetServer::begin(IPAddress address) sprintf(portstr, "%d", port); if ((rv = getaddrinfo(address.toString().c_str(), portstr, &hints, &servinfo)) != 0) { - fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); + mys_log(LOG_ERR, "getaddrinfo: %s\n", gai_strerror(rv)); return; } // loop through all the results and bind to the first we can for (p = servinfo; p != NULL; p = p->ai_next) { if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { - perror("socket"); + mys_log(LOG_ERR, "socket: %s\n", strerror(errno)); continue; } if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { - perror("setsockopt"); + mys_log(LOG_ERR, "setsockopt: %s\n", strerror(errno)); freeaddrinfo(servinfo); return; } if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { close(sockfd); - perror("bind"); + mys_log(LOG_ERR, "bind: %s\n", strerror(errno)); continue; } @@ -83,13 +84,13 @@ void EthernetServer::begin(IPAddress address) } if (p == NULL) { - fprintf(stderr, "failed to bind\n"); + mys_log(LOG_ERR, "failed to bind\n"); freeaddrinfo(servinfo); return; } if (listen(sockfd, ETHERNETSERVER_BACKLOG) == -1) { - perror("listen"); + mys_log(LOG_ERR, "listen: %s\n", strerror(errno)); freeaddrinfo(servinfo); return; } @@ -101,7 +102,7 @@ void EthernetServer::begin(IPAddress address) struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr; void *addr = &(ipv4->sin_addr); inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr); - ETHERNETSERVER_DEBUG("Listening for connections on %s:%s\n", ipstr, portstr); + mys_log(LOG_DEBUG, "Listening for connections on %s:%s\n", ipstr, portstr); } bool EthernetServer::hasClient() @@ -141,7 +142,7 @@ size_t EthernetServer::write(const uint8_t *buffer, size_t size) client.stop(); clients[i] = clients.back(); clients.pop_back(); - ETHERNETSERVER_DEBUG("Client disconnected."); + mys_log(LOG_DEBUG, "Client disconnected."); } } @@ -191,7 +192,7 @@ void EthernetServer::_accept() } } if (no_free_slots) { - ETHERNETSERVER_DEBUG("Max number of ethernet clients reached."); + mys_log(LOG_DEBUG, "Max number of ethernet clients reached."); return; } } @@ -200,7 +201,7 @@ void EthernetServer::_accept() new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size); if (new_fd == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { - perror("accept"); + mys_log(LOG_ERR, "accept: %s\n", strerror(errno)); } return; } @@ -210,5 +211,5 @@ void EthernetServer::_accept() void *addr = &(((struct sockaddr_in*)&client_addr)->sin_addr); inet_ntop(client_addr.ss_family, addr, ipstr, sizeof ipstr); - ETHERNETSERVER_DEBUG("New connection from %s\n", ipstr); + mys_log(LOG_DEBUG, "New connection from %s\n", ipstr); } diff --git a/drivers/Linux/EthernetServer.h b/drivers/Linux/EthernetServer.h index 8bb4c6dd7..4240e9690 100644 --- a/drivers/Linux/EthernetServer.h +++ b/drivers/Linux/EthernetServer.h @@ -34,13 +34,6 @@ #define ETHERNETSERVER_BACKLOG 10 //!< Maximum length to which the queue of pending connections may grow. #endif -// debug -#if defined(ETHERNETSERVER_VERBOSE) - #define ETHERNETSERVER_DEBUG(x,...) printf(x, ##__VA_ARGS__) //!< debug -#else - #define ETHERNETSERVER_DEBUG(x,...) //!< debug NULL -#endif - class EthernetClient; /** diff --git a/drivers/Linux/Print.cpp b/drivers/Linux/Print.cpp index 306b82c8f..94eb81448 100644 --- a/drivers/Linux/Print.cpp +++ b/drivers/Linux/Print.cpp @@ -38,7 +38,11 @@ size_t Print::write(const uint8_t *buffer, size_t size) { return n; } -size_t Print::printf(const char *format, ...) { +size_t +#ifdef __GNUC__ +__attribute__((format(printf, 2, 3))) +#endif +Print::printf(const char *format, ...) { va_list arg; va_start(arg, format); char temp[64]; diff --git a/drivers/Linux/SerialPort.cpp b/drivers/Linux/SerialPort.cpp index 048db46b6..79b8484c8 100644 --- a/drivers/Linux/SerialPort.cpp +++ b/drivers/Linux/SerialPort.cpp @@ -28,6 +28,7 @@ #include #include #include +#include "log.h" #include "SerialPort.h" SerialPort::SerialPort(const char *port, bool isPty) : serialPort(std::string(port)), isPty(isPty) @@ -38,7 +39,7 @@ SerialPort::SerialPort(const char *port, bool isPty) : serialPort(std::string(po void SerialPort::begin(int bauds) { if (!open(bauds)) { - fprintf(stderr, "Failed to open serial port.\n"); + mys_log(LOG_ERR, "Failed to open serial port.\n"); exit(1); } } @@ -51,35 +52,29 @@ bool SerialPort::open(int bauds) if (isPty) { sd = posix_openpt(O_RDWR | O_NOCTTY | O_NDELAY); if (sd < 0) { - perror("Couldn't open a PTY"); + mys_log(LOG_ERR, "Couldn't open a PTY: %s\n", strerror(errno)); return false; } if (grantpt(sd) != 0) { - perror("Couldn't grant permission to the PTY"); + mys_log(LOG_ERR, "Couldn't grant permission to the PTY: %s\n", strerror(errno)); return false; } if (unlockpt(sd) != 0) { - perror("Couldn't unlock the PTY"); - return false; - } - - // Get the current options of the port - if (tcgetattr(sd, &options) < 0) { - perror("Couldn't get term attributes"); + mys_log(LOG_ERR, "Couldn't unlock the PTY: %s\n", strerror(errno)); return false; } /* create a symlink with predictable name to the PTY device */ unlink(serialPort.c_str()); // remove the symlink if it already exists if (symlink(ptsname(sd), serialPort.c_str()) != 0) { - fprintf(stderr, "Couldn't create a symlink '%s' to PTY! (%d) %s\n", serialPort.c_str(), errno, strerror(errno)); + mys_log(LOG_ERR, "Couldn't create a symlink '%s' to PTY! (%d) %s\n", serialPort.c_str(), errno, strerror(errno)); return false; } } else { if ((sd = ::open(serialPort.c_str(), O_RDWR | O_NOCTTY | O_NDELAY)) == -1) { - fprintf(stderr, "Unable to open the serial port %s\n", serialPort.c_str()); + mys_log(LOG_ERR, "Unable to open the serial port %s\n", serialPort.c_str()); return false; } @@ -109,7 +104,7 @@ bool SerialPort::open(int bauds) // Get the current options of the port if (tcgetattr(sd, &options) < 0) { - perror("Couldn't get term attributes"); + mys_log(LOG_ERR, "Couldn't get term attributes: %s\n", strerror(errno)); return false; } @@ -132,13 +127,13 @@ bool SerialPort::open(int bauds) // Set parameters if (tcsetattr(sd, TCSANOW, &options) < 0) { - perror("Couldn't set term attributes"); + mys_log(LOG_ERR, "Couldn't set term attributes: %s\n", strerror(errno)); return false; } // flush if (tcflush(sd, TCIOFLUSH) < 0) { - perror("Couldn't flush serial"); + mys_log(LOG_ERR, "Couldn't flush serial: %s\n", strerror(errno)); return false; } @@ -157,7 +152,7 @@ bool SerialPort::setGroupPerm(const char *groupName) if (sd != -1 && groupName != NULL) { devGrp = getgrnam(groupName); if (devGrp == NULL) { - fprintf(stderr, "getgrnam: %s failed. (%d) %s\n", groupName, errno, strerror(errno)); + mys_log(LOG_ERR, "getgrnam: %s failed. (%d) %s\n", groupName, errno, strerror(errno)); return false; } @@ -169,13 +164,13 @@ bool SerialPort::setGroupPerm(const char *groupName) ret = chown(dev, -1, devGrp->gr_gid); if (ret == -1) { - fprintf(stderr, "Could not change PTY owner! (%d) %s\n", errno, strerror(errno)); + mys_log(LOG_ERR, "Could not change PTY owner! (%d) %s\n", errno, strerror(errno)); return false; } ret = chmod(dev, ttyPermissions); if (ret != 0) { - fprintf(stderr, "Could not change PTY permissions! (%d) %s\n", errno, strerror(errno)); + mys_log(LOG_ERR, "Could not change PTY permissions! (%d) %s\n", errno, strerror(errno)); return false; } @@ -189,7 +184,7 @@ int SerialPort::available() int nbytes = 0; if (ioctl(sd, FIONREAD, &nbytes) < 0) { - fprintf(stderr, "Failed to get byte count on serial.\n"); + mys_log(LOG_ERR, "Failed to get byte count on serial.\n"); exit(-1); } return nbytes; diff --git a/drivers/Linux/log.cpp b/drivers/Linux/log.cpp new file mode 100644 index 000000000..b45df4e5a --- /dev/null +++ b/drivers/Linux/log.cpp @@ -0,0 +1,22 @@ +#include +#include +#include +#include "log.h" + +void mys_log_v(int level, const char *fmt, va_list args) +{ + vsyslog(level, fmt, args); +} + +void +#ifdef __GNUC__ +__attribute__((format(printf, 2, 3))) +#endif +mys_log(int level, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + mys_log_v(level, fmt, args); + va_end(args); +} diff --git a/drivers/Linux/log.h b/drivers/Linux/log.h new file mode 100644 index 000000000..791e4b999 --- /dev/null +++ b/drivers/Linux/log.h @@ -0,0 +1,10 @@ +#ifndef LOG_H +#define LOG_H + +#include +#include + +extern void mys_log_v(int level, const char *fmt, va_list args); +extern void mys_log(int level, const char *fmt, ...) __attribute__((format(printf,2,3))); + +#endif diff --git a/initscripts/mysgateway.sysvinit b/initscripts/mysgateway.sysvinit index 34ee0c490..5ca7e12f3 100644 --- a/initscripts/mysgateway.sysvinit +++ b/initscripts/mysgateway.sysvinit @@ -10,11 +10,6 @@ # placed in /etc/init.d. ### END INIT INFO -# Author: Foo Bar -# -# Please remove the "Author" lines above and replace them -# with your own name if you copy and modify this script. - # Do NOT "set -e" # PATH should only include /usr/* if it runs after the mountnfs.sh script @@ -22,7 +17,7 @@ PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin DESC="MySensors Gateway" NAME=mysGateway DAEMON=%gateway_dir%/$NAME -DAEMON_ARGS="-d" +DAEMON_ARGS="-b" PIDFILE=/var/run/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME From 4175a5f42321771becd73ab9c57a9b5950bd6353 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Fri, 9 Sep 2016 14:02:24 -0300 Subject: [PATCH 074/167] Cleanup configure script --- configure | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/configure b/configure index 13d69fd16..b8375908b 100755 --- a/configure +++ b/configure @@ -17,10 +17,8 @@ Building options: --cpu-flags= CPU defining/optimizing flags to be used. [configure autodetected] --extra-cxxflags= Extra C flags passed to C/C++ compilation. [] --extra-ldflags= Extra C flags passed to linking. [] - --libname= Library name. [rf24] --cxx_compiler= C++ compiler [arm-linux-gnueabihf-g++][g++] --no-clean Don't clean previous build artifacts. - --rf24h-lib-dir RF24 library files directory. Installation options: --prefix= Installation prefix path. [/usr/local] @@ -39,7 +37,7 @@ MySensors options: Use commas instead of points. Example: 127,0,0,1 --my-port= The port to keep open on gateway mode. If gateway is set to mqtt, it sets the broker port. - --my-serial-port= Serial port. [/dev/ttyUSB0] + --my-serial-port= Serial port. [/dev/ttyACM0] --my-serial-baudrate= Serial baud rate. [115200] --my-serial-is-pty Set the serial port to be a pseudo terminal. Use this if you want to connect to a controller running on the same device. @@ -52,9 +50,9 @@ MySensors options: --my-mqtt-subscribe-topic-prefix= MQTT subscribe topic prefix. --my-radio=[none|nrf24] Radio type, set to none to disable radio feature. [rf24] - --my-rf24-channel=<0-125> RF channel for the sensor net, 0-125. + --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 level. [RF24_PA_MAX] --my-rf24-irq-pin= Pin number connected to nRF24L01 IRQ pin. For RaspberryPi use BCM numbering. --my-rx-message-buffer-size= @@ -229,9 +227,6 @@ for opt do --prefix=*) PREFIX="$optarg" ;; - --rf24h-lib-dir=*) - RF24H_LIB_DIR="$optarg" - ;; --gateway-dir=*) GATEWAY_DIR="$optarg" ;; @@ -331,7 +326,6 @@ if [[ ${gateway_type} == "ethernet" ]]; then elif [[ ${gateway_type} == "serial" ]]; then CXXFLAGS="-DMY_GATEWAY_SERIAL $CXXFLAGS" elif [[ ${gateway_type} == "mqtt" ]]; then - LDFLAGS="-lmosquitto $LDFLAGS" CXXFLAGS="-DMY_GATEWAY_LINUX -DMY_GATEWAY_MQTT_CLIENT $CXXFLAGS" fi From fab2112f9bf7846b53b6dedc5137303329b5dbb7 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Fri, 9 Sep 2016 19:21:19 -0300 Subject: [PATCH 075/167] Use mysensors built-in nrf24 library for RPi --- Makefile | 29 +- MyConfig.h | 4 +- MySensors.h | 10 +- configure | 6 +- core/MyHwLinuxGeneric.cpp | 6 + core/MyHwLinuxGeneric.h | 1 + core/MyMainLinux.cpp | 19 +- core/MyTransportNRF24.cpp | 6 +- drivers/Linux/Arduino.h | 11 +- drivers/Linux/compatibility.cpp | 2 +- drivers/Linux/{log.cpp => log.c} | 0 drivers/Linux/log.h | 8 + drivers/RF24/RF24.cpp | 53 +- drivers/RF24/RF24_Linux.cpp | 200 ---- drivers/RF24/RF24_Linux.h | 302 ------ drivers/RPi/SPI.cpp | 106 ++ drivers/RPi/SPI.h | 231 +++++ drivers/RPi/bcm2835.c | 1504 +++++++++++++++++++++++++++ drivers/RPi/bcm2835.h | 1648 ++++++++++++++++++++++++++++++ drivers/RPi/piHiPri.c | 48 + drivers/RPi/rpi_util.cpp | 330 ++++++ drivers/RPi/rpi_util.h | 71 ++ 22 files changed, 4051 insertions(+), 544 deletions(-) rename drivers/Linux/{log.cpp => log.c} (100%) delete mode 100644 drivers/RF24/RF24_Linux.cpp delete mode 100644 drivers/RF24/RF24_Linux.h create mode 100644 drivers/RPi/SPI.cpp create mode 100644 drivers/RPi/SPI.h create mode 100644 drivers/RPi/bcm2835.c create mode 100644 drivers/RPi/bcm2835.h create mode 100644 drivers/RPi/piHiPri.c create mode 100644 drivers/RPi/rpi_util.cpp create mode 100644 drivers/RPi/rpi_util.h diff --git a/Makefile b/Makefile index 159691922..3ee190c38 100644 --- a/Makefile +++ b/Makefile @@ -13,14 +13,22 @@ include $(CONFIG_FILE) GATEWAY_BIN=mysGateway GATEWAY=examples_linux/$(GATEWAY_BIN) -GATEWAY_SOURCES=$(wildcard drivers/Linux/*.cpp) examples_linux/mysGateway.cpp -GATEWAY_OBJECTS=$(patsubst %.cpp,%.o,$(GATEWAY_SOURCES)) -DEPS+=$(patsubst %.cpp,%.d,$(GATEWAY_SOURCES)) +GATEWAY_C_SOURCES=$(wildcard drivers/Linux/*.c) +GATEWAY_CPP_SOURCES=$(wildcard drivers/Linux/*.cpp) examples_linux/mysGateway.cpp +OBJECTS=$(patsubst %.c,%.o,$(GATEWAY_C_SOURCES)) $(patsubst %.cpp,%.o,$(GATEWAY_CPP_SOURCES)) + +DEPS+=$(patsubst %.c,%.d,$(GATEWAY_C_SOURCES)) $(patsubst %.cpp,%.d,$(GATEWAY_CPP_SOURCES)) CINCLUDE=-I. -I./core -I./drivers/Linux -ifneq ($(RF24H_LIB_DIR),) -CINCLUDE+=-I$(RF24H_LIB_DIR) +ifeq ($(SOC),$(filter $(SOC),BCM2835 BCM2836)) +RPI_C_SOURCES=$(wildcard drivers/RPi/*.c) +RPI_CPP_SOURCES=$(wildcard drivers/RPi/*.cpp) +OBJECTS+=$(patsubst %.c,%.o,$(RPI_C_SOURCES)) $(patsubst %.cpp,%.o,$(RPI_CPP_SOURCES)) + +DEPS+=$(patsubst %.c,%.d,$(RPI_C_SOURCES)) $(patsubst %.cpp,%.d,$(RPI_CPP_SOURCES)) + +CINCLUDE+=-I./drivers/RPi endif .PHONY: all gateway cleanconfig clean install uninstall force @@ -28,15 +36,18 @@ endif all: $(GATEWAY) # Gateway Build -$(GATEWAY): $(GATEWAY_OBJECTS) - $(CXX) $(LDFLAGS) -o $@ $(GATEWAY_OBJECTS) +$(GATEWAY): $(OBJECTS) + $(CXX) $(LDFLAGS) -o $@ $(OBJECTS) # Include all .d files -include $(DEPS) - + %.o: %.cpp $(CXX) $(CXXFLAGS) $(CINCLUDE) -MMD -c -o $@ $< +%.o: %.c + $(CC) $(CFLAGS) $(CINCLUDE) -MMD -c -o $@ $< + # clear configuration files cleanconfig: @echo "[Cleaning configuration]" @@ -45,7 +56,7 @@ cleanconfig: # clear build files clean: @echo "[Cleaning]" - rm -rf build $(GATEWAY_OBJECTS) $(GATEWAY) $(DEPS) + rm -rf build $(OBJECTS) $(GATEWAY) $(DEPS) $(CONFIG_FILE): @echo "[Running configure]" diff --git a/MyConfig.h b/MyConfig.h index dff0d6e76..10c32408e 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -410,7 +410,7 @@ #define MY_RF24_CE_PIN 4 #elif defined(ARDUINO_ARCH_SAMD) #define MY_RF24_CE_PIN 27 - #elif defined(__linux__) + #elif defined(LINUX_ARCH_RASPBERRYPI) #define MY_RF24_CE_PIN 22 #else #define MY_RF24_CE_PIN 9 @@ -426,7 +426,7 @@ #define MY_RF24_CS_PIN 15 #elif defined(ARDUINO_ARCH_SAMD) #define MY_RF24_CS_PIN 3 - #elif defined(__linux__) + #elif defined(LINUX_ARCH_RASPBERRYPI) #define MY_RF24_CS_PIN 24 #else #define MY_RF24_CS_PIN 10 diff --git a/MySensors.h b/MySensors.h index 2b7e82019..ad59f3f93 100644 --- a/MySensors.h +++ b/MySensors.h @@ -276,6 +276,10 @@ #include "drivers/AVR/DigitalIO/DigitalIO.h" #endif + #if defined(MY_RADIO_NRF24) && defined(__linux__) && !defined(LINUX_ARCH_RASPBERRYPI) + #error No support for nRF24 radio on this platform + #endif + #include "core/MyTransport.cpp" #if (defined(MY_RADIO_NRF24) && defined(MY_RADIO_RFM69)) || (defined(MY_RADIO_NRF24) && defined(MY_RS485)) || (defined(MY_RADIO_RFM69) && defined(MY_RS485)) #error Only one forward link driver can be activated @@ -284,11 +288,7 @@ #if defined(MY_RF24_ENABLE_ENCRYPTION) #include "drivers/AES/AES.cpp" #endif - #if defined(__linux__) - #include "drivers/RF24/RF24_Linux.cpp" - #else - #include "drivers/RF24/RF24.cpp" - #endif + #include "drivers/RF24/RF24.cpp" #include "core/MyTransportNRF24.cpp" #elif defined(MY_RS485) #include "drivers/AltSoftSerial/AltSoftSerial.cpp" diff --git a/configure b/configure index b8375908b..b2b2dc83b 100755 --- a/configure +++ b/configure @@ -54,7 +54,6 @@ MySensors options: --my-rf24-pa-level=[RF24_PA_MAX|RF24_PA_LOW] RF24 PA level. [RF24_PA_MAX] --my-rf24-irq-pin= Pin number connected to nRF24L01 IRQ pin. - For RaspberryPi use BCM numbering. --my-rx-message-buffer-size= Buffer size for incoming messages when using rf24 interrupts. [20] @@ -197,7 +196,7 @@ debug=enable gateway_type=ethernet radio_type=nrf24 -params="SOC CXXFLAGS LDFLAGS PREFIX CXX RF24H_LIB_DIR GATEWAY_DIR INIT_SYSTEM" +params="SOC CXXFLAGS LDFLAGS PREFIX CXX GATEWAY_DIR INIT_SYSTEM" for opt do if [ "$opt" = "-h" ] || [ "$opt" = "--help" ]; then @@ -312,6 +311,7 @@ if [ -z "${CPUFLAGS}" ]; then fi CXXFLAGS="$CPUFLAGS -Ofast -g -Wall -Wextra $CXXFLAGS" +CFLAGS="-Ofast -g -Wall -Wextra $CFLAGS" if [[ $TYPE == "RPi2" || $TYPE == "RPi3" || $REV == "0010" ]]; then CXXFLAGS+="-D__RPI_BPLUS" @@ -331,8 +331,6 @@ fi if [[ ${radio_type} == "nrf24" ]]; then CXXFLAGS="-DMY_RADIO_NRF24 $CXXFLAGS" - LDFLAGS="-lrf24-bcm $LDFLAGS" - RF24H_LIB_DIR=${PREFIX}/include/RF24 fi LDFLAGS="-pthread $LDFLAGS" diff --git a/core/MyHwLinuxGeneric.cpp b/core/MyHwLinuxGeneric.cpp index cc66f0544..ea5ddb824 100644 --- a/core/MyHwLinuxGeneric.cpp +++ b/core/MyHwLinuxGeneric.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include "log.h" static const char* CONFIG_FILE = MY_LINUX_CONFIG_FILE; @@ -124,6 +125,11 @@ void hwWriteConfig(int adr, uint8_t value) } } +void hwRandomNumberInit() +{ + randomSeed(time(NULL)); +} + // Not supported! int8_t hwSleep(unsigned long ms) { diff --git a/core/MyHwLinuxGeneric.h b/core/MyHwLinuxGeneric.h index eb5fee36d..067b93a06 100644 --- a/core/MyHwLinuxGeneric.h +++ b/core/MyHwLinuxGeneric.h @@ -44,6 +44,7 @@ void hwReadConfigBlock(void* buf, void* adr, size_t length); void hwWriteConfigBlock(void* buf, void* adr, size_t length); uint8_t hwReadConfig(int adr); void hwWriteConfig(int adr, uint8_t value); +void hwRandomNumberInit(); #ifdef MY_RF24_IRQ_PIN static pthread_mutex_t hw_mutex = PTHREAD_MUTEX_INITIALIZER; diff --git a/core/MyMainLinux.cpp b/core/MyMainLinux.cpp index a461184c5..56a2d47d6 100644 --- a/core/MyMainLinux.cpp +++ b/core/MyMainLinux.cpp @@ -72,6 +72,15 @@ static int daemonize(void) return 0; } +void print_usage() +{ + printf("Usage: mysGateway [options]\n\n" \ + "Options:\n" \ + " -h Display a short summary of all program options.\n" \ + " -d Enable debug.\n" \ + " -b Become a daemon.\n"); +} + int main(int argc, char *argv[]) { int opt, log_opts, debug = 0, foreground = 1; @@ -83,11 +92,7 @@ int main(int argc, char *argv[]) while ((opt = getopt(argc, argv, "hdb")) != -1) { switch (opt) { case 'h': - printf("Usage: mysGateway [options]\n\n" \ - "Options:\n" \ - "-h Display a short summary of all program options.\n" \ - "-d Enable debug.\n" \ - "-b Become a daemon.\n"); + print_usage(); exit(0); case 'd': debug = 1; @@ -95,11 +100,15 @@ int main(int argc, char *argv[]) case 'b': foreground = 0; break; + default: + print_usage(); + exit(0); } } log_opts = LOG_CONS; if (foreground && isatty(STDIN_FILENO)) { + // Also print syslog to stderror log_opts |= LOG_PERROR; } if (!debug) { diff --git a/core/MyTransportNRF24.cpp b/core/MyTransportNRF24.cpp index cdd3f2b1a..e458eeefc 100644 --- a/core/MyTransportNRF24.cpp +++ b/core/MyTransportNRF24.cpp @@ -20,11 +20,7 @@ #include "MyConfig.h" #include "MyTransport.h" -#ifdef __linux__ - #include "drivers/RF24/RF24_Linux.h" -#else - #include "drivers/RF24/RF24.h" -#endif +#include "drivers/RF24/RF24.h" #include "drivers/CircularBuffer/CircularBuffer.h" diff --git a/drivers/Linux/Arduino.h b/drivers/Linux/Arduino.h index e1dc088cb..41081d5a3 100644 --- a/drivers/Linux/Arduino.h +++ b/drivers/Linux/Arduino.h @@ -13,6 +13,11 @@ #include #include "stdlib_noniso.h" +#ifdef LINUX_ARCH_RASPBERRYPI + #include "rpi_util.h" + using namespace rpi_util; +#endif + #define PI 3.1415926535897932384626433832795 #define HALF_PI 1.5707963267948966192313216916398 #define TWO_PI 6.283185307179586476925286766559 @@ -39,6 +44,10 @@ #define GET_MACRO(_0, _1, _2, NAME, ...) NAME #define random(...) GET_MACRO(_0, ##__VA_ARGS__, randMinMax, randMax, rand)(__VA_ARGS__) +#ifndef delay + #define delay _delay_ms +#endif + using std::string; using std::min; using std::max; @@ -50,7 +59,7 @@ typedef string String; void yield(void); unsigned long millis(void); -void delay(unsigned int millis); +void _delay_ms(unsigned int millis); void randomSeed(unsigned long seed); long randMax(long howbig); long randMinMax(long howsmall, long howbig); diff --git a/drivers/Linux/compatibility.cpp b/drivers/Linux/compatibility.cpp index a0a0eb3f9..b0ceee114 100644 --- a/drivers/Linux/compatibility.cpp +++ b/drivers/Linux/compatibility.cpp @@ -21,7 +21,7 @@ unsigned long millis(void) return ((curTime.tv_sec - millis_at_start) * 1000) + (curTime.tv_usec / 1000); } -void delay(unsigned int millis) +void _delay_ms(unsigned int millis) { struct timespec sleeper; diff --git a/drivers/Linux/log.cpp b/drivers/Linux/log.c similarity index 100% rename from drivers/Linux/log.cpp rename to drivers/Linux/log.c diff --git a/drivers/Linux/log.h b/drivers/Linux/log.h index 791e4b999..5c93dcc68 100644 --- a/drivers/Linux/log.h +++ b/drivers/Linux/log.h @@ -4,7 +4,15 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + extern void mys_log_v(int level, const char *fmt, va_list args); extern void mys_log(int level, const char *fmt, ...) __attribute__((format(printf,2,3))); +#ifdef __cplusplus +} +#endif + #endif diff --git a/drivers/RF24/RF24.cpp b/drivers/RF24/RF24.cpp index bd84c5609..aea2bd702 100644 --- a/drivers/RF24/RF24.cpp +++ b/drivers/RF24/RF24.cpp @@ -29,8 +29,13 @@ LOCAL uint8_t MY_RF24_NODE_ADDRESS = AUTO; LOCAL RF24_receiveCallbackType RF24_receiveCallback = NULL; #endif +#ifdef LINUX_ARCH_RASPBERRYPI + 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 + LOCAL void RF24_csn(bool level) { - digitalWrite(MY_RF24_CS_PIN, level); + digitalWrite(MY_RF24_CS_PIN, level); } LOCAL void RF24_ce(bool level) { @@ -38,6 +43,7 @@ LOCAL void RF24_ce(bool level) { } LOCAL uint8_t RF24_spiMultiByteTransfer(uint8_t cmd, uint8_t* buf, uint8_t len, bool aReadMode) { + uint8_t status; uint8_t* current = buf; #if !defined(MY_SOFTSPI) _SPI.beginTransaction(SPISettings(MY_RF24_SPI_MAX_SPEED, MY_RF24_SPI_DATA_ORDER, MY_RF24_SPI_DATA_MODE)); @@ -45,13 +51,40 @@ LOCAL uint8_t RF24_spiMultiByteTransfer(uint8_t cmd, uint8_t* buf, uint8_t len, RF24_csn(LOW); // timing delayMicroseconds(10); - uint8_t status = _SPI.transfer( cmd ); - while ( len-- ) { - if (aReadMode) { - status = _SPI.transfer( NOP ); - if(buf != NULL) *current++ = status; - } else status = _SPI.transfer(*current++); - } + #ifdef LINUX_ARCH_RASPBERRYPI + uint8_t * prx = spi_rxbuff; + uint8_t * ptx = spi_txbuff; + uint8_t size = len + 1; // Add register value to transmit buffer + + *ptx++ = cmd; + while ( len-- ) { + if (aReadMode) { + *ptx++ = NOP ; + } else { + *ptx++ = *current++; + } + } + _SPI.transfernb( (char *) spi_txbuff, (char *) spi_rxbuff, size); + if (aReadMode) { + if (size == 2) { + status = *++prx; // result is 2nd byte of receive buffer + } else { + status = *prx++; // status is 1st byte of receive buffer + // decrement before to skip status byte + while (--size) { *buf++ = *prx++; } + } + } else { + status = *prx; // status is 1st byte of receive buffer + } + #else + status = _SPI.transfer( cmd ); + while ( len-- ) { + if (aReadMode) { + status = _SPI.transfer( NOP ); + if (buf != NULL) *current++ = status; + } else status = _SPI.transfer(*current++); + } + #endif RF24_csn(HIGH); #if !defined(MY_SOFTSPI) _SPI.endTransaction(); @@ -268,7 +301,7 @@ LOCAL void RF24_irqHandler( void ) // rx coming in during our stay will not be handled and will cause characters to be lost. // As a workaround we re-enable interrupts to allow nested processing of other interrupts. // Our own handler is disconnected to prevent recursive calling of this handler. - #ifdef MY_GATEWAY_SERIAL + #if defined(MY_GATEWAY_SERIAL) && !defined(__linux__) detachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN)); interrupts(); #endif @@ -283,7 +316,7 @@ LOCAL void RF24_irqHandler( void ) RF24_receiveCallback(); // Must call RF24_readMessage(), which will clear RX_DR IRQ ! } // Restore our interrupt handler. - #ifdef MY_GATEWAY_SERIAL + #if defined(MY_GATEWAY_SERIAL) && !defined(__linux__) noInterrupts(); attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING); #endif diff --git a/drivers/RF24/RF24_Linux.cpp b/drivers/RF24/RF24_Linux.cpp deleted file mode 100644 index 9b4c25a8d..000000000 --- a/drivers/RF24/RF24_Linux.cpp +++ /dev/null @@ -1,200 +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. - * - * This is a wrapper for maniacbug's RF24 library, copyright (C) 2011 J. Coliz - */ - -#include -#include "RF24_Linux.h" - -#ifdef MY_RX_MESSAGE_BUFFER_FEATURE - typedef void (*RF24_receiveCallbackType)(void); - - void (* RF24_receiveCallback)(void) = NULL; - - static pthread_mutex_t rf24_mutex = PTHREAD_MUTEX_INITIALIZER; -#endif - -static uint8_t MY_RF24_BASE_ADDR[MY_RF24_ADDR_WIDTH] = { MY_RF24_BASE_RADIO_ID }; -static uint8_t MY_RF24_NODE_ADDRESS = AUTO; - -RF24 _rf24(RF24_CE_PIN, RF24_CS_PIN, MY_RF24_SPI_MAX_SPEED); - -static void RF24_startListening(void) { - RF24_DEBUG(PSTR("start listening\n")); - - _rf24.startListening(); -} - -static void RF24_powerDown(void) { -#ifdef MY_RX_MESSAGE_BUFFER_FEATURE - pthread_mutex_lock(&rf24_mutex); -#endif - _rf24.powerDown(); -#ifdef MY_RX_MESSAGE_BUFFER_FEATURE - pthread_mutex_unlock(&rf24_mutex); -#endif -} - -static bool RF24_sendMessage( uint8_t recipient, const void* buf, uint8_t len ) { -#ifdef MY_RX_MESSAGE_BUFFER_FEATURE - pthread_mutex_lock(&rf24_mutex); -#endif - // Make sure radio has powered up - _rf24.powerUp(); - _rf24.stopListening(); - - RF24_DEBUG(PSTR("send message to %d, len=%d\n"), recipient,len); - - MY_RF24_BASE_ADDR[0] = recipient; - _rf24.openWritingPipe(MY_RF24_BASE_ADDR); - bool ok = _rf24.write(buf, len, recipient == BROADCAST_ADDRESS); - _rf24.startListening(); -#ifdef MY_RX_MESSAGE_BUFFER_FEATURE - pthread_mutex_unlock(&rf24_mutex); -#endif - return ok; -} - -static bool RF24_isDataAvailable() { -#ifdef MY_RX_MESSAGE_BUFFER_FEATURE - pthread_mutex_lock(&rf24_mutex); -#endif - uint8_t pipe_num = 255; - _rf24.available(&pipe_num); -#ifdef MY_RX_MESSAGE_BUFFER_FEATURE - pthread_mutex_unlock(&rf24_mutex); -#endif - return (pipe_num <= 5); -} - -static uint8_t RF24_readMessage( void* buf) { -#ifdef MY_RX_MESSAGE_BUFFER_FEATURE - pthread_mutex_lock(&rf24_mutex); -#endif - uint8_t len = _rf24.getDynamicPayloadSize(); - _rf24.read(buf, len); -#ifdef MY_RX_MESSAGE_BUFFER_FEATURE - pthread_mutex_unlock(&rf24_mutex); -#endif - return len; -} - -static void RF24_setNodeAddress(uint8_t address) { -#ifdef MY_RX_MESSAGE_BUFFER_FEATURE - pthread_mutex_lock(&rf24_mutex); -#endif - if (address != AUTO){ - MY_RF24_NODE_ADDRESS = address; - // enable node pipe - MY_RF24_BASE_ADDR[0] = MY_RF24_NODE_ADDRESS; - _rf24.openReadingPipe(NODE_PIPE, MY_RF24_BASE_ADDR); - // enable autoACK on node pipe - _rf24.setAutoAck(NODE_PIPE, true); - } -#ifdef MY_RX_MESSAGE_BUFFER_FEATURE - pthread_mutex_unlock(&rf24_mutex); -#endif -} - -static uint8_t RF24_getNodeID(void) { - return MY_RF24_NODE_ADDRESS; -} - -bool RF24_sanityCheck(void) { - bool ok = true; -#ifdef MY_RX_MESSAGE_BUFFER_FEATURE - pthread_mutex_lock(&rf24_mutex); -#endif - // detect HW defect ot interrupted SPI line, CE disconnect cannot be detected - if (_rf24.getPALevel() != MY_RF24_PA_LEVEL || _rf24.getDataRate() != MY_RF24_DATARATE || - _rf24.getChannel() != MY_RF24_CHANNEL) { - ok = false; - } -#ifdef MY_RX_MESSAGE_BUFFER_FEATURE - pthread_mutex_unlock(&rf24_mutex); -#endif - return ok; -} - -#ifdef MY_RX_MESSAGE_BUFFER_FEATURE -void RF24_irqHandler(void) { - if (RF24_receiveCallback) { - while (RF24_isDataAvailable()) { - RF24_receiveCallback(); - } - } else { - // clear RX interrupt - bool tx_ok,tx_fail,rx; - _rf24.whatHappened(tx_ok,tx_fail,rx); - } -} - -void RF24_registerReceiveCallback(RF24_receiveCallbackType cb) { - RF24_receiveCallback = cb; -} -#endif - -static bool RF24_initialize(void) { - // start up the radio library - _rf24.begin(); - // determine whether the hardware is an nRF24L01+ or not - if (!_rf24.isPVariant()) { - RF24_DEBUG(PSTR("radio hardware not compatible")); - return false; - } - // set CRC - _rf24.setCRCLength(RF24_CRC_16); - // set address width - _rf24.setAddressWidth(MY_RF24_ADDR_WIDTH); - // auto retransmit delay 1500us, auto retransmit count 15 - _rf24.setRetries(5, 15); - // channel - _rf24.setChannel(MY_RF24_CHANNEL); - // PA level - _rf24.setPALevel(MY_RF24_PA_LEVEL); - // data rate - _rf24.setDataRate(MY_RF24_DATARATE); - // sanity check - #if defined(MY_RF24_SANITY_CHECK) - if (!RF24_sanityCheck()) { - RF24_DEBUG(PSTR("RF24:Sanity check failed: configuration mismatch! Check wiring, replace module or non-P version\n")); - return false; - } - #endif - // enable Dynamic payload - _rf24.enableDynamicPayloads(); - // enable ACK payload - _rf24.enableAckPayload(); - // disable AA on all pipes, activate when node pipe set - _rf24.setAutoAck(false); - // all nodes listen to broadcast pipe (for FIND_PARENT_RESPONSE messages) - MY_RF24_BASE_ADDR[0] = BROADCAST_ADDRESS; - _rf24.openReadingPipe(BROADCAST_PIPE, MY_RF24_BASE_ADDR); - - //_rf24.printDetails(); - - #ifdef MY_RX_MESSAGE_BUFFER_FEATURE - // Mask all interrupts except the receive interrupt - _rf24.maskIRQ(1,1,0); - - attachInterrupt(MY_RF24_IRQ_PIN, INT_EDGE_FALLING, RF24_irqHandler); - #endif - - return true; -} diff --git a/drivers/RF24/RF24_Linux.h b/drivers/RF24/RF24_Linux.h deleted file mode 100644 index d1e00ac91..000000000 --- a/drivers/RF24/RF24_Linux.h +++ /dev/null @@ -1,302 +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. - * - */ - -#ifndef __RF24_LINUX_H__ -#define __RF24_LINUX_H__ - -// SPI settings -#if !defined(MY_RF24_SPI_MAX_SPEED) - #define MY_RF24_SPI_MAX_SPEED BCM2835_SPI_SPEED_8MHZ -#endif - -// verify RF24 IRQ defs -#if defined(MY_RX_MESSAGE_BUFFER_FEATURE) - #if !defined(MY_RF24_IRQ_PIN) - #error Message buffering feature requires MY_RF24_IRQ_PIN to be defined! - #endif - #ifndef SPI_HAS_TRANSACTION - #error RF24 IRQ usage requires transactional SPI support - #endif -#else - #ifdef MY_RX_MESSAGE_BUFFER_SIZE - #error Receive message buffering requires RF24 IRQ usage - #endif -#endif - -// pipes -#define BROADCAST_PIPE 1 -#define NODE_PIPE 2 - -// debug -#if defined(MY_DEBUG_VERBOSE_RF24) - #define RF24_DEBUG(x,...) debug(x, ##__VA_ARGS__) -#else - #define RF24_DEBUG(x,...) -#endif - -#ifdef LINUX_ARCH_RASPBERRYPI - // CE pin - #ifdef MY_RF24_CE_PIN - #ifdef __RPI_BPLUS - #if MY_RF24_CE_PIN == 3 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_03 - #elif MY_RF24_CE_PIN == 5 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_05 - #elif MY_RF24_CE_PIN == 7 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_07 - #elif MY_RF24_CE_PIN == 8 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_08 - #elif MY_RF24_CE_PIN == 10 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_10 - #elif MY_RF24_CE_PIN == 11 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_11 - #elif MY_RF24_CE_PIN == 12 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_12 - #elif MY_RF24_CE_PIN == 13 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_13 - #elif MY_RF24_CE_PIN == 15 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_15 - #elif MY_RF24_CE_PIN == 16 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_16 - #elif MY_RF24_CE_PIN == 18 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_18 - #elif MY_RF24_CE_PIN == 19 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_19 - #elif MY_RF24_CE_PIN == 21 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_21 - #elif MY_RF24_CE_PIN == 22 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_22 - #elif MY_RF24_CE_PIN == 23 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_23 - #elif MY_RF24_CE_PIN == 24 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_24 - #elif MY_RF24_CE_PIN == 26 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_26 - #elif MY_RF24_CE_PIN == 29 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_29 - #elif MY_RF24_CE_PIN == 31 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_31 - #elif MY_RF24_CE_PIN == 32 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_32 - #elif MY_RF24_CE_PIN == 33 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_33 - #elif MY_RF24_CE_PIN == 35 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_35 - #elif MY_RF24_CE_PIN == 36 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_36 - #elif MY_RF24_CE_PIN == 37 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_37 - #elif MY_RF24_CE_PIN == 38 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_38 - #elif MY_RF24_CE_PIN == 40 - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_40 - #else - #error invalid value for MY_RF24_CE_PIN - #endif - #else - #if MY_RF24_CE_PIN == 3 - #define RF24_CE_PIN RPI_V2_GPIO_P1_03 - #elif MY_RF24_CE_PIN == 5 - #define RF24_CE_PIN RPI_V2_GPIO_P1_05 - #elif MY_RF24_CE_PIN == 7 - #define RF24_CE_PIN RPI_V2_GPIO_P1_07 - #elif MY_RF24_CE_PIN == 8 - #define RF24_CE_PIN RPI_V2_GPIO_P1_08 - #elif MY_RF24_CE_PIN == 10 - #define RF24_CE_PIN RPI_V2_GPIO_P1_10 - #elif MY_RF24_CE_PIN == 11 - #define RF24_CE_PIN RPI_V2_GPIO_P1_11 - #elif MY_RF24_CE_PIN == 12 - #define RF24_CE_PIN RPI_V2_GPIO_P1_12 - #elif MY_RF24_CE_PIN == 13 - #define RF24_CE_PIN RPI_V2_GPIO_P1_13 - #elif MY_RF24_CE_PIN == 15 - #define RF24_CE_PIN RPI_V2_GPIO_P1_15 - #elif MY_RF24_CE_PIN == 16 - #define RF24_CE_PIN RPI_V2_GPIO_P1_16 - #elif MY_RF24_CE_PIN == 18 - #define RF24_CE_PIN RPI_V2_GPIO_P1_18 - #elif MY_RF24_CE_PIN == 19 - #define RF24_CE_PIN RPI_V2_GPIO_P1_19 - #elif MY_RF24_CE_PIN == 21 - #define RF24_CE_PIN RPI_V2_GPIO_P1_21 - #elif MY_RF24_CE_PIN == 22 - #define RF24_CE_PIN RPI_V2_GPIO_P1_22 - #elif MY_RF24_CE_PIN == 23 - #define RF24_CE_PIN RPI_V2_GPIO_P1_23 - #elif MY_RF24_CE_PIN == 24 - #define RF24_CE_PIN RPI_V2_GPIO_P1_24 - #elif MY_RF24_CE_PIN == 26 - #define RF24_CE_PIN RPI_V2_GPIO_P1_26 - #elif MY_RF24_CE_PIN == 29 - #define RF24_CE_PIN RPI_V2_GPIO_P1_29 - #elif MY_RF24_CE_PIN == 31 - #define RF24_CE_PIN RPI_V2_GPIO_P1_31 - #elif MY_RF24_CE_PIN == 32 - #define RF24_CE_PIN RPI_V2_GPIO_P1_32 - #elif MY_RF24_CE_PIN == 33 - #define RF24_CE_PIN RPI_V2_GPIO_P1_33 - #elif MY_RF24_CE_PIN == 35 - #define RF24_CE_PIN RPI_V2_GPIO_P1_35 - #elif MY_RF24_CE_PIN == 36 - #define RF24_CE_PIN RPI_V2_GPIO_P1_36 - #elif MY_RF24_CE_PIN == 37 - #define RF24_CE_PIN RPI_V2_GPIO_P1_37 - #elif MY_RF24_CE_PIN == 38 - #define RF24_CE_PIN RPI_V2_GPIO_P1_38 - #elif MY_RF24_CE_PIN == 40 - #define RF24_CE_PIN RPI_V2_GPIO_P1_40 - #else - #error invalid value for MY_RF24_CE_PIN - #endif - #endif - #else - #ifdef __RPI_BPLUS - #define RF24_CE_PIN RPI_BPLUS_GPIO_J8_22 - #else - #define RF24_CE_PIN RPI_V2_GPIO_P1_22 - #endif - #endif - - // CS pin - #ifdef MY_RF24_CS_PIN - #ifdef __RPI_BPLUS - #if MY_RF24_CS_PIN == 3 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_03 - #elif MY_RF24_CS_PIN == 5 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_05 - #elif MY_RF24_CS_PIN == 7 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_07 - #elif MY_RF24_CS_PIN == 8 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_08 - #elif MY_RF24_CS_PIN == 10 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_10 - #elif MY_RF24_CS_PIN == 11 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_11 - #elif MY_RF24_CS_PIN == 12 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_12 - #elif MY_RF24_CS_PIN == 13 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_13 - #elif MY_RF24_CS_PIN == 15 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_15 - #elif MY_RF24_CS_PIN == 16 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_16 - #elif MY_RF24_CS_PIN == 18 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_18 - #elif MY_RF24_CS_PIN == 19 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_19 - #elif MY_RF24_CS_PIN == 21 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_21 - #elif MY_RF24_CS_PIN == 22 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_22 - #elif MY_RF24_CS_PIN == 23 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_23 - #elif MY_RF24_CS_PIN == 24 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_24 - #elif MY_RF24_CS_PIN == 26 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_26 - #elif MY_RF24_CS_PIN == 29 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_29 - #elif MY_RF24_CS_PIN == 31 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_31 - #elif MY_RF24_CS_PIN == 32 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_32 - #elif MY_RF24_CS_PIN == 33 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_33 - #elif MY_RF24_CS_PIN == 35 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_35 - #elif MY_RF24_CS_PIN == 36 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_36 - #elif MY_RF24_CS_PIN == 37 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_37 - #elif MY_RF24_CS_PIN == 38 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_38 - #elif MY_RF24_CS_PIN == 40 - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_40 - #else - #error invalid value for MY_RF24_CS_PIN - #endif - #else - #if MY_RF24_CS_PIN == 3 - #define RF24_CS_PIN RPI_V2_GPIO_P1_03 - #elif MY_RF24_CS_PIN == 5 - #define RF24_CS_PIN RPI_V2_GPIO_P1_05 - #elif MY_RF24_CS_PIN == 7 - #define RF24_CS_PIN RPI_V2_GPIO_P1_07 - #elif MY_RF24_CS_PIN == 8 - #define RF24_CS_PIN RPI_V2_GPIO_P1_08 - #elif MY_RF24_CS_PIN == 10 - #define RF24_CS_PIN RPI_V2_GPIO_P1_10 - #elif MY_RF24_CS_PIN == 11 - #define RF24_CS_PIN RPI_V2_GPIO_P1_11 - #elif MY_RF24_CS_PIN == 12 - #define RF24_CS_PIN RPI_V2_GPIO_P1_12 - #elif MY_RF24_CS_PIN == 13 - #define RF24_CS_PIN RPI_V2_GPIO_P1_13 - #elif MY_RF24_CS_PIN == 15 - #define RF24_CS_PIN RPI_V2_GPIO_P1_15 - #elif MY_RF24_CS_PIN == 16 - #define RF24_CS_PIN RPI_V2_GPIO_P1_16 - #elif MY_RF24_CS_PIN == 18 - #define RF24_CS_PIN RPI_V2_GPIO_P1_18 - #elif MY_RF24_CS_PIN == 19 - #define RF24_CS_PIN RPI_V2_GPIO_P1_19 - #elif MY_RF24_CS_PIN == 21 - #define RF24_CS_PIN RPI_V2_GPIO_P1_21 - #elif MY_RF24_CS_PIN == 22 - #define RF24_CS_PIN RPI_V2_GPIO_P1_22 - #elif MY_RF24_CS_PIN == 23 - #define RF24_CS_PIN RPI_V2_GPIO_P1_23 - #elif MY_RF24_CS_PIN == 24 - #define RF24_CS_PIN BCM2835_SPI_CS0 - #elif MY_RF24_CS_PIN == 26 - #define RF24_CS_PIN BCM2835_SPI_CS1 - #elif MY_RF24_CS_PIN == 29 - #define RF24_CS_PIN RPI_V2_GPIO_P1_29 - #elif MY_RF24_CS_PIN == 31 - #define RF24_CS_PIN RPI_V2_GPIO_P1_31 - #elif MY_RF24_CS_PIN == 32 - #define RF24_CS_PIN RPI_V2_GPIO_P1_32 - #elif MY_RF24_CS_PIN == 33 - #define RF24_CS_PIN RPI_V2_GPIO_P1_33 - #elif MY_RF24_CS_PIN == 35 - #define RF24_CS_PIN RPI_V2_GPIO_P1_35 - #elif MY_RF24_CS_PIN == 36 - #define RF24_CS_PIN RPI_V2_GPIO_P1_36 - #elif MY_RF24_CS_PIN == 37 - #define RF24_CS_PIN RPI_V2_GPIO_P1_37 - #elif MY_RF24_CS_PIN == 38 - #define RF24_CS_PIN RPI_V2_GPIO_P1_38 - #elif MY_RF24_CS_PIN == 40 - #define RF24_CS_PIN RPI_V2_GPIO_P1_40 - #else - #error invalid value for MY_RF24_CS_PIN - #endif - #endif - #else - #ifdef __RPI_BPLUS - #define RF24_CS_PIN RPI_BPLUS_GPIO_J8_24 - #else - #define RF24_CS_PIN BCM2835_SPI_CS0 - #endif - #endif -#endif - -#endif diff --git a/drivers/RPi/SPI.cpp b/drivers/RPi/SPI.cpp new file mode 100644 index 000000000..8431daf4a --- /dev/null +++ b/drivers/RPi/SPI.cpp @@ -0,0 +1,106 @@ +/* + * 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 TMRh20 RF24 library, Copyright (c) 2015 Charles-Henri Hallard + */ + +#include "SPI.h" +#include +#include +#include "log.h" + +static pthread_mutex_t spiMutex = PTHREAD_MUTEX_INITIALIZER; + +// Declare a single default instance +SPIClass SPI = SPIClass(); + +uint8_t SPIClass::initialized = 0; + +SPIClass::SPIClass() { + if (!bcm2835_init()) { + mys_log(LOG_ERR, "Failed to initialized bcm2835.\n"); + exit(1); + } +} + +SPIClass::~SPIClass() {} + +uint8_t SPIClass::isInitialized() { + return initialized; +} + +void SPIClass::begin() { + if (!initialized) { + if (!bcm2835_spi_begin()) { + mys_log(LOG_ERR, "You need to be root to use SPI.\n"); + exit(1); + } + } + + initialized++; // reference count +} + +void SPIClass::end() { + if (initialized) { + initialized--; + } + + if (!initialized) { + // End the SPI + bcm2835_spi_end(); + } +} + +void SPIClass::setBitOrder(uint8_t bit_order) { + bcm2835_spi_setBitOrder(bit_order); +} + +void SPIClass::setDataMode(uint8_t data_mode) { + bcm2835_spi_setDataMode(data_mode); +} + +void SPIClass::setClockDivider(uint16_t divider) { + bcm2835_spi_setClockDivider(divider); +} + +void SPIClass::chipSelect(int csn_pin) { + if (csn_pin == RPI_GPIO_P1_26) csn_pin = BCM2835_SPI_CS1; + else if (csn_pin == RPI_GPIO_P1_24) csn_pin = BCM2835_SPI_CS0; + else csn_pin = BCM2835_SPI_CS0; + bcm2835_spi_chipSelect(csn_pin); + delayMicroseconds(5); +} + +void SPIClass::beginTransaction(SPISettings settings) { + pthread_mutex_lock(&spiMutex); + setBitOrder(settings.border); + setDataMode(settings.dmode); + setClockDivider(settings.cdiv); +} + +void SPIClass::endTransaction() { + pthread_mutex_unlock(&spiMutex); +} + +void SPIClass::usingInterrupt(uint8_t interruptNumber) { + (void)interruptNumber; +} + +void SPIClass::notUsingInterrupt(uint8_t interruptNumber) { + (void)interruptNumber; +} diff --git a/drivers/RPi/SPI.h b/drivers/RPi/SPI.h new file mode 100644 index 000000000..84a411740 --- /dev/null +++ b/drivers/RPi/SPI.h @@ -0,0 +1,231 @@ +/* + * 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 TMRh20 RF24 library, Copyright (c) 2015 Charles-Henri Hallard + */ +#ifndef _SPI_H_ +#define _SPI_H_ + +#include +#include "bcm2835.h" + +#define SPI_HAS_TRANSACTION + +// 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 + +// SPI Data mode +#define SPI_MODE0 BCM2835_SPI_MODE0 +#define SPI_MODE1 BCM2835_SPI_MODE1 +#define SPI_MODE2 BCM2835_SPI_MODE2 +#define SPI_MODE3 BCM2835_SPI_MODE3 + +/** + * SPISettings class + */ +class SPISettings { + +public: + /** + * @brief SPISettings constructor. + * + * Default clock speed is 8Mhz. + */ + SPISettings() { + init(BCM2835_SPI_CLOCK_DIVIDER_32, BCM2835_SPI_BIT_ORDER_MSBFIRST, BCM2835_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) { + 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; + } + + init(divider, bitOrder, dataMode); + } + + uint16_t cdiv; //!< @brief SPI clock divider. + uint8_t border; //!< @brief SPI bit order. + uint8_t dmode; //!< @brief SPI data mode. + +private: + /** + * @brief Initialized class members. + * + * @param divider SPI clock divider. + * @param bitOrder SPI bit order. + * @param dataMode SPI data mode. + */ + void init(uint16_t divider, uint8_t bitOrder, uint8_t dataMode) { + cdiv = divider; + border = bitOrder; + dmode = dataMode; + } + + friend class SPIClass; +}; + +/** + * SPIClass class + */ +class SPIClass { + +private: + static uint8_t initialized; //!< @brief SPI initialized flag. + +public: + /** + * @brief SPIClass constructor. + */ + SPIClass(); + /** + * @brief SPIClass destructor. + */ + virtual ~SPIClass(); + /** + * @brief Checks if SPI was initialized. + * + * @return 0 if wasn't initialized, else 1 or more. + */ + static uint8_t isInitialized(); + /** + * @brief Send and receive a byte. + * + * @param data to send. + * @return byte received. + */ + inline static uint8_t transfer(uint8_t data); + /** + * @brief Send and receive a number of bytes. + * + * @param tbuf Sending buffer. + * @param rbuf Receive buffer. + * @param len Buffer length. + */ + inline static void transfernb(char* tbuf, char* rbuf, uint32_t len); + /** + * @brief Send and receive a number of bytes. + * + * @param buf Buffer to read from and write to. + * @param len Buffer length. + */ + inline static void transfern(char* buf, uint32_t len); + /** + * @brief Start SPI operations. + */ + static void begin(); + /** + * @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_pin Specifies the CS pin. + */ + static void chipSelect(int csn_pin); + /** + * @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); +}; + +uint8_t SPIClass::transfer(uint8_t data) { + return bcm2835_spi_transfer(data); +} + +void SPIClass::transfernb(char* tbuf, char* rbuf, uint32_t len) { + bcm2835_spi_transfernb( tbuf, rbuf, len); +} + +void SPIClass::transfern(char* buf, uint32_t len) { + transfernb(buf, buf, len); +} + +extern SPIClass SPI; + +#endif diff --git a/drivers/RPi/bcm2835.c b/drivers/RPi/bcm2835.c new file mode 100644 index 000000000..84a0f0de2 --- /dev/null +++ b/drivers/RPi/bcm2835.c @@ -0,0 +1,1504 @@ +/* bcm2835.c +// C and C++ support for Broadcom BCM 2835 as used in Raspberry Pi +// http://elinux.org/RPi_Low-level_peripherals +// http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf +// +// Author: Mike McCauley +// Copyright (C) 2011-2013 Mike McCauley +// $Id: bcm2835.c,v 1.23 2015/03/31 04:55:41 mikem Exp mikem $ +// +// Modified September 2016 by Marcelo Aquino +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "log.h" + +#define BCK2835_LIBRARY_BUILD +#include "bcm2835.h" + +/* This define enables a little test program (by default a blinking output on pin RPI_GPIO_PIN_11) +// You can do some safe, non-destructive testing on any platform with: +// gcc bcm2835.c -D BCM2835_TEST +// ./a.out +*/ +/*#define BCM2835_TEST*/ + +/* Uncommenting this define compiles alternative I2C code for the version 1 RPi +// The P1 header I2C pins are connected to SDA0 and SCL0 on V1. +// By default I2C code is generated for the V2 RPi which has SDA1 and SCL1 connected. +*/ +/* #define I2C_V1*/ + +/* Physical address and size of the peripherals block +// May be overridden on RPi2 +*/ +uint32_t *bcm2835_peripherals_base = (uint32_t *)BCM2835_PERI_BASE; +uint32_t bcm2835_peripherals_size = BCM2835_PERI_SIZE; + +/* Virtual memory address of the mapped peripherals block + */ +uint32_t *bcm2835_peripherals = (uint32_t *)MAP_FAILED; + +/* And the register bases within the peripherals block + */ +volatile uint32_t *bcm2835_gpio = (uint32_t *)MAP_FAILED; +volatile uint32_t *bcm2835_pwm = (uint32_t *)MAP_FAILED; +volatile uint32_t *bcm2835_clk = (uint32_t *)MAP_FAILED; +volatile uint32_t *bcm2835_pads = (uint32_t *)MAP_FAILED; +volatile uint32_t *bcm2835_spi0 = (uint32_t *)MAP_FAILED; +volatile uint32_t *bcm2835_bsc0 = (uint32_t *)MAP_FAILED; +volatile uint32_t *bcm2835_bsc1 = (uint32_t *)MAP_FAILED; +volatile uint32_t *bcm2835_st = (uint32_t *)MAP_FAILED; + + +/* This variable allows us to test on hardware other than RPi. +// It prevents access to the kernel memory, and does not do any peripheral access +// Instead it prints out what it _would_ do if debug were 0 +*/ +static uint8_t debug = 0; + +/* I2C The time needed to transmit one byte. In microseconds. + */ +static int i2c_byte_wait_us = 0; + +/* +// Low level register access functions +*/ + +/* Function to return the pointers to the hardware register bases */ +uint32_t* bcm2835_regbase(uint8_t regbase) +{ + switch (regbase) + { + case BCM2835_REGBASE_ST: + return (uint32_t *)bcm2835_st; + case BCM2835_REGBASE_GPIO: + return (uint32_t *)bcm2835_gpio; + case BCM2835_REGBASE_PWM: + return (uint32_t *)bcm2835_pwm; + case BCM2835_REGBASE_CLK: + return (uint32_t *)bcm2835_clk; + case BCM2835_REGBASE_PADS: + return (uint32_t *)bcm2835_pads; + case BCM2835_REGBASE_SPI0: + return (uint32_t *)bcm2835_spi0; + case BCM2835_REGBASE_BSC0: + return (uint32_t *)bcm2835_bsc0; + case BCM2835_REGBASE_BSC1: + return (uint32_t *)bcm2835_st; + } + return (uint32_t *)MAP_FAILED; +} + +void bcm2835_set_debug(uint8_t d) +{ + debug = d; +} + +unsigned int bcm2835_version(void) +{ + return BCM2835_VERSION; +} + +/* Read with memory barriers from peripheral + * + */ +uint32_t bcm2835_peri_read(volatile uint32_t* paddr) +{ + uint32_t ret; + if (debug) + { + printf("bcm2835_peri_read paddr %08X\n", (unsigned) paddr); + return 0; + } + else + { + __sync_synchronize(); + ret = *paddr; + __sync_synchronize(); + return ret; + } +} + +/* read from peripheral without the read barrier + * This can only be used if more reads to THE SAME peripheral + * will follow. The sequence must terminate with memory barrier + * before any read or write to another peripheral can occur. + * The MB can be explicit, or one of the barrier read/write calls. + */ +uint32_t bcm2835_peri_read_nb(volatile uint32_t* paddr) +{ + if (debug) + { + printf("bcm2835_peri_read_nb paddr %08X\n", (unsigned) paddr); + return 0; + } + else + { + return *paddr; + } +} + +/* Write with memory barriers to peripheral + */ + +void bcm2835_peri_write(volatile uint32_t* paddr, uint32_t value) +{ + if (debug) + { + printf("bcm2835_peri_write paddr %08X, value %08X\n", (unsigned) paddr, value); + } + else + { + __sync_synchronize(); + *paddr = value; + __sync_synchronize(); + } +} + +/* write to peripheral without the write barrier */ +void bcm2835_peri_write_nb(volatile uint32_t* paddr, uint32_t value) +{ + if (debug) + { + printf("bcm2835_peri_write_nb paddr %08X, value %08X\n", + (unsigned) paddr, value); + } + else + { + *paddr = value; + } +} + +/* Set/clear only the bits in value covered by the mask + * This is not atomic - can be interrupted. + */ +void bcm2835_peri_set_bits(volatile uint32_t* paddr, uint32_t value, uint32_t mask) +{ + uint32_t v = bcm2835_peri_read(paddr); + v = (v & ~mask) | (value & mask); + bcm2835_peri_write(paddr, v); +} + +/* +// Low level convenience functions +*/ + +/* Function select +// pin is a BCM2835 GPIO pin number NOT RPi pin number +// There are 6 control registers, each control the functions of a block +// of 10 pins. +// Each control register has 10 sets of 3 bits per GPIO pin: +// +// 000 = GPIO Pin X is an input +// 001 = GPIO Pin X is an output +// 100 = GPIO Pin X takes alternate function 0 +// 101 = GPIO Pin X takes alternate function 1 +// 110 = GPIO Pin X takes alternate function 2 +// 111 = GPIO Pin X takes alternate function 3 +// 011 = GPIO Pin X takes alternate function 4 +// 010 = GPIO Pin X takes alternate function 5 +// +// So the 3 bits for port X are: +// X / 10 + ((X % 10) * 3) +*/ +void bcm2835_gpio_fsel(uint8_t pin, uint8_t mode) +{ + /* Function selects are 10 pins per 32 bit word, 3 bits per pin */ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPFSEL0/4 + (pin/10); + uint8_t shift = (pin % 10) * 3; + uint32_t mask = BCM2835_GPIO_FSEL_MASK << shift; + uint32_t value = mode << shift; + bcm2835_peri_set_bits(paddr, value, mask); +} + +/* Set output pin */ +void bcm2835_gpio_set(uint8_t pin) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPSET0/4 + pin/32; + uint8_t shift = pin % 32; + bcm2835_peri_write(paddr, 1 << shift); +} + +/* Clear output pin */ +void bcm2835_gpio_clr(uint8_t pin) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPCLR0/4 + pin/32; + uint8_t shift = pin % 32; + bcm2835_peri_write(paddr, 1 << shift); +} + +/* Set all output pins in the mask */ +void bcm2835_gpio_set_multi(uint32_t mask) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPSET0/4; + bcm2835_peri_write(paddr, mask); +} + +/* Clear all output pins in the mask */ +void bcm2835_gpio_clr_multi(uint32_t mask) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPCLR0/4; + bcm2835_peri_write(paddr, mask); +} + +/* Read input pin */ +uint8_t bcm2835_gpio_lev(uint8_t pin) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEV0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = bcm2835_peri_read(paddr); + return (value & (1 << shift)) ? HIGH : LOW; +} + +/* See if an event detection bit is set +// Sigh cant support interrupts yet +*/ +uint8_t bcm2835_gpio_eds(uint8_t pin) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = bcm2835_peri_read(paddr); + return (value & (1 << shift)) ? HIGH : LOW; +} + +uint32_t bcm2835_gpio_eds_multi(uint32_t mask) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4; + uint32_t value = bcm2835_peri_read(paddr); + return (value & mask); +} + +/* Write a 1 to clear the bit in EDS */ +void bcm2835_gpio_set_eds(uint8_t pin) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_write(paddr, value); +} + +void bcm2835_gpio_set_eds_multi(uint32_t mask) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4; + bcm2835_peri_write(paddr, mask); +} + +/* Rising edge detect enable */ +void bcm2835_gpio_ren(uint8_t pin) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPREN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, value, value); +} +void bcm2835_gpio_clr_ren(uint8_t pin) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPREN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, 0, value); +} + +/* Falling edge detect enable */ +void bcm2835_gpio_fen(uint8_t pin) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPFEN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, value, value); +} +void bcm2835_gpio_clr_fen(uint8_t pin) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPFEN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, 0, value); +} + +/* High detect enable */ +void bcm2835_gpio_hen(uint8_t pin) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPHEN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, value, value); +} +void bcm2835_gpio_clr_hen(uint8_t pin) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPHEN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, 0, value); +} + +/* Low detect enable */ +void bcm2835_gpio_len(uint8_t pin) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, value, value); +} +void bcm2835_gpio_clr_len(uint8_t pin) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, 0, value); +} + +/* Async rising edge detect enable */ +void bcm2835_gpio_aren(uint8_t pin) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAREN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, value, value); +} +void bcm2835_gpio_clr_aren(uint8_t pin) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAREN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, 0, value); +} + +/* Async falling edge detect enable */ +void bcm2835_gpio_afen(uint8_t pin) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAFEN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, value, value); +} +void bcm2835_gpio_clr_afen(uint8_t pin) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAFEN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, 0, value); +} + +/* Set pullup/down */ +void bcm2835_gpio_pud(uint8_t pud) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUD/4; + bcm2835_peri_write(paddr, pud); +} + +/* Pullup/down clock +// Clocks the value of pud into the GPIO pin +*/ +void bcm2835_gpio_pudclk(uint8_t pin, uint8_t on) +{ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUDCLK0/4 + pin/32; + uint8_t shift = pin % 32; + bcm2835_peri_write(paddr, (on ? 1 : 0) << shift); +} + +/* Read GPIO pad behaviour for groups of GPIOs */ +uint32_t bcm2835_gpio_pad(uint8_t group) +{ + if (bcm2835_pads == MAP_FAILED) { + return 0; + } + + volatile uint32_t* paddr = bcm2835_pads + BCM2835_PADS_GPIO_0_27/4 + group; + return bcm2835_peri_read(paddr); +} + +/* Set GPIO pad behaviour for groups of GPIOs +// powerup value for all pads is +// BCM2835_PAD_SLEW_RATE_UNLIMITED | BCM2835_PAD_HYSTERESIS_ENABLED | BCM2835_PAD_DRIVE_8mA +*/ +void bcm2835_gpio_set_pad(uint8_t group, uint32_t control) +{ + if (bcm2835_pads == MAP_FAILED) { + return; + } + + volatile uint32_t* paddr = bcm2835_pads + BCM2835_PADS_GPIO_0_27/4 + group; + bcm2835_peri_write(paddr, control | BCM2835_PAD_PASSWRD); +} + +/* Some convenient arduino-like functions +// milliseconds +*/ +void bcm2835_delay(unsigned int millis) +{ + struct timespec sleeper; + + sleeper.tv_sec = (time_t)(millis / 1000); + sleeper.tv_nsec = (long)(millis % 1000) * 1000000; + nanosleep(&sleeper, NULL); +} + +/* microseconds */ +void bcm2835_delayMicroseconds(uint64_t micros) +{ + struct timespec t1; + uint64_t start; + + if (debug) + { + /* Cant access sytem timers in debug mode */ + printf("bcm2835_delayMicroseconds %lld\n", micros); + return; + } + + /* Calling nanosleep() takes at least 100-200 us, so use it for + // long waits and use a busy wait on the System Timer for the rest. + */ + start = bcm2835_st_read(); + + if (micros > 450) + { + t1.tv_sec = 0; + t1.tv_nsec = 1000 * (long)(micros - 200); + nanosleep(&t1, NULL); + } + + bcm2835_st_delay(start, micros); +} + +/* +// Higher level convenience functions +*/ + +/* Set the state of an output */ +void bcm2835_gpio_write(uint8_t pin, uint8_t on) +{ + if (on) + bcm2835_gpio_set(pin); + else + bcm2835_gpio_clr(pin); +} + +/* Set the state of a all 32 outputs in the mask to on or off */ +void bcm2835_gpio_write_multi(uint32_t mask, uint8_t on) +{ + if (on) + bcm2835_gpio_set_multi(mask); + else + bcm2835_gpio_clr_multi(mask); +} + +/* Set the state of a all 32 outputs in the mask to the values in value */ +void bcm2835_gpio_write_mask(uint32_t value, uint32_t mask) +{ + bcm2835_gpio_set_multi(value & mask); + bcm2835_gpio_clr_multi((~value) & mask); +} + +/* Set the pullup/down resistor for a pin +// +// The GPIO Pull-up/down Clock Registers control the actuation of internal pull-downs on +// the respective GPIO pins. These registers must be used in conjunction with the GPPUD +// register to effect GPIO Pull-up/down changes. The following sequence of events is +// required: +// 1. Write to GPPUD to set the required control signal (i.e. Pull-up or Pull-Down or neither +// to remove the current Pull-up/down) +// 2. Wait 150 cycles ? this provides the required set-up time for the control signal +// 3. Write to GPPUDCLK0/1 to clock the control signal into the GPIO pads you wish to +// modify ? NOTE only the pads which receive a clock will be modified, all others will +// retain their previous state. +// 4. Wait 150 cycles ? this provides the required hold time for the control signal +// 5. Write to GPPUD to remove the control signal +// 6. Write to GPPUDCLK0/1 to remove the clock +// +// RPi has P1-03 and P1-05 with 1k8 pullup resistor +*/ +void bcm2835_gpio_set_pud(uint8_t pin, uint8_t pud) +{ + bcm2835_gpio_pud(pud); + delayMicroseconds(10); + bcm2835_gpio_pudclk(pin, 1); + delayMicroseconds(10); + bcm2835_gpio_pud(BCM2835_GPIO_PUD_OFF); + bcm2835_gpio_pudclk(pin, 0); +} + +int bcm2835_spi_begin(void) +{ + volatile uint32_t* paddr; + + if (bcm2835_spi0 == MAP_FAILED) + return 0; /* bcm2835_init() failed, or not root */ + + /* Set the SPI0 pins to the Alt 0 function to enable SPI0 access on them */ + bcm2835_gpio_fsel(RPI_GPIO_P1_26, BCM2835_GPIO_FSEL_ALT0); /* CE1 */ + bcm2835_gpio_fsel(RPI_GPIO_P1_24, BCM2835_GPIO_FSEL_ALT0); /* CE0 */ + bcm2835_gpio_fsel(RPI_GPIO_P1_21, BCM2835_GPIO_FSEL_ALT0); /* MISO */ + bcm2835_gpio_fsel(RPI_GPIO_P1_19, BCM2835_GPIO_FSEL_ALT0); /* MOSI */ + bcm2835_gpio_fsel(RPI_GPIO_P1_23, BCM2835_GPIO_FSEL_ALT0); /* CLK */ + + /* Set the SPI CS register to the some sensible defaults */ + paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; + bcm2835_peri_write(paddr, 0); /* All 0s */ + + /* Clear TX and RX fifos */ + bcm2835_peri_write_nb(paddr, BCM2835_SPI0_CS_CLEAR); + + return 1; // OK +} + +void bcm2835_spi_end(void) +{ + /* Set all the SPI0 pins back to input */ + bcm2835_gpio_fsel(RPI_GPIO_P1_26, BCM2835_GPIO_FSEL_INPT); /* CE1 */ + bcm2835_gpio_fsel(RPI_GPIO_P1_24, BCM2835_GPIO_FSEL_INPT); /* CE0 */ + bcm2835_gpio_fsel(RPI_GPIO_P1_21, BCM2835_GPIO_FSEL_INPT); /* MISO */ + bcm2835_gpio_fsel(RPI_GPIO_P1_19, BCM2835_GPIO_FSEL_INPT); /* MOSI */ + bcm2835_gpio_fsel(RPI_GPIO_P1_23, BCM2835_GPIO_FSEL_INPT); /* CLK */ +} + +void bcm2835_spi_setBitOrder(uint8_t __attribute__((unused)) order) +{ + /* BCM2835_SPI_BIT_ORDER_MSBFIRST is the only one supported by SPI0 */ +} + +/* defaults to 0, which means a divider of 65536. +// The divisor must be a power of 2. Odd numbers +// rounded down. The maximum SPI clock rate is +// of the APB clock +*/ +void bcm2835_spi_setClockDivider(uint16_t divider) +{ + volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CLK/4; + bcm2835_peri_write(paddr, divider); +} + +void bcm2835_spi_setDataMode(uint8_t mode) +{ + volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; + /* Mask in the CPO and CPHA bits of CS */ + bcm2835_peri_set_bits(paddr, mode << 2, BCM2835_SPI0_CS_CPOL | BCM2835_SPI0_CS_CPHA); +} + +/* Writes (and reads) a single byte to SPI */ +uint8_t bcm2835_spi_transfer(uint8_t value) +{ + volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; + volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; + uint32_t ret; + + /* This is Polled transfer as per section 10.6.1 + // BUG ALERT: what happens if we get interupted in this section, and someone else + // accesses a different peripheral? + // Clear TX and RX fifos + */ + bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); + + /* Set TA = 1 */ + bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); + + /* Maybe wait for TXD */ + while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD)) + ; + + /* Write to FIFO, no barrier */ + bcm2835_peri_write_nb(fifo, value); + + /* Wait for DONE to be set */ + while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) + ; + + /* Read any byte that was sent back by the slave while we sere sending to it */ + ret = bcm2835_peri_read_nb(fifo); + + /* Set TA = 0, and also set the barrier */ + bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); + + return ret; +} + +/* Writes (and reads) an number of bytes to SPI */ +void bcm2835_spi_transfernb(char* tbuf, char* rbuf, uint32_t len) +{ + volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; + volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; + uint32_t TXCnt=0; + uint32_t RXCnt=0; + + /* This is Polled transfer as per section 10.6.1 + // BUG ALERT: what happens if we get interupted in this section, and someone else + // accesses a different peripheral? + */ + + /* Clear TX and RX fifos */ + bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); + + /* Set TA = 1 */ + bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); + + /* Use the FIFO's to reduce the interbyte times */ + while((TXCnt < len)||(RXCnt < len)) + { + /* TX fifo not full, so add some more bytes */ + while(((bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD))&&(TXCnt < len )) + { + bcm2835_peri_write_nb(fifo, tbuf[TXCnt]); + TXCnt++; + } + /* Rx fifo not empty, so get the next received bytes */ + while(((bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD))&&( RXCnt < len )) + { + rbuf[RXCnt] = bcm2835_peri_read_nb(fifo); + RXCnt++; + } + } + /* Wait for DONE to be set */ + while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) + ; + + /* Set TA = 0, and also set the barrier */ + bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); +} + +/* Writes an number of bytes to SPI */ +void bcm2835_spi_writenb(char* tbuf, uint32_t len) +{ + volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; + volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; + uint32_t i; + + /* This is Polled transfer as per section 10.6.1 + // BUG ALERT: what happens if we get interupted in this section, and someone else + // accesses a different peripheral? + // Answer: an ISR is required to issue the required memory barriers. + */ + + /* Clear TX and RX fifos */ + bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); + + /* Set TA = 1 */ + bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); + + for (i = 0; i < len; i++) + { + /* Maybe wait for TXD */ + while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD)) + ; + + /* Write to FIFO, no barrier */ + bcm2835_peri_write_nb(fifo, tbuf[i]); + + /* Read from FIFO to prevent stalling */ + while (bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD) + (void) bcm2835_peri_read_nb(fifo); + } + + /* Wait for DONE to be set */ + while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) { + while (bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD) + (void) bcm2835_peri_read_nb(fifo); + }; + + /* Set TA = 0, and also set the barrier */ + bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); +} + +/* Writes (and reads) an number of bytes to SPI +// Read bytes are copied over onto the transmit buffer +*/ +void bcm2835_spi_transfern(char* buf, uint32_t len) +{ + bcm2835_spi_transfernb(buf, buf, len); +} + +void bcm2835_spi_chipSelect(uint8_t cs) +{ + volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; + /* Mask in the CS bits of CS */ + bcm2835_peri_set_bits(paddr, cs, BCM2835_SPI0_CS_CS); +} + +void bcm2835_spi_setChipSelectPolarity(uint8_t cs, uint8_t active) +{ + volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; + uint8_t shift = 21 + cs; + /* Mask in the appropriate CSPOLn bit */ + bcm2835_peri_set_bits(paddr, active << shift, 1 << shift); +} + +int bcm2835_i2c_begin(void) +{ + uint16_t cdiv; + + if ( bcm2835_bsc0 == MAP_FAILED + || bcm2835_bsc1 == MAP_FAILED) + return 0; /* bcm2835_init() failed, or not root */ + +#ifdef I2C_V1 + volatile uint32_t* paddr = bcm2835_bsc0 + BCM2835_BSC_DIV/4; + /* Set the I2C/BSC0 pins to the Alt 0 function to enable I2C access on them */ + bcm2835_gpio_fsel(RPI_GPIO_P1_03, BCM2835_GPIO_FSEL_ALT0); /* SDA */ + bcm2835_gpio_fsel(RPI_GPIO_P1_05, BCM2835_GPIO_FSEL_ALT0); /* SCL */ +#else + volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_DIV/4; + /* Set the I2C/BSC1 pins to the Alt 0 function to enable I2C access on them */ + bcm2835_gpio_fsel(RPI_V2_GPIO_P1_03, BCM2835_GPIO_FSEL_ALT0); /* SDA */ + bcm2835_gpio_fsel(RPI_V2_GPIO_P1_05, BCM2835_GPIO_FSEL_ALT0); /* SCL */ +#endif + + /* Read the clock divider register */ + cdiv = bcm2835_peri_read(paddr); + /* Calculate time for transmitting one byte + // 1000000 = micros seconds in a second + // 9 = Clocks per byte : 8 bits + ACK + */ + i2c_byte_wait_us = ((float)cdiv / BCM2835_CORE_CLK_HZ) * 1000000 * 9; + + return 1; +} + +void bcm2835_i2c_end(void) +{ +#ifdef I2C_V1 + /* Set all the I2C/BSC0 pins back to input */ + bcm2835_gpio_fsel(RPI_GPIO_P1_03, BCM2835_GPIO_FSEL_INPT); /* SDA */ + bcm2835_gpio_fsel(RPI_GPIO_P1_05, BCM2835_GPIO_FSEL_INPT); /* SCL */ +#else + /* Set all the I2C/BSC1 pins back to input */ + bcm2835_gpio_fsel(RPI_V2_GPIO_P1_03, BCM2835_GPIO_FSEL_INPT); /* SDA */ + bcm2835_gpio_fsel(RPI_V2_GPIO_P1_05, BCM2835_GPIO_FSEL_INPT); /* SCL */ +#endif +} + +void bcm2835_i2c_setSlaveAddress(uint8_t addr) +{ + /* Set I2C Device Address */ +#ifdef I2C_V1 + volatile uint32_t* paddr = bcm2835_bsc0 + BCM2835_BSC_A/4; +#else + volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_A/4; +#endif + bcm2835_peri_write(paddr, addr); +} + +/* defaults to 0x5dc, should result in a 166.666 kHz I2C clock frequency. +// The divisor must be a power of 2. Odd numbers +// rounded down. +*/ +void bcm2835_i2c_setClockDivider(uint16_t divider) +{ +#ifdef I2C_V1 + volatile uint32_t* paddr = bcm2835_bsc0 + BCM2835_BSC_DIV/4; +#else + volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_DIV/4; +#endif + bcm2835_peri_write(paddr, divider); + /* Calculate time for transmitting one byte + // 1000000 = micros seconds in a second + // 9 = Clocks per byte : 8 bits + ACK + */ + i2c_byte_wait_us = ((float)divider / BCM2835_CORE_CLK_HZ) * 1000000 * 9; +} + +/* set I2C clock divider by means of a baudrate number */ +void bcm2835_i2c_set_baudrate(uint32_t baudrate) +{ + uint32_t divider; + /* use 0xFFFE mask to limit a max value and round down any odd number */ + divider = (BCM2835_CORE_CLK_HZ / baudrate) & 0xFFFE; + bcm2835_i2c_setClockDivider( (uint16_t)divider ); +} + +/* Writes an number of bytes to I2C */ +uint8_t bcm2835_i2c_write(const char * buf, uint32_t len) +{ +#ifdef I2C_V1 + volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; + volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; + volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; + volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; +#else + volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; + volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; + volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; + volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; +#endif + + uint32_t remaining = len; + uint32_t i = 0; + uint8_t reason = BCM2835_I2C_REASON_OK; + + /* Clear FIFO */ + bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); + /* Clear Status */ + bcm2835_peri_write(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); + /* Set Data Length */ + bcm2835_peri_write(dlen, len); + /* pre populate FIFO with max buffer */ + while( remaining && ( i < BCM2835_BSC_FIFO_SIZE ) ) + { + bcm2835_peri_write_nb(fifo, buf[i]); + i++; + remaining--; + } + + /* Enable device and start transfer */ + bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST); + + /* Transfer is over when BCM2835_BSC_S_DONE */ + while(!(bcm2835_peri_read(status) & BCM2835_BSC_S_DONE )) + { + while ( remaining && (bcm2835_peri_read(status) & BCM2835_BSC_S_TXD )) + { + /* Write to FIFO */ + bcm2835_peri_write(fifo, buf[i]); + i++; + remaining--; + } + } + + /* Received a NACK */ + if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) + { + reason = BCM2835_I2C_REASON_ERROR_NACK; + } + + /* Received Clock Stretch Timeout */ + else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) + { + reason = BCM2835_I2C_REASON_ERROR_CLKT; + } + + /* Not all data is sent */ + else if (remaining) + { + reason = BCM2835_I2C_REASON_ERROR_DATA; + } + + bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); + + return reason; +} + +/* Read an number of bytes from I2C */ +uint8_t bcm2835_i2c_read(char* buf, uint32_t len) +{ +#ifdef I2C_V1 + volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; + volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; + volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; + volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; +#else + volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; + volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; + volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; + volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; +#endif + + uint32_t remaining = len; + uint32_t i = 0; + uint8_t reason = BCM2835_I2C_REASON_OK; + + /* Clear FIFO */ + bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); + /* Clear Status */ + bcm2835_peri_write_nb(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); + /* Set Data Length */ + bcm2835_peri_write_nb(dlen, len); + /* Start read */ + bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ); + + /* wait for transfer to complete */ + while (!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE)) + { + /* we must empty the FIFO as it is populated and not use any delay */ + while (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD) + { + /* Read from FIFO, no barrier */ + buf[i] = bcm2835_peri_read_nb(fifo); + i++; + remaining--; + } + } + + /* transfer has finished - grab any remaining stuff in FIFO */ + while (remaining && (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD)) + { + /* Read from FIFO, no barrier */ + buf[i] = bcm2835_peri_read_nb(fifo); + i++; + remaining--; + } + + /* Received a NACK */ + if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) + { + reason = BCM2835_I2C_REASON_ERROR_NACK; + } + + /* Received Clock Stretch Timeout */ + else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) + { + reason = BCM2835_I2C_REASON_ERROR_CLKT; + } + + /* Not all data is received */ + else if (remaining) + { + reason = BCM2835_I2C_REASON_ERROR_DATA; + } + + bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); + + return reason; +} + +/* Read an number of bytes from I2C sending a repeated start after writing +// the required register. Only works if your device supports this mode +*/ +uint8_t bcm2835_i2c_read_register_rs(char* regaddr, char* buf, uint32_t len) +{ +#ifdef I2C_V1 + volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; + volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; + volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; + volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; +#else + volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; + volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; + volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; + volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; +#endif + uint32_t remaining = len; + uint32_t i = 0; + uint8_t reason = BCM2835_I2C_REASON_OK; + + /* Clear FIFO */ + bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); + /* Clear Status */ + bcm2835_peri_write(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); + /* Set Data Length */ + bcm2835_peri_write(dlen, 1); + /* Enable device and start transfer */ + bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN); + bcm2835_peri_write(fifo, regaddr[0]); + bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST); + + /* poll for transfer has started */ + while ( !( bcm2835_peri_read(status) & BCM2835_BSC_S_TA ) ) + { + /* Linux may cause us to miss entire transfer stage */ + if(bcm2835_peri_read(status) & BCM2835_BSC_S_DONE) + break; + } + + /* Send a repeated start with read bit set in address */ + bcm2835_peri_write(dlen, len); + bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ ); + + /* Wait for write to complete and first byte back. */ + bcm2835_delayMicroseconds(i2c_byte_wait_us * 3); + + /* wait for transfer to complete */ + while (!(bcm2835_peri_read(status) & BCM2835_BSC_S_DONE)) + { + /* we must empty the FIFO as it is populated and not use any delay */ + while (remaining && bcm2835_peri_read(status) & BCM2835_BSC_S_RXD) + { + /* Read from FIFO */ + buf[i] = bcm2835_peri_read(fifo); + i++; + remaining--; + } + } + + /* transfer has finished - grab any remaining stuff in FIFO */ + while (remaining && (bcm2835_peri_read(status) & BCM2835_BSC_S_RXD)) + { + /* Read from FIFO */ + buf[i] = bcm2835_peri_read(fifo); + i++; + remaining--; + } + + /* Received a NACK */ + if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) + { + reason = BCM2835_I2C_REASON_ERROR_NACK; + } + + /* Received Clock Stretch Timeout */ + else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) + { + reason = BCM2835_I2C_REASON_ERROR_CLKT; + } + + /* Not all data is sent */ + else if (remaining) + { + reason = BCM2835_I2C_REASON_ERROR_DATA; + } + + bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); + + return reason; +} + +/* Sending an arbitrary number of bytes before issuing a repeated start +// (with no prior stop) and reading a response. Some devices require this behavior. +*/ +uint8_t bcm2835_i2c_write_read_rs(char* cmds, uint32_t cmds_len, char* buf, uint32_t buf_len) +{ +#ifdef I2C_V1 + volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; + volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; + volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; + volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; +#else + volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; + volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; + volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; + volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; +#endif + + uint32_t remaining = cmds_len; + uint32_t i = 0; + uint8_t reason = BCM2835_I2C_REASON_OK; + + /* Clear FIFO */ + bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); + + /* Clear Status */ + bcm2835_peri_write(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); + + /* Set Data Length */ + bcm2835_peri_write(dlen, cmds_len); + + /* pre populate FIFO with max buffer */ + while( remaining && ( i < BCM2835_BSC_FIFO_SIZE ) ) + { + bcm2835_peri_write_nb(fifo, cmds[i]); + i++; + remaining--; + } + + /* Enable device and start transfer */ + bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST); + + /* poll for transfer has started (way to do repeated start, from BCM2835 datasheet) */ + while ( !( bcm2835_peri_read(status) & BCM2835_BSC_S_TA ) ) + { + /* Linux may cause us to miss entire transfer stage */ + if(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE) + break; + } + + remaining = buf_len; + i = 0; + + /* Send a repeated start with read bit set in address */ + bcm2835_peri_write(dlen, buf_len); + bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ ); + + /* Wait for write to complete and first byte back. */ + bcm2835_delayMicroseconds(i2c_byte_wait_us * (cmds_len + 1)); + + /* wait for transfer to complete */ + while (!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE)) + { + /* we must empty the FIFO as it is populated and not use any delay */ + while (remaining && bcm2835_peri_read(status) & BCM2835_BSC_S_RXD) + { + /* Read from FIFO, no barrier */ + buf[i] = bcm2835_peri_read_nb(fifo); + i++; + remaining--; + } + } + + /* transfer has finished - grab any remaining stuff in FIFO */ + while (remaining && (bcm2835_peri_read(status) & BCM2835_BSC_S_RXD)) + { + /* Read from FIFO */ + buf[i] = bcm2835_peri_read(fifo); + i++; + remaining--; + } + + /* Received a NACK */ + if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) + { + reason = BCM2835_I2C_REASON_ERROR_NACK; + } + + /* Received Clock Stretch Timeout */ + else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) + { + reason = BCM2835_I2C_REASON_ERROR_CLKT; + } + + /* Not all data is sent */ + else if (remaining) + { + reason = BCM2835_I2C_REASON_ERROR_DATA; + } + + bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); + + return reason; +} + +/* Read the System Timer Counter (64-bits) */ +uint64_t bcm2835_st_read(void) +{ + volatile uint32_t* paddr; + uint32_t hi, lo; + uint64_t st; + paddr = bcm2835_st + BCM2835_ST_CHI/4; + hi = bcm2835_peri_read(paddr); + + paddr = bcm2835_st + BCM2835_ST_CLO/4; + lo = bcm2835_peri_read(paddr); + + paddr = bcm2835_st + BCM2835_ST_CHI/4; + st = bcm2835_peri_read(paddr); + + /* Test for overflow */ + if (st == hi) + { + st <<= 32; + st += lo; + } + else + { + st <<= 32; + paddr = bcm2835_st + BCM2835_ST_CLO/4; + st += bcm2835_peri_read(paddr); + } + return st; +} + +/* Delays for the specified number of microseconds with offset */ +void bcm2835_st_delay(uint64_t offset_micros, uint64_t micros) +{ + uint64_t compare = offset_micros + micros; + + while(bcm2835_st_read() < compare) + ; +} + +/* PWM */ + +void bcm2835_pwm_set_clock(uint32_t divisor) +{ + if ( bcm2835_clk == MAP_FAILED + || bcm2835_pwm == MAP_FAILED) + return; /* bcm2835_init() failed or not root */ + + /* From Gerts code */ + divisor &= 0xfff; + /* Stop PWM clock */ + bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_CNTL, BCM2835_PWM_PASSWRD | 0x01); + bcm2835_delay(110); /* Prevents clock going slow */ + /* Wait for the clock to be not busy */ + while ((bcm2835_peri_read(bcm2835_clk + BCM2835_PWMCLK_CNTL) & 0x80) != 0) + bcm2835_delay(1); + /* set the clock divider and enable PWM clock */ + bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_DIV, BCM2835_PWM_PASSWRD | (divisor << 12)); + bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_CNTL, BCM2835_PWM_PASSWRD | 0x11); /* Source=osc and enable */ +} + +void bcm2835_pwm_set_mode(uint8_t channel, uint8_t markspace, uint8_t enabled) +{ + if ( bcm2835_clk == MAP_FAILED + || bcm2835_pwm == MAP_FAILED) + return; /* bcm2835_init() failed or not root */ + + uint32_t control = bcm2835_peri_read(bcm2835_pwm + BCM2835_PWM_CONTROL); + + if (channel == 0) + { + if (markspace) + control |= BCM2835_PWM0_MS_MODE; + else + control &= ~BCM2835_PWM0_MS_MODE; + if (enabled) + control |= BCM2835_PWM0_ENABLE; + else + control &= ~BCM2835_PWM0_ENABLE; + } + else if (channel == 1) + { + if (markspace) + control |= BCM2835_PWM1_MS_MODE; + else + control &= ~BCM2835_PWM1_MS_MODE; + if (enabled) + control |= BCM2835_PWM1_ENABLE; + else + control &= ~BCM2835_PWM1_ENABLE; + } + + /* If you use the barrier here, wierd things happen, and the commands dont work */ + bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM_CONTROL, control); + /* bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM_CONTROL, BCM2835_PWM0_ENABLE | BCM2835_PWM1_ENABLE | BCM2835_PWM0_MS_MODE | BCM2835_PWM1_MS_MODE); */ + +} + +void bcm2835_pwm_set_range(uint8_t channel, uint32_t range) +{ + if ( bcm2835_clk == MAP_FAILED + || bcm2835_pwm == MAP_FAILED) + return; /* bcm2835_init() failed or not root */ + + if (channel == 0) + bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM0_RANGE, range); + else if (channel == 1) + bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM1_RANGE, range); +} + +void bcm2835_pwm_set_data(uint8_t channel, uint32_t data) +{ + if ( bcm2835_clk == MAP_FAILED + || bcm2835_pwm == MAP_FAILED) + return; /* bcm2835_init() failed or not root */ + + if (channel == 0) + bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM0_DATA, data); + else if (channel == 1) + bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM1_DATA, data); +} + +/* Allocate page-aligned memory. */ +void *malloc_aligned(size_t size) +{ + void *mem; + errno = posix_memalign(&mem, BCM2835_PAGE_SIZE, size); + return (errno ? NULL : mem); +} + +/* Map 'size' bytes starting at 'off' in file 'fd' to memory. +// Return mapped address on success, MAP_FAILED otherwise. +// On error print message. +*/ +static void *mapmem(const char *msg, size_t size, int fd, off_t off) +{ + void *map = mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, off); + if (map == MAP_FAILED) + mys_log(LOG_ERR, "bcm2835_init: %s mmap failed: %s\n", msg, strerror(errno)); + return map; +} + +static void unmapmem(void **pmem, size_t size) +{ + if (*pmem == MAP_FAILED) return; + munmap(*pmem, size); + *pmem = MAP_FAILED; +} + +/* Initialise this library. */ +int bcm2835_init(void) +{ + int memfd; + int ok; + FILE *fp; + + if (debug) + { + bcm2835_peripherals = (uint32_t*)BCM2835_PERI_BASE; + + bcm2835_pads = bcm2835_peripherals + BCM2835_GPIO_PADS/4; + bcm2835_clk = bcm2835_peripherals + BCM2835_CLOCK_BASE/4; + bcm2835_gpio = bcm2835_peripherals + BCM2835_GPIO_BASE/4; + bcm2835_pwm = bcm2835_peripherals + BCM2835_GPIO_PWM/4; + bcm2835_spi0 = bcm2835_peripherals + BCM2835_SPI0_BASE/4; + bcm2835_bsc0 = bcm2835_peripherals + BCM2835_BSC0_BASE/4; + bcm2835_bsc1 = bcm2835_peripherals + BCM2835_BSC1_BASE/4; + bcm2835_st = bcm2835_peripherals + BCM2835_ST_BASE/4; + return 1; /* Success */ + } + + /* Figure out the base and size of the peripheral address block + // using the device-tree. Required for RPi2, optional for RPi 1 + */ + if ((fp = fopen(BMC2835_RPI2_DT_FILENAME , "rb"))) + { + unsigned char buf[4]; + fseek(fp, BMC2835_RPI2_DT_PERI_BASE_ADDRESS_OFFSET, SEEK_SET); + if (fread(buf, 1, sizeof(buf), fp) == sizeof(buf)) + bcm2835_peripherals_base = (uint32_t *)(buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0); + fseek(fp, BMC2835_RPI2_DT_PERI_SIZE_OFFSET, SEEK_SET); + if (fread(buf, 1, sizeof(buf), fp) == sizeof(buf)) + bcm2835_peripherals_size = (buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0); + fclose(fp); + } + /* else we are prob on RPi 1 with BCM2835, and use the hardwired defaults */ + + /* Now get ready to map the peripherals block + * If we are not root, try for the new /dev/gpiomem interface and accept + * the fact that we can only access GPIO + * else try for the /dev/mem interface and get access to everything + */ + memfd = -1; + ok = 0; + if (geteuid() == 0) + { + /* Open the master /dev/mem device */ + if ((memfd = open("/dev/mem", O_RDWR | O_SYNC) ) < 0) + { + mys_log(LOG_ERR, "bcm2835_init: Unable to open /dev/mem: %s\n", + strerror(errno)) ; + goto exit; + } + + /* Base of the peripherals block is mapped to VM */ + bcm2835_peripherals = mapmem("gpio", bcm2835_peripherals_size, memfd, (uint32_t)bcm2835_peripherals_base); + if (bcm2835_peripherals == MAP_FAILED) goto exit; + + /* Now compute the base addresses of various peripherals, + // which are at fixed offsets within the mapped peripherals block + // Caution: bcm2835_peripherals is uint32_t*, so divide offsets by 4 + */ + bcm2835_gpio = bcm2835_peripherals + BCM2835_GPIO_BASE/4; + bcm2835_pwm = bcm2835_peripherals + BCM2835_GPIO_PWM/4; + bcm2835_clk = bcm2835_peripherals + BCM2835_CLOCK_BASE/4; + bcm2835_pads = bcm2835_peripherals + BCM2835_GPIO_PADS/4; + bcm2835_spi0 = bcm2835_peripherals + BCM2835_SPI0_BASE/4; + bcm2835_bsc0 = bcm2835_peripherals + BCM2835_BSC0_BASE/4; /* I2C */ + bcm2835_bsc1 = bcm2835_peripherals + BCM2835_BSC1_BASE/4; /* I2C */ + bcm2835_st = bcm2835_peripherals + BCM2835_ST_BASE/4; + + ok = 1; + } + else + { + /* Not root, try /dev/gpiomem */ + /* Open the master /dev/mem device */ + if ((memfd = open("/dev/gpiomem", O_RDWR | O_SYNC) ) < 0) + { + mys_log(LOG_ERR, "bcm2835_init: Unable to open /dev/gpiomem: %s\n", + strerror(errno)) ; + goto exit; + } + + /* Base of the peripherals block is mapped to VM */ + bcm2835_peripherals_base = 0; + bcm2835_peripherals = mapmem("gpio", bcm2835_peripherals_size, memfd, (uint32_t)bcm2835_peripherals_base); + if (bcm2835_peripherals == MAP_FAILED) goto exit; + bcm2835_gpio = bcm2835_peripherals; + ok = 1; + } + +exit: + if (memfd >= 0) + close(memfd); + + if (!ok) + bcm2835_close(); + + return ok; +} + +/* Close this library and deallocate everything */ +int bcm2835_close(void) +{ + if (debug) return 1; /* Success */ + + unmapmem((void**) &bcm2835_peripherals, bcm2835_peripherals_size); + bcm2835_peripherals = MAP_FAILED; + bcm2835_gpio = MAP_FAILED; + bcm2835_pwm = MAP_FAILED; + bcm2835_clk = MAP_FAILED; + bcm2835_pads = MAP_FAILED; + bcm2835_spi0 = MAP_FAILED; + bcm2835_bsc0 = MAP_FAILED; + bcm2835_bsc1 = MAP_FAILED; + bcm2835_st = MAP_FAILED; + return 1; /* Success */ +} + +#ifdef BCM2835_TEST +/* this is a simple test program that prints out what it will do rather than +// actually doing it +*/ +int main(int argc, char **argv) +{ + /* Be non-destructive */ + bcm2835_set_debug(1); + + if (!bcm2835_init()) + return 1; + + /* Configure some GPIO pins fo some testing + // Set RPI pin P1-11 to be an output + */ + bcm2835_gpio_fsel(RPI_GPIO_P1_11, BCM2835_GPIO_FSEL_OUTP); + /* Set RPI pin P1-15 to be an input */ + bcm2835_gpio_fsel(RPI_GPIO_P1_15, BCM2835_GPIO_FSEL_INPT); + /* with a pullup */ + bcm2835_gpio_set_pud(RPI_GPIO_P1_15, BCM2835_GPIO_PUD_UP); + /* And a low detect enable */ + bcm2835_gpio_len(RPI_GPIO_P1_15); + /* and input hysteresis disabled on GPIOs 0 to 27 */ + bcm2835_gpio_set_pad(BCM2835_PAD_GROUP_GPIO_0_27, BCM2835_PAD_SLEW_RATE_UNLIMITED|BCM2835_PAD_DRIVE_8mA); + +#if 1 + /* Blink */ + while (1) + { + /* Turn it on */ + bcm2835_gpio_write(RPI_GPIO_P1_11, HIGH); + + /* wait a bit */ + bcm2835_delay(500); + + /* turn it off */ + bcm2835_gpio_write(RPI_GPIO_P1_11, LOW); + + /* wait a bit */ + bcm2835_delay(500); + } +#endif + +#if 0 + /* Read input */ + while (1) + { + /* Read some data */ + uint8_t value = bcm2835_gpio_lev(RPI_GPIO_P1_15); + printf("read from pin 15: %d\n", value); + + /* wait a bit */ + bcm2835_delay(500); + } +#endif + +#if 0 + /* Look for a low event detection + // eds will be set whenever pin 15 goes low + */ + while (1) + { + if (bcm2835_gpio_eds(RPI_GPIO_P1_15)) + { + /* Now clear the eds flag by setting it to 1 */ + bcm2835_gpio_set_eds(RPI_GPIO_P1_15); + printf("low event detect for pin 15\n"); + } + + /* wait a bit */ + bcm2835_delay(500); + } +#endif + + if (!bcm2835_close()) + return 1; + + return 0; +} +#endif diff --git a/drivers/RPi/bcm2835.h b/drivers/RPi/bcm2835.h new file mode 100644 index 000000000..26acee2ca --- /dev/null +++ b/drivers/RPi/bcm2835.h @@ -0,0 +1,1648 @@ +/* bcm2835.h + + C and C++ support for Broadcom BCM 2835 as used in Raspberry Pi + + Author: Mike McCauley + Copyright (C) 2011-2013 Mike McCauley + $Id: bcm2835.h,v 1.20 2015/03/31 04:55:41 mikem Exp mikem $ +*/ + +/*! \defgroup BCM2835grp C library for Broadcom BCM 2835 as used in Raspberry Pi + \ingroup internals + + This is a C library for Raspberry Pi (RPi). It provides access to + GPIO and other IO functions on the Broadcom BCM 2835 chip, + allowing access to the GPIO pins on the + 26 pin IDE plug on the RPi board so you can control and interface with various external devices. + + It provides functions for reading digital inputs and setting digital outputs, using SPI and I2C, + and for accessing the system timers. + Pin event detection is supported by polling (interrupts are not supported). + + It is C++ compatible, and installs as a header file and non-shared library on + any Linux-based distro (but clearly is no use except on Raspberry Pi or another board with + BCM 2835). + + The version of the package that this documentation refers to can be downloaded + from http://www.airspayce.com/mikem/bcm2835/bcm2835-1.50.tar.gz + You can find the latest version at http://www.airspayce.com/mikem/bcm2835 + + Several example programs are provided. + + Based on data in http://elinux.org/RPi_Low-level_peripherals and + http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf + and http://www.scribd.com/doc/101830961/GPIO-Pads-Control2 + + You can also find online help and discussion at http://groups.google.com/group/bcm2835 + Please use that group for all questions and discussions on this topic. + Do not contact the author directly, unless it is to discuss commercial licensing. + Before asking a question or reporting a bug, please read http://www.catb.org/esr/faqs/smart-questions.html + + Tested on debian6-19-04-2012, 2012-07-15-wheezy-raspbian, 2013-07-26-wheezy-raspbian + and Occidentalisv01, 2016-02-09 Raspbian Jessie. + CAUTION: it has been observed that when detect enables such as bcm2835_gpio_len() + are used and the pin is pulled LOW + it can cause temporary hangs on 2012-07-15-wheezy-raspbian, 2013-07-26-wheezy-raspbian + and Occidentalisv01. + Reason for this is not yet determined, but we suspect that an interrupt handler is + hitting a hard loop on those OSs. + If you must use bcm2835_gpio_len() and friends, make sure you disable the pins with + bcm2835_gpio_clr_len() and friends after use. + + \par Running as root + + Prior to the release of Raspbian Jessie in Feb 2016, access to any + peripheral device via /dev/mem on the RPi required the process to + run as root. Raspbian Jessie permits non-root users to access the + GPIO peripheral (only) via /dev/gpiomem, and this library supports + that limited mode of operation. + + If the library runs with effective UID of 0 (ie root), then + bcm2835_init() will attempt to open /dev/mem, and, if successful, it + will permit use of all peripherals and library functions. + + If the library runs with any other effective UID (ie not root), then + bcm2835_init() will attempt to open /dev/gpiomem, and, if + successful, will only permit GPIO operations. In particular, + bcm2835_spi_begin() and bcm2835_i2c_begin() will return false and all + other non-gpio operations may fail silently or crash. + + \par Installation + + This library consists of a single non-shared library and header file, which will be + installed in the usual places by make install + + \code + # download the latest version of the library, say bcm2835-1.xx.tar.gz, then: + tar zxvf bcm2835-1.xx.tar.gz + cd bcm2835-1.xx + ./configure + make + sudo make check + sudo make install + \endcode + + \par Physical Addresses + + The functions bcm2835_peri_read(), bcm2835_peri_write() and bcm2835_peri_set_bits() + are low level peripheral register access functions. They are designed to use + physical addresses as described in section 1.2.3 ARM physical addresses + of the BCM2835 ARM Peripherals manual. + Physical addresses range from 0x20000000 to 0x20FFFFFF for peripherals. The bus + addresses for peripherals are set up to map onto the peripheral bus address range starting at + 0x7E000000. Thus a peripheral advertised in the manual at bus address 0x7Ennnnnn is available at + physical address 0x20nnnnnn. + + On RPI 2, the peripheral addresses are different and the bcm2835 library gets them + from reading /proc/device-tree/soc/ranges. This is only availble with recent versions of the kernel on RPI 2. + + After initialisation, the base address of the various peripheral + registers are available with the following + externals: + bcm2835_gpio + bcm2835_pwm + bcm2835_clk + bcm2835_pads + bcm2835_spio0 + bcm2835_st + bcm2835_bsc0 + bcm2835_bsc1 + + \par Raspberry Pi 2 (RPI2) + + For this library to work correctly on RPI2, you MUST have the device tree support enabled in the kernel. + You should also ensure you are using the latest version of Linux. The library has been tested on RPI2 + with 2015-02-16-raspbian-wheezy and ArchLinuxARM-rpi-2 as of 2015-03-29. + + When device tree suport is enabled, the file /proc/device-tree/soc/ranges will appear in the file system, + and the bcm2835 module relies on its presence to correctly run on RPI2 (it is optional for RPI1). + Without device tree support enabled and the presence of this file, it will not work on RPI2. + + To enable device tree support: + + \code + sudo raspi-config + under Advanced Options - enable Device Tree + Reboot. + \endcode + + \par Pin Numbering + + The GPIO pin numbering as used by RPi is different to and inconsistent with the underlying + BCM 2835 chip pin numbering. http://elinux.org/RPi_BCM2835_GPIOs + + RPi has a 26 pin IDE header that provides access to some of the GPIO pins on the BCM 2835, + as well as power and ground pins. Not all GPIO pins on the BCM 2835 are available on the + IDE header. + + RPi Version 2 also has a P5 connector with 4 GPIO pins, 5V, 3.3V and Gnd. + + The functions in this library are designed to be passed the BCM 2835 GPIO pin number and _not_ + the RPi pin number. There are symbolic definitions for each of the available pins + that you should use for convenience. See \ref RPiGPIOPin. + + \par SPI Pins + + The bcm2835_spi_* functions allow you to control the BCM 2835 SPI0 interface, + allowing you to send and received data by SPI (Serial Peripheral Interface). + For more information about SPI, see http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus + + When bcm2835_spi_begin() is called it changes the bahaviour of the SPI interface pins from their + default GPIO behaviour in order to support SPI. While SPI is in use, you will not be able + to control the state of the SPI pins through the usual bcm2835_spi_gpio_write(). + When bcm2835_spi_end() is called, the SPI pins will all revert to inputs, and can then be + configured and controled with the usual bcm2835_gpio_* calls. + + The Raspberry Pi GPIO pins used for SPI are: + + - P1-19 (MOSI) + - P1-21 (MISO) + - P1-23 (CLK) + - P1-24 (CE0) + - P1-26 (CE1) + + \par I2C Pins + + The bcm2835_i2c_* functions allow you to control the BCM 2835 BSC interface, + allowing you to send and received data by I2C ("eye-squared cee"; generically referred to as "two-wire interface") . + For more information about I?C, see http://en.wikipedia.org/wiki/I%C2%B2C + + The Raspberry Pi V2 GPIO pins used for I2C are: + + - P1-03 (SDA) + - P1-05 (SLC) + + \par PWM + + The BCM2835 supports hardware PWM on a limited subset of GPIO pins. This bcm2835 library provides + functions for configuring and controlling PWM output on these pins. + + The BCM2835 contains 2 independent PWM channels (0 and 1), each of which be connnected to a limited subset of + GPIO pins. The following GPIO pins may be connected to the following PWM channels (from section 9.5): + \code + GPIO PIN RPi pin PWM Channel ALT FUN + 12 0 0 + 13 1 0 + 18 1-12 0 5 + 19 1 5 + 40 0 0 + 41 1 0 + 45 1 0 + 52 0 1 + 53 1 1 + \endcode + In order for a GPIO pin to emit output from its PWM channel, it must be set to the Alt Function given above. + Note carefully that current versions of the Raspberry Pi only expose one of these pins (GPIO 18 = RPi Pin 1-12) + on the IO headers, and therefore this is the only IO pin on the RPi that can be used for PWM. + Further it must be set to ALT FUN 5 to get PWM output. + + Both PWM channels are driven by the same PWM clock, whose clock dvider can be varied using + bcm2835_pwm_set_clock(). Each channel can be separately enabled with bcm2835_pwm_set_mode(). + The average output of the PWM channel is determined by the ratio of DATA/RANGE for that channel. + Use bcm2835_pwm_set_range() to set the range and bcm2835_pwm_set_data() to set the data in that ratio + + Each PWM channel can run in either Balanced or Mark-Space mode. In Balanced mode, the hardware + sends a combination of clock pulses that results in an overall DATA pulses per RANGE pulses. + In Mark-Space mode, the hardware sets the output HIGH for DATA clock pulses wide, followed by + LOW for RANGE-DATA clock pulses. + + The PWM clock can be set to control the PWM pulse widths. The PWM clock is derived from + a 19.2MHz clock. You can set any divider, but some common ones are provided by the BCM2835_PWM_CLOCK_DIVIDER_* + values of \ref bcm2835PWMClockDivider. + + For example, say you wanted to drive a DC motor with PWM at about 1kHz, + and control the speed in 1/1024 increments from + 0/1024 (stopped) through to 1024/1024 (full on). In that case you might set the + clock divider to be 16, and the RANGE to 1024. The pulse repetition frequency will be + 1.2MHz/1024 = 1171.875Hz. + + \par SPI + + In order for bcm2835 library SPI to work, you may need to disable the SPI kernel module using: + + \code + sudo raspi-config + under Advanced Options - enable Device Tree + under Advanced Options - disable SPI + Reboot. + \endcode + + \par Real Time performance constraints + + The bcm2835 is a library for user programs (i.e. they run in 'userland'). + Such programs are not part of the kernel and are usually + subject to paging and swapping by the kernel while it does other things besides running your program. + This means that you should not expect to get real-time performance or + real-time timing constraints from such programs. In particular, there is no guarantee that the + bcm2835_delay() and bcm2835_delayMicroseconds() will return after exactly the time requested. + In fact, depending on other activity on the host, IO etc, you might get significantly longer delay times + than the one you asked for. So please dont expect to get exactly the time delay you request. + + Arjan reports that you can prevent swapping on Linux with the following code fragment: + + \code + struct sched_param sp; + memset(&sp, 0, sizeof(sp)); + sp.sched_priority = sched_get_priority_max(SCHED_FIFO); + sched_setscheduler(0, SCHED_FIFO, &sp); + mlockall(MCL_CURRENT | MCL_FUTURE); + \endcode + + \par Bindings to other languages + + mikem has made Perl bindings available at CPAN: + http://search.cpan.org/~mikem/Device-BCM2835-1.9/lib/Device/BCM2835.pm + Matthew Baker has kindly made Python bindings available at: + https: github.com/mubeta06/py-libbcm2835 + Gary Marks has created a Serial Peripheral Interface (SPI) command-line utility + for Raspberry Pi, based on the bcm2835 library. The + utility, spincl, is licensed under Open Source GNU GPLv3 by iP Solutions (http://ipsolutionscorp.com), as a + free download with source included: http://ipsolutionscorp.com/raspberry-pi-spi-utility/ + + \par Open Source Licensing GPL V2 + + This is the appropriate option if you want to share the source code of your + application with everyone you distribute it to, and you also want to give them + the right to share who uses it. If you wish to use this software under Open + Source Licensing, you must contribute all your source code to the open source + community in accordance with the GPL Version 2 when your application is + distributed. See http://www.gnu.org/copyleft/gpl.html and COPYING + + \par Acknowledgements + + Some of this code has been inspired by Dom and Gert. + The I2C code has been inspired by Alan Barr. + + \par Revision History + + \version 1.0 Initial release + + \version 1.1 Minor bug fixes + + \version 1.2 Added support for SPI + + \version 1.3 Added bcm2835_spi_transfern() + + \version 1.4 Fixed a problem that prevented SPI CE1 being used. Reported by David Robinson. + + \version 1.5 Added bcm2835_close() to deinit the library. Suggested by C?sar Ortiz + + \version 1.6 Document testing on 2012-07-15-wheezy-raspbian and Occidentalisv01 + Functions bcm2835_gpio_ren(), bcm2835_gpio_fen(), bcm2835_gpio_hen() + bcm2835_gpio_len(), bcm2835_gpio_aren() and bcm2835_gpio_afen() now + changes only the pin specified. Other pins that were already previously + enabled stay enabled. + Added bcm2835_gpio_clr_ren(), bcm2835_gpio_clr_fen(), bcm2835_gpio_clr_hen() + bcm2835_gpio_clr_len(), bcm2835_gpio_clr_aren(), bcm2835_gpio_clr_afen() + to clear the enable for individual pins, suggested by Andreas Sundstrom. + + \version 1.7 Added bcm2835_spi_transfernb to support different buffers for read and write. + + \version 1.8 Improvements to read barrier, as suggested by maddin. + + \version 1.9 Improvements contributed by mikew: + I noticed that it was mallocing memory for the mmaps on /dev/mem. + It's not necessary to do that, you can just mmap the file directly, + so I've removed the mallocs (and frees). + I've also modified delayMicroseconds() to use nanosleep() for long waits, + and a busy wait on a high resolution timer for the rest. This is because + I've found that calling nanosleep() takes at least 100-200 us. + You need to link using '-lrt' using this version. + I've added some unsigned casts to the debug prints to silence compiler + warnings I was getting, fixed some typos, and changed the value of + BCM2835_PAD_HYSTERESIS_ENABLED to 0x08 as per Gert van Loo's doc at + http://www.scribd.com/doc/101830961/GPIO-Pads-Control2 + Also added a define for the passwrd value that Gert says is needed to + change pad control settings. + + \version 1.10 Changed the names of the delay functions to bcm2835_delay() + and bcm2835_delayMicroseconds() to prevent collisions with wiringPi. + Macros to map delay()-> bcm2835_delay() and + Macros to map delayMicroseconds()-> bcm2835_delayMicroseconds(), which + can be disabled by defining BCM2835_NO_DELAY_COMPATIBILITY + + \version 1.11 Fixed incorrect link to download file + + \version 1.12 New GPIO pin definitions for RPi version 2 (which has a different GPIO mapping) + + \version 1.13 New GPIO pin definitions for RPi version 2 plug P5 + Hardware base pointers are now available (after initialisation) externally as bcm2835_gpio + bcm2835_pwm bcm2835_clk bcm2835_pads bcm2835_spi0. + + \version 1.14 Now compiles even if CLOCK_MONOTONIC_RAW is not available, uses CLOCK_MONOTONIC instead. + Fixed errors in documentation of SPI divider frequencies based on 250MHz clock. + Reported by Ben Simpson. + + \version 1.15 Added bcm2835_close() to end of examples as suggested by Mark Wolfe. + + \version 1.16 Added bcm2835_gpio_set_multi, bcm2835_gpio_clr_multi and bcm2835_gpio_write_multi + to allow a mask of pins to be set all at once. Requested by Sebastian Loncar. + + \version 1.17 Added bcm2835_gpio_write_mask. Requested by Sebastian Loncar. + + \version 1.18 Added bcm2835_i2c_* functions. Changes to bcm2835_delayMicroseconds: + now uses the RPi system timer counter, instead of clock_gettime, for improved accuracy. + No need to link with -lrt now. Contributed by Arjan van Vught. + \version 1.19 Removed inlines added by previous patch since they don't seem to work everywhere. + Reported by olly. + + \version 1.20 Patch from Mark Dootson to close /dev/mem after access to the peripherals has been granted. + + \version 1.21 delayMicroseconds is now not susceptible to 32 bit timer overruns. + Patch courtesy Jeremy Mortis. + + \version 1.22 Fixed incorrect definition of BCM2835_GPFEN0 which broke the ability to set + falling edge events. Reported by Mark Dootson. + + \version 1.23 Added bcm2835_i2c_set_baudrate and bcm2835_i2c_read_register_rs. + Improvements to bcm2835_i2c_read and bcm2835_i2c_write functions + to fix ocasional reads not completing. Patched by Mark Dootson. + + \version 1.24 Mark Dootson p[atched a problem with his previously submitted code + under high load from other processes. + + \version 1.25 Updated author and distribution location details to airspayce.com + + \version 1.26 Added missing unmapmem for pads in bcm2835_close to prevent a memory leak. + Reported by Hartmut Henkel. + + \version 1.27 bcm2835_gpio_set_pad() no longer needs BCM2835_PAD_PASSWRD: it is + now automatically included. + Added suport for PWM mode with bcm2835_pwm_* functions. + + \version 1.28 Fixed a problem where bcm2835_spi_writenb() would have problems with transfers of more than + 64 bytes dues to read buffer filling. Patched by Peter Würtz. + + \version 1.29 Further fix to SPI from Peter Würtz. + + \version 1.30 10 microsecond delays from bcm2835_spi_transfer and bcm2835_spi_transfern for + significant performance improvements, Patch by Alan Watson. + + \version 1.31 Fix a GCC warning about dummy variable, patched by Alan Watson. Thanks. + + \version 1.32 Added option I2C_V1 definition to compile for version 1 RPi. + By default I2C code is generated for the V2 RPi which has SDA1 and SCL1 connected. + Contributed by Malcolm Wiles based on work by Arvi Govindaraj. + + \version 1.33 Added command line utilities i2c and gpio to examples. Contributed by Shahrooz Shahparnia. + + \version 1.34 Added bcm2835_i2c_write_read_rs() which writes an arbitrary number of bytes, + sends a repeat start, and reads from the device. Contributed by Eduardo Steinhorst. + + \version 1.35 Fix build errors when compiled under Qt. Also performance improvements with SPI transfers. Contributed b Udo Klaas. + + \version 1.36 Make automake's test runner detect that we're skipping tests when not root, the second + one makes us skip the test when using fakeroot (as used when building + Debian packages). Contributed by Guido Günther. + + \version 1.37 Moved confiure.in to configure.ac as receommnded by autoreconf.
+ Improvements to bcm2835_st_read to account for possible timer overflow, contributed by 'Ed'.
+ Added definitions for Raspberry Pi B+ J8 header GPIO pins.
+ + \version 1.38 Added bcm2835_regbase for the benefit of C# wrappers, patch by Frank Hommers
+ + \version 1.39 Beta version of RPi2 compatibility. Not tested here on RPi2 hardware. + Testers please confirm correct operation on RPi2.
+ Unneccessary 'volatile' qualifiers removed from all variables and signatures.
+ Removed unsupportable PWM dividers, based on a report from Christophe Cecillon.
+ Minor improvements to spi.c example.
+ + \version 1.40 Correct operation on RPi2 has been confirmed.
+ Fixed a number of compiler errors and warnings that occur when bcm2835.h is included + in code compiled with -Wall -Woverflow -Wstrict-overflow -Wshadow -Wextra -pedantic. + Reported by tlhackque.
+ Fixed a problem where calling bcm2835_delayMicroseconds loops forever when debug is set. Reported by tlhackque.
+ Reinstated use of volatile in 2 functions where there was a danger of lost reads or writes. Reported by tlhackque.
+ + \version 1.41 Added BCM2835_VERSION macro and new function bcm2835_version(); Requested by tlhackque.
+ Improvements to peripheral memory barriers as suggested by tlhackque.
+ Reinstated some necessary volatile declarations as requested by tlhackque.
+ + \version 1.42 Further improvements to memory barriers with the patient assistance and patches of tlhackque.
+ + \version 1.43 Fixed problems with compiling barriers on RPI 2 with Arch Linux and gcc 4.9.2. + Reported and patched by Lars Christensen.
+ Testing on RPI 2, with ArchLinuxARM-rpi-2-latest and 2015-02-16-raspbian-wheezy.
+ + \version 1.44 Added documention about the need for device tree to be enabled on RPI2.
+ Improvements to detection of availablity of DMB instruction based on value of __ARM_ARCH macro.
+ + \version 1.45 Fixed an error in the pad group offsets that would prevent bcm2835_gpio_set_pad() + and bcm2835_gpio_pad() working correctly with non-0 pad groups. Reported by Guido. + + \version 1.46 2015-09-18 + Added symbolic definitions for remaining pins on 40 pin GPIO header on RPi 2.
+ + \version 1.47 2015-11-18 + Fixed possibly incorrect reads in bcm2835_i2c_read_register_rs, patch from Eckhardt Ulrich.
+ + \version 1.48 2015-12-08 + Added patch from Eckhardt Ulrich that fixed problems that could cause hanging with bcm2835_i2c_read_register_rs + and others. + + \version 1.49 2016-01-05 + Added patch from Jonathan Perkin with new functions bcm2835_gpio_eds_multi() and bcm2835_gpio_set_eds_multi(). + + \version 1.50 2016-02-28 + Added support for running as non-root, permitting access to GPIO only. Functions + bcm2835_spi_begin() and bcm2835_i2c_begin() will now return 0 if not running as root + (which prevents access to the SPI and I2C peripherals, amongst others). + Testing on Raspbian Jessie. + + \author Mike McCauley (mikem@airspayce.com) DO NOT CONTACT THE AUTHOR DIRECTLY: USE THE LISTS + + + Modified September 2016 by Marcelo Aquino +*/ + + +/* Defines for BCM2835 */ +#ifndef BCM2835_H +#define BCM2835_H + +#include + +#define BCM2835_VERSION 10050 /* Version 1.50 */ + +/* RPi 2 is ARM v7, and has DMB instruction for memory barriers. + Older RPis are ARM v6 and don't, so a coprocessor instruction must be used instead. + However, not all versions of gcc in all distros support the dmb assembler instruction even on conmpatible processors. + This test is so any ARMv7 or higher processors with suitable GCC will use DMB. +*/ +#if __ARM_ARCH >= 7 +#define BCM2835_HAVE_DMB +#endif + +/*! \defgroup BCM2835constantsgrp Constants for passing to and from library functions + \ingroup BCM2835grp + The values here are designed to be passed to various functions in the bcm2835 library. + @{ +*/ + +/*! This means pin HIGH, true, 3.3volts on a pin. */ +#define HIGH 0x1 +/*! This means pin LOW, false, 0volts on a pin. */ +#define LOW 0x0 + +/*! Speed of the core clock core_clk */ +#define BCM2835_CORE_CLK_HZ 250000000 /*!< 250 MHz */ + +/*! On RPi2 with BCM2836, and all recent OSs, the base of the peripherals is read from a /proc file */ +#define BMC2835_RPI2_DT_FILENAME "/proc/device-tree/soc/ranges" +/*! Offset into BMC2835_RPI2_DT_FILENAME for the peripherals base address */ +#define BMC2835_RPI2_DT_PERI_BASE_ADDRESS_OFFSET 4 +/*! Offset into BMC2835_RPI2_DT_FILENAME for the peripherals size address */ +#define BMC2835_RPI2_DT_PERI_SIZE_OFFSET 8 + +/*! Physical addresses for various peripheral register sets + Base Physical Address of the BCM 2835 peripheral registers + Note this is different for the RPi2 BCM2836, where this is derived from /proc/device-tree/soc/ranges + If /proc/device-tree/soc/ranges exists on a RPi 1 OS, it would be expected to contain the + following numbers: +*/ +/*! Peripherals block base address on RPi 1 */ +#define BCM2835_PERI_BASE 0x20000000 +/*! Size of the peripherals block on RPi 1 */ +#define BCM2835_PERI_SIZE 0x01000000 + +/*! Offsets for the bases of various peripherals within the peripherals block + / Base Address of the System Timer registers +*/ +#define BCM2835_ST_BASE 0x3000 +/*! Base Address of the Pads registers */ +#define BCM2835_GPIO_PADS 0x100000 +/*! Base Address of the Clock/timer registers */ +#define BCM2835_CLOCK_BASE 0x101000 +/*! Base Address of the GPIO registers */ +#define BCM2835_GPIO_BASE 0x200000 +/*! Base Address of the SPI0 registers */ +#define BCM2835_SPI0_BASE 0x204000 +/*! Base Address of the BSC0 registers */ +#define BCM2835_BSC0_BASE 0x205000 +/*! Base Address of the PWM registers */ +#define BCM2835_GPIO_PWM 0x20C000 +/*! Base Address of the BSC1 registers */ +#define BCM2835_BSC1_BASE 0x804000 + +/*! Physical address and size of the peripherals block + May be overridden on RPi2 +*/ +extern uint32_t *bcm2835_peripherals_base; +/*! Size of the peripherals block to be mapped */ +extern uint32_t bcm2835_peripherals_size; + +/*! Virtual memory address of the mapped peripherals block */ +extern uint32_t *bcm2835_peripherals; + +/*! Base of the ST (System Timer) registers. + Available after bcm2835_init has been called (as root) +*/ +extern volatile uint32_t *bcm2835_st; + +/*! Base of the GPIO registers. + Available after bcm2835_init has been called +*/ +extern volatile uint32_t *bcm2835_gpio; + +/*! Base of the PWM registers. + Available after bcm2835_init has been called (as root) +*/ +extern volatile uint32_t *bcm2835_pwm; + +/*! Base of the CLK registers. + Available after bcm2835_init has been called (as root) +*/ +extern volatile uint32_t *bcm2835_clk; + +/*! Base of the PADS registers. + Available after bcm2835_init has been called (as root) +*/ +extern volatile uint32_t *bcm2835_pads; + +/*! Base of the SPI0 registers. + Available after bcm2835_init has been called (as root) +*/ +extern volatile uint32_t *bcm2835_spi0; + +/*! Base of the BSC0 registers. + Available after bcm2835_init has been called (as root) +*/ +extern volatile uint32_t *bcm2835_bsc0; + +/*! Base of the BSC1 registers. + Available after bcm2835_init has been called (as root) +*/ +extern volatile uint32_t *bcm2835_bsc1; + +/*! \brief bcm2835RegisterBase + Register bases for bcm2835_regbase() +*/ +typedef enum +{ + BCM2835_REGBASE_ST = 1, /*!< Base of the ST (System Timer) registers. */ + BCM2835_REGBASE_GPIO = 2, /*!< Base of the GPIO registers. */ + BCM2835_REGBASE_PWM = 3, /*!< Base of the PWM registers. */ + BCM2835_REGBASE_CLK = 4, /*!< Base of the CLK registers. */ + BCM2835_REGBASE_PADS = 5, /*!< Base of the PADS registers. */ + BCM2835_REGBASE_SPI0 = 6, /*!< Base of the SPI0 registers. */ + BCM2835_REGBASE_BSC0 = 7, /*!< Base of the BSC0 registers. */ + BCM2835_REGBASE_BSC1 = 8 /*!< Base of the BSC1 registers. */ +} bcm2835RegisterBase; + +/*! Size of memory page on RPi */ +#define BCM2835_PAGE_SIZE (4*1024) +/*! Size of memory block on RPi */ +#define BCM2835_BLOCK_SIZE (4*1024) + + +/* Defines for GPIO + The BCM2835 has 54 GPIO pins. + BCM2835 data sheet, Page 90 onwards. +*/ +/*! GPIO register offsets from BCM2835_GPIO_BASE. + Offsets into the GPIO Peripheral block in bytes per 6.1 Register View +*/ +#define BCM2835_GPFSEL0 0x0000 /*!< GPIO Function Select 0 */ +#define BCM2835_GPFSEL1 0x0004 /*!< GPIO Function Select 1 */ +#define BCM2835_GPFSEL2 0x0008 /*!< GPIO Function Select 2 */ +#define BCM2835_GPFSEL3 0x000c /*!< GPIO Function Select 3 */ +#define BCM2835_GPFSEL4 0x0010 /*!< GPIO Function Select 4 */ +#define BCM2835_GPFSEL5 0x0014 /*!< GPIO Function Select 5 */ +#define BCM2835_GPSET0 0x001c /*!< GPIO Pin Output Set 0 */ +#define BCM2835_GPSET1 0x0020 /*!< GPIO Pin Output Set 1 */ +#define BCM2835_GPCLR0 0x0028 /*!< GPIO Pin Output Clear 0 */ +#define BCM2835_GPCLR1 0x002c /*!< GPIO Pin Output Clear 1 */ +#define BCM2835_GPLEV0 0x0034 /*!< GPIO Pin Level 0 */ +#define BCM2835_GPLEV1 0x0038 /*!< GPIO Pin Level 1 */ +#define BCM2835_GPEDS0 0x0040 /*!< GPIO Pin Event Detect Status 0 */ +#define BCM2835_GPEDS1 0x0044 /*!< GPIO Pin Event Detect Status 1 */ +#define BCM2835_GPREN0 0x004c /*!< GPIO Pin Rising Edge Detect Enable 0 */ +#define BCM2835_GPREN1 0x0050 /*!< GPIO Pin Rising Edge Detect Enable 1 */ +#define BCM2835_GPFEN0 0x0058 /*!< GPIO Pin Falling Edge Detect Enable 0 */ +#define BCM2835_GPFEN1 0x005c /*!< GPIO Pin Falling Edge Detect Enable 1 */ +#define BCM2835_GPHEN0 0x0064 /*!< GPIO Pin High Detect Enable 0 */ +#define BCM2835_GPHEN1 0x0068 /*!< GPIO Pin High Detect Enable 1 */ +#define BCM2835_GPLEN0 0x0070 /*!< GPIO Pin Low Detect Enable 0 */ +#define BCM2835_GPLEN1 0x0074 /*!< GPIO Pin Low Detect Enable 1 */ +#define BCM2835_GPAREN0 0x007c /*!< GPIO Pin Async. Rising Edge Detect 0 */ +#define BCM2835_GPAREN1 0x0080 /*!< GPIO Pin Async. Rising Edge Detect 1 */ +#define BCM2835_GPAFEN0 0x0088 /*!< GPIO Pin Async. Falling Edge Detect 0 */ +#define BCM2835_GPAFEN1 0x008c /*!< GPIO Pin Async. Falling Edge Detect 1 */ +#define BCM2835_GPPUD 0x0094 /*!< GPIO Pin Pull-up/down Enable */ +#define BCM2835_GPPUDCLK0 0x0098 /*!< GPIO Pin Pull-up/down Enable Clock 0 */ +#define BCM2835_GPPUDCLK1 0x009c /*!< GPIO Pin Pull-up/down Enable Clock 1 */ + +/*! \brief bcm2835PortFunction + Port function select modes for bcm2835_gpio_fsel() +*/ +typedef enum +{ + BCM2835_GPIO_FSEL_INPT = 0x00, /*!< Input 0b000 */ + BCM2835_GPIO_FSEL_OUTP = 0x01, /*!< Output 0b001 */ + BCM2835_GPIO_FSEL_ALT0 = 0x04, /*!< Alternate function 0 0b100 */ + BCM2835_GPIO_FSEL_ALT1 = 0x05, /*!< Alternate function 1 0b101 */ + BCM2835_GPIO_FSEL_ALT2 = 0x06, /*!< Alternate function 2 0b110, */ + BCM2835_GPIO_FSEL_ALT3 = 0x07, /*!< Alternate function 3 0b111 */ + BCM2835_GPIO_FSEL_ALT4 = 0x03, /*!< Alternate function 4 0b011 */ + BCM2835_GPIO_FSEL_ALT5 = 0x02, /*!< Alternate function 5 0b010 */ + BCM2835_GPIO_FSEL_MASK = 0x07 /*!< Function select bits mask 0b111 */ +} bcm2835FunctionSelect; + +/*! \brief bcm2835PUDControl + Pullup/Pulldown defines for bcm2835_gpio_pud() +*/ +typedef enum +{ + BCM2835_GPIO_PUD_OFF = 0x00, /*!< Off ? disable pull-up/down 0b00 */ + BCM2835_GPIO_PUD_DOWN = 0x01, /*!< Enable Pull Down control 0b01 */ + BCM2835_GPIO_PUD_UP = 0x02 /*!< Enable Pull Up control 0b10 */ +} bcm2835PUDControl; + +/*! Pad control register offsets from BCM2835_GPIO_PADS */ +#define BCM2835_PADS_GPIO_0_27 0x002c /*!< Pad control register for pads 0 to 27 */ +#define BCM2835_PADS_GPIO_28_45 0x0030 /*!< Pad control register for pads 28 to 45 */ +#define BCM2835_PADS_GPIO_46_53 0x0034 /*!< Pad control register for pads 46 to 53 */ + +/*! Pad Control masks */ +#define BCM2835_PAD_PASSWRD (0x5A << 24) /*!< Password to enable setting pad mask */ +#define BCM2835_PAD_SLEW_RATE_UNLIMITED 0x10 /*!< Slew rate unlimited */ +#define BCM2835_PAD_HYSTERESIS_ENABLED 0x08 /*!< Hysteresis enabled */ +#define BCM2835_PAD_DRIVE_2mA 0x00 /*!< 2mA drive current */ +#define BCM2835_PAD_DRIVE_4mA 0x01 /*!< 4mA drive current */ +#define BCM2835_PAD_DRIVE_6mA 0x02 /*!< 6mA drive current */ +#define BCM2835_PAD_DRIVE_8mA 0x03 /*!< 8mA drive current */ +#define BCM2835_PAD_DRIVE_10mA 0x04 /*!< 10mA drive current */ +#define BCM2835_PAD_DRIVE_12mA 0x05 /*!< 12mA drive current */ +#define BCM2835_PAD_DRIVE_14mA 0x06 /*!< 14mA drive current */ +#define BCM2835_PAD_DRIVE_16mA 0x07 /*!< 16mA drive current */ + +/*! \brief bcm2835PadGroup + Pad group specification for bcm2835_gpio_pad() +*/ +typedef enum +{ + BCM2835_PAD_GROUP_GPIO_0_27 = 0, /*!< Pad group for GPIO pads 0 to 27 */ + BCM2835_PAD_GROUP_GPIO_28_45 = 1, /*!< Pad group for GPIO pads 28 to 45 */ + BCM2835_PAD_GROUP_GPIO_46_53 = 2 /*!< Pad group for GPIO pads 46 to 53 */ +} bcm2835PadGroup; + +/*! \brief GPIO Pin Numbers + + Here we define Raspberry Pin GPIO pins on P1 in terms of the underlying BCM GPIO pin numbers. + These can be passed as a pin number to any function requiring a pin. + Not all pins on the RPi 26 bin IDE plug are connected to GPIO pins + and some can adopt an alternate function. + RPi version 2 has some slightly different pinouts, and these are values RPI_V2_*. + RPi B+ has yet differnet pinouts and these are defined in RPI_BPLUS_*. + At bootup, pins 8 and 10 are set to UART0_TXD, UART0_RXD (ie the alt0 function) respectively + When SPI0 is in use (ie after bcm2835_spi_begin()), SPI0 pins are dedicated to SPI + and cant be controlled independently. + If you are using the RPi Compute Module, just use the GPIO number: there is no need to use one of these + symbolic names +*/ +typedef enum +{ + RPI_GPIO_P1_03 = 0, /*!< Version 1, Pin P1-03 */ + RPI_GPIO_P1_05 = 1, /*!< Version 1, Pin P1-05 */ + RPI_GPIO_P1_07 = 4, /*!< Version 1, Pin P1-07 */ + RPI_GPIO_P1_08 = 14, /*!< Version 1, Pin P1-08, defaults to alt function 0 UART0_TXD */ + RPI_GPIO_P1_10 = 15, /*!< Version 1, Pin P1-10, defaults to alt function 0 UART0_RXD */ + RPI_GPIO_P1_11 = 17, /*!< Version 1, Pin P1-11 */ + RPI_GPIO_P1_12 = 18, /*!< Version 1, Pin P1-12, can be PWM channel 0 in ALT FUN 5 */ + RPI_GPIO_P1_13 = 21, /*!< Version 1, Pin P1-13 */ + RPI_GPIO_P1_15 = 22, /*!< Version 1, Pin P1-15 */ + RPI_GPIO_P1_16 = 23, /*!< Version 1, Pin P1-16 */ + RPI_GPIO_P1_18 = 24, /*!< Version 1, Pin P1-18 */ + RPI_GPIO_P1_19 = 10, /*!< Version 1, Pin P1-19, MOSI when SPI0 in use */ + RPI_GPIO_P1_21 = 9, /*!< Version 1, Pin P1-21, MISO when SPI0 in use */ + RPI_GPIO_P1_22 = 25, /*!< Version 1, Pin P1-22 */ + RPI_GPIO_P1_23 = 11, /*!< Version 1, Pin P1-23, CLK when SPI0 in use */ + RPI_GPIO_P1_24 = 8, /*!< Version 1, Pin P1-24, CE0 when SPI0 in use */ + RPI_GPIO_P1_26 = 7, /*!< Version 1, Pin P1-26, CE1 when SPI0 in use */ + + /* RPi Version 2 */ + RPI_V2_GPIO_P1_03 = 2, /*!< Version 2, Pin P1-03 */ + RPI_V2_GPIO_P1_05 = 3, /*!< Version 2, Pin P1-05 */ + RPI_V2_GPIO_P1_07 = 4, /*!< Version 2, Pin P1-07 */ + RPI_V2_GPIO_P1_08 = 14, /*!< Version 2, Pin P1-08, defaults to alt function 0 UART0_TXD */ + RPI_V2_GPIO_P1_10 = 15, /*!< Version 2, Pin P1-10, defaults to alt function 0 UART0_RXD */ + RPI_V2_GPIO_P1_11 = 17, /*!< Version 2, Pin P1-11 */ + RPI_V2_GPIO_P1_12 = 18, /*!< Version 2, Pin P1-12, can be PWM channel 0 in ALT FUN 5 */ + RPI_V2_GPIO_P1_13 = 27, /*!< Version 2, Pin P1-13 */ + RPI_V2_GPIO_P1_15 = 22, /*!< Version 2, Pin P1-15 */ + RPI_V2_GPIO_P1_16 = 23, /*!< Version 2, Pin P1-16 */ + RPI_V2_GPIO_P1_18 = 24, /*!< Version 2, Pin P1-18 */ + RPI_V2_GPIO_P1_19 = 10, /*!< Version 2, Pin P1-19, MOSI when SPI0 in use */ + RPI_V2_GPIO_P1_21 = 9, /*!< Version 2, Pin P1-21, MISO when SPI0 in use */ + RPI_V2_GPIO_P1_22 = 25, /*!< Version 2, Pin P1-22 */ + RPI_V2_GPIO_P1_23 = 11, /*!< Version 2, Pin P1-23, CLK when SPI0 in use */ + RPI_V2_GPIO_P1_24 = 8, /*!< Version 2, Pin P1-24, CE0 when SPI0 in use */ + RPI_V2_GPIO_P1_26 = 7, /*!< Version 2, Pin P1-26, CE1 when SPI0 in use */ + RPI_V2_GPIO_P1_29 = 5, /*!< Version 2, Pin P1-29 */ + RPI_V2_GPIO_P1_31 = 6, /*!< Version 2, Pin P1-31 */ + RPI_V2_GPIO_P1_32 = 12, /*!< Version 2, Pin P1-32 */ + RPI_V2_GPIO_P1_33 = 13, /*!< Version 2, Pin P1-33 */ + RPI_V2_GPIO_P1_35 = 19, /*!< Version 2, Pin P1-35 */ + RPI_V2_GPIO_P1_36 = 16, /*!< Version 2, Pin P1-36 */ + RPI_V2_GPIO_P1_37 = 26, /*!< Version 2, Pin P1-37 */ + RPI_V2_GPIO_P1_38 = 20, /*!< Version 2, Pin P1-38 */ + RPI_V2_GPIO_P1_40 = 21, /*!< Version 2, Pin P1-40 */ + + /* RPi Version 2, new plug P5 */ + RPI_V2_GPIO_P5_03 = 28, /*!< Version 2, Pin P5-03 */ + RPI_V2_GPIO_P5_04 = 29, /*!< Version 2, Pin P5-04 */ + RPI_V2_GPIO_P5_05 = 30, /*!< Version 2, Pin P5-05 */ + RPI_V2_GPIO_P5_06 = 31, /*!< Version 2, Pin P5-06 */ + + /* RPi B+ J8 header, also RPi 2 40 pin GPIO header */ + RPI_BPLUS_GPIO_J8_03 = 2, /*!< B+, Pin J8-03 */ + RPI_BPLUS_GPIO_J8_05 = 3, /*!< B+, Pin J8-05 */ + RPI_BPLUS_GPIO_J8_07 = 4, /*!< B+, Pin J8-07 */ + RPI_BPLUS_GPIO_J8_08 = 14, /*!< B+, Pin J8-08, defaults to alt function 0 UART0_TXD */ + RPI_BPLUS_GPIO_J8_10 = 15, /*!< B+, Pin J8-10, defaults to alt function 0 UART0_RXD */ + RPI_BPLUS_GPIO_J8_11 = 17, /*!< B+, Pin J8-11 */ + RPI_BPLUS_GPIO_J8_12 = 18, /*!< B+, Pin J8-12, can be PWM channel 0 in ALT FUN 5 */ + RPI_BPLUS_GPIO_J8_13 = 27, /*!< B+, Pin J8-13 */ + RPI_BPLUS_GPIO_J8_15 = 22, /*!< B+, Pin J8-15 */ + RPI_BPLUS_GPIO_J8_16 = 23, /*!< B+, Pin J8-16 */ + RPI_BPLUS_GPIO_J8_18 = 24, /*!< B+, Pin J8-18 */ + RPI_BPLUS_GPIO_J8_19 = 10, /*!< B+, Pin J8-19, MOSI when SPI0 in use */ + RPI_BPLUS_GPIO_J8_21 = 9, /*!< B+, Pin J8-21, MISO when SPI0 in use */ + RPI_BPLUS_GPIO_J8_22 = 25, /*!< B+, Pin J8-22 */ + RPI_BPLUS_GPIO_J8_23 = 11, /*!< B+, Pin J8-23, CLK when SPI0 in use */ + RPI_BPLUS_GPIO_J8_24 = 8, /*!< B+, Pin J8-24, CE0 when SPI0 in use */ + RPI_BPLUS_GPIO_J8_26 = 7, /*!< B+, Pin J8-26, CE1 when SPI0 in use */ + RPI_BPLUS_GPIO_J8_29 = 5, /*!< B+, Pin J8-29, */ + RPI_BPLUS_GPIO_J8_31 = 6, /*!< B+, Pin J8-31, */ + RPI_BPLUS_GPIO_J8_32 = 12, /*!< B+, Pin J8-32, */ + RPI_BPLUS_GPIO_J8_33 = 13, /*!< B+, Pin J8-33, */ + RPI_BPLUS_GPIO_J8_35 = 19, /*!< B+, Pin J8-35, */ + RPI_BPLUS_GPIO_J8_36 = 16, /*!< B+, Pin J8-36, */ + RPI_BPLUS_GPIO_J8_37 = 26, /*!< B+, Pin J8-37, */ + RPI_BPLUS_GPIO_J8_38 = 20, /*!< B+, Pin J8-38, */ + RPI_BPLUS_GPIO_J8_40 = 21 /*!< B+, Pin J8-40, */ +} RPiGPIOPin; + +/* Defines for SPI + GPIO register offsets from BCM2835_SPI0_BASE. + Offsets into the SPI Peripheral block in bytes per 10.5 SPI Register Map +*/ +#define BCM2835_SPI0_CS 0x0000 /*!< SPI Master Control and Status */ +#define BCM2835_SPI0_FIFO 0x0004 /*!< SPI Master TX and RX FIFOs */ +#define BCM2835_SPI0_CLK 0x0008 /*!< SPI Master Clock Divider */ +#define BCM2835_SPI0_DLEN 0x000c /*!< SPI Master Data Length */ +#define BCM2835_SPI0_LTOH 0x0010 /*!< SPI LOSSI mode TOH */ +#define BCM2835_SPI0_DC 0x0014 /*!< SPI DMA DREQ Controls */ + +/* Register masks for SPI0_CS */ +#define BCM2835_SPI0_CS_LEN_LONG 0x02000000 /*!< Enable Long data word in Lossi mode if DMA_LEN is set */ +#define BCM2835_SPI0_CS_DMA_LEN 0x01000000 /*!< Enable DMA mode in Lossi mode */ +#define BCM2835_SPI0_CS_CSPOL2 0x00800000 /*!< Chip Select 2 Polarity */ +#define BCM2835_SPI0_CS_CSPOL1 0x00400000 /*!< Chip Select 1 Polarity */ +#define BCM2835_SPI0_CS_CSPOL0 0x00200000 /*!< Chip Select 0 Polarity */ +#define BCM2835_SPI0_CS_RXF 0x00100000 /*!< RXF - RX FIFO Full */ +#define BCM2835_SPI0_CS_RXR 0x00080000 /*!< RXR RX FIFO needs Reading (full) */ +#define BCM2835_SPI0_CS_TXD 0x00040000 /*!< TXD TX FIFO can accept Data */ +#define BCM2835_SPI0_CS_RXD 0x00020000 /*!< RXD RX FIFO contains Data */ +#define BCM2835_SPI0_CS_DONE 0x00010000 /*!< Done transfer Done */ +#define BCM2835_SPI0_CS_TE_EN 0x00008000 /*!< Unused */ +#define BCM2835_SPI0_CS_LMONO 0x00004000 /*!< Unused */ +#define BCM2835_SPI0_CS_LEN 0x00002000 /*!< LEN LoSSI enable */ +#define BCM2835_SPI0_CS_REN 0x00001000 /*!< REN Read Enable */ +#define BCM2835_SPI0_CS_ADCS 0x00000800 /*!< ADCS Automatically Deassert Chip Select */ +#define BCM2835_SPI0_CS_INTR 0x00000400 /*!< INTR Interrupt on RXR */ +#define BCM2835_SPI0_CS_INTD 0x00000200 /*!< INTD Interrupt on Done */ +#define BCM2835_SPI0_CS_DMAEN 0x00000100 /*!< DMAEN DMA Enable */ +#define BCM2835_SPI0_CS_TA 0x00000080 /*!< Transfer Active */ +#define BCM2835_SPI0_CS_CSPOL 0x00000040 /*!< Chip Select Polarity */ +#define BCM2835_SPI0_CS_CLEAR 0x00000030 /*!< Clear FIFO Clear RX and TX */ +#define BCM2835_SPI0_CS_CLEAR_RX 0x00000020 /*!< Clear FIFO Clear RX */ +#define BCM2835_SPI0_CS_CLEAR_TX 0x00000010 /*!< Clear FIFO Clear TX */ +#define BCM2835_SPI0_CS_CPOL 0x00000008 /*!< Clock Polarity */ +#define BCM2835_SPI0_CS_CPHA 0x00000004 /*!< Clock Phase */ +#define BCM2835_SPI0_CS_CS 0x00000003 /*!< Chip Select */ + +/*! \brief bcm2835SPIBitOrder SPI Bit order + Specifies the SPI data bit ordering for bcm2835_spi_setBitOrder() +*/ +typedef enum +{ + BCM2835_SPI_BIT_ORDER_LSBFIRST = 0, /*!< LSB First */ + BCM2835_SPI_BIT_ORDER_MSBFIRST = 1 /*!< MSB First */ +}bcm2835SPIBitOrder; + +/*! \brief SPI Data mode + Specify the SPI data mode to be passed to bcm2835_spi_setDataMode() +*/ +typedef enum +{ + BCM2835_SPI_MODE0 = 0, /*!< CPOL = 0, CPHA = 0 */ + BCM2835_SPI_MODE1 = 1, /*!< CPOL = 0, CPHA = 1 */ + BCM2835_SPI_MODE2 = 2, /*!< CPOL = 1, CPHA = 0 */ + BCM2835_SPI_MODE3 = 3 /*!< CPOL = 1, CPHA = 1 */ +}bcm2835SPIMode; + +/*! \brief bcm2835SPIChipSelect + Specify the SPI chip select pin(s) +*/ +typedef enum +{ + BCM2835_SPI_CS0 = 0, /*!< Chip Select 0 */ + BCM2835_SPI_CS1 = 1, /*!< Chip Select 1 */ + BCM2835_SPI_CS2 = 2, /*!< Chip Select 2 (ie pins CS1 and CS2 are asserted) */ + BCM2835_SPI_CS_NONE = 3 /*!< No CS, control it yourself */ +} bcm2835SPIChipSelect; + +/*! \brief bcm2835SPIClockDivider + Specifies the divider used to generate the SPI clock from the system clock. + Figures below give the divider, clock period and clock frequency. + Clock divided is based on nominal base clock rate of 250MHz + It is reported that (contrary to the documentation) any even divider may used. + The frequencies shown for each divider have been confirmed by measurement. +*/ +typedef enum +{ + BCM2835_SPI_CLOCK_DIVIDER_65536 = 0, /*!< 65536 = 262.144us = 3.814697260kHz */ + BCM2835_SPI_CLOCK_DIVIDER_32768 = 32768, /*!< 32768 = 131.072us = 7.629394531kHz */ + BCM2835_SPI_CLOCK_DIVIDER_16384 = 16384, /*!< 16384 = 65.536us = 15.25878906kHz */ + BCM2835_SPI_CLOCK_DIVIDER_8192 = 8192, /*!< 8192 = 32.768us = 30/51757813kHz */ + BCM2835_SPI_CLOCK_DIVIDER_4096 = 4096, /*!< 4096 = 16.384us = 61.03515625kHz */ + BCM2835_SPI_CLOCK_DIVIDER_2048 = 2048, /*!< 2048 = 8.192us = 122.0703125kHz */ + BCM2835_SPI_CLOCK_DIVIDER_1024 = 1024, /*!< 1024 = 4.096us = 244.140625kHz */ + BCM2835_SPI_CLOCK_DIVIDER_512 = 512, /*!< 512 = 2.048us = 488.28125kHz */ + BCM2835_SPI_CLOCK_DIVIDER_256 = 256, /*!< 256 = 1.024us = 976.5625kHz */ + BCM2835_SPI_CLOCK_DIVIDER_128 = 128, /*!< 128 = 512ns = = 1.953125MHz */ + BCM2835_SPI_CLOCK_DIVIDER_64 = 64, /*!< 64 = 256ns = 3.90625MHz */ + BCM2835_SPI_CLOCK_DIVIDER_32 = 32, /*!< 32 = 128ns = 7.8125MHz */ + BCM2835_SPI_CLOCK_DIVIDER_16 = 16, /*!< 16 = 64ns = 15.625MHz */ + BCM2835_SPI_CLOCK_DIVIDER_8 = 8, /*!< 8 = 32ns = 31.25MHz */ + BCM2835_SPI_CLOCK_DIVIDER_4 = 4, /*!< 4 = 16ns = 62.5MHz */ + BCM2835_SPI_CLOCK_DIVIDER_2 = 2, /*!< 2 = 8ns = 125MHz, fastest you can get */ + BCM2835_SPI_CLOCK_DIVIDER_1 = 1 /*!< 1 = 262.144us = 3.814697260kHz, same as 0/65536 */ +} bcm2835SPIClockDivider; + +/* Defines for I2C + GPIO register offsets from BCM2835_BSC*_BASE. + Offsets into the BSC Peripheral block in bytes per 3.1 BSC Register Map +*/ +#define BCM2835_BSC_C 0x0000 /*!< BSC Master Control */ +#define BCM2835_BSC_S 0x0004 /*!< BSC Master Status */ +#define BCM2835_BSC_DLEN 0x0008 /*!< BSC Master Data Length */ +#define BCM2835_BSC_A 0x000c /*!< BSC Master Slave Address */ +#define BCM2835_BSC_FIFO 0x0010 /*!< BSC Master Data FIFO */ +#define BCM2835_BSC_DIV 0x0014 /*!< BSC Master Clock Divider */ +#define BCM2835_BSC_DEL 0x0018 /*!< BSC Master Data Delay */ +#define BCM2835_BSC_CLKT 0x001c /*!< BSC Master Clock Stretch Timeout */ + +/* Register masks for BSC_C */ +#define BCM2835_BSC_C_I2CEN 0x00008000 /*!< I2C Enable, 0 = disabled, 1 = enabled */ +#define BCM2835_BSC_C_INTR 0x00000400 /*!< Interrupt on RX */ +#define BCM2835_BSC_C_INTT 0x00000200 /*!< Interrupt on TX */ +#define BCM2835_BSC_C_INTD 0x00000100 /*!< Interrupt on DONE */ +#define BCM2835_BSC_C_ST 0x00000080 /*!< Start transfer, 1 = Start a new transfer */ +#define BCM2835_BSC_C_CLEAR_1 0x00000020 /*!< Clear FIFO Clear */ +#define BCM2835_BSC_C_CLEAR_2 0x00000010 /*!< Clear FIFO Clear */ +#define BCM2835_BSC_C_READ 0x00000001 /*!< Read transfer */ + +/* Register masks for BSC_S */ +#define BCM2835_BSC_S_CLKT 0x00000200 /*!< Clock stretch timeout */ +#define BCM2835_BSC_S_ERR 0x00000100 /*!< ACK error */ +#define BCM2835_BSC_S_RXF 0x00000080 /*!< RXF FIFO full, 0 = FIFO is not full, 1 = FIFO is full */ +#define BCM2835_BSC_S_TXE 0x00000040 /*!< TXE FIFO full, 0 = FIFO is not full, 1 = FIFO is full */ +#define BCM2835_BSC_S_RXD 0x00000020 /*!< RXD FIFO contains data */ +#define BCM2835_BSC_S_TXD 0x00000010 /*!< TXD FIFO can accept data */ +#define BCM2835_BSC_S_RXR 0x00000008 /*!< RXR FIFO needs reading (full) */ +#define BCM2835_BSC_S_TXW 0x00000004 /*!< TXW FIFO needs writing (full) */ +#define BCM2835_BSC_S_DONE 0x00000002 /*!< Transfer DONE */ +#define BCM2835_BSC_S_TA 0x00000001 /*!< Transfer Active */ + +#define BCM2835_BSC_FIFO_SIZE 16 /*!< BSC FIFO size */ + +/*! \brief bcm2835I2CClockDivider + Specifies the divider used to generate the I2C clock from the system clock. + Clock divided is based on nominal base clock rate of 250MHz +*/ +typedef enum +{ + BCM2835_I2C_CLOCK_DIVIDER_2500 = 2500, /*!< 2500 = 10us = 100 kHz */ + BCM2835_I2C_CLOCK_DIVIDER_626 = 626, /*!< 622 = 2.504us = 399.3610 kHz */ + BCM2835_I2C_CLOCK_DIVIDER_150 = 150, /*!< 150 = 60ns = 1.666 MHz (default at reset) */ + BCM2835_I2C_CLOCK_DIVIDER_148 = 148 /*!< 148 = 59ns = 1.689 MHz */ +} bcm2835I2CClockDivider; + +/*! \brief bcm2835I2CReasonCodes + Specifies the reason codes for the bcm2835_i2c_write and bcm2835_i2c_read functions. +*/ +typedef enum +{ + BCM2835_I2C_REASON_OK = 0x00, /*!< Success */ + BCM2835_I2C_REASON_ERROR_NACK = 0x01, /*!< Received a NACK */ + BCM2835_I2C_REASON_ERROR_CLKT = 0x02, /*!< Received Clock Stretch Timeout */ + BCM2835_I2C_REASON_ERROR_DATA = 0x04 /*!< Not all data is sent / received */ +} bcm2835I2CReasonCodes; + +/* Defines for ST + GPIO register offsets from BCM2835_ST_BASE. + Offsets into the ST Peripheral block in bytes per 12.1 System Timer Registers + The System Timer peripheral provides four 32-bit timer channels and a single 64-bit free running counter. + BCM2835_ST_CLO is the System Timer Counter Lower bits register. + The system timer free-running counter lower register is a read-only register that returns the current value + of the lower 32-bits of the free running counter. + BCM2835_ST_CHI is the System Timer Counter Upper bits register. + The system timer free-running counter upper register is a read-only register that returns the current value + of the upper 32-bits of the free running counter. +*/ +#define BCM2835_ST_CS 0x0000 /*!< System Timer Control/Status */ +#define BCM2835_ST_CLO 0x0004 /*!< System Timer Counter Lower 32 bits */ +#define BCM2835_ST_CHI 0x0008 /*!< System Timer Counter Upper 32 bits */ + +/* Defines for PWM, word offsets (ie 4 byte multiples) */ +#define BCM2835_PWM_CONTROL 0 /*!< PWM Control register */ +#define BCM2835_PWM_STATUS 1 /*!< PWM Status register */ +#define BCM2835_PWM_DMAC 2 /*!< PWM DMA Configuration */ +#define BCM2835_PWM0_RANGE 4 /*!< PWM Channel 0 Range */ +#define BCM2835_PWM0_DATA 5 /*!< PWM Channel 0 Data */ +#define BCM2835_PWM_FIF1 6 /*!< PWM FIFO Input */ +#define BCM2835_PWM1_RANGE 8 /*!< PWM Channel 1 Range */ +#define BCM2835_PWM1_DATA 9 /*!< PWM Channel 1 Data */ + +/* Defines for PWM Clock, word offsets (ie 4 byte multiples) */ +#define BCM2835_PWMCLK_CNTL 40 /*!< PWM Clock Control */ +#define BCM2835_PWMCLK_DIV 41 /*!< PWM Clock Divider */ +#define BCM2835_PWM_PASSWRD (0x5A << 24) /*!< Password to enable setting PWM clock */ + +#define BCM2835_PWM1_MS_MODE 0x8000 /*!< Run in Mark/Space mode */ +#define BCM2835_PWM1_USEFIFO 0x2000 /*!< Data from FIFO */ +#define BCM2835_PWM1_REVPOLAR 0x1000 /*!< Reverse polarity */ +#define BCM2835_PWM1_OFFSTATE 0x0800 /*!< Ouput Off state */ +#define BCM2835_PWM1_REPEATFF 0x0400 /*!< Repeat last value if FIFO empty */ +#define BCM2835_PWM1_SERIAL 0x0200 /*!< Run in serial mode */ +#define BCM2835_PWM1_ENABLE 0x0100 /*!< Channel Enable */ + +#define BCM2835_PWM0_MS_MODE 0x0080 /*!< Run in Mark/Space mode */ +#define BCM2835_PWM_CLEAR_FIFO 0x0040 /*!< Clear FIFO */ +#define BCM2835_PWM0_USEFIFO 0x0020 /*!< Data from FIFO */ +#define BCM2835_PWM0_REVPOLAR 0x0010 /*!< Reverse polarity */ +#define BCM2835_PWM0_OFFSTATE 0x0008 /*!< Ouput Off state */ +#define BCM2835_PWM0_REPEATFF 0x0004 /*!< Repeat last value if FIFO empty */ +#define BCM2835_PWM0_SERIAL 0x0002 /*!< Run in serial mode */ +#define BCM2835_PWM0_ENABLE 0x0001 /*!< Channel Enable */ + +/*! \brief bcm2835PWMClockDivider + Specifies the divider used to generate the PWM clock from the system clock. + Figures below give the divider, clock period and clock frequency. + Clock divided is based on nominal PWM base clock rate of 19.2MHz + The frequencies shown for each divider have been confirmed by measurement +*/ +typedef enum +{ + BCM2835_PWM_CLOCK_DIVIDER_2048 = 2048, /*!< 2048 = 9.375kHz */ + BCM2835_PWM_CLOCK_DIVIDER_1024 = 1024, /*!< 1024 = 18.75kHz */ + BCM2835_PWM_CLOCK_DIVIDER_512 = 512, /*!< 512 = 37.5kHz */ + BCM2835_PWM_CLOCK_DIVIDER_256 = 256, /*!< 256 = 75kHz */ + BCM2835_PWM_CLOCK_DIVIDER_128 = 128, /*!< 128 = 150kHz */ + BCM2835_PWM_CLOCK_DIVIDER_64 = 64, /*!< 64 = 300kHz */ + BCM2835_PWM_CLOCK_DIVIDER_32 = 32, /*!< 32 = 600.0kHz */ + BCM2835_PWM_CLOCK_DIVIDER_16 = 16, /*!< 16 = 1.2MHz */ + BCM2835_PWM_CLOCK_DIVIDER_8 = 8, /*!< 8 = 2.4MHz */ + BCM2835_PWM_CLOCK_DIVIDER_4 = 4, /*!< 4 = 4.8MHz */ + BCM2835_PWM_CLOCK_DIVIDER_2 = 2, /*!< 2 = 9.6MHz, fastest you can get */ + BCM2835_PWM_CLOCK_DIVIDER_1 = 1 /*!< 1 = 4.6875kHz, same as divider 4096 */ +} bcm2835PWMClockDivider; + +/*! @} */ + +/* Historical name compatibility */ +#ifndef BCM2835_NO_DELAY_COMPATIBILITY +#define delay(x) bcm2835_delay(x) +#define delayMicroseconds(x) bcm2835_delayMicroseconds(x) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + /*! \defgroup BCM2835initgrp Library initialisation and management + \ingroup BCM2835grp + These functions allow you to intialise and control the bcm2835 library + @{ + */ + + /*! Initialise the library by opening /dev/mem (if you are root) + or /dev/gpiomem (if you are not) + and getting pointers to the + internal memory for BCM 2835 device registers. You must call this (successfully) + before calling any other + functions in this library (except bcm2835_set_debug). + If bcm2835_init() fails by returning 0, + calling any other function may result in crashes or other failures. + If bcm2835_init() succeeds but you are not running as root, then only gpio operations + are permitted, and calling any other functions may result in crashes or other failures. . + Prints messages to stderr in case of errors. + \return 1 if successful else 0 + */ + extern int bcm2835_init(void); + + /*! Close the library, deallocating any allocated memory and closing /dev/mem + \return 1 if successful else 0 + */ + extern int bcm2835_close(void); + + /*! Sets the debug level of the library. + A value of 1 prevents mapping to /dev/mem, and makes the library print out + what it would do, rather than accessing the GPIO registers. + A value of 0, the default, causes normal operation. + Call this before calling bcm2835_init(); + \param[in] debug The new debug level. 1 means debug + */ + extern void bcm2835_set_debug(uint8_t debug); + + /*! Returns the version number of the library, same as BCM2835_VERSION + \return the current library version number + */ + extern unsigned int bcm2835_version(void); + + /*! @} */ + + /*! \defgroup BCM2835lowlevelgrp Low level register access + \ingroup BCM2835grp + These functions provide low level register access, and should not generally + need to be used + + @{ + */ + + /*! Gets the base of a register + \param[in] regbase You can use one of the common values BCM2835_REGBASE_* + in \ref bcm2835RegisterBase + \return the register base + \sa Physical Addresses + */ + extern uint32_t* bcm2835_regbase(uint8_t regbase); + + /*! Reads 32 bit value from a peripheral address WITH a memory barrier before and after each read. + This is safe, but slow. The MB before protects this read from any in-flight reads that didn't + use a MB. The MB after protects subsequent reads from another peripheral. + + \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc. + \return the value read from the 32 bit register + \sa Physical Addresses + */ + extern uint32_t bcm2835_peri_read(volatile uint32_t* paddr); + + /*! Reads 32 bit value from a peripheral address WITHOUT the read barriers + You should only use this when: + o your code has previously called bcm2835_peri_read() for a register + within the same peripheral, and no read or write to another peripheral has occurred since. + o your code has called bcm2835_memory_barrier() since the last access to ANOTHER peripheral. + + \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc. + \return the value read from the 32 bit register + \sa Physical Addresses + */ + extern uint32_t bcm2835_peri_read_nb(volatile uint32_t* paddr); + + + /*! Writes 32 bit value from a peripheral address WITH a memory barrier before and after each write + This is safe, but slow. The MB before ensures that any in-flight write to another peripheral + completes before this write is issued. The MB after ensures that subsequent reads and writes + to another peripheral will see the effect of this write. + + This is a tricky optimization; if you aren't sure, use the barrier version. + + \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc. + \param[in] value The 32 bit value to write + \sa Physical Addresses + */ + extern void bcm2835_peri_write(volatile uint32_t* paddr, uint32_t value); + + /*! Writes 32 bit value from a peripheral address without the write barrier + You should only use this when: + o your code has previously called bcm2835_peri_write() for a register + within the same peripheral, and no other peripheral access has occurred since. + o your code has called bcm2835_memory_barrier() since the last access to ANOTHER peripheral. + + This is a tricky optimization; if you aren't sure, use the barrier version. + + \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc. + \param[in] value The 32 bit value to write + \sa Physical Addresses + */ + extern void bcm2835_peri_write_nb(volatile uint32_t* paddr, uint32_t value); + + /*! Alters a number of bits in a 32 peripheral regsiter. + It reads the current valu and then alters the bits defines as 1 in mask, + according to the bit value in value. + All other bits that are 0 in the mask are unaffected. + Use this to alter a subset of the bits in a register. + Memory barriers are used. Note that this is not atomic; an interrupt + routine can cause unexpected results. + \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc. + \param[in] value The 32 bit value to write, masked in by mask. + \param[in] mask Bitmask that defines the bits that will be altered in the register. + \sa Physical Addresses + */ + extern void bcm2835_peri_set_bits(volatile uint32_t* paddr, uint32_t value, uint32_t mask); + /*! @} end of lowlevel */ + + /*! \defgroup BCM2835gpiogrp GPIO register access + \ingroup BCM2835grp + These functions allow you to control the GPIO interface. You can set the + function of each GPIO pin, read the input state and set the output state. + @{ + */ + + /*! Sets the Function Select register for the given pin, which configures + the pin as Input, Output or one of the 6 alternate functions. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + \param[in] mode Mode to set the pin to, one of BCM2835_GPIO_FSEL_* from \ref bcm2835FunctionSelect + */ + extern void bcm2835_gpio_fsel(uint8_t pin, uint8_t mode); + + /*! Sets the specified pin output to + HIGH. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + \sa bcm2835_gpio_write() + */ + extern void bcm2835_gpio_set(uint8_t pin); + + /*! Sets the specified pin output to + LOW. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + \sa bcm2835_gpio_write() + */ + extern void bcm2835_gpio_clr(uint8_t pin); + + /*! Sets any of the first 32 GPIO output pins specified in the mask to + HIGH. + \param[in] mask Mask of pins to affect. Use eg: (1 << RPI_GPIO_P1_03) | (1 << RPI_GPIO_P1_05) + \sa bcm2835_gpio_write_multi() + */ + extern void bcm2835_gpio_set_multi(uint32_t mask); + + /*! Sets any of the first 32 GPIO output pins specified in the mask to + LOW. + \param[in] mask Mask of pins to affect. Use eg: (1 << RPI_GPIO_P1_03) | (1 << RPI_GPIO_P1_05) + \sa bcm2835_gpio_write_multi() + */ + extern void bcm2835_gpio_clr_multi(uint32_t mask); + + /*! Reads the current level on the specified + pin and returns either HIGH or LOW. Works whether or not the pin + is an input or an output. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + \return the current level either HIGH or LOW + */ + extern uint8_t bcm2835_gpio_lev(uint8_t pin); + + /*! Event Detect Status. + Tests whether the specified pin has detected a level or edge + as requested by bcm2835_gpio_ren(), bcm2835_gpio_fen(), bcm2835_gpio_hen(), + bcm2835_gpio_len(), bcm2835_gpio_aren(), bcm2835_gpio_afen(). + Clear the flag for a given pin by calling bcm2835_gpio_set_eds(pin); + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + \return HIGH if the event detect status for the given pin is true. + */ + extern uint8_t bcm2835_gpio_eds(uint8_t pin); + + /*! Same as bcm2835_gpio_eds() but checks if any of the pins specified in + the mask have detected a level or edge. + \param[in] mask Mask of pins to check. Use eg: (1 << RPI_GPIO_P1_03) | (1 << RPI_GPIO_P1_05) + \return Mask of pins HIGH if the event detect status for the given pin is true. + */ + extern uint32_t bcm2835_gpio_eds_multi(uint32_t mask); + + /*! Sets the Event Detect Status register for a given pin to 1, + which has the effect of clearing the flag. Use this afer seeing + an Event Detect Status on the pin. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + */ + extern void bcm2835_gpio_set_eds(uint8_t pin); + + /*! Same as bcm2835_gpio_set_eds() but clears the flag for any pin which + is set in the mask. + \param[in] mask Mask of pins to clear. Use eg: (1 << RPI_GPIO_P1_03) | (1 << RPI_GPIO_P1_05) + */ + extern void bcm2835_gpio_set_eds_multi(uint32_t mask); + + /*! Enable Rising Edge Detect Enable for the specified pin. + When a rising edge is detected, sets the appropriate pin in Event Detect Status. + The GPRENn registers use + synchronous edge detection. This means the input signal is sampled using the + system clock and then it is looking for a ?011? pattern on the sampled signal. This + has the effect of suppressing glitches. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + */ + extern void bcm2835_gpio_ren(uint8_t pin); + + /*! Disable Rising Edge Detect Enable for the specified pin. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + */ + extern void bcm2835_gpio_clr_ren(uint8_t pin); + + /*! Enable Falling Edge Detect Enable for the specified pin. + When a falling edge is detected, sets the appropriate pin in Event Detect Status. + The GPRENn registers use + synchronous edge detection. This means the input signal is sampled using the + system clock and then it is looking for a ?100? pattern on the sampled signal. This + has the effect of suppressing glitches. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + */ + extern void bcm2835_gpio_fen(uint8_t pin); + + /*! Disable Falling Edge Detect Enable for the specified pin. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + */ + extern void bcm2835_gpio_clr_fen(uint8_t pin); + + /*! Enable High Detect Enable for the specified pin. + When a HIGH level is detected on the pin, sets the appropriate pin in Event Detect Status. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + */ + extern void bcm2835_gpio_hen(uint8_t pin); + + /*! Disable High Detect Enable for the specified pin. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + */ + extern void bcm2835_gpio_clr_hen(uint8_t pin); + + /*! Enable Low Detect Enable for the specified pin. + When a LOW level is detected on the pin, sets the appropriate pin in Event Detect Status. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + */ + extern void bcm2835_gpio_len(uint8_t pin); + + /*! Disable Low Detect Enable for the specified pin. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + */ + extern void bcm2835_gpio_clr_len(uint8_t pin); + + /*! Enable Asynchronous Rising Edge Detect Enable for the specified pin. + When a rising edge is detected, sets the appropriate pin in Event Detect Status. + Asynchronous means the incoming signal is not sampled by the system clock. As such + rising edges of very short duration can be detected. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + */ + extern void bcm2835_gpio_aren(uint8_t pin); + + /*! Disable Asynchronous Rising Edge Detect Enable for the specified pin. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + */ + extern void bcm2835_gpio_clr_aren(uint8_t pin); + + /*! Enable Asynchronous Falling Edge Detect Enable for the specified pin. + When a falling edge is detected, sets the appropriate pin in Event Detect Status. + Asynchronous means the incoming signal is not sampled by the system clock. As such + falling edges of very short duration can be detected. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + */ + extern void bcm2835_gpio_afen(uint8_t pin); + + /*! Disable Asynchronous Falling Edge Detect Enable for the specified pin. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + */ + extern void bcm2835_gpio_clr_afen(uint8_t pin); + + /*! Sets the Pull-up/down register for the given pin. This is + used with bcm2835_gpio_pudclk() to set the Pull-up/down resistor for the given pin. + However, it is usually more convenient to use bcm2835_gpio_set_pud(). + \param[in] pud The desired Pull-up/down mode. One of BCM2835_GPIO_PUD_* from bcm2835PUDControl + \sa bcm2835_gpio_set_pud() + */ + extern void bcm2835_gpio_pud(uint8_t pud); + + /*! Clocks the Pull-up/down value set earlier by bcm2835_gpio_pud() into the pin. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + \param[in] on HIGH to clock the value from bcm2835_gpio_pud() into the pin. + LOW to remove the clock. + \sa bcm2835_gpio_set_pud() + */ + extern void bcm2835_gpio_pudclk(uint8_t pin, uint8_t on); + + /*! Reads and returns the Pad Control for the given GPIO group. + \param[in] group The GPIO pad group number, one of BCM2835_PAD_GROUP_GPIO_* + \return Mask of bits from BCM2835_PAD_* from \ref bcm2835PadGroup + */ + extern uint32_t bcm2835_gpio_pad(uint8_t group); + + /*! Sets the Pad Control for the given GPIO group. + \param[in] group The GPIO pad group number, one of BCM2835_PAD_GROUP_GPIO_* + \param[in] control Mask of bits from BCM2835_PAD_* from \ref bcm2835PadGroup. Note + that it is not necessary to include BCM2835_PAD_PASSWRD in the mask as this + is automatically included. + */ + extern void bcm2835_gpio_set_pad(uint8_t group, uint32_t control); + + /*! Delays for the specified number of milliseconds. + Uses nanosleep(), and therefore does not use CPU until the time is up. + However, you are at the mercy of nanosleep(). From the manual for nanosleep(): + If the interval specified in req is not an exact multiple of the granularity + underlying clock (see time(7)), then the interval will be + rounded up to the next multiple. Furthermore, after the sleep completes, + there may still be a delay before the CPU becomes free to once + again execute the calling thread. + \param[in] millis Delay in milliseconds + */ + extern void bcm2835_delay (unsigned int millis); + + /*! Delays for the specified number of microseconds. + Uses a combination of nanosleep() and a busy wait loop on the BCM2835 system timers, + However, you are at the mercy of nanosleep(). From the manual for nanosleep(): + If the interval specified in req is not an exact multiple of the granularity + underlying clock (see time(7)), then the interval will be + rounded up to the next multiple. Furthermore, after the sleep completes, + there may still be a delay before the CPU becomes free to once + again execute the calling thread. + For times less than about 450 microseconds, uses a busy wait on the System Timer. + It is reported that a delay of 0 microseconds on RaspberryPi will in fact + result in a delay of about 80 microseconds. Your mileage may vary. + \param[in] micros Delay in microseconds + */ + extern void bcm2835_delayMicroseconds (uint64_t micros); + + /*! Sets the output state of the specified pin + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + \param[in] on HIGH sets the output to HIGH and LOW to LOW. + */ + extern void bcm2835_gpio_write(uint8_t pin, uint8_t on); + + /*! Sets any of the first 32 GPIO output pins specified in the mask to the state given by on + \param[in] mask Mask of pins to affect. Use eg: (1 << RPI_GPIO_P1_03) | (1 << RPI_GPIO_P1_05) + \param[in] on HIGH sets the output to HIGH and LOW to LOW. + */ + extern void bcm2835_gpio_write_multi(uint32_t mask, uint8_t on); + + /*! Sets the first 32 GPIO output pins specified in the mask to the value given by value + \param[in] value values required for each bit masked in by mask, eg: (1 << RPI_GPIO_P1_03) | (1 << RPI_GPIO_P1_05) + \param[in] mask Mask of pins to affect. Use eg: (1 << RPI_GPIO_P1_03) | (1 << RPI_GPIO_P1_05) + */ + extern void bcm2835_gpio_write_mask(uint32_t value, uint32_t mask); + + /*! Sets the Pull-up/down mode for the specified pin. This is more convenient than + clocking the mode in with bcm2835_gpio_pud() and bcm2835_gpio_pudclk(). + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + \param[in] pud The desired Pull-up/down mode. One of BCM2835_GPIO_PUD_* from bcm2835PUDControl + */ + extern void bcm2835_gpio_set_pud(uint8_t pin, uint8_t pud); + + /*! @} */ + + /*! \defgroup BCM2835spigrp SPI access + \ingroup BCM2835grp + These functions let you use SPI0 (Serial Peripheral Interface) to + interface with an external SPI device. + @{ + */ + + /*! Start SPI operations. + Forces RPi SPI0 pins P1-19 (MOSI), P1-21 (MISO), P1-23 (CLK), P1-24 (CE0) and P1-26 (CE1) + to alternate function ALT0, which enables those pins for SPI interface. + You should call bcm2835_spi_end() when all SPI funcitons are complete to return the pins to + their default functions. + \sa bcm2835_spi_end() + \return 1 if successful, 0 otherwise (perhaps because you are not running as root) + */ + extern int bcm2835_spi_begin(void); + + /*! End SPI operations. + SPI0 pins P1-19 (MOSI), P1-21 (MISO), P1-23 (CLK), P1-24 (CE0) and P1-26 (CE1) + are returned to their default INPUT behaviour. + */ + extern void bcm2835_spi_end(void); + + /*! Sets the SPI bit order + NOTE: has no effect. Not supported by SPI0. + Defaults to + \param[in] order The desired bit order, one of BCM2835_SPI_BIT_ORDER_*, + see \ref bcm2835SPIBitOrder + */ + extern void bcm2835_spi_setBitOrder(uint8_t order); + + /*! Sets the SPI clock divider and therefore the + SPI clock speed. + \param[in] divider The desired SPI clock divider, one of BCM2835_SPI_CLOCK_DIVIDER_*, + see \ref bcm2835SPIClockDivider + */ + extern void bcm2835_spi_setClockDivider(uint16_t divider); + + /*! Sets the SPI data mode + Sets the clock polariy and phase + \param[in] mode The desired data mode, one of BCM2835_SPI_MODE*, + see \ref bcm2835SPIMode + */ + extern void bcm2835_spi_setDataMode(uint8_t mode); + + /*! Sets the chip select pin(s) + When an bcm2835_spi_transfer() is made, the selected pin(s) will be asserted during the + transfer. + \param[in] cs Specifies the CS pins(s) that are used to activate the desired slave. + One of BCM2835_SPI_CS*, see \ref bcm2835SPIChipSelect + */ + extern void bcm2835_spi_chipSelect(uint8_t cs); + + /*! Sets the chip select pin polarity for a given pin + When an bcm2835_spi_transfer() occurs, the currently selected chip select pin(s) + will be asserted to the + value given by active. When transfers are not happening, the chip select pin(s) + return to the complement (inactive) value. + \param[in] cs The chip select pin to affect + \param[in] active Whether the chip select pin is to be active HIGH + */ + extern void bcm2835_spi_setChipSelectPolarity(uint8_t cs, uint8_t active); + + /*! Transfers one byte to and from the currently selected SPI slave. + Asserts the currently selected CS pins (as previously set by bcm2835_spi_chipSelect) + during the transfer. + Clocks the 8 bit value out on MOSI, and simultaneously clocks in data from MISO. + Returns the read data byte from the slave. + Uses polled transfer as per section 10.6.1 of the BCM 2835 ARM Peripherls manual + \param[in] value The 8 bit data byte to write to MOSI + \return The 8 bit byte simultaneously read from MISO + \sa bcm2835_spi_transfern() + */ + extern uint8_t bcm2835_spi_transfer(uint8_t value); + + /*! Transfers any number of bytes to and from the currently selected SPI slave. + Asserts the currently selected CS pins (as previously set by bcm2835_spi_chipSelect) + during the transfer. + Clocks the len 8 bit bytes out on MOSI, and simultaneously clocks in data from MISO. + The data read read from the slave is placed into rbuf. rbuf must be at least len bytes long + Uses polled transfer as per section 10.6.1 of the BCM 2835 ARM Peripherls manual + \param[in] tbuf Buffer of bytes to send. + \param[out] rbuf Received bytes will by put in this buffer + \param[in] len Number of bytes in the tbuf buffer, and the number of bytes to send/received + \sa bcm2835_spi_transfer() + */ + extern void bcm2835_spi_transfernb(char* tbuf, char* rbuf, uint32_t len); + + /*! Transfers any number of bytes to and from the currently selected SPI slave + using bcm2835_spi_transfernb. + The returned data from the slave replaces the transmitted data in the buffer. + \param[in,out] buf Buffer of bytes to send. Received bytes will replace the contents + \param[in] len Number of bytes int eh buffer, and the number of bytes to send/received + \sa bcm2835_spi_transfer() + */ + extern void bcm2835_spi_transfern(char* buf, uint32_t len); + + /*! Transfers any number of bytes to the currently selected SPI slave. + Asserts the currently selected CS pins (as previously set by bcm2835_spi_chipSelect) + during the transfer. + \param[in] buf Buffer of bytes to send. + \param[in] len Number of bytes in the tbuf buffer, and the number of bytes to send + */ + extern void bcm2835_spi_writenb(char* buf, uint32_t len); + + /*! @} */ + + /*! \defgroup BCM2835i2cgrp I2C access + \ingroup BCM2835grp + These functions let you use I2C (The Broadcom Serial Control bus with the Philips + I2C bus/interface version 2.1 January 2000.) to interface with an external I2C device. + @{ + */ + + /*! Start I2C operations. + Forces RPi I2C pins P1-03 (SDA) and P1-05 (SCL) + to alternate function ALT0, which enables those pins for I2C interface. + You should call bcm2835_i2c_end() when all I2C functions are complete to return the pins to + their default functions + \return 1 if successful, 0 otherwise (perhaps because you are not running as root) + \sa bcm2835_i2c_end() + */ + extern int bcm2835_i2c_begin(void); + + /*! End I2C operations. + I2C pins P1-03 (SDA) and P1-05 (SCL) + are returned to their default INPUT behaviour. + */ + extern void bcm2835_i2c_end(void); + + /*! Sets the I2C slave address. + \param[in] addr The I2C slave address. + */ + extern void bcm2835_i2c_setSlaveAddress(uint8_t addr); + + /*! Sets the I2C clock divider and therefore the I2C clock speed. + \param[in] divider The desired I2C clock divider, one of BCM2835_I2C_CLOCK_DIVIDER_*, + see \ref bcm2835I2CClockDivider + */ + extern void bcm2835_i2c_setClockDivider(uint16_t divider); + + /*! Sets the I2C clock divider by converting the baudrate parameter to + the equivalent I2C clock divider. ( see \sa bcm2835_i2c_setClockDivider) + For the I2C standard 100khz you would set baudrate to 100000 + The use of baudrate corresponds to its use in the I2C kernel device + driver. (Of course, bcm2835 has nothing to do with the kernel driver) + */ + extern void bcm2835_i2c_set_baudrate(uint32_t baudrate); + + /*! Transfers any number of bytes to the currently selected I2C slave. + (as previously set by \sa bcm2835_i2c_setSlaveAddress) + \param[in] buf Buffer of bytes to send. + \param[in] len Number of bytes in the buf buffer, and the number of bytes to send. + \return reason see \ref bcm2835I2CReasonCodes + */ + extern uint8_t bcm2835_i2c_write(const char * buf, uint32_t len); + + /*! Transfers any number of bytes from the currently selected I2C slave. + (as previously set by \sa bcm2835_i2c_setSlaveAddress) + \param[in] buf Buffer of bytes to receive. + \param[in] len Number of bytes in the buf buffer, and the number of bytes to received. + \return reason see \ref bcm2835I2CReasonCodes + */ + extern uint8_t bcm2835_i2c_read(char* buf, uint32_t len); + + /*! Allows reading from I2C slaves that require a repeated start (without any prior stop) + to read after the required slave register has been set. For example, the popular + MPL3115A2 pressure and temperature sensor. Note that your device must support or + require this mode. If your device does not require this mode then the standard + combined: + \sa bcm2835_i2c_write + \sa bcm2835_i2c_read + are a better choice. + Will read from the slave previously set by \sa bcm2835_i2c_setSlaveAddress + \param[in] regaddr Buffer containing the slave register you wish to read from. + \param[in] buf Buffer of bytes to receive. + \param[in] len Number of bytes in the buf buffer, and the number of bytes to received. + \return reason see \ref bcm2835I2CReasonCodes + */ + extern uint8_t bcm2835_i2c_read_register_rs(char* regaddr, char* buf, uint32_t len); + + /*! Allows sending an arbitrary number of bytes to I2C slaves before issuing a repeated + start (with no prior stop) and reading a response. + Necessary for devices that require such behavior, such as the MLX90620. + Will write to and read from the slave previously set by \sa bcm2835_i2c_setSlaveAddress + \param[in] cmds Buffer containing the bytes to send before the repeated start condition. + \param[in] cmds_len Number of bytes to send from cmds buffer + \param[in] buf Buffer of bytes to receive. + \param[in] buf_len Number of bytes to receive in the buf buffer. + \return reason see \ref bcm2835I2CReasonCodes + */ + extern uint8_t bcm2835_i2c_write_read_rs(char* cmds, uint32_t cmds_len, char* buf, uint32_t buf_len); + + /*! @} */ + + /*! \defgroup BCM2835stgrp System Timer access + \ingroup BCM2835grp + Allows access to and delays using the System Timer Counter. + @{ + */ + + /*! Read the System Timer Counter register. + \return the value read from the System Timer Counter Lower 32 bits register + */ + extern uint64_t bcm2835_st_read(void); + + /*! Delays for the specified number of microseconds with offset. + \param[in] offset_micros Offset in microseconds + \param[in] micros Delay in microseconds + */ + extern void bcm2835_st_delay(uint64_t offset_micros, uint64_t micros); + + /*! @} */ + + /*! \defgroup BCM2835pwmgrp Pulse Width Modulation + \ingroup BCM2835grp + Allows control of 2 independent PWM channels. A limited subset of GPIO pins + can be connected to one of these 2 channels, allowing PWM control of GPIO pins. + You have to set the desired pin into a particular Alt Fun to PWM output. See the PWM + documentation on the Main Page. + @{ + */ + + /*! Sets the PWM clock divisor, + to control the basic PWM pulse widths. + \param[in] divisor Divides the basic 19.2MHz PWM clock. You can use one of the common + values BCM2835_PWM_CLOCK_DIVIDER_* in \ref bcm2835PWMClockDivider + */ + extern void bcm2835_pwm_set_clock(uint32_t divisor); + + /*! Sets the mode of the given PWM channel, + allowing you to control the PWM mode and enable/disable that channel + \param[in] channel The PWM channel. 0 or 1. + \param[in] markspace Set true if you want Mark-Space mode. 0 for Balanced mode. + \param[in] enabled Set true to enable this channel and produce PWM pulses. + */ + extern void bcm2835_pwm_set_mode(uint8_t channel, uint8_t markspace, uint8_t enabled); + + /*! Sets the maximum range of the PWM output. + The data value can vary between 0 and this range to control PWM output + \param[in] channel The PWM channel. 0 or 1. + \param[in] range The maximum value permitted for DATA. + */ + extern void bcm2835_pwm_set_range(uint8_t channel, uint32_t range); + + /*! Sets the PWM pulse ratio to emit to DATA/RANGE, + where RANGE is set by bcm2835_pwm_set_range(). + \param[in] channel The PWM channel. 0 or 1. + \param[in] data Controls the PWM output ratio as a fraction of the range. + Can vary from 0 to RANGE. + */ + extern void bcm2835_pwm_set_data(uint8_t channel, uint32_t data); + + /*! @} */ +#ifdef __cplusplus +} +#endif + +#endif /* BCM2835_H */ diff --git a/drivers/RPi/piHiPri.c b/drivers/RPi/piHiPri.c new file mode 100644 index 000000000..63c021662 --- /dev/null +++ b/drivers/RPi/piHiPri.c @@ -0,0 +1,48 @@ +/* + * 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.cpp b/drivers/RPi/rpi_util.cpp new file mode 100644 index 000000000..5954fcc28 --- /dev/null +++ b/drivers/RPi/rpi_util.cpp @@ -0,0 +1,330 @@ +/* + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rpi_util.h" +#include "SPI.h" +#include "log.h" + +extern "C" { + int piHiPri(const int pri); +} + +struct ThreadArgs { + void (*func)(); + int gpioPin; +}; + +static pthread_mutex_t intMutex = PTHREAD_MUTEX_INITIALIZER; + +static pthread_t *threadIds[64] = {NULL}; + +// sysFds: +// Map a file descriptor from the /sys/class/gpio/gpioX/value +static int sysFds[64] = +{ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; + +#ifdef __RPI_BPLUS +static uint8_t physToGpio[64] = +{ + 255, // 0 + 255, 255, // 1, 2 + 2, 255, + 3, 255, + 4, 14, + 255, 15, + 17, 18, + 27, 255, + 22, 23, + 255, 24, + 10, 255, + 9, 25, + 11, 8, + 255, 7, // 25, 26 +// B+ + 0, 1, + 5, 255, + 6, 12, + 13, 255, + 19, 16, + 26, 20, + 255, 21, +// the P5 connector on the Rev 2 boards: + 255, 255, + 255, 255, + 255, 255, + 255, 255, + 255, 255, + 28, 29, + 30, 31, + 255, 255, + 255, 255, + 255, 255, + 255, 255, +}; +#else +static uint8_t physToGpio[64] = +{ + 255, // 0 + 255, 255, // 1, 2 + 0, 255, + 1, 255, + 4, 14, + 255, 15, + 17, 18, + 21, 255, + 22, 23, + 255, 24, + 10, 255, + 9, 25, + 11, 8, + 255, 7, // 25, 26 + 255, 255, 255, 255, 255, // ... 31 + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // ... 47 + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // ... 63 +}; +#endif + +void *interruptHandler(void *args) { + int fd, ret; + struct pollfd polls; + char c; + struct ThreadArgs *arguments = (struct ThreadArgs *)args; + int gpioPin = arguments->gpioPin; + void (*func)() = arguments->func; + delete arguments; + + (void)piHiPri(55); // Only effective if we run as root + + if ((fd = sysFds[gpioPin]) == -1) { + mys_log(LOG_ERR, "Failed to attach interrupt for pin %d\n", gpioPin); + return NULL; + } + + // Setup poll structure + polls.fd = fd; + polls.events = POLLPRI; + + while (1) { + // Wait for it ... + ret = poll(&polls, 1, -1); + if (ret < 0) { + mys_log(LOG_ERR, "Error waiting for interrupt: %s\n", strerror(errno)); + break; + } + // 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) ; + // Call user function. + func(); + } + + close(fd); + + return NULL; +} + +void rpi_util::pinMode(uint8_t physPin, uint8_t mode) { + uint8_t gpioPin = (physPin > 63)? 255 : physToGpio[physPin]; + if (gpioPin == 255) { + mys_log(LOG_ERR, "pinMode: invalid pin: %d\n", physPin); + return; + } + // Check if SPI is in use and target pin is related to SPI + if (SPIClass::isInitialized() && 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 = (physPin > 63)? 255 : physToGpio[physPin]; + if (gpioPin == 255) { + mys_log(LOG_ERR, "digitalWrite: invalid pin: %d\n", physPin); + return; + } + // Check if SPI is in use and target pin is related to SPI + if (SPIClass::isInitialized() && 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 = (physPin > 63)? 255 : physToGpio[physPin]; + if (gpioPin == 255) { + mys_log(LOG_ERR, "digitalRead: invalid pin: %d\n", physPin); + return 0; + } + // Check if SPI is in use and target pin is related to SPI + if (SPIClass::isInitialized() && 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) { + FILE *fd; + char fName[40]; + char c; + int count, i; + + uint8_t gpioPin = (physPin > 63)? 255 : physToGpio[physPin]; + if (gpioPin == 255) { + mys_log(LOG_ERR, "attachInterrupt: invalid pin: %d\n", physPin); + return; + } + + if (threadIds[gpioPin] == NULL) { + threadIds[gpioPin] = new pthread_t; + } else { + // Cancel the existing thread for that pin + pthread_cancel(*threadIds[gpioPin]); + // Wait a bit + delay(1L); + } + + // Export pin for interrupt + if ((fd = fopen("/sys/class/gpio/export", "w")) == NULL) { + mys_log(LOG_ERR, "attachInterrupt: Unable to export pin %d for interrupt: %s\n", physPin, strerror(errno)); + exit(1); + } + fprintf(fd, "%d\n", gpioPin); + fclose(fd); + + // Wait a bit the system to create /sys/class/gpio/gpio + delay(1L); + + snprintf(fName, sizeof(fName), "/sys/class/gpio/gpio%d/direction", gpioPin) ; + if ((fd = fopen (fName, "w")) == NULL) { + fprintf (stderr, "attachInterrupt: Unable to open GPIO direction interface for pin %d: %s\n", physPin, strerror(errno)); + exit(1) ; + } + fprintf(fd, "in\n") ; + fclose(fd) ; + + snprintf(fName, sizeof(fName), "/sys/class/gpio/gpio%d/edge", gpioPin) ; + if ((fd = fopen(fName, "w")) == NULL) { + fprintf (stderr, "attachInterrupt: Unable to open GPIO edge interface for pin %d: %s\n", physPin, strerror(errno)); + exit(1) ; + } + switch (mode) { + case CHANGE: fprintf(fd, "both\n"); break; + case FALLING: fprintf(fd, "falling\n"); break; + case RISING: fprintf(fd, "rising\n"); break; + case NONE: fprintf(fd, "none\n"); break; + default: + mys_log(LOG_ERR, "attachInterrupt: Invalid mode\n"); + fclose(fd); + return; + } + fclose(fd); + + if (sysFds[gpioPin] == -1) { + snprintf(fName, sizeof(fName), "/sys/class/gpio/gpio%d/value", gpioPin); + if ((sysFds[gpioPin] = open(fName, O_RDWR)) < 0) { + fprintf (stderr, "Error reading pin %d: %s\n", physPin, strerror(errno)); + exit(1); + } + } + + // Clear any initial pending interrupt + ioctl(sysFds[gpioPin], FIONREAD, &count); + for (i = 0; i < count; ++i) { + if (read(sysFds[gpioPin], &c, 1) == -1) { + mys_log(LOG_ERR, "attachInterrupt: failed to read pin status: %s\n", strerror(errno)); + } + } + + struct ThreadArgs *threadArgs = new struct ThreadArgs; + threadArgs->func = func; + threadArgs->gpioPin = gpioPin; + + // Create a thread passing the pin and function + pthread_create(threadIds[gpioPin], NULL, interruptHandler, (void *)threadArgs); +} + +void rpi_util::detachInterrupt(uint8_t physPin) { + uint8_t gpioPin = (physPin > 63)? 255 : physToGpio[physPin]; + if (gpioPin == 255) { + mys_log(LOG_ERR, "detachInterrupt: invalid pin: %d\n", physPin); + return; + } + + // Cancel the thread + if (threadIds[gpioPin] != NULL) { + pthread_cancel(*threadIds[gpioPin]); + delete threadIds[gpioPin]; + threadIds[gpioPin] = NULL; + } + + // Close filehandle + if (sysFds[gpioPin] != -1) { + close(sysFds[gpioPin]); + sysFds[gpioPin] = -1; + } + + FILE *fp = fopen("/sys/class/gpio/unexport", "w"); + if (fp == NULL) { + mys_log(LOG_ERR, "Unable to unexport pin %d for interrupt\n", gpioPin); + exit(1); + } + fprintf(fp, "%d", gpioPin); + 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() { + pthread_mutex_unlock(&intMutex); +} + +void rpi_util::noInterrupts() { + pthread_mutex_lock(&intMutex); +} diff --git a/drivers/RPi/rpi_util.h b/drivers/RPi/rpi_util.h new file mode 100644 index 000000000..3d31eb9c3 --- /dev/null +++ b/drivers/RPi/rpi_util.h @@ -0,0 +1,71 @@ +/* + * 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 pins_io_h +#define pins_io_h + +#include +#include "bcm2835.h" + +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 = RPI_GPIO_P1_24, + PIN_SPI_MOSI = RPI_GPIO_P1_19, + PIN_SPI_MISO = RPI_GPIO_P1_21, + PIN_SPI_SCK = RPI_GPIO_P1_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 From a6cdec2008760ebf068b16980ea0def0c4c8ae1f Mon Sep 17 00:00:00 2001 From: tekka007 Date: Sun, 14 Aug 2016 20:05:55 +0200 Subject: [PATCH 076/167] Redesign sleep() functions - unified sleeping function _sleep(), including smartSleep - prevent sleeping if transport is not ready - add debug log messages --- MyConfig.h | 16 +++- core/MyHwATMega328.cpp | 6 +- core/MyHwESP8266.cpp | 6 +- core/MyHwSAMD.cpp | 6 +- core/MySensorsCore.cpp | 169 ++++++++++++++++++++++------------------- core/MySensorsCore.h | 120 +++++++++++++++++++---------- 6 files changed, 190 insertions(+), 133 deletions(-) diff --git a/MyConfig.h b/MyConfig.h index 9582a1da4..ea59adebd 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -153,14 +153,22 @@ // #define MY_REPEATER_FEATURE /** - * @def MY_SMART_SLEEP_WAIT_DURATION - * @brief The wait period before going to sleep when using smartSleep-functions. +* @def MY_SLEEP_TRANSPORT_RECONNECT_TIMEOUT_MS +* @brief Timeout (in ms) to re-establish link if node is send to sleep and transport is not ready. +*/ +#ifndef MY_SLEEP_TRANSPORT_RECONNECT_TIMEOUT_MS +#define MY_SLEEP_TRANSPORT_RECONNECT_TIMEOUT_MS (10*1000ul) +#endif + +/** + * @def MY_SMART_SLEEP_WAIT_DURATION_MS + * @brief The wait period (in ms) before going to sleep when using smartSleep-functions. * * This period has to be long enough for controller to be able to send out * potential buffered messages. */ -#ifndef MY_SMART_SLEEP_WAIT_DURATION -#define MY_SMART_SLEEP_WAIT_DURATION 500 +#ifndef MY_SMART_SLEEP_WAIT_DURATION_MS +#define MY_SMART_SLEEP_WAIT_DURATION_MS (500ul) #endif /********************************** diff --git a/core/MyHwATMega328.cpp b/core/MyHwATMega328.cpp index 100d7ed96..59b9526fd 100644 --- a/core/MyHwATMega328.cpp +++ b/core/MyHwATMega328.cpp @@ -21,7 +21,7 @@ #include "MyHwATMega328.h" -#define INVALID_INTERRUPT_NUM (0xFFu) +#define INVALID_INTERRUPT_NUM (0xFFu) volatile uint8_t _wokeUpByInterrupt = INVALID_INTERRUPT_NUM; // Interrupt number that woke the mcu. volatile uint8_t _wakeUp1Interrupt = INVALID_INTERRUPT_NUM; // Interrupt number for wakeUp1-callback. @@ -105,7 +105,7 @@ void hwInternalSleep(unsigned long ms) { int8_t hwSleep(unsigned long ms) { hwInternalSleep(ms); - return -1; + return MY_WAKE_UP_BY_TIMER; } int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { @@ -131,7 +131,7 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo } // Return what woke the mcu. - int ret = -1; // default: no interrupt triggered, timer wake up + int8_t ret = MY_WAKE_UP_BY_TIMER; // default: no interrupt triggered, timer wake up if (interruptWakeUp()) ret = static_cast(_wokeUpByInterrupt); // Clear woke-up-by-interrupt flag, so next sleeps won't return immediately. diff --git a/core/MyHwESP8266.cpp b/core/MyHwESP8266.cpp index 3c1010550..1760b68e0 100644 --- a/core/MyHwESP8266.cpp +++ b/core/MyHwESP8266.cpp @@ -93,7 +93,7 @@ void hwWriteConfig(int adr, uint8_t value) int8_t hwSleep(unsigned long ms) { // TODO: Not supported! (void)ms; - return -2; + return MY_SLEEP_NOT_POSSIBLE; } int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { @@ -101,7 +101,7 @@ int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { (void)interrupt; (void)mode; (void)ms; - return -2; + return MY_SLEEP_NOT_POSSIBLE; } int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { @@ -111,7 +111,7 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo (void)interrupt2; (void)mode2; (void)ms; - return -2; + return MY_SLEEP_NOT_POSSIBLE; } ADC_MODE(ADC_VCC); diff --git a/core/MyHwSAMD.cpp b/core/MyHwSAMD.cpp index 2d8550137..976d4cd25 100644 --- a/core/MyHwSAMD.cpp +++ b/core/MyHwSAMD.cpp @@ -117,7 +117,7 @@ void hwReboot() { int8_t hwSleep(unsigned long ms) { // TODO: Not supported! (void)ms; - return -2; + return MY_SLEEP_NOT_POSSIBLE; } int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { @@ -125,7 +125,7 @@ int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { (void)interrupt; (void)mode; (void)ms; - return -2; + return MY_SLEEP_NOT_POSSIBLE; } int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { @@ -135,7 +135,7 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo (void)interrupt2; (void)mode2; (void)ms; - return -2; + return MY_SLEEP_NOT_POSSIBLE; } uint16_t hwCPUVoltage() { diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 8e5a5fad2..8fab3450d 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -280,12 +280,10 @@ void sendBatteryLevel(uint8_t value, bool enableAck) { } void sendHeartbeat(void) { - #if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) || defined(MY_RS485) + #if defined(MY_RADIO_FEATURE) uint32_t heartbeat = transportGetHeartbeat(); - #else - uint32_t heartbeat = hwMillis(); + _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_HEARTBEAT_RESPONSE, false).set(heartbeat)); #endif - _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_HEARTBEAT_RESPONSE, false).set(heartbeat)); } void present(uint8_t childSensorId, uint8_t sensorType, const char *description, bool enableAck) { @@ -444,104 +442,118 @@ bool wait(unsigned long ms, uint8_t cmd, uint8_t msgtype) { return expectedResponse; } - -int8_t sleep(unsigned long ms) { +int8_t _sleep(const uint32_t ms, const bool smartSleep, const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, const uint8_t mode2) { + debug(PSTR("MCO:SLP:MS=%lu,SMS=%d,I1=%d,M1=%d,I2=%d,M2=%d\n"), ms, smartSleep, interrupt1, mode1, interrupt2, mode2); + // OTA FW feature: do not sleep if FW update ongoing #if defined(MY_OTA_FIRMWARE_FEATURE) - if (_fwUpdateOngoing) { - // Do not sleep node while fw update is ongoing - wait(ms); - return -1; - } + if (_fwUpdateOngoing) { + debug(PSTR("!MCO:SLP:FWUPD\n")); // sleeping not possible, FW update ongoing + wait(ms); + return MY_SLEEP_NOT_POSSIBLE; + } #endif - // if repeater, do not sleep + // repeater feature: sleeping not possible #if defined(MY_REPEATER_FEATURE) + (void)smartSleep; + (void)interrupt1; + (void)mode1; + (void)interrupt2; + (void)mode2; + + debug(PSTR("!MCO:SLP:REP\n")); // sleeping not possible, repeater feature enabled wait(ms); - return -1; + return MY_SLEEP_NOT_POSSIBLE; #else + uint32_t sleepingTime = ms; #if defined(MY_RADIO_FEATURE) - transportPowerDown(); + // Do not sleep if transport not ready + if (!isTransportReady()) { + debug(PSTR("!MCO:SLP:TNR\n")); // sleeping not possible, transport not ready + uint32_t sleepEnter = hwMillis(); + uint32_t sleepDelta = 0; + while (!isTransportReady() && (sleepDelta < sleepingTime) && (sleepDelta < MY_SLEEP_TRANSPORT_RECONNECT_TIMEOUT_MS)) { + _process(); + #if defined(ARDUINO_ARCH_ESP8266) + yield(); + #endif + sleepDelta = hwMillis() - sleepEnter; + } + // sleep remainder + if (sleepDelta < sleepingTime) { + sleepingTime -= sleepDelta; // calculate remaining sleeping time + debug(PSTR("MCO:SLP:MS=%lu\n"), sleepingTime); + } + else { + // no sleeping time left + return MY_SLEEP_NOT_POSSIBLE; + } + } #endif - setIndication(INDICATION_SLEEP); - const int8_t res = hwSleep(ms); - setIndication(INDICATION_WAKEUP); - return res; - #endif -} -int8_t smartSleep(unsigned long ms) { - // notify controller about going to sleep - sendHeartbeat(); - // listen for incoming messages - wait(MY_SMART_SLEEP_WAIT_DURATION); - return sleep(ms); -} + if (smartSleep) { + // notify controller about going to sleep + sendHeartbeat(); + wait(MY_SMART_SLEEP_WAIT_DURATION_MS); // listen for incoming messages + } -int8_t sleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { - #if defined(MY_OTA_FIRMWARE_FEATURE) - if (_fwUpdateOngoing) { - // not supported - return -2; - } - #endif - #if defined(MY_REPEATER_FEATURE) - // not supported - (void)interrupt; - (void)mode; - (void)ms; - return -2; - #else #if defined(MY_RADIO_FEATURE) + debug(PSTR("MCO:SLP:TPD\n")); // sleep, power down transport transportPowerDown(); #endif + setIndication(INDICATION_SLEEP); - const int8_t res = hwSleep(interrupt, mode, ms); + + int8_t res = MY_SLEEP_NOT_POSSIBLE; // default + + if (interrupt1 != INTERRUPT_NOT_DEFINED && interrupt2 != INTERRUPT_NOT_DEFINED) { + // both IRQs + res = hwSleep(interrupt1, mode1, interrupt2, mode2, sleepingTime); + } + else if (interrupt1 != INTERRUPT_NOT_DEFINED && interrupt2 == INTERRUPT_NOT_DEFINED) { + // one IRQ + res = hwSleep(interrupt1, mode1, sleepingTime); + } + else if (interrupt1 == INTERRUPT_NOT_DEFINED && interrupt2 == INTERRUPT_NOT_DEFINED) { + // no IRQ + res = hwSleep(sleepingTime); + } + setIndication(INDICATION_WAKEUP); + debug(PSTR("MCO:SLP:WUP=%d\n"), res); // sleep wake-up return res; #endif } -int8_t smartSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { - // notify controller about going to sleep - sendHeartbeat(); - // listen for incoming messages - wait(MY_SMART_SLEEP_WAIT_DURATION); - return sleep(interrupt, mode, ms); +// sleep functions +int8_t sleep(const uint32_t ms, const bool smartSleep) { + return _sleep(ms, smartSleep); } -int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { - #if defined(MY_OTA_FIRMWARE_FEATURE) - if (_fwUpdateOngoing) { - // not supported - return -2; - } - #endif - #if defined(MY_REPEATER_FEATURE) - // not supported - (void)interrupt1; - (void)mode1; - (void)interrupt2; - (void)mode2; - (void)ms; - return -2; - #else - #if defined(MY_RADIO_FEATURE) - transportPowerDown(); - #endif - setIndication(INDICATION_SLEEP); - const int8_t res = hwSleep(interrupt1, mode1, interrupt2, mode2, ms); - setIndication(INDICATION_WAKEUP); - return res; - #endif +int8_t sleep(const uint8_t interrupt, const uint8_t mode, const uint32_t ms, const bool smartSleep) { + return _sleep(ms, smartSleep, interrupt, mode); } -int8_t smartSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { - // notify controller about going to sleep - sendHeartbeat(); - // listen for incoming messages - wait(MY_SMART_SLEEP_WAIT_DURATION); - return sleep(interrupt1, mode1, interrupt2, mode2, ms); +int8_t sleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, const uint8_t mode2, const uint32_t ms, const bool smartSleep) { + return _sleep(ms, smartSleep, interrupt1, mode1, interrupt2, mode2); } +// deprecated smartSleep() functions +int8_t smartSleep(const uint32_t ms) { + // compatibility + return _sleep(ms, true); +} + +int8_t smartSleep(const uint8_t interrupt, const uint8_t mode, const uint32_t ms) { + // compatibility + return _sleep(ms, true, interrupt, mode); +} + +int8_t smartSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, const uint8_t mode2, const uint32_t ms) { + // compatibility + return _sleep(ms, true, interrupt1, mode1, interrupt2, mode2); +} + + #ifdef MY_NODE_LOCK_FEATURE void nodeLock(const char* str) { // Make sure EEPROM is updated to locked status @@ -555,6 +567,7 @@ void nodeLock(const char* str) { _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID,C_INTERNAL, I_LOCKED, false).set(str)); #if defined(MY_RADIO_FEATURE) transportPowerDown(); + debug(PSTR("MCO:NLK:TPD\n")); // power down transport #endif setIndication(INDICATION_SLEEP); (void)hwSleep((unsigned long)1000*60*30); // Sleep for 30 min before resending LOCKED message diff --git a/core/MySensorsCore.h b/core/MySensorsCore.h index d9dafa69b..f88a028d2 100644 --- a/core/MySensorsCore.h +++ b/core/MySensorsCore.h @@ -37,20 +37,26 @@ * * MySensorsCore debug log messages: * - * |E| SYS | SUB | Message | Comment - * |-|------|-------|-------------------------------------------|---------------------------------------------------------------------------- - * | | MCO | BGN | INIT %%s,CP=%%s,LIB=%%s | Core initialization, capabilities (CP), library version (VER) - * | | MCO | BGN | BFR | Callback before() - * | | MCO | BGN | STP | Callback setup() - * | | MCO | BGN | INIT OK,ID=%%d,PAR=%%d,DIS=%%d,REG=%%d | Core initialized, parent ID (PAR), distance to GW (DIS), registration (REG) - * | | MCO | BGN | NODE UNLOCKED | Node successfully unlocked (see signing chapter) - * |!| MCO | BGN | TSP FAIL | Transport initialization failed - * | | MCO | REG | REQ | Registration request - * | | MCO | REG | NOT NEEDED | No registration needed (i.e. GW) - * |!| MCO | SND | NODE NOT REG | Node is not registered, cannot send message - * | | MCO | PIM | NODE REG=%%d | Registration response received, registration status (REG) - * | | MCO | PIM | ROUTE N=%%d,R=%%d | Routing table, messages to node (N) are routed via node (R) - * | | MCO | NLK | NODE LOCKED. UNLOCK: GND PIN %%d AND RESET| Node locked during booting, see signing chapter for additional information + * |E| SYS | SUB | Message | Comment + * |-|------|-------|-----------------------------------------------|---------------------------------------------------------------------------- + * | | MCO | BGN | INIT %%s,CP=%%s,LIB=%%s | Core initialization, capabilities (CP), library version (VER) + * | | MCO | BGN | BFR | Callback before() + * | | MCO | BGN | STP | Callback setup() + * | | MCO | BGN | INIT OK,ID=%%d,PAR=%%d,DIS=%%d,REG=%%d | Core initialized, parent ID (PAR), distance to GW (DIS), registration (REG) + * | | MCO | BGN | NODE UNLOCKED | Node successfully unlocked (see signing chapter) + * |!| MCO | BGN | TSP FAIL | Transport initialization failed + * | | MCO | REG | REQ | Registration request + * | | MCO | REG | NOT NEEDED | No registration needed (i.e. GW) + * |!| MCO | SND | NODE NOT REG | Node is not registered, cannot send message + * | | MCO | PIM | NODE REG=%%d | Registration response received, registration status (REG) + * | | MCO | PIM | ROUTE N=%%d,R=%%d | Routing table, messages to node (N) are routed via node (R) + * | | MCO | SLP | MS=%%lu,SMS=%%d,I1=%%d,M1=%%d,I2=%%d,M2=%%d | Sleep node, time (MS), smartSleep (SMS), Int1/M1, Int2/M2 + * | | MCO | SLP | TPD | Sleep node, powerdown transport + * | | MCO | SLP | WUP=%%d | Node woke-up, reason/IRQ (WUP) + * |!| MCO | SLP | FWUPD | Sleeping not possible, FW update ongoing + * |!| MCO | SLP | REP | Sleeping not possible, repeater feature enabled + * | | MCO | NLK | NODE LOCKED. UNLOCK: GND PIN %%d AND RESET | Node locked during booting, see signing chapter for additional information + * | | MCO | NLK | TPD | Powerdown transport * * * @brief API declaration for MySensorsCore @@ -67,10 +73,16 @@ #include #include -#define GATEWAY_ADDRESS ((uint8_t)0) //!< Node ID for GW sketch -#define NODE_SENSOR_ID 0xFF //!< Node child is always created/presented when a node is started -#define MY_CORE_VERSION ((uint8_t)2) //!< core version -#define MY_CORE_MIN_VERSION ((uint8_t)2) //!< min core version required for compatibility +#define GATEWAY_ADDRESS ((uint8_t)0) //!< Node ID for GW sketch +#define NODE_SENSOR_ID ((uint8_t)255) //!< Node child is always created/presented when a node is started +#define MY_CORE_VERSION ((uint8_t)2) //!< core version +#define MY_CORE_MIN_VERSION ((uint8_t)2) //!< min core version required for compatibility + +#define MY_WAKE_UP_BY_TIMER ((int8_t)-1) //!< Sleeping wake up by timer +#define MY_SLEEP_NOT_POSSIBLE ((int8_t)-2) //!< Sleeping not possible +#define INTERRUPT_NOT_DEFINED ((uint8_t)255) //!< _sleep() param: no interrupt defined +#define MODE_NOT_DEFINED ((uint8_t)255) //!< _sleep() param: no mode defined + #ifdef MY_DEBUG #define debug(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug @@ -232,16 +244,10 @@ bool wait(unsigned long ms, uint8_t cmd, uint8_t msgtype); /** * Sleep (PowerDownMode) the MCU and radio. Wake up on timer. * @param ms Number of milliseconds to sleep. - * @return -1 if timer woke it up, -2 if not possible (e.g. ongoing FW update) + * @param smartSleep Set True if sending heartbeat and process incoming messages before going to sleep. + * @return @ref MY_WAKE_UP_BY_TIMER if timer woke it up, @ref MY_SLEEP_NOT_POSSIBLE if not possible (e.g. ongoing FW update) */ -int8_t sleep(unsigned long ms); -/** -* Same as sleep(), send heartbeat and process incoming messages before going to sleep. -* Specify the time to wait for incoming messages by defining MY_SMART_SLEEP_WAIT_DURATION to a time (ms). -* @param ms Number of milliseconds to sleep. -* @return -1 if timer woke it up, -2 if not possible (e.g. ongoing FW update) -*/ -int8_t smartSleep(unsigned long ms); +int8_t sleep(const uint32_t ms, const bool smartSleep = false); /** * Sleep (PowerDownMode) the MCU and radio. Wake up on timer or pin change. @@ -250,18 +256,10 @@ int8_t smartSleep(unsigned long ms); * @param interrupt Interrupt that should trigger the wakeup * @param mode RISING, FALLING, CHANGE * @param ms Number of milliseconds to sleep or 0 to sleep forever - * @return Interrupt number if wake up was triggered by pin change, -1 if wake up was triggered by timer, -2 if sleep was not possible (e.g. ongoing FW update) + * @param smartSleep Set True if sending heartbeat and process incoming messages before going to sleep + * @return Interrupt number if wake up was triggered by pin change, @ref MY_WAKE_UP_BY_TIMER if wake up was triggered by timer, @ref MY_SLEEP_NOT_POSSIBLE if sleep was not possible (e.g. ongoing FW update) */ -int8_t sleep(uint8_t interrupt, uint8_t mode, unsigned long ms=0); -/** -* Same as sleep(), send heartbeat and process incoming messages before going to sleep. -* Specify the time to wait for incoming messages by defining MY_SMART_SLEEP_WAIT_DURATION to a time (ms). -* @param interrupt Interrupt that should trigger the wakeup -* @param mode RISING, FALLING, CHANGE -* @param ms Number of milliseconds to sleep or 0 to sleep forever -* @return Interrupt number if wake up was triggered by pin change, -1 if wake up was triggered by timer, -2 if sleep was not possible (e.g. ongoing FW update) -*/ -int8_t smartSleep(uint8_t interrupt, uint8_t mode, unsigned long ms=0); +int8_t sleep(const uint8_t interrupt, const uint8_t mode, const uint32_t ms=0, const bool smartSleep = false); /** * Sleep (PowerDownMode) the MCU and radio. Wake up on timer or pin change for two separate interrupts. @@ -272,10 +270,33 @@ int8_t smartSleep(uint8_t interrupt, uint8_t mode, unsigned long ms=0); * @param interrupt2 Second interrupt that should trigger the wakeup * @param mode2 Mode for second interrupt (RISING, FALLING, CHANGE) * @param ms Number of milliseconds to sleep or 0 to sleep forever - * @return Interrupt number if wake up was triggered by pin change, -1 if wake up was triggered by timer, -2 if sleep was not possible (e.g. ongoing FW update) + * @param smartSleep Set True if sending heartbeat and process incoming messages before going to sleep. + * @return Interrupt number if wake up was triggered by pin change, @ref MY_WAKE_UP_BY_TIMER if wake up was triggered by timer, @ref MY_SLEEP_NOT_POSSIBLE if sleep was not possible (e.g. ongoing FW update) */ -int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms=0); +int8_t sleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, const uint8_t mode2, const uint32_t ms=0, const bool smartSleep = false); + +/** +* \deprecated Use sleep(ms, true) instead +* Same as sleep(), send heartbeat and process incoming messages before going to sleep. +* Specify the time to wait for incoming messages by defining MY_SMART_SLEEP_WAIT_DURATION to a time (ms). +* @param ms Number of milliseconds to sleep. +* @return @ref MY_WAKE_UP_BY_TIMER if timer woke it up, @ref MY_SLEEP_NOT_POSSIBLE if not possible (e.g. ongoing FW update) +*/ +int8_t smartSleep(const uint32_t ms); + /** +* \deprecated Use sleep(interrupt, mode, ms, true) instead +* Same as sleep(), send heartbeat and process incoming messages before going to sleep. +* Specify the time to wait for incoming messages by defining MY_SMART_SLEEP_WAIT_DURATION to a time (ms). +* @param interrupt Interrupt that should trigger the wakeup +* @param mode RISING, FALLING, CHANGE +* @param ms Number of milliseconds to sleep or 0 to sleep forever +* @return Interrupt number if wake up was triggered by pin change, @ref MY_WAKE_UP_BY_TIMER if wake up was triggered by timer, @ref MY_SLEEP_NOT_POSSIBLE if sleep was not possible (e.g. ongoing FW update) +*/ +int8_t smartSleep(const uint8_t interrupt, const uint8_t mode, const uint32_t ms = 0); + +/** +* \deprecated Use sleep(interrupt1, mode1, interrupt2, mode2, ms, true) instead * Same as sleep(), send heartbeat and process incoming messages before going to sleep. * Specify the time to wait for incoming messages by defining MY_SMART_SLEEP_WAIT_DURATION to a time (ms). * @param interrupt1 First interrupt that should trigger the wakeup @@ -283,9 +304,24 @@ int8_t sleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode * @param interrupt2 Second interrupt that should trigger the wakeup * @param mode2 Mode for second interrupt (RISING, FALLING, CHANGE) * @param ms Number of milliseconds to sleep or 0 to sleep forever -* @return Interrupt number if wake up was triggered by pin change, -1 if wake up was triggered by timer, -2 if sleep was not possible (e.g. ongoing FW update) +* @return Interrupt number if wake up was triggered by pin change, @ref MY_WAKE_UP_BY_TIMER if wake up was triggered by timer, @ref MY_SLEEP_NOT_POSSIBLE if sleep was not possible (e.g. ongoing FW update) +*/ +int8_t smartSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, const uint8_t mode2, const uint32_t ms=0); + +/** +* Sleep (PowerDownMode) the MCU and radio. Wake up on timer or pin change for two separate interrupts. +* See: http://arduino.cc/en/Reference/attachInterrupt for details on modes and which pin +* is assigned to what interrupt. On Nano/Pro Mini: 0=Pin2, 1=Pin3 +* @param ms Number of milliseconds to sleep or 0 to sleep forever +* @param interrupt1 (optional) First interrupt that should trigger the wakeup +* @param mode1 (optional) Mode for first interrupt (RISING, FALLING, CHANGE) +* @param interrupt2 (optional) Second interrupt that should trigger the wakeup +* @param mode2 (optional) Mode for second interrupt (RISING, FALLING, CHANGE) +* @param smartSleep (optional) Set True if sending heartbeat and process incoming messages before going to sleep. +* @return Interrupt number if wake up was triggered by pin change, @ref MY_WAKE_UP_BY_TIMER if wake up was triggered by timer, @ref MY_SLEEP_NOT_POSSIBLE if sleep was not possible (e.g. ongoing FW update) */ -int8_t smartSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms=0); +int8_t _sleep(const uint32_t ms, const bool smartSleep = false, const uint8_t interrupt1 = INTERRUPT_NOT_DEFINED, const uint8_t mode1 = MODE_NOT_DEFINED, const uint8_t interrupt2 = INTERRUPT_NOT_DEFINED, const uint8_t mode2 = MODE_NOT_DEFINED); + #ifdef MY_NODE_LOCK_FEATURE /** From f8c6156057ac82ad30ea3ae4677fca245bcbd6a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Mon, 19 Sep 2016 21:14:15 +0200 Subject: [PATCH 077/167] Updated sketch with analog check (#580) --- .../SensebenderGatewaySerial.ino | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino b/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino index e0d6510ff..5e9c89c2f 100644 --- a/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino +++ b/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino @@ -22,6 +22,8 @@ * The ArduinoGateway prints data received from sensors on the serial link. * The gateway accepts input on seral which will be sent out on radio network. * +the last one is meant for the end user to break up into the various connectors used on the board. + * This GW code is designed for Sensebender GateWay / Arduino Zero * * Wire connections (OPTIONAL): @@ -36,7 +38,7 @@ * */ -#define SKETCH_VERSION "0.1" +#define SKETCH_VERSION "0.2" // Enable debug prints to serial monitor #define MY_DEBUG @@ -124,6 +126,7 @@ void preHwInit() { delay(500); } // Wait for USB to be connected, before spewing out data. } + digitalWrite(LED_BLUE, LOW); if (Serial) { Serial.println("Sensebender GateWay test routine"); Serial.print("Mysensors core version : "); @@ -146,7 +149,11 @@ void preHwInit() { digitalWrite(LED_ORANGE, HIGH); tests++; } - if (tests == 3) { + if (testAnalog()) { + digitalWrite(LED_BLUE, HIGH); + tests++; + } + if (tests == 4) { while(1) { for (int i=0; i analog : "); + Serial.print(bat_detect); + if (bat_detect < 400 || bat_detect > 650) { + Serial.println(" Failed"); + return false; + } + Serial.println(" Passed"); + return true; +} + + From ec6b6ea2bfa6d26f556a6e125e36d6cb8e031f5c Mon Sep 17 00:00:00 2001 From: Olivier Date: Mon, 19 Sep 2016 21:31:00 +0200 Subject: [PATCH 078/167] Refactor and doxygenize EEPROM address definitions (#582) --- core/MyEepromAddresses.h | 87 ++++++++++++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 21 deletions(-) diff --git a/core/MyEepromAddresses.h b/core/MyEepromAddresses.h index 3c94be3bf..417ffa858 100644 --- a/core/MyEepromAddresses.h +++ b/core/MyEepromAddresses.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-2016 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -17,28 +17,73 @@ * version 2 as published by the Free Software Foundation. */ + /** + * @file MyEepromAddresses.h + * @brief Eeprom addresses for MySensors library data + * + * @defgroup MyEepromAddressesgrp MyEepromAddresses + * @ingroup internals + * @{ + * + */ + + #ifndef MyEepromAddresses_h #define MyEepromAddresses_h -// EEPROM start address for mysensors library data + +// EEPROM variable sizes, in bytes +#define SIZE_NODE_ID (1) //!< Size node ID +#define SIZE_PARENT_NODE_ID (1) //!< Size parent node ID +#define SIZE_DISTANCE (1) //!< Size GW distance +#define SIZE_ROUTES (256) //!< Size routing table +#define SIZE_CONTROLLER_CONFIG (24) //!< Size controller config +#define SIZE_FIRMWARE_TYPE (2) //!< Size firmware type +#define SIZE_FIRMWARE_VERSION (2) //!< Size firmware version +#define SIZE_FIRMWARE_BLOCKS (2) //!< Size firmware blocks +#define SIZE_FIRMWARE_CRC (2) //!< Size firmware CRC +#define SIZE_SIGNING_REQUIREMENT_TABLE (32) //!< Size signing requirement table +#define SIZE_WHITELIST_REQUIREMENT_TABLE (32) //!< Size whitelist requirement table +#define SIZE_SIGNING_SOFT_HMAC_KEY (32) //!< Size soft signing HMAC key +#define SIZE_SIGNING_SOFT_SERIAL (9) //!< Size soft signing serial +#define SIZE_RF_ENCRYPTION_AES_KEY (16) //!< Size RF AES encryption key +#define SIZE_NODE_LOCK_COUNTER (1) //!< Size node lock counter + + +/** @brief EEPROM start address */ #define EEPROM_START 0 -// EEPROM location of node id +/** @brief Address node ID */ #define EEPROM_NODE_ID_ADDRESS EEPROM_START -// EEPROM location of parent id -#define EEPROM_PARENT_NODE_ID_ADDRESS (EEPROM_START+1) -// EEPROM location of distance to gateway -#define EEPROM_DISTANCE_ADDRESS (EEPROM_PARENT_NODE_ID_ADDRESS+1) -#define EEPROM_ROUTES_ADDRESS (EEPROM_DISTANCE_ADDRESS+1) // Where to start storing routing information in EEPROM. Will allocate 256 bytes. -#define EEPROM_CONTROLLER_CONFIG_ADDRESS (EEPROM_ROUTES_ADDRESS+256) // Location of controller sent configuration (we allow one payload of config data from controller) -#define EEPROM_FIRMWARE_TYPE_ADDRESS (EEPROM_CONTROLLER_CONFIG_ADDRESS+24) -#define EEPROM_FIRMWARE_VERSION_ADDRESS (EEPROM_FIRMWARE_TYPE_ADDRESS+2) -#define EEPROM_FIRMWARE_BLOCKS_ADDRESS (EEPROM_FIRMWARE_VERSION_ADDRESS+2) -#define EEPROM_FIRMWARE_CRC_ADDRESS (EEPROM_FIRMWARE_BLOCKS_ADDRESS+2) -#define EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS (EEPROM_FIRMWARE_CRC_ADDRESS+2) -#define EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS (EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS+32) -#define EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS (EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS+32) // This is set with SecurityPersonalizer.ino -#define EEPROM_SIGNING_SOFT_SERIAL_ADDRESS (EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS+32) // This is set with SecurityPersonalizer.ino -#define EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS (EEPROM_SIGNING_SOFT_SERIAL_ADDRESS+9) // This is set with SecurityPersonalizer.ino -#define EEPROM_NODE_LOCK_COUNTER (EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS+16) -#define EEPROM_LOCAL_CONFIG_ADDRESS (EEPROM_NODE_LOCK_COUNTER+1) // First free address for sketch static configuration +/** @brief Address parent node ID */ +#define EEPROM_PARENT_NODE_ID_ADDRESS (EEPROM_NODE_ID_ADDRESS + SIZE_NODE_ID) +/** @brief Address distance to GW */ +#define EEPROM_DISTANCE_ADDRESS (EEPROM_PARENT_NODE_ID_ADDRESS + SIZE_PARENT_NODE_ID) +/** @brief Address routing table */ +#define EEPROM_ROUTES_ADDRESS (EEPROM_DISTANCE_ADDRESS + SIZE_DISTANCE) +/** @brief Address configuration bytes sent by controller */ +#define EEPROM_CONTROLLER_CONFIG_ADDRESS (EEPROM_ROUTES_ADDRESS + SIZE_ROUTES) +/** @brief Address firmware type */ +#define EEPROM_FIRMWARE_TYPE_ADDRESS (EEPROM_CONTROLLER_CONFIG_ADDRESS + SIZE_CONTROLLER_CONFIG) +/** @brief Address firmware version */ +#define EEPROM_FIRMWARE_VERSION_ADDRESS (EEPROM_FIRMWARE_TYPE_ADDRESS + SIZE_FIRMWARE_TYPE) +/** @brief Address firmware blocks */ +#define EEPROM_FIRMWARE_BLOCKS_ADDRESS (EEPROM_FIRMWARE_VERSION_ADDRESS + SIZE_FIRMWARE_VERSION) +/** @brief Address firmware CRC */ +#define EEPROM_FIRMWARE_CRC_ADDRESS (EEPROM_FIRMWARE_BLOCKS_ADDRESS + SIZE_FIRMWARE_BLOCKS) +/** @brief Address signing requirement table */ +#define EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS (EEPROM_FIRMWARE_CRC_ADDRESS + SIZE_FIRMWARE_CRC) +/** @brief Address whitelist requirement table */ +#define EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS (EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS + SIZE_SIGNING_REQUIREMENT_TABLE) +/** @brief Address soft signing HMAC key. This is set with @ref SecurityPersonalizer.ino */ +#define EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS (EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS + SIZE_WHITELIST_REQUIREMENT_TABLE) +/** @brief Address soft signing serial key. This is set with @ref SecurityPersonalizer.ino */ +#define EEPROM_SIGNING_SOFT_SERIAL_ADDRESS (EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS + SIZE_SIGNING_SOFT_HMAC_KEY) +/** @brief Address RF AES encryption key. This is set with @ref SecurityPersonalizer.ino */ +#define EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS (EEPROM_SIGNING_SOFT_SERIAL_ADDRESS + SIZE_SIGNING_SOFT_SERIAL) +/** @brief Address node lock couner. This is set with @ref SecurityPersonalizer.ino */ +#define EEPROM_NODE_LOCK_COUNTER (EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS + SIZE_RF_ENCRYPTION_AES_KEY) +/** @brief First free address for sketch static configuration */ +#define EEPROM_LOCAL_CONFIG_ADDRESS (EEPROM_NODE_LOCK_COUNTER + SIZE_NODE_LOCK_COUNTER) + +#endif // MyEepromAddresses_h -#endif +/** @}*/ From 8ccb1ca86dada9ca9a7bbd19eda165b061e5bf15 Mon Sep 17 00:00:00 2001 From: Embedded Innovation Date: Thu, 22 Sep 2016 18:21:02 +0200 Subject: [PATCH 079/167] Fix gateway RX indication Added GW RX indication for MQTT and Serial gateway (PR #585). Only send RX indication when valid message has been received. --- core/MyGatewayTransportEthernet.cpp | 10 +++++++--- core/MyGatewayTransportMQTTClient.cpp | 1 + core/MyGatewayTransportSerial.cpp | 6 +++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/core/MyGatewayTransportEthernet.cpp b/core/MyGatewayTransportEthernet.cpp index cef41e7be..299e33963 100644 --- a/core/MyGatewayTransportEthernet.cpp +++ b/core/MyGatewayTransportEthernet.cpp @@ -272,19 +272,23 @@ bool gatewayTransportAvailable() if (packet_size) { //debug(PSTR("UDP packet available. Size:%d\n"), packet_size); - setIndication(INDICATION_GW_RX); #if defined(MY_GATEWAY_ESP8266) _ethernetServer.read(inputString[0].string, MY_GATEWAY_MAX_RECEIVE_LENGTH); inputString[0].string[packet_size] = 0; debug(PSTR("UDP packet received: %s\n"), inputString[0].string); - return protocolParse(_ethernetMsg, inputString[0].string); + const bool ok = protocolParse(_ethernetMsg, inputString[0].string); #else _ethernetServer.read(inputString.string, MY_GATEWAY_MAX_RECEIVE_LENGTH); inputString.string[packet_size] = 0; debug(PSTR("UDP packet received: %s\n"), inputString.string); _w5100_spi_en(false); - return protocolParse(_ethernetMsg, inputString.string); + const bool ok = protocolParse(_ethernetMsg, inputString.string); #endif + if (ok) + { + setIndication(INDICATION_GW_RX); + } + return ok; } #else #if defined(MY_GATEWAY_ESP8266) diff --git a/core/MyGatewayTransportMQTTClient.cpp b/core/MyGatewayTransportMQTTClient.cpp index b6ca3779a..a385382ee 100644 --- a/core/MyGatewayTransportMQTTClient.cpp +++ b/core/MyGatewayTransportMQTTClient.cpp @@ -131,6 +131,7 @@ void incomingMQTT(char* topic, byte* payload, unsigned int length) { _MQTT_msg.set((const char*)payload); } _MQTT_available = true; + setIndication(INDICATION_GW_RX); } } i++; diff --git a/core/MyGatewayTransportSerial.cpp b/core/MyGatewayTransportSerial.cpp index bbad4b3c0..74a118e1a 100644 --- a/core/MyGatewayTransportSerial.cpp +++ b/core/MyGatewayTransportSerial.cpp @@ -58,7 +58,11 @@ bool gatewayTransportAvailable() { if (inChar == '\n') { _serialInputString[_serialInputPos] = 0; bool ok = protocolParse(_serialMsg, _serialInputString); - _serialInputPos = 0; + if (ok) + { + setIndication(INDICATION_GW_RX); + } + _serialInputPos = 0; return ok; } else { // add it to the inputString: From efc71165c74ecf6971d6f1bcf6ef4708c4736806 Mon Sep 17 00:00:00 2001 From: tekka007 Date: Tue, 16 Aug 2016 22:44:45 +0200 Subject: [PATCH 080/167] Various MyTransport optimisations --- MyConfig.h | 67 +++- MySensors.h | 10 + core/MyCapabilities.h | 4 +- core/MyGatewayTransportSerial.cpp | 2 +- core/MyHwATMega328.cpp | 4 + core/MyIndication.h | 5 +- core/MyMessage.h | 6 +- core/MySensorsCore.cpp | 18 +- core/MySensorsCore.h | 4 +- core/MyTransport.cpp | 645 ++++++++++++++++++------------ core/MyTransport.h | 188 ++++++--- 11 files changed, 609 insertions(+), 344 deletions(-) diff --git a/MyConfig.h b/MyConfig.h index 9582a1da4..764d1fe9e 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -2,7 +2,7 @@ * 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 + * repeater and gateway builds a routing tables in RAM or EEPROM which keeps track of the * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad @@ -81,18 +81,54 @@ //#define MY_RADIO_RFM69 //#define MY_RS485 +/** +* @def MY_RAM_ROUTING_TABLE_FEATURE +* @brief If enabled, the routing table is kept in RAM (if memory allows) and saved in regular intervals. +* note: AVR has limited memory, use with care +*/ +#define MY_RAM_ROUTING_TABLE_FEATURE + +/** +* @def MY_ROUTING_TABLE_SAVE_INTERVAL_MS +* @brief Interval to dump content of routing table to eeprom +*/ +#ifndef MY_ROUTING_TABLE_SAVE_INTERVAL_MS +#define MY_ROUTING_TABLE_SAVE_INTERVAL_MS (10*60*1000ul) +#endif /** * @def MY_TRANSPORT_SANITY_CHECK -* @brief If enabled, node will check transport in regular intervals to detect HW issues and re-initialize in case of failure. This feature is enabled for all repeater nodes (incl. GW) +* @brief If enabled, node will check transport in regular intervals to detect HW issues and re-initialize in case of failure. +* This feature is enabled for all repeater nodes (incl. GW) */ //#define MY_TRANSPORT_SANITY_CHECK + /** -* @def MY_TRANSPORT_SANITY_CHECK_INTERVAL +* @def MY_TRANSPORT_SANITY_CHECK_INTERVAL_MS * @brief Interval (in ms) of transport sanity checks */ -#ifndef MY_TRANSPORT_SANITY_CHECK_INTERVAL -#define MY_TRANSPORT_SANITY_CHECK_INTERVAL ((uint32_t)60000) +#ifndef MY_TRANSPORT_SANITY_CHECK_INTERVAL_MS +#define MY_TRANSPORT_SANITY_CHECK_INTERVAL_MS (60*1000ul) +#endif +/** +* @def MY_TRANSPORT_DISCOVERY_INTERVAL_MS +* @brief This is a gateway-only feature: Interval (in ms) to issue network discovery checks +*/ +#ifndef MY_TRANSPORT_DISCOVERY_INTERVAL_MS +#define MY_TRANSPORT_DISCOVERY_INTERVAL_MS (10*60*1000ul) #endif + +/** + *@def MY_TRANSPORT_UPLINK_CHECK_DISABLED + *@brief If set, uplink check to GW is disabled during transport initialisation + */ +//#define MY_TRANSPORT_UPLINK_CHECK_DISABLED + +/** + *@def MY_TRANSPORT_MAX_TX_FAILURES + *@brief Set to override max. consecutive TX failures until SNP is initiated + */ +//#define MY_TRANSPORT_MAX_TX_FAILURES (10u) + /** * @def MY_REGISTRATION_FEATURE * @brief If enabled, node has to register to gateway/controller before allowed to send sensor data. @@ -105,14 +141,13 @@ */ #ifndef MY_REGISTRATION_RETRIES -#define MY_REGISTRATION_RETRIES 3 +#define MY_REGISTRATION_RETRIES (3u) #endif /** * @def MY_REGISTRATION_DEFAULT - * @brief Node registration default - this applies if no registration response is recieved from controller + * @brief Node registration default - this applies if no registration response is received from controller */ - #define MY_REGISTRATION_DEFAULT true /** @@ -149,8 +184,11 @@ */ //#define MY_PARENT_NODE_IS_STATIC -// Enables repeater functionality (relays messages from other nodes) -// #define MY_REPEATER_FEATURE +/** +* @def MY_REPEATER_FEATURE +* @brief Enables repeater functionality (relays messages from other nodes) +*/ +//#define MY_REPEATER_FEATURE /** * @def MY_SMART_SLEEP_WAIT_DURATION @@ -160,7 +198,7 @@ * potential buffered messages. */ #ifndef MY_SMART_SLEEP_WAIT_DURATION -#define MY_SMART_SLEEP_WAIT_DURATION 500 +#define MY_SMART_SLEEP_WAIT_DURATION (500ul) #endif /********************************** @@ -199,7 +237,7 @@ * @brief Max buffersize needed for messages coming from controller. */ #ifndef MY_GATEWAY_MAX_RECEIVE_LENGTH -#define MY_GATEWAY_MAX_RECEIVE_LENGTH 100 +#define MY_GATEWAY_MAX_RECEIVE_LENGTH (100u) #endif /** @@ -207,7 +245,7 @@ * @brief Max buffer size when sending messages. */ #ifndef MY_GATEWAY_MAX_SEND_LENGTH -#define MY_GATEWAY_MAX_SEND_LENGTH 120 +#define MY_GATEWAY_MAX_SEND_LENGTH (120u) #endif /** @@ -215,7 +253,7 @@ * @brief Max number of parallel clients (sever mode). */ #ifndef MY_GATEWAY_MAX_CLIENTS -#define MY_GATEWAY_MAX_CLIENTS 1 +#define MY_GATEWAY_MAX_CLIENTS (1u) #endif @@ -716,4 +754,5 @@ #define MY_RX_MESSAGE_BUFFER_FEATURE #define MY_RX_MESSAGE_BUFFER_SIZE #define MY_NODE_LOCK_FEATURE +#define MY_REPEATER_FEATURE #endif diff --git a/MySensors.h b/MySensors.h index 70bc9361c..963066465 100644 --- a/MySensors.h +++ b/MySensors.h @@ -239,6 +239,16 @@ #endif #endif +// RAM ROUTING TABLE +#if defined(MY_RAM_ROUTING_TABLE_FEATURE) && defined(MY_REPEATER_FEATURE) + // activate feature based on architecture + #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_SAMD) || defined(LINUX_ARCH_RASPBERRYPI) + #define MY_RAM_ROUTING_TABLE_ENABLED + #elif defined(ARDUINO_ARCH_AVR) + // memory limited, enable with care + // #define MY_RAM_ROUTING_TABLE_ENABLED + #endif +#endif // RADIO #if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) || defined(MY_RS485) diff --git a/core/MyCapabilities.h b/core/MyCapabilities.h index 735ec3282..d861961c0 100644 --- a/core/MyCapabilities.h +++ b/core/MyCapabilities.h @@ -70,7 +70,7 @@ #define MY_CAP_SIGN "-" #endif -#if defined(MY_RX_MESSAGE_BUFFER_SIZE) +#if defined(MY_RX_MESSAGE_BUFFER_FEATURE) #define MY_CAP_RXBUF "Q" #else #define MY_CAP_RXBUF "-" @@ -79,4 +79,4 @@ #define MY_CAPABILITIES MY_CAP_RESET MY_CAP_RADIO MY_CAP_OTA_FW MY_CAP_TYPE MY_CAP_ARCH MY_CAP_SIGN MY_CAP_RXBUF -#endif /* MyGatewayTransportEthernet_h */ +#endif /* MyCapabilities_h */ diff --git a/core/MyGatewayTransportSerial.cpp b/core/MyGatewayTransportSerial.cpp index bbad4b3c0..b28cb56f4 100644 --- a/core/MyGatewayTransportSerial.cpp +++ b/core/MyGatewayTransportSerial.cpp @@ -28,7 +28,7 @@ extern MyMessage _msgTmp; char _serialInputString[MY_GATEWAY_MAX_RECEIVE_LENGTH]; // A buffer for incoming commands from serial interface -int _serialInputPos; +uint8_t _serialInputPos; MyMessage _serialMsg; diff --git a/core/MyHwATMega328.cpp b/core/MyHwATMega328.cpp index 100d7ed96..30560feab 100644 --- a/core/MyHwATMega328.cpp +++ b/core/MyHwATMega328.cpp @@ -203,6 +203,10 @@ void hwDebugPrint(const char *fmt, ... ) { // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) snprintf_P(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); MY_SERIALDEVICE.print(fmtBuffer); + #else + // prepend timestamp (AVR nodes) + MY_SERIALDEVICE.print(hwMillis()); + MY_SERIALDEVICE.print(" "); #endif va_list args; va_start (args, fmt ); diff --git a/core/MyIndication.h b/core/MyIndication.h index ab2bbbc02..7e9cd0733 100644 --- a/core/MyIndication.h +++ b/core/MyIndication.h @@ -34,11 +34,12 @@ typedef enum { INDICATION_GOT_PARENT, //!< Found parent node. INDICATION_REQ_NODEID, //!< Request node ID. INDICATION_GOT_NODEID, //!< Got a node ID. + INDICATION_CHECK_UPLINK, //!< Check uplink INDICATION_REQ_REGISTRATION, //!< Request node registration. INDICATION_GOT_REGISTRATION, //!< Got registration reponse. INDICATION_REBOOT, //!< Rebooting node. INDICATION_PRESENT, //!< Presenting node to gateway. - INDICATION_CLEAR_ROUTING, //!< Clear rrouting table requested. + INDICATION_CLEAR_ROUTING, //!< Clear routing table requested. INDICATION_SLEEP, //!< Node goes to sleep. INDICATION_WAKEUP, //!< Node just woke from sleep. INDICATION_FW_UPDATE_START, //!< Start of OTA firmware update process. @@ -50,7 +51,9 @@ typedef enum { INDICATION_ERR_INIT_TRANSPORT, //!< MySensors transport hardware (radio) init failure. INDICATION_ERR_FIND_PARENT, //!< Failed to find parent node. INDICATION_ERR_GET_NODEID, //!< Failed to receive node ID. + INDICATION_ERR_CHECK_UPLINK, //!< Failed to check uplink INDICATION_ERR_SIGN, //!< Error signing. + INDICATION_ERR_LENGTH, //!< Invalid message length. INDICATION_ERR_VERSION, //!< Protocol version mismatch. INDICATION_ERR_NET_FULL, //!< Network full. All node ID's are taken. INDICATION_ERR_INIT_GWTRANSPORT, //!< Gateway transport hardware init failure. diff --git a/core/MyMessage.h b/core/MyMessage.h index a4fe002e8..ee0e3fcce 100644 --- a/core/MyMessage.h +++ b/core/MyMessage.h @@ -36,9 +36,9 @@ #include #endif -#define PROTOCOL_VERSION 2 //!< The version of the protocol -#define MAX_MESSAGE_LENGTH 32 //!< The maximum size of a message (including header) -#define HEADER_SIZE 7 //!< The size of the header +#define PROTOCOL_VERSION (2u) //!< The version of the protocol +#define MAX_MESSAGE_LENGTH (32u) //!< The maximum size of a message (including header) +#define HEADER_SIZE (7u) //!< The size of the header #define MAX_PAYLOAD (MAX_MESSAGE_LENGTH - HEADER_SIZE) //!< The maximum size of a payload depends on #MAX_MESSAGE_LENGTH and #HEADER_SIZE /// @brief The command field (message-type) defines the overall properties of a message diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 8e5a5fad2..84cc0e185 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -99,7 +99,7 @@ void _begin() { #if defined(MY_RADIO_FEATURE) // Save static parent id in eeprom (used by bootloader) hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, MY_PARENT_NODE_ID); - transportInitialize(); + transportInitialise(); while (!isTransportReady()) { hwWatchdogReset(); transportProcess(); @@ -142,7 +142,7 @@ void _begin() { inclusionInit(); #endif - // initialize the transport driver + // initialise the transport driver if (!gatewayTransportInit()) { setIndication(INDICATION_ERR_INIT_GWTRANSPORT); debug(PSTR("!MCO:BGN:TSP FAIL\n")); @@ -353,15 +353,15 @@ bool _processInternalMessages() { } else if (type == I_DEBUG) { #if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG) - char debug_msg = _msg.data[0]; + const char debug_msg = _msg.data[0]; if (debug_msg == 'R') { // routing table #if defined(MY_REPEATER_FEATURE) for (uint8_t cnt = 0; cnt != 255; cnt++) { - uint8_t route = hwReadConfig(EEPROM_ROUTES_ADDRESS + cnt); + const uint8_t route = transportGetRoute(cnt); if (route != BROADCAST_ADDRESS) { debug(PSTR("MCO:PIM:ROUTE N=%d,R=%d\n"), cnt, route); - uint8_t OutBuf[2] = { cnt,route }; - _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set(OutBuf, 2)); + uint8_t outBuf[2] = { cnt,route }; + _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set(outBuf, 2)); wait(200); } } @@ -390,15 +390,15 @@ bool _processInternalMessages() { // sender is a node if (type == I_REGISTRATION_REQUEST) { #if defined(MY_GATEWAY_FEATURE) - // register request are exclusively handled by GW/Controller - // !!! eventually define if AUTO ACK or register request forwarded to controller + // registeration requests are exclusively handled by GW/Controller #if !defined(MY_REGISTRATION_CONTROLLER) - // auto register if version compatible + // auto registration if version compatible bool approveRegistration = true; #if defined(MY_CORE_COMPATIBILITY_CHECK) approveRegistration = (_msg.getByte() >= MY_CORE_MIN_VERSION); #endif + // delay for slow nodes ***************************** _sendRoute(build(_msgTmp, _nc.nodeId, _msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REGISTRATION_RESPONSE, false).set(approveRegistration)); #else return false; // processing of this request via controller diff --git a/core/MySensorsCore.h b/core/MySensorsCore.h index d9dafa69b..76f5a7d43 100644 --- a/core/MySensorsCore.h +++ b/core/MySensorsCore.h @@ -25,7 +25,7 @@ * @{ * * MySensorsCore-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE - * - [!] Exclamation mark is prepended in case of error + * - [!] Exclamation mark is prepended in case of error or warning * - SYSTEM: * - MCO messages emitted by MySensorsCore * - SUB SYSTEMS: @@ -44,7 +44,7 @@ * | | MCO | BGN | STP | Callback setup() * | | MCO | BGN | INIT OK,ID=%%d,PAR=%%d,DIS=%%d,REG=%%d | Core initialized, parent ID (PAR), distance to GW (DIS), registration (REG) * | | MCO | BGN | NODE UNLOCKED | Node successfully unlocked (see signing chapter) - * |!| MCO | BGN | TSP FAIL | Transport initialization failed + * |!| MCO | BGN | TSP FAIL | Transport initialisation failed * | | MCO | REG | REQ | Registration request * | | MCO | REG | NOT NEEDED | No registration needed (i.e. GW) * |!| MCO | SND | NODE NOT REG | Node is not registered, cannot send message diff --git a/core/MyTransport.cpp b/core/MyTransport.cpp index da4134043..fd596eede 100644 --- a/core/MyTransport.cpp +++ b/core/MyTransport.cpp @@ -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-2016 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -20,30 +20,61 @@ #include "MyTransport.h" // SM: transitions and update states -static transportState stInit = { stInitTransition, NULL }; +static transportState stInit = { stInitTransition, stInitUpdate }; static transportState stParent = { stParentTransition, stParentUpdate }; static transportState stID = { stIDTransition, stIDUpdate }; -static transportState stUplink = { stUplinkTransition, NULL }; +static transportState stUplink = { stUplinkTransition, stUplinkUpdate }; static transportState stReady = { stReadyTransition, stReadyUpdate }; static transportState stFailure = { stFailureTransition, stFailureUpdate }; // transport SM variables static transportSM _transportSM; -// stInit: initialize transport HW -void stInitTransition() { +// global variables +extern MyMessage _msg; // incoming message +extern MyMessage _msgTmp; // outgoing message +extern NodeConfig _nc; // node config + +#if defined(MY_RAM_ROUTING_TABLE_ENABLED) + static routingTable _transportRoutingTable; //!< routing table + static uint32_t _lastRoutingTableSave; //!< last routing table dump +#endif + +// regular sanity check, activated by default on GW and repeater nodes +#if defined(MY_TRANSPORT_SANITY_CHECK) + static uint32_t _lastSanityCheck; //!< last sanity check +#endif + +// regular network discovery, sends I_DISCOVER_REQUESTS to update routing table +// sufficient to have GW triggering requests to also update repeater nodes +#if defined(MY_GATEWAY_FEATURE) + static uint32_t _lastNetworkDiscovery; //! last network discovery +#endif + +// stInit: initialise transport HW +void stInitTransition(void) { TRANSPORT_DEBUG(PSTR("TSM:INIT\n")); - // initialize status variables + // initialise status variables _transportSM.pingActive = false; _transportSM.transportActive = false; - #if defined(MY_TRANSPORT_SANITY_CHECK) || defined(MY_REPEATER_FEATURE) - _transportSM.lastSanityCheck = hwMillis(); + _transportSM.lastUplinkCheck = 0ul; + + #if defined(MY_TRANSPORT_SANITY_CHECK) + _lastSanityCheck = hwMillis(); + #endif + #if defined(MY_GATEWAY_FEATURE) + _lastNetworkDiscovery = 0ul; + #endif + #if defined(MY_RAM_ROUTING_TABLE_ENABLED) + _lastRoutingTableSave = hwMillis(); #endif - _transportSM.lastUplinkCheck = 0; - // Read node settings (ID, parentId, GW distance) from EEPROM + + // Read node settings (ID, parent ID, GW distance) from EEPROM hwReadConfigBlock((void*)&_nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); +} - // initialize radio +void stInitUpdate(void) { + // initialise radio if (!transportInit()) { TRANSPORT_DEBUG(PSTR("!TSM:INIT:TSP FAIL\n")); setIndication(INDICATION_ERR_INIT_TRANSPORT); @@ -56,26 +87,26 @@ void stInitTransition() { // Set configuration for gateway TRANSPORT_DEBUG(PSTR("TSM:INIT:GW MODE\n")); _nc.parentNodeId = GATEWAY_ADDRESS; - _nc.distance = 0; + _nc.distance = 0u; _nc.nodeId = GATEWAY_ADDRESS; transportSetAddress(GATEWAY_ADDRESS); // GW mode: skip FPAR,ID,UPL states transportSwitchSM(stReady); #else if ((uint8_t)MY_NODE_ID != AUTO) { - TRANSPORT_DEBUG(PSTR("TSM:INIT:STATID,ID=%d\n"),MY_NODE_ID); - // Set static id - _nc.nodeId = MY_NODE_ID; - // Save static id in eeprom - hwWriteConfig(EEPROM_NODE_ID_ADDRESS, MY_NODE_ID); + TRANSPORT_DEBUG(PSTR("TSM:INIT:STATID=%d\n"),(uint8_t)MY_NODE_ID); + // Set static ID + _nc.nodeId = (uint8_t)MY_NODE_ID; + // Save static ID to eeprom (for bootloader) + hwWriteConfig(EEPROM_NODE_ID_ADDRESS, (uint8_t)MY_NODE_ID); } - // set ID if static or set in EEPROM + // assign ID if set if (_nc.nodeId == AUTO || transportAssignNodeID(_nc.nodeId)) { - // if node ID > 0, proceed to next state + // if node ID valid (>0 and <255), proceed to next state transportSwitchSM(stParent); } else { - // ID invalid (=0), nothing we can do + // ID invalid (0 or 255) transportSwitchSM(stFailure); } #endif @@ -83,32 +114,35 @@ void stInitTransition() { } // stParent: find parent -void stParentTransition() { +void stParentTransition(void) { TRANSPORT_DEBUG(PSTR("TSM:FPAR\n")); // find parent setIndication(INDICATION_FIND_PARENT); _transportSM.uplinkOk = false; _transportSM.preferredParentFound = false; #if defined(MY_PARENT_NODE_IS_STATIC) - TRANSPORT_DEBUG(PSTR("TSM:FPAR:STATP=%d\n"),MY_PARENT_NODE_ID); // static parent + TRANSPORT_DEBUG(PSTR("TSM:FPAR:STATP=%d\n"), (uint8_t)MY_PARENT_NODE_ID); // static parent _transportSM.findingParentNode = false; - _nc.distance = 1; // assumption, CHKUPL:GWDC will update this variable - _nc.parentNodeId = MY_PARENT_NODE_ID; - // skipping find parent - setIndication(INDICATION_GOT_PARENT); - transportSwitchSM(stID); + _nc.distance = 1u; // assumption, CHKUPL:GWDC will update this variable + _nc.parentNodeId = (uint8_t)MY_PARENT_NODE_ID; + // save parent ID to eeprom (for bootloader) + hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, (uint8_t)MY_PARENT_NODE_ID); #else _transportSM.findingParentNode = true; _nc.distance = DISTANCE_INVALID; // Set distance to max and invalidate parent node ID _nc.parentNodeId = AUTO; // Broadcast find parent request - transportRouteMessage(build(_msgTmp, _nc.nodeId, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_REQUEST, false).set("")); + (void)transportRouteMessage(build(_msgTmp, _nc.nodeId, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_REQUEST, false).set("")); #endif } // stParentUpdate -void stParentUpdate() { - #if !defined(MY_PARENT_NODE_IS_STATIC) - if (transportTimeInState() > STATE_TIMEOUT || _transportSM.preferredParentFound) { +void stParentUpdate(void) { + #if defined(MY_PARENT_NODE_IS_STATIC) + // skipping find parent + setIndication(INDICATION_GOT_PARENT); + transportSwitchSM(stID); + #else + if (transportTimeInState() > MY_TRANSPORT_STATE_TIMEOUT_MS || _transportSM.preferredParentFound) { // timeout or preferred parent found if (_nc.parentNodeId != AUTO) { // parent assigned @@ -118,9 +152,9 @@ void stParentUpdate() { // go to next state transportSwitchSM(stID); } - else if (transportTimeInState() > STATE_TIMEOUT) { + else { // timeout w/o reply or valid parent - if (_transportSM.retries < STATE_RETRIES) { + if (_transportSM.stateRetries < MY_TRANSPORT_STATE_RETRIES) { // retries left TRANSPORT_DEBUG(PSTR("!TSM:FPAR:NO REPLY\n")); // find parent, no reply // reenter state @@ -128,7 +162,7 @@ void stParentUpdate() { } else { // no retries left, finding parent failed - TRANSPORT_DEBUG(PSTR("!TSM:FPAR:FAIL\n")); // find parent fail + TRANSPORT_DEBUG(PSTR("!TSM:FPAR:FAIL\n")); setIndication(INDICATION_ERR_FIND_PARENT); transportSwitchSM(stFailure); } @@ -138,67 +172,100 @@ void stParentUpdate() { } // stID: verify and request ID if necessary -void stIDTransition() { +void stIDTransition(void) { TRANSPORT_DEBUG(PSTR("TSM:ID\n")); // verify/request node ID if (_nc.nodeId == AUTO) { // send ID request setIndication(INDICATION_REQ_NODEID); TRANSPORT_DEBUG(PSTR("TSM:ID:REQ\n")); // request node ID - transportRouteMessage(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_ID_REQUEST, false).set("")); + (void)transportRouteMessage(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_ID_REQUEST, false).set("")); } } -void stIDUpdate() { +void stIDUpdate(void) { if (_nc.nodeId != AUTO) { // current node ID is valid - TRANSPORT_DEBUG(PSTR("TSM:ID:OK,ID=%d\n"), _nc.nodeId); + TRANSPORT_DEBUG(PSTR("TSM:ID:OK\n")); setIndication(INDICATION_GOT_NODEID); // proceed to next state transportSwitchSM(stUplink); } - else if (transportTimeInState() > STATE_TIMEOUT) { + else if (transportTimeInState() > MY_TRANSPORT_STATE_TIMEOUT_MS) { // timeout - if (_transportSM.retries < STATE_RETRIES) { - // reenter + if (_transportSM.stateRetries < MY_TRANSPORT_STATE_RETRIES) { + // retries left: reenter state transportSwitchSM(stID); } else { // no retries left - TRANSPORT_DEBUG(PSTR("!TSM:ID:FAIL,ID=%d\n"), _nc.nodeId); + TRANSPORT_DEBUG(PSTR("!TSM:ID:FAIL\n")); setIndication(INDICATION_ERR_GET_NODEID); transportSwitchSM(stFailure); } } } -void stUplinkTransition() { - TRANSPORT_DEBUG(PSTR("TSM:UPL\n")); - // check uplink - if(transportCheckUplink(true)) { - // uplink ok, i.e. GW replied - TRANSPORT_DEBUG(PSTR("TSM:UPL:OK\n")); // uplink ok - // proceed to next state +void stUplinkTransition(void) { + #if !defined(MY_TRANSPORT_UPLINK_CHECK_DISABLED) + TRANSPORT_DEBUG(PSTR("TSM:UPL\n")); + setIndication(INDICATION_CHECK_UPLINK); + _transportSM.pingResponse = INVALID_HOPS; + _transportSM.pingActive = true; + (void)transportRouteMessage(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_PING, false).set((uint8_t)1)); + #endif +} + +void stUplinkUpdate(void) { + #if !defined(MY_TRANSPORT_UPLINK_CHECK_DISABLED) + if (_transportSM.pingResponse != INVALID_HOPS) { + _transportSM.lastUplinkCheck = hwMillis(); + // uplink ok, i.e. GW replied + TRANSPORT_DEBUG(PSTR("TSM:UPL:OK\n")); // uplink ok + //_transportSM.pingActive = false; ==> set false upon receiving I_PONG + if (_transportSM.pingResponse != _nc.distance) { + TRANSPORT_DEBUG(PSTR("TSM:UPL:DGWC,O=%d,N=%d\n"), _nc.distance, _transportSM.pingResponse); // distance to GW changed + _nc.distance = _transportSM.pingResponse; + } + transportSwitchSM(stReady); // proceed to next state + } + else if (transportTimeInState() > MY_TRANSPORT_STATE_TIMEOUT_MS) { + // timeout + if (_transportSM.stateRetries < MY_TRANSPORT_STATE_RETRIES) { + // retries left: reenter state + transportSwitchSM(stUplink); + } + else { + // no retries left + TRANSPORT_DEBUG(PSTR("!TSM:UPL:FAIL\n")); // uplink check failed + _transportSM.pingActive = false; + setIndication(INDICATION_ERR_CHECK_UPLINK); + transportSwitchSM(stParent); // go back to stParent + } + } + #else + TRANSPORT_DEBUG(PSTR("TSM:UPL:DISABLED\n")); // uplink check disabled transportSwitchSM(stReady); - } - else { - // uplink failed, at this point, no retries or timeout - TRANSPORT_DEBUG(PSTR("!TSM:UPL:FAIL\n")); // uplink failed - // go back to stParent - transportSwitchSM(stParent); - } + #endif } -void stReadyTransition() { +void stReadyTransition(void) { // transport is ready and fully operational TRANSPORT_DEBUG(PSTR("TSM:READY\n")); // transport is ready _transportSM.uplinkOk = true; - _transportSM.failedUplinkTransmissions = 0; // reset counter + _transportSM.failureCounter = 0u; // reset failure counter + _transportSM.failedUplinkTransmissions = 0u; // reset failed uplink TX counter } -// stReadyUpdate: monitors uplink failures -void stReadyUpdate() { - #if !defined(MY_GATEWAY_FEATURE) - if (_transportSM.failedUplinkTransmissions > TRANSMISSION_FAILURES) { +// stReadyUpdate: monitors link +void stReadyUpdate(void) { + #if defined(MY_GATEWAY_FEATURE) + if (hwMillis() - _lastNetworkDiscovery > MY_TRANSPORT_DISCOVERY_INTERVAL_MS) { + _lastNetworkDiscovery = hwMillis(); + TRANSPORT_DEBUG(PSTR("TSM:READY:NWD REQ\n")); // send transport network discovery + (void)transportRouteMessage(build(_msgTmp, GATEWAY_ADDRESS, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DISCOVER_REQUEST, false).set("")); + } + #else + if (_transportSM.failedUplinkTransmissions > MY_TRANSPORT_MAX_TX_FAILURES) { // too many uplink transmissions failed, find new parent (if non-static) #if !defined(MY_PARENT_NODE_IS_STATIC) TRANSPORT_DEBUG(PSTR("!TSM:READY:UPL FAIL,SNP\n")); // uplink failed, search new parent @@ -206,70 +273,84 @@ void stReadyUpdate() { #else TRANSPORT_DEBUG(PSTR("!TSM:READY:UPL FAIL,STATP\n")); // uplink failed, static parent // reset counter - _transportSM.failedUplinkTransmissions = 0; + _transportSM.failedUplinkTransmissions = 0u; #endif } #endif + + #if defined(MY_RAM_ROUTING_TABLE_ENABLED) + if (hwMillis() - _lastRoutingTableSave > MY_ROUTING_TABLE_SAVE_INTERVAL_MS) { + _lastRoutingTableSave = hwMillis(); + TRANSPORT_DEBUG(PSTR("TSM:READY:SRT\n")); // save routing table + transportSaveRoutingTable(); + } + #endif } // stFailure: entered upon HW init failure or max retries exceeded -void stFailureTransition() { - TRANSPORT_DEBUG(PSTR("TSM:FAILURE\n")); - _transportSM.uplinkOk = false; // uplink nok +void stFailureTransition(void) { + if (_transportSM.failureCounter < MY_TRANSPORT_MAX_TSM_FAILURES) { + _transportSM.failureCounter++; // increment consecutive TSM failure counter + } + TRANSPORT_DEBUG(PSTR("TSM:FAIL:CNT=%d\n"),_transportSM.failureCounter); + _transportSM.uplinkOk = false; // uplink nok _transportSM.transportActive = false; // transport inactive setIndication(INDICATION_ERR_INIT_TRANSPORT); - // power down transport, no need until re-init - TRANSPORT_DEBUG(PSTR("TSM:FAILURE:PDT\n")); // power down transport - transportPowerDown(); + #if defined(MY_RADIO_FEATURE) + TRANSPORT_DEBUG(PSTR("TSM:FAIL:PDT\n")); // power down transport, no need until re-init + transportPowerDown(); + #endif } -void stFailureUpdate() { - if (transportTimeInState()> TIMEOUT_FAILURE_STATE) { - TRANSPORT_DEBUG(PSTR("TSM:FAILURE:RE-INIT\n")); // attempt to re-initialize transport +void stFailureUpdate(void) { + if (transportTimeInState() > ( isTransportExtendedFailure()? MY_TRANSPORT_TIMEOUT_EXT_FAILURE_STATE: MY_TRANSPORT_TIMEOUT_FAILURE_STATE) ) { + TRANSPORT_DEBUG(PSTR("TSM:FAIL:RE-INIT\n")); // attempt to re-initialise transport transportSwitchSM(stInit); } } void transportSwitchSM(transportState& newState) { if (_transportSM.currentState != &newState) { - // state change, reset retry counter - _transportSM.retries = 0; - // change state - _transportSM.currentState = &newState; + _transportSM.stateRetries = 0u; // state change, reset retry counter + _transportSM.currentState = &newState; // change state } else { - _transportSM.retries++; // increment retries + _transportSM.stateRetries++; // increment retries } - // Transition event - if (_transportSM.currentState->Transition) _transportSM.currentState->Transition(); - // save time - _transportSM.stateEnter = hwMillis(); + if (_transportSM.currentState->Transition) _transportSM.currentState->Transition(); // State transition + _transportSM.stateEnter = hwMillis(); // save time } -uint32_t transportTimeInState() { +uint32_t transportTimeInState(void) { return hwMillis() - _transportSM.stateEnter; } -void transportUpdateSM(){ +void transportUpdateSM(void) { if (_transportSM.currentState->Update) _transportSM.currentState->Update(); } -bool isTransportReady() { +bool isTransportReady(void) { return _transportSM.uplinkOk; } -bool isTransportSearchingParent() { +bool isTransportExtendedFailure(void) { + return _transportSM.failureCounter == MY_TRANSPORT_MAX_TSM_FAILURES; +} + +bool isTransportSearchingParent(void) { return _transportSM.findingParentNode; } -void transportInitialize() { +void transportInitialise(void) { + _transportSM.failureCounter = 0u; // reset failure counter + transportLoadRoutingTable(); // load routing table to RAM (if feature enabled) // intial state - _transportSM.currentState = &stFailure; + _transportSM.currentState = NULL; transportSwitchSM(stInit); } // update TSM and process incoming messages -void transportProcess() { +void transportProcess(void) { // update state machine transportUpdateSM(); // process transport FIFO @@ -277,54 +358,55 @@ void transportProcess() { } -bool transportCheckUplink(bool force) { - if (!force && (hwMillis() - _transportSM.lastUplinkCheck) < CHKUPL_INTERVAL) { - TRANSPORT_DEBUG(PSTR("TSF:CHKUPL:OK,FCTRL\n")); // flood control +bool transportCheckUplink(const bool force) { + if (!force && (hwMillis() - _transportSM.lastUplinkCheck) < MY_TRANSPORT_CHKUPL_INTERVAL_MS) { + TRANSPORT_DEBUG(PSTR("TSF:CKU:OK,FCTRL\n")); // flood control return true; } // ping GW - uint8_t hopsCount = transportPingNode(GATEWAY_ADDRESS); + const uint8_t hopsCount = transportPingNode(GATEWAY_ADDRESS); // verify hops if (hopsCount != INVALID_HOPS) { // update _transportSM.lastUplinkCheck = hwMillis(); - TRANSPORT_DEBUG(PSTR("TSF:CHKUPL:OK\n")); + TRANSPORT_DEBUG(PSTR("TSF:CKU:OK\n")); // did distance to GW change upstream, eg. re-routing of uplink nodes if (hopsCount != _nc.distance) { - TRANSPORT_DEBUG(PSTR("TSF:CHKUPL:DGWC,O=%d,N=%d\n"), _nc.distance, hopsCount); // distance to GW changed + TRANSPORT_DEBUG(PSTR("TSF:CKU:DGWC,O=%d,N=%d\n"), _nc.distance, hopsCount); // distance to GW changed _nc.distance = hopsCount; } return true; } else { - TRANSPORT_DEBUG(PSTR("TSF:CHKUPL:FAIL\n")); + TRANSPORT_DEBUG(PSTR("TSF:CKU:FAIL\n")); return false; } } -bool transportAssignNodeID(uint8_t newNodeId) { +bool transportAssignNodeID(const uint8_t newNodeId) { // verify if ID valid if (newNodeId != GATEWAY_ADDRESS && newNodeId != AUTO) { _nc.nodeId = newNodeId; transportSetAddress(newNodeId); // Write ID to EEPROM hwWriteConfig(EEPROM_NODE_ID_ADDRESS, newNodeId); - TRANSPORT_DEBUG(PSTR("TSF:ASID:OK,ID=%d\n"),newNodeId); + TRANSPORT_DEBUG(PSTR("TSF:SID:OK,ID=%d\n"),newNodeId); // Node ID assigned return true; } else { - TRANSPORT_DEBUG(PSTR("!TSF:ASID:FAIL,ID=%d\n"),newNodeId); + TRANSPORT_DEBUG(PSTR("!TSF:SID:FAIL,ID=%d\n"),newNodeId); // ID is invalid, cannot assign ID setIndication(INDICATION_ERR_NET_FULL); + _nc.nodeId = AUTO; return false; } } bool transportRouteMessage(MyMessage &message) { - uint8_t destination = message.destination; - uint8_t route; + const uint8_t destination = message.destination; + uint8_t route = _nc.parentNodeId; // by default, all traffic is routed via parent node if (_transportSM.findingParentNode && destination != BROADCAST_ADDRESS) { - TRANSPORT_DEBUG(PSTR("!TSF:ROUTE:FPAR ACTIVE\n")); // find parent active, message not sent + TRANSPORT_DEBUG(PSTR("!TSF:RTE:FPAR ACTIVE\n")); // find parent active, message not sent // request to send a non-BC message while finding parent active, abort return false; } @@ -338,122 +420,130 @@ bool transportRouteMessage(MyMessage &message) { else { #if defined(MY_REPEATER_FEATURE) // destination not GW & not BC, get route - route = hwReadConfig(EEPROM_ROUTES_ADDRESS + destination); + route = transportGetRoute(destination); if (route == AUTO) { - // route unknown - if (message.last != _nc.parentNodeId) { - // message not from parent, i.e. child node - route it to parent - TRANSPORT_DEBUG(PSTR("!TSF:ROUTE:%d UNKNOWN\n"), destination); - route = _nc.parentNodeId; - } - else { - // route unknown and msg received from parent, send it to destination assuming in rx radius + TRANSPORT_DEBUG(PSTR("!TSF:RTE:%d UNKNOWN\n"), destination); // route unknown + #if !defined(MY_GATEWAY_FEATURE) + if (message.last != _nc.parentNodeId) { + // message not from parent, i.e. child node - route it to parent + route = _nc.parentNodeId; + } + else { + // route unknown and msg received from parent, send it to destination assuming in rx radius + route = destination; + } + #else + // if GW, all unknown destinations are directly addressed route = destination; - } + #endif } #else route = _nc.parentNodeId; // not a repeater, all traffic routed via parent #endif } // send message - bool ok = transportSendWrite(route, message); + const bool result = transportSendWrite(route, message); #if !defined(MY_GATEWAY_FEATURE) // update counter if (route == _nc.parentNodeId) { - if (!ok) { + if (!result) { setIndication(INDICATION_ERR_TX); _transportSM.failedUplinkTransmissions++; } - else _transportSM.failedUplinkTransmissions = 0; + else _transportSM.failedUplinkTransmissions = 0u; } #else - if(!ok) setIndication(INDICATION_ERR_TX); + if(!result) setIndication(INDICATION_ERR_TX); #endif - return ok; + return result; } bool transportSendRoute(MyMessage &message) { + bool result = false; if (isTransportReady()) { - return transportRouteMessage(message); + result = transportRouteMessage(message); } else { // TNR: transport not ready - TRANSPORT_DEBUG(PSTR("!TSF:SEND:TNR\n")); - return false; + TRANSPORT_DEBUG(PSTR("!TSF:SND:TNR\n")); } + return result; } // only be used inside transport -bool transportWait(uint32_t ms, uint8_t cmd, uint8_t msgtype){ - uint32_t enter = hwMillis(); +bool transportWait(const uint32_t ms, const uint8_t cmd, const uint8_t msgtype){ + const uint32_t enter = hwMillis(); // invalidate msg type _msg.type = !msgtype; bool expectedResponse = false; while ((hwMillis() - enter < ms) && !expectedResponse) { // process incoming messages transportProcessFIFO(); - #if defined(ARDUINO_ARCH_ESP8266) - yield(); - #endif + yield(); // process esp8266 stack, ignored for AVR expectedResponse = (mGetCommand(_msg) == cmd && _msg.type == msgtype); } return expectedResponse; } -uint8_t transportPingNode(uint8_t targetId) { +uint8_t transportPingNode(const uint8_t targetId) { if(!_transportSM.pingActive){ + TRANSPORT_DEBUG(PSTR("TSF:PNG:SEND,TO=%d\n"), targetId); if(targetId == _nc.nodeId) { - // ping to ourself, pingActive remains false - return 0; + // pinging self + _transportSM.pingResponse = 0u; + } + else { + _transportSM.pingActive = true; + _transportSM.pingResponse = INVALID_HOPS; + (void)transportRouteMessage(build(_msgTmp, _nc.nodeId, targetId, NODE_SENSOR_ID, C_INTERNAL, I_PING, false).set((uint8_t)1)); + // Wait for ping reply or timeout + (void)transportWait(2000, C_INTERNAL, I_PONG); } - _transportSM.pingActive = true; - _transportSM.pingResponse = INVALID_HOPS; - TRANSPORT_DEBUG(PSTR("TSF:PING:SEND,TO=%d\n"), targetId); - transportRouteMessage(build(_msgTmp, _nc.nodeId, targetId, NODE_SENSOR_ID, C_INTERNAL, I_PING, false).set((uint8_t)0x01)); - // Wait for ping reply or timeout - transportWait(2000, C_INTERNAL, I_PONG); // make sure missing I_PONG msg does not block pinging function by leaving pignActive=true _transportSM.pingActive = false; return _transportSM.pingResponse; } else { + TRANSPORT_DEBUG(PSTR("!TSF:PNG:ACTIVE\n")); // ping active, cannot start new ping return INVALID_HOPS; } } -void transportClearRoutingTable() { - for (uint8_t i = 0; i != 255; i++) { - hwWriteConfig(EEPROM_ROUTES_ADDRESS + i, BROADCAST_ADDRESS); - } - TRANSPORT_DEBUG(PSTR("TSF:CRT:OK\n")); // clear routing table -} - -uint32_t transportGetHeartbeat() { +uint32_t transportGetHeartbeat(void) { return transportTimeInState(); } -void transportProcessMessage() { - (void)signerCheckTimer(); // Manage signing timeout - - uint8_t payloadLength = transportReceive((uint8_t *)&_msg); - (void)payloadLength; // currently not used - +void transportProcessMessage(void) { + // Manage signing timeout + (void)signerCheckTimer(); + // receive message setIndication(INDICATION_RX); - - uint8_t command = mGetCommand(_msg); - uint8_t type = _msg.type; - uint8_t sender = _msg.sender; - uint8_t last = _msg.last; - uint8_t destination = _msg.destination; + const uint8_t payloadLength = transportReceive((uint8_t *)&_msg); + // get message length and limit size + const uint8_t msgLength = min(mGetLength(_msg), MAX_PAYLOAD); + // calculate expected length + const uint8_t expectedMessageLength = HEADER_SIZE + (mGetSigned(_msg) ? MAX_PAYLOAD : msgLength); + const uint8_t command = mGetCommand(_msg); + const uint8_t type = _msg.type; + const uint8_t sender = _msg.sender; + const uint8_t last = _msg.last; + const uint8_t destination = _msg.destination; TRANSPORT_DEBUG(PSTR("TSF:MSG:READ,%d-%d-%d,s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d:%s\n"), - sender, last, destination, _msg.sensor, mGetCommand(_msg), type, mGetPayloadType(_msg), mGetLength(_msg), mGetSigned(_msg), _msg.getString(_convBuf)); + sender, last, destination, _msg.sensor, command, type, mGetPayloadType(_msg), msgLength, mGetSigned(_msg), _msg.getString(_convBuf)); + + // Reject payloads with incorrect length + if (payloadLength != expectedMessageLength) { + setIndication(INDICATION_ERR_LENGTH); + TRANSPORT_DEBUG(PSTR("!TSF:MSG:LEN,%d!=%d\n"), payloadLength, expectedMessageLength); // invalid payload length + return; + } - // verify protocol version - if(mGetVersion(_msg) != PROTOCOL_VERSION) { + // Reject messages with incorrect protocol version + if (mGetVersion(_msg) != PROTOCOL_VERSION) { setIndication(INDICATION_ERR_VERSION); - TRANSPORT_DEBUG(PSTR("!TSF:MSG:PVER,%d!=%d\n"), mGetVersion(_msg),PROTOCOL_VERSION); // protocol version mismatch + TRANSPORT_DEBUG(PSTR("!TSF:MSG:PVER,%d=%d\n"), mGetVersion(_msg), PROTOCOL_VERSION); // protocol version mismatch return; } @@ -463,33 +553,34 @@ void transportProcessMessage() { TRANSPORT_DEBUG(PSTR("!TSF:MSG:SIGN VERIFY FAIL\n")); return; } + + // update routing table if msg not from parent + #if defined(MY_REPEATER_FEATURE) + #if !defined(MY_GATEWAY_FEATURE) + if (last != _nc.parentNodeId) { + #else + // GW doesn't have parent + { + #endif + // Message is from one of the child nodes. Add it to routing table. + transportSetRoute(sender, last); + } + #endif // Is message addressed to this node? if (destination == _nc.nodeId) { - // prevent buffer overflow by limiting max. possible message length (5 bits=31 bytes max) to MAX_PAYLOAD (25 bytes) - mSetLength(_msg, min(mGetLength(_msg),MAX_PAYLOAD)); // null terminate data - _msg.data[mGetLength(_msg)] = 0x00; - - // update routing table if msg not from parent - #if defined(MY_REPEATER_FEATURE) - if (last != _nc.parentNodeId) { - // Message is from one of the child nodes. Add it to routing table. - hwWriteConfig(EEPROM_ROUTES_ADDRESS+sender, last); - } - #endif - + _msg.data[msgLength] = 0u; // Check if sender requests an ack back. if (mGetRequestAck(_msg)) { + TRANSPORT_DEBUG(PSTR("TSF:MSG:ACK REQ\n")); // ACK requested _msgTmp = _msg; // Copy message mSetRequestAck(_msgTmp, false); // Reply without ack flag (otherwise we would end up in an eternal loop) mSetAck(_msgTmp, true); // set ACK flag _msgTmp.sender = _nc.nodeId; _msgTmp.destination = sender; - // send ACK - TRANSPORT_DEBUG(PSTR("TSF:MSG:ACK REQ\n")); // ACK requested - // use transportSendRoute since ACK reply is not internal, i.e. if !transportOK do not reply - transportSendRoute(_msgTmp); + // send ACK, use transportSendRoute since ACK reply is not internal, i.e. if !transportOK do not reply + (void)transportSendRoute(_msgTmp); } if(!mGetAck(_msg)) { // only process if not ACK @@ -500,27 +591,25 @@ void transportProcessMessage() { } #if !defined(MY_GATEWAY_FEATURE) if (type == I_ID_RESPONSE) { - #if (MY_NODE_ID == AUTO) - // only active if node ID dynamic - transportAssignNodeID(_msg.getByte()); - #endif - return; // no further processing required + #if (MY_NODE_ID == AUTO) + // only active if node ID dynamic + (void)transportAssignNodeID(_msg.getByte()); + #endif + return; // no further processing required } if (type == I_FIND_PARENT_RESPONSE) { #if !defined(MY_GATEWAY_FEATURE) && !defined(MY_PARENT_NODE_IS_STATIC) if (_transportSM.findingParentNode) { // only process if find parent active // Reply to a I_FIND_PARENT_REQUEST message. Check if the distance is shorter than we already have. uint8_t distance = _msg.getByte(); - TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR RES,ID=%d,D=%d\n"), sender, distance); // find parent response if (isValidDistance(distance)) { - // Distance to gateway is one more for us w.r.t. parent - distance++; + distance++; // Distance to gateway is one more for us w.r.t. parent // update settings if distance shorter or preferred parent found - if (((isValidDistance(distance) && distance < _nc.distance) || (!_autoFindParent && sender == MY_PARENT_NODE_ID)) && !_transportSM.preferredParentFound) { + if (((isValidDistance(distance) && distance < _nc.distance) || (!_autoFindParent && sender == (uint8_t)MY_PARENT_NODE_ID)) && !_transportSM.preferredParentFound) { // Found a neighbor closer to GW than previously found - if (!_autoFindParent && sender == MY_PARENT_NODE_ID) { + if (!_autoFindParent && sender == (uint8_t)MY_PARENT_NODE_ID) { _transportSM.preferredParentFound = true; - TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR PREF FOUND\n")); // find parent, preferred parent found + TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR PREF\n")); // find parent, preferred parent found } _nc.distance = distance; _nc.parentNodeId = sender; @@ -529,7 +618,7 @@ void transportProcessMessage() { } } else { - TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR INACTIVE\n")); // find parent response received, but inactive + TRANSPORT_DEBUG(PSTR("!TSF:MSG:FPAR INACTIVE\n")); // find parent response received, but inactive } return; #endif @@ -538,7 +627,11 @@ void transportProcessMessage() { // general if (type == I_PING) { TRANSPORT_DEBUG(PSTR("TSF:MSG:PINGED,ID=%d,HP=%d\n"), sender, _msg.getByte()); // node pinged - transportRouteMessage(build(_msgTmp, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_PONG, false).set((uint8_t)0x01)); + // delay for slow nodes ***************************** + #if defined(MY_GATEWAY_FEATURE) && (F_CPU<=16000000) + delay(5); + #endif + (void)transportRouteMessage(build(_msgTmp, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_PONG, false).set((uint8_t)1)); return; // no further processing required } if (type == I_PONG) { @@ -547,9 +640,11 @@ void transportProcessMessage() { _transportSM.pingResponse = _msg.getByte(); TRANSPORT_DEBUG(PSTR("TSF:MSG:PONG RECV,HP=%d\n"), _transportSM.pingResponse); // pong received } + else { + TRANSPORT_DEBUG(PSTR("!TSF:MSG:PONG RECV,INACTIVE\n")); // pong received, but !pingActive + } return; // no further processing required } - if (_processInternalMessages()) { return; // no further processing required } @@ -566,13 +661,12 @@ void transportProcessMessage() { } #if defined(MY_GATEWAY_FEATURE) // Hand over message to controller - gatewayTransportSend(_msg); + (void)gatewayTransportSend(_msg); #endif // Call incoming message callback if available if (receive) { receive(_msg); } - return; } else if (destination == BROADCAST_ADDRESS) { TRANSPORT_DEBUG(PSTR("TSF:MSG:BC\n")); // broadcast msg @@ -581,49 +675,61 @@ void transportProcessMessage() { // only reply if node is fully operational if (type == I_FIND_PARENT_REQUEST) { #if defined(MY_REPEATER_FEATURE) - if (sender != _nc.parentNodeId) { // no circular reference - TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR REQ,ID=%d\n"), sender); // FPR: find parent request - // node is in our range, update routing table - important if node has new repeater as parent - hwWriteConfig(EEPROM_ROUTES_ADDRESS + sender, sender); - // check if uplink functional - node can only be parent node if link to GW functional - // this also prevents circular references in case GW ooo - if(transportCheckUplink(false)){ - _transportSM.lastUplinkCheck = hwMillis(); - TRANSPORT_DEBUG(PSTR("TSF:MSG:GWL OK\n")); // GW uplink ok - // delay minimizes collisions - delay(hwMillis() & 0x3ff); - transportRouteMessage(build(_msgTmp, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(_nc.distance)); - } - else { - TRANSPORT_DEBUG(PSTR("!TSF:MSG:GWL FAIL\n")); // GW uplink fail, do not respond to parent request - } + if (sender != _nc.parentNodeId) { // no circular reference + TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR REQ,ID=%d\n"), sender); // FPAR: find parent request + // check if uplink functional - node can only be parent node if link to GW functional + // this also prevents circular references in case GW ooo + if (transportCheckUplink()) { + _transportSM.lastUplinkCheck = hwMillis(); + TRANSPORT_DEBUG(PSTR("TSF:MSG:GWL OK\n")); // GW uplink ok + // random delay minimizes collisions + delay(hwMillis() & 0x3ff); + (void)transportRouteMessage(build(_msgTmp, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(_nc.distance)); } - + else { + TRANSPORT_DEBUG(PSTR("!TSF:MSG:GWL FAIL\n")); // GW uplink fail, do not respond to parent request + } + } #endif - return; // no further processing required + return; // no further processing required, do not forward } + } // isTransportReady + if (type == I_FIND_PARENT_RESPONSE) { + return; // no further processing required, do not forward } - if (type == I_DISCOVER_REQUEST) { - if (last == _nc.parentNodeId) { - // random wait to minimize collisions - delay(hwMillis() & 0x3ff); - transportRouteMessage(build(_msgTmp, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_DISCOVER_RESPONSE, false).set(_nc.parentNodeId)); - // no return here (for fwd if repeater) + #if !defined(MY_GATEWAY_FEATURE) + if (type == I_DISCOVER_REQUEST) { + if (last == _nc.parentNodeId) { + // random wait to minimize collisions + delay(hwMillis() & 0x3ff); + (void)transportRouteMessage(build(_msgTmp, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_DISCOVER_RESPONSE, false).set(_nc.parentNodeId)); + // no return here (for fwd if repeater) + } } - } + #endif } // controlled BC relay #if defined(MY_REPEATER_FEATURE) // controlled BC repeating: forward only if message received from parent and sender not self to prevent circular fwds if(last == _nc.parentNodeId && sender != _nc.nodeId && isTransportReady()){ TRANSPORT_DEBUG(PSTR("TSF:MSG:FWD BC MSG\n")); // controlled broadcast msg forwarding - transportRouteMessage(_msg); + (void)transportRouteMessage(_msg); } #endif - // Call incoming message callback if available, but only if message received from parent - if (command != C_INTERNAL && last == _nc.parentNodeId && receive) { - receive(_msg); + // Callback for BC, only for non-internal messages + if (command != C_INTERNAL) { + #if !defined(MY_GATEWAY_FEATURE) + // only proceed if message received from parent + if (last != _nc.parentNodeId) return; + #endif + #if defined(MY_GATEWAY_FEATURE) + // Hand over message to controller + (void)gatewayTransportSend(_msg); + #endif + if (receive) { + receive(_msg); + } } } @@ -632,52 +738,48 @@ void transportProcessMessage() { #if defined(MY_REPEATER_FEATURE) if (isTransportReady()) { TRANSPORT_DEBUG(PSTR("TSF:MSG:REL MSG\n")); // relay msg - // update routing table if message not received from parent - if (last != _nc.parentNodeId) { - hwWriteConfig(EEPROM_ROUTES_ADDRESS + sender, last); - } if (command == C_INTERNAL) { if (type == I_PING || type == I_PONG) { uint8_t hopsCnt = _msg.getByte(); if (hopsCnt != MAX_HOPS) { TRANSPORT_DEBUG(PSTR("TSF:MSG:REL PxNG,HP=%d\n"), hopsCnt); - _msg.set((uint8_t)(hopsCnt + 1)); + hopsCnt++; + _msg.set(hopsCnt); } } } // Relay this message to another node - transportRouteMessage(_msg); + (void)transportRouteMessage(_msg); } #else - TRANSPORT_DEBUG(PSTR("!TSF:MSG:REL MSG,NORP\n")); // message relaying request, but not a repeater + TRANSPORT_DEBUG(PSTR("!TSF:MSG:REL MSG,NREP\n")); // message relaying request, but not a repeater #endif } } -void transportInvokeSanityCheck() { +void transportInvokeSanityCheck(void) { if (!transportSanityCheck()) { - TRANSPORT_DEBUG(PSTR("!TSF:SANCHK:FAIL\n")); // sanity check fail + TRANSPORT_DEBUG(PSTR("!TSF:SNK:FAIL\n")); // sanity check fail transportSwitchSM(stFailure); - return; } else { - TRANSPORT_DEBUG(PSTR("TSF:SANCHK:OK\n")); // sanity check ok + TRANSPORT_DEBUG(PSTR("TSF:SNK:OK\n")); // sanity check ok } } -inline void transportProcessFIFO() { - if (_transportSM.transportActive) { - #if defined(MY_TRANSPORT_SANITY_CHECK) || defined(MY_REPEATER_FEATURE) - if (hwMillis() - _transportSM.lastSanityCheck > MY_TRANSPORT_SANITY_CHECK_INTERVAL) { - _transportSM.lastSanityCheck = hwMillis(); - transportInvokeSanityCheck(); - } - #endif - } - else { - // transport not active, nothing to be done +void transportProcessFIFO(void) { + if (!_transportSM.transportActive) { + // transport not active, no further processing required return; } + + #if defined(MY_TRANSPORT_SANITY_CHECK) + if (hwMillis() - _lastSanityCheck > MY_TRANSPORT_SANITY_CHECK_INTERVAL_MS) { + _lastSanityCheck = hwMillis(); + transportInvokeSanityCheck(); + } + #endif + uint8_t _processedMessages = MAX_SUBSEQ_MSGS; // process all msgs in FIFO or counter exit while (transportAvailable() && _processedMessages--) { @@ -691,10 +793,8 @@ inline void transportProcessFIFO() { #endif } -bool transportSendWrite(uint8_t to, MyMessage &message) { - // Update last - message.last = _nc.nodeId; - +bool transportSendWrite(const uint8_t to, MyMessage &message) { + message.last = _nc.nodeId; // Update last // sign message if required if (!signerSignMsg(message)) { TRANSPORT_DEBUG(PSTR("!TSF:MSG:SIGN FAIL\n")); @@ -703,17 +803,58 @@ bool transportSendWrite(uint8_t to, MyMessage &message) { } // msg length changes if signed - uint8_t length = mGetSigned(message) ? MAX_MESSAGE_LENGTH : mGetLength(message); - + const uint8_t totalMsgLength = HEADER_SIZE + ( mGetSigned(message) ? MAX_PAYLOAD : mGetLength(message) ); + // send setIndication(INDICATION_TX); - bool ok = transportSend(to, &message, min(MAX_MESSAGE_LENGTH, HEADER_SIZE + length)); - + bool result = transportSend(to, &message, min(MAX_MESSAGE_LENGTH, totalMsgLength)); + // broadcasting (workaround counterfeits) + result |= (to == BROADCAST_ADDRESS); + TRANSPORT_DEBUG(PSTR("%sTSF:MSG:SEND,%d-%d-%d-%d,s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d,ft=%d,st=%s:%s\n"), - (ok || to == BROADCAST_ADDRESS ? "" : "!"),message.sender,message.last, to, message.destination, message.sensor, mGetCommand(message), message.type, - mGetPayloadType(message), mGetLength(message), mGetSigned(message), _transportSM.failedUplinkTransmissions, to==BROADCAST_ADDRESS ? "bc" : (ok ? "OK":"NACK"), message.getString(_convBuf)); - - return (ok || to==BROADCAST_ADDRESS); + (result ? "" : "!"), message.sender, message.last, to, message.destination, message.sensor, mGetCommand(message), message.type, + mGetPayloadType(message), mGetLength(message), mGetSigned(message), _transportSM.failedUplinkTransmissions, (result ? "OK" : "NACK"), message.getString(_convBuf)); + + return result; } +void transportClearRoutingTable(void) { + for (uint8_t i = 0; i != 255; i++) { + transportSetRoute(i, BROADCAST_ADDRESS); + } + transportSaveRoutingTable(); // save cleared routing table to EEPROM (if feature enabled) + TRANSPORT_DEBUG(PSTR("TSF:CRT:OK\n")); // clear routing table +} + +void transportLoadRoutingTable(void) { + #if defined(MY_RAM_ROUTING_TABLE_ENABLED) + hwReadConfigBlock((void*)&_transportRoutingTable.route, (void*)EEPROM_ROUTES_ADDRESS, 256); + #endif +} + +void transportSaveRoutingTable(void) { + #if defined(MY_RAM_ROUTING_TABLE_ENABLED) + hwWriteConfigBlock((void*)EEPROM_ROUTES_ADDRESS, (void*)&_transportRoutingTable.route, 256); + #endif +} + +void transportSetRoute(const uint8_t node, const uint8_t route) { + #if defined(MY_RAM_ROUTING_TABLE_ENABLED) + _transportRoutingTable.route[node] = route; + #else + hwWriteConfig(EEPROM_ROUTES_ADDRESS + node, route); + #endif +} + +uint8_t transportGetRoute(const uint8_t node) { + uint8_t result; + #if defined(MY_RAM_ROUTING_TABLE_ENABLED) + result = _transportRoutingTable.route[node]; + #else + result = hwReadConfig(EEPROM_ROUTES_ADDRESS + node); + #endif + return result; +} + + // EOF MyTransport.cpp \ No newline at end of file diff --git a/core/MyTransport.h b/core/MyTransport.h index 2267bee3b..a8b989f31 100644 --- a/core/MyTransport.h +++ b/core/MyTransport.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-2016 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -36,7 +36,7 @@ * - TSM:ID from stID Check/request node ID, if dynamic node ID set * - TSM:UPL from stUplink Verify uplink connection by pinging GW * - TSM:READY from stReady Transport is ready and fully operational - * - TSM:FAILURE from stFailure Failure in transport link or transport HW + * - TSM:FAIL from stFailure Failure in transport link or transport HW * - Transport support function (TSF) * - TSF:CHKUPL from @ref transportCheckUplink(), checks connection to GW * - TSF:ASID from @ref transportAssignNodeID(), assigns node ID @@ -52,7 +52,7 @@ * |E| SYS | SUB | Message | Comment * |-|------|-----------|-----------------------|--------------------------------------------------------------------- * | | TSM | INIT | | Transition to stInit state - * | | TSM | INIT | STATID,ID=%%d | Node ID is static + * | | TSM | INIT | STATID=%%d | Node ID is static * | | TSM | INIT | TSP OK | Transport device configured and fully operational * | | TSM | INIT | GW MODE | Node is set up as GW, thus omitting ID and findParent states * |!| TSM | INIT | TSP FAIL | Transport device initialization failed @@ -67,13 +67,14 @@ * |!| TSM | ID | FAIL,ID=%%d | ID verification failed, ID invalid * | | TSM | UPL | | Transition to stUplink state * | | TSM | UPL | OK | Uplink OK, GW returned ping + * | | TSF | UPL | DGWC,O=%%d,N=%%d | Uplink check revealed changed network topology, old distance (O), new distance (N) * |!| TSM | UPL | FAIL | Uplink check failed, i.e. GW could not be pinged * | | TSM | READY | | Transition to stReady, i.e. transport is ready and fully operational * |!| TSM | READY | UPL FAIL,SNP | Too many failed uplink transmissions, search new parent * |!| TSM | READY | FAIL,STATP | Too many failed uplink transmissions, static parent enforced - * | | TSM | FAILURE | | Transition to stFailure state - * | | TSM | FAILURE | PDT | Power-down transport - * | | TSM | FAILURE | RE-INIT | Attempt to re-initialize transport + * | | TSM | FAIL | CNT=%%d | Transition to stFailure state, consecutive failure counter (CNT) + * | | TSM | FAIL | PDT | Power-down transport + * | | TSM | FAIL | RE-INIT | Attempt to re-initialize transport * | | TSF | CHKUPL | OK | Uplink OK * | | TSF | CHKUPL | OK,FCTRL | Uplink OK, flood control prevents pinging GW in too short intervals * | | TSF | CHKUPL | DGWC,O=%%d,N=%%d | Uplink check revealed changed network topology, old distance (O), new distance (N) @@ -95,7 +96,8 @@ * | | TSF | MSG | FWD BC MSG | Controlled broadcast message forwarding * | | TSF | MSG | REL MSG | Relay message * | | TSF | MSG | REL PxNG,HP=%%d | Relay PING/PONG message, increment hop counter (HP) - * |!| TSF | MSG | PVER,%%d!=%%d | Message protocol version mismatch + * |!| TSF | MSG | LEN,%%d!=%%d | Invalid message length, (actual!=expected) + * |!| TSF | MSG | PVER,%%d!=%%d | Message protocol version mismatch (actual!=expected) * |!| TSF | MSG | SIGN VERIFY FAIL | Signing verification failed * |!| TSF | MSG | REL MSG,NORP | Node received a message for relaying, but node is not a repeater, message skipped * |!| TSF | MSG | SIGN FAIL | Signing message failed @@ -123,8 +125,9 @@ * - t=msg type * - pt=payload type * - l=length - * - ft=failed uplink transmission counter * - sg=signing flag + * - ft=failed uplink transmission counter + * - st=send status, OK=success, NACK=no radio ACK received * * @brief API declaration for MyTransport * @@ -139,15 +142,50 @@ #if defined(MY_DEBUG) #define TRANSPORT_DEBUG(x,...) debug(x, ##__VA_ARGS__) //!< debug #else - #define TRANSPORT_DEBUG(x,...) //!< debug NULL + #define TRANSPORT_DEBUG(x,...) //!< debug NULL #endif #if defined(MY_REPEATER_FEATURE) - #define TRANSMISSION_FAILURES 10 //!< search for a new parent node after this many transmission failures, higher threshold for repeating nodes + #define MY_TRANSPORT_MAX_TX_FAILURES (10u) //!< search for a new parent node after this many transmission failures, higher threshold for repeating nodes #else - #define TRANSMISSION_FAILURES 5 //!< search for a new parent node after this many transmission failures, lower threshold for non-repeating nodes + #define MY_TRANSPORT_MAX_TX_FAILURES (5u) //!< search for a new parent node after this many transmission failures, lower threshold for non-repeating nodes +#endif + +#define MY_TRANSPORT_MAX_TSM_FAILURES (15u) //!< Max. number of consecutive TSM failure state entries (4bit) + +#ifndef MY_TRANSPORT_TIMEOUT_FAILURE_STATE + #define MY_TRANSPORT_TIMEOUT_FAILURE_STATE (10*1000ul) //!< Duration failure state (in ms) #endif +#ifndef MY_TRANSPORT_TIMEOUT_EXT_FAILURE_STATE + #define MY_TRANSPORT_TIMEOUT_EXT_FAILURE_STATE (60*1000ul) //!< Duration extended failure state (in ms) +#endif +#ifndef MY_TRANSPORT_STATE_TIMEOUT_MS + #define MY_TRANSPORT_STATE_TIMEOUT_MS (2*1000ul) //!< general state timeout (in ms) +#endif +#ifndef MY_TRANSPORT_CHKUPL_INTERVAL_MS + #define MY_TRANSPORT_CHKUPL_INTERVAL_MS (10*1000ul) //!< Interval to re-check uplink (in ms) +#endif +#ifndef MY_TRANSPORT_STATE_RETRIES + #define MY_TRANSPORT_STATE_RETRIES (3u) //!< retries before switching to FAILURE +#endif + +#define AUTO (255u) //!< ID 255 is reserved +#define BROADCAST_ADDRESS (255u) //!< broadcasts are addressed to ID 255 +#define DISTANCE_INVALID (255u) //!< invalid distance when searching for parent +#define MAX_HOPS (254u) //!< maximal mumber of hops for ping/pong +#define INVALID_HOPS (255u) //!< invalid hops +#define MAX_SUBSEQ_MSGS (5u) //!< Maximum number of subsequentially processed messages in FIFO (to prevent transport deadlock if HW issue) +// parent node check +#if defined(MY_PARENT_NODE_IS_STATIC) && !defined(MY_PARENT_NODE_ID) + #error MY_PARENT_NODE_IS_STATIC but no MY_PARENT_NODE_ID defined! +#endif + +#define _autoFindParent (bool)(MY_PARENT_NODE_ID == AUTO) //!< returns true if static parent id is undefined +#define isValidDistance(distance) (bool)(distance!=DISTANCE_INVALID) //!< returns true if distance is valid +#define isValidParent(parent) (bool)(parent != AUTO) //!< returns true if parent is valid + +// RX queue #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) #if defined(MY_RADIO_RFM69) #error Receive message buffering not supported for RFM69! @@ -159,20 +197,6 @@ #error Receive message buffering requires message buffering feature enabled! #endif -#define TIMEOUT_FAILURE_STATE 10000 //!< duration failure state -#define STATE_TIMEOUT 2000 //!< general state timeout -#define STATE_RETRIES 3 //!< retries before switching to FAILURE -#define AUTO 255 //!< ID 255 is reserved for auto initialization of nodeId. -#define BROADCAST_ADDRESS ((uint8_t)255) //!< broadcasts are addressed to ID 255 -#define DISTANCE_INVALID ((uint8_t)255) //!< invalid distance when searching for parent -#define MAX_HOPS ((uint8_t)254) //!< maximal mumber of hops for ping/pong -#define INVALID_HOPS ((uint8_t)255) //!< invalid hops -#define MAX_SUBSEQ_MSGS 5 //!< Maximum number of subsequentially processed messages in FIFO (to prevent transport deadlock if HW issue) -#define CHKUPL_INTERVAL ((uint32_t)10000) //!< Minimum time interval to re-check uplink - -#define _autoFindParent (bool)(MY_PARENT_NODE_ID == AUTO) //!< returns true if static parent id is undefined -#define isValidDistance(distance) (bool)(distance!=DISTANCE_INVALID) //!< returns true if distance is valid -#define isValidParent(parent) (bool)(parent != AUTO) //!< returns true if parent is valid /** * @brief SM state @@ -190,67 +214,82 @@ struct transportState { * This structure stores transport status and SM variables */ typedef struct { + // SM variables transportState* currentState; //!< pointer to current fsm state uint32_t stateEnter; //!< state enter timepoint + // general transport variables uint32_t lastUplinkCheck; //!< last uplink check, required to prevent GW flooding - uint32_t lastSanityCheck; //!< last sanity check // 8 bits bool findingParentNode : 1; //!< flag finding parent node is active bool preferredParentFound : 1; //!< flag preferred parent found bool uplinkOk : 1; //!< flag uplink ok bool pingActive : 1; //!< flag ping active bool transportActive : 1; //!< flag transport active - uint8_t reserved : 3; //!< reserved + uint8_t stateRetries : 3; //!< retries / state re-enter (max 7) // 8 bits - uint8_t retries : 4; //!< retries / state re-enter - uint8_t failedUplinkTransmissions : 4; //!< counter failed uplink transmissions + uint8_t failedUplinkTransmissions : 4; //!< counter failed uplink transmissions (max 15) + uint8_t failureCounter : 4; //!< counter for TSM failures (max 15) // 8 bits - uint8_t pingResponse; //!< stores hops received in I_PONG -} __attribute__((packed)) transportSM; + uint8_t pingResponse; //!< stores I_PONG hops +} transportSM; +/** +* @brief RAM routing table +*/ +typedef struct { + uint8_t route[256]; //!< route for node +} routingTable; // PRIVATE functions /** -* @brief Initialize SM variables and transport HW +* @brief Initialise SM variables and transport HW +*/ +void stInitTransition(void); +/** +* @brief Initialise transport */ -void stInitTransition(); +void stInitUpdate(void); /** * @brief Find parent */ -void stParentTransition(); +void stParentTransition(void); /** * @brief Verify find parent responses */ -void stParentUpdate(); +void stParentUpdate(void); /** * @brief Send ID request */ -void stIDTransition(); +void stIDTransition(void); /** * @brief Verify ID response and GW link */ -void stIDUpdate(); +void stIDUpdate(void); /** * @brief Send uplink ping request */ -void stUplinkTransition(); +void stUplinkTransition(void); +/** +* @brief Verify uplink response +*/ +void stUplinkUpdate(void); /** * @brief Set transport OK */ -void stReadyTransition(); +void stReadyTransition(void); /** * @brief Monitor transport link */ -void stReadyUpdate(); +void stReadyUpdate(void); /** * @brief Transport failure and power down radio */ -void stFailureTransition(); +void stFailureTransition(void); /** * @brief Re-initialize transport after timeout */ -void stFailureUpdate(); +void stFailureUpdate(void); /** * @brief Switch SM state * @param newState New state to switch SM to @@ -259,30 +298,30 @@ void transportSwitchSM(transportState& newState); /** * @brief Update SM state */ -void transportUpdateSM(); +void transportUpdateSM(void); /** * @brief Request time in current SM state * @return ms in current state */ -uint32_t transportTimeInState(); +uint32_t transportTimeInState(void); /** * @brief Call transport driver sanity check */ -void transportInvokeSanityCheck(); +void transportInvokeSanityCheck(void); /** * @brief Process all pending messages in RX FIFO */ -void transportProcessFIFO(); +void transportProcessFIFO(void); /** * @brief Receive message from RX FIFO and process */ -void transportProcessMessage(); +void transportProcessMessage(void); /** * @brief Assign node ID * @param newNodeId New node ID * @return true if node ID valid and successfully assigned */ -bool transportAssignNodeID(uint8_t newNodeId); +bool transportAssignNodeID(const uint8_t newNodeId); /** * @brief Wait and process messages for a defined amount of time until specified message received * @param ms Time to wait and process incoming messages in ms @@ -290,13 +329,13 @@ bool transportAssignNodeID(uint8_t newNodeId); * @param msgtype Specific message type * @return true if specified command received within waiting time */ -bool transportWait(uint32_t ms, uint8_t cmd, uint8_t msgtype); +bool transportWait(const uint32_t ms, const uint8_t cmd, const uint8_t msgtype); /** * @brief Ping node * @param targetId Node to be pinged * @return hops from pinged node or 255 if no answer received within 2000ms */ -uint8_t transportPingNode(uint8_t targetId); +uint8_t transportPingNode(const uint8_t targetId); /** * @brief Send and route message according to destination * @@ -318,44 +357,73 @@ bool transportSendRoute(MyMessage &message); * @param message * @return true if message sent successfully */ -bool transportSendWrite(uint8_t to, MyMessage &message); +bool transportSendWrite(const uint8_t to, MyMessage &message); /** * @brief Check uplink to GW, includes flooding control * @param force to override flood control timer * @return true if uplink ok */ -bool transportCheckUplink(bool force); +bool transportCheckUplink(bool force=false); // PUBLIC functions /** * @brief Initialize transport and SM */ -void transportInitialize(); +void transportInitialize(void); /** * @brief Process FIFO msg and update SM */ -void transportProcess(); +void transportProcess(void); /** * @brief Flag transport ready * @return true if transport is initialize and ready */ -bool isTransportReady(); +bool isTransportReady(void); /** * @brief Flag searching parent ongoing * @return true if transport is searching for parent */ -bool isTransportSearchingParent(); +bool isTransportSearchingParent(void); +/** +* @brief Flag TSM extended failure +* @return true if TSM had too many consecutive failure state entries +*/ +bool isTransportExtendedFailure(void); /** * @brief Clear routing table */ -void transportClearRoutingTable(); +void transportClearRoutingTable(void); /** -* @brief Return heart beat, i.e. ms in current state +* @brief Return heart beat +* @return MS in current state */ -uint32_t transportGetHeartbeat(); +uint32_t transportGetHeartbeat(void); +/** +* @brief Load routing table from EEPROM to RAM. +* Only for GW devices with enough RAM, i.e. ESP8266, RPI Sensebender GW, etc. +* Atmega328 has only limited amount of RAM +*/ +void transportLoadRoutingTable(void); +/** +* @brief Save routing table to EEPROM. +*/ +void transportSaveRoutingTable(void); +/** +* @brief Update routing table +* @param node +* @param route +*/ +void transportSetRoute(const uint8_t node, const uint8_t route); +/** +* @brief Load route to node +* @param node +* @return route to node +*/ +uint8_t transportGetRoute(const uint8_t node); + -// interface functions for radio driver +// interface functions for radio driver ************************************************ /** * @brief Initialize transport HW From 6d47c33ad8b7475d08b25900435037de0a588c96 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Sat, 24 Sep 2016 21:55:01 -0300 Subject: [PATCH 081/167] Add support for RX/TX/ERR leds to RPi --- MySensors.h | 5 +++++ examples_linux/mysGateway.cpp | 11 +++++++++++ 2 files changed, 16 insertions(+) diff --git a/MySensors.h b/MySensors.h index ad59f3f93..39adeeeb1 100644 --- a/MySensors.h +++ b/MySensors.h @@ -82,6 +82,11 @@ #define pgm_read_dword(x) (*x) #define pgm_read_byte_near(x) (*x) #include "core/MyHwLinuxGeneric.cpp" + // Ugly hack + #ifdef LINUX_ARCH_RASPBERRYPI + #undef hwDigitalWrite + #define hwDigitalWrite(__pin, __value) (digitalWrite(__pin, __value)) + #endif #endif // LEDS diff --git a/examples_linux/mysGateway.cpp b/examples_linux/mysGateway.cpp index 1d7c745e6..3c653279f 100644 --- a/examples_linux/mysGateway.cpp +++ b/examples_linux/mysGateway.cpp @@ -50,6 +50,17 @@ //#define MY_MQTT_USER "username" //#define MY_MQTT_PASSWORD "password" +// Flash leds on rx/tx/err +//#define MY_LEDS_BLINKING_FEATURE +// Inverse the blinking feature +//#define MY_WITH_LEDS_BLINKING_INVERSE +// Set blinking period +//#define MY_DEFAULT_LED_BLINK_PERIOD 300 + +// Led pins used if blinking feature is enabled above +#define MY_DEFAULT_ERR_LED_PIN 12 // Error led pin +#define MY_DEFAULT_RX_LED_PIN 16 // Receive led pin +#define MY_DEFAULT_TX_LED_PIN 18 // the PCB, on board #include From 0c11354a2a9a0b67079b6c2723e9134923e1137a Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Thu, 22 Sep 2016 21:35:22 -0300 Subject: [PATCH 082/167] Fix Client Mode for Ethernet gateway If MY_GATEWAY_CLIENT_MODE or MY_CONTROLLER_URL_ADDRESS are present, set MY_GATEWAY_CLIENT_MODE. MY_USE_UDP requires that MY_GATEWAY_CLIENT_MODE is set. Add some ifdefs to filter some variables not needed in client mode. Using global variables to keep the connection to controller open therefore, no need to reconnect every time we need to send/receive something. Add the remaining code to handle incoming messages from controllers. --- MySensors.h | 12 ++-- core/MyGatewayTransportEthernet.cpp | 99 ++++++++++++++++++++++------- 2 files changed, 84 insertions(+), 27 deletions(-) diff --git a/MySensors.h b/MySensors.h index 821af2008..8d5ad27b7 100644 --- a/MySensors.h +++ b/MySensors.h @@ -141,6 +141,13 @@ #endif // GATEWAY - TRANSPORT +#if defined(MY_CONTROLLER_IP_ADDRESS) || defined(MY_CONTROLLER_URL_ADDRESS) + #define MY_GATEWAY_CLIENT_MODE +#endif +#if defined(MY_USE_UDP) && !defined(MY_GATEWAY_CLIENT_MODE) + #error You must specify MY_CONTROLLER_IP_ADDRESS or MY_CONTROLLER_URL_ADDRESS for UDP +#endif + #if defined(MY_GATEWAY_MQTT_CLIENT) #if defined(MY_RADIO_FEATURE) // We assume that a gateway having a radio also should act as repeater @@ -148,7 +155,7 @@ #endif // GATEWAY - COMMON FUNCTIONS // We only support MQTT Client using W5100 and ESP8266 at the moment - #if !(defined(MY_CONTROLLER_URL_ADDRESS) || defined(MY_CONTROLLER_IP_ADDRESS)) + #if !defined(MY_GATEWAY_CLIENT_MODE) #error You must specify MY_CONTROLLER_IP_ADDRESS or MY_CONTROLLER_URL_ADDRESS #endif @@ -177,9 +184,6 @@ // We assume that a gateway having a radio also should act as repeater #define MY_REPEATER_FEATURE #endif - #if defined(MY_CONTROLLER_IP_ADDRESS) - #define MY_GATEWAY_CLIENT_MODE - #endif #if !defined(MY_PORT) #error You must define MY_PORT (controller or gatway port to open) #endif diff --git a/core/MyGatewayTransportEthernet.cpp b/core/MyGatewayTransportEthernet.cpp index 299e33963..c27d501f5 100644 --- a/core/MyGatewayTransportEthernet.cpp +++ b/core/MyGatewayTransportEthernet.cpp @@ -52,17 +52,19 @@ typedef struct IPAddress _gatewayIp(MY_IP_GATEWAY_ADDRESS); IPAddress _subnetIp(MY_IP_SUBNET_ADDRESS); #endif - static bool clientsConnected[MY_GATEWAY_MAX_CLIENTS]; + #if !defined(MY_GATEWAY_CLIENT_MODE) + static bool clientsConnected[MY_GATEWAY_MAX_CLIENTS]; + #endif #endif #if defined(MY_USE_UDP) EthernetUDP _ethernetServer; -#else +#elif !defined(MY_GATEWAY_CLIENT_MODE) EthernetServer _ethernetServer(_ethernetGatewayPort); #endif -#if defined(MY_GATEWAY_ESP8266) +#if defined(MY_GATEWAY_ESP8266) && !defined(MY_GATEWAY_CLIENT_MODE) static EthernetClient clients[MY_GATEWAY_MAX_CLIENTS]; static inputBuffer inputString[MY_GATEWAY_MAX_CLIENTS]; #else @@ -137,14 +139,29 @@ bool gatewayTransportInit() { MY_SERIALDEVICE.println(Ethernet.localIP()); // give the Ethernet interface a second to initialize delay(1000); - #endif + #endif /* MY_GATEWAY_ESP8266 */ #ifdef MY_USE_UDP _ethernetServer.begin(_ethernetGatewayPort); + #elif defined(MY_GATEWAY_CLIENT_MODE) + #if defined(MY_CONTROLLER_URL_ADDRESS) + if (!client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) { + #else + if (!client.connect(_ethernetControllerIP, MY_PORT)) { + #endif + client.stop(); + debug(PSTR("Eth: Failed to connect\n")); + } else { + debug(PSTR("Eth: connect\n")); + _w5100_spi_en(false); + gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete.")); + _w5100_spi_en(true); + presentNode(); + } #else // we have to use pointers due to the constructor of EthernetServer _ethernetServer.begin(); - #endif /* USE_UDP */ + #endif _w5100_spi_en(false); return true; } @@ -157,25 +174,37 @@ bool gatewayTransportSend(MyMessage &message) setIndication(INDICATION_GW_TX); _w5100_spi_en(true); - #if defined(MY_CONTROLLER_IP_ADDRESS) + #if defined(MY_GATEWAY_CLIENT_MODE) #if defined(MY_USE_UDP) - _ethernetServer.beginPacket(_ethernetControllerIP, MY_PORT); + #if defined(MY_CONTROLLER_URL_ADDRESS) + _ethernetServer.beginPacket(MY_CONTROLLER_URL_ADDRESS, MY_PORT); + #else + _ethernetServer.beginPacket(_ethernetControllerIP, MY_PORT); + #endif _ethernetServer.write(_ethernetMsg, strlen(_ethernetMsg)); // returns 1 if the packet was sent successfully ret = _ethernetServer.endPacket(); #else - EthernetClient client; + if (!client.connected()) { + client.stop(); #if defined(MY_CONTROLLER_URL_ADDRESS) - if (client.connected() || client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) { - #else - if (client.connected() || client.connect(_ethernetControllerIP, MY_PORT)) { - #endif - client.write(_ethernetMsg, strlen(_ethernetMsg)); - } - else { - // connecting to the server failed! - ret = false; - } + if (!client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) { + #else + if (!client.connect(_ethernetControllerIP, MY_PORT)) { + #endif + // connecting to the server failed! + debug(PSTR("Eth: Failed to connect\n")); + ret = false; + } else { + debug(PSTR("Eth: connect\n")); + _w5100_spi_en(false); + gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete.")); + _w5100_spi_en(true); + presentNode(); + } + } else { + ret = client.write(_ethernetMsg, strlen(_ethernetMsg)) > 0; + } #endif #else // Send message to connected clients @@ -188,16 +217,16 @@ bool gatewayTransportSend(MyMessage &message) } } #else - _ethernetServer.write(_ethernetMsg); + ret = _ethernetServer.write(_ethernetMsg) > 0; #endif - #endif + #endif /* MY_GATEWAY_CLIENT_MODE */ _w5100_spi_en(false); return ret; } -#if defined(MY_GATEWAY_ESP8266) +#if defined(MY_GATEWAY_ESP8266) && !defined(MY_GATEWAY_CLIENT_MODE) bool _readFromClient(uint8_t i) { while (clients[i].connected() && clients[i].available()) { char inChar = clients[i].read(); @@ -290,6 +319,30 @@ bool gatewayTransportAvailable() } return ok; } + #elif defined(MY_GATEWAY_CLIENT_MODE) + if (!client.connected()) { + client.stop(); + #if defined(MY_CONTROLLER_URL_ADDRESS) + if (!client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) { + #else + if (!client.connect(_ethernetControllerIP, MY_PORT)) { + #endif + debug(PSTR("Eth: Failed to connect\n")); + _w5100_spi_en(false); + return false; + } else { + debug(PSTR("Eth: connect\n")); + _w5100_spi_en(false); + gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete.")); + _w5100_spi_en(true); + presentNode(); + } + } + if (_readFromClient()) { + setIndication(INDICATION_GW_RX); + _w5100_spi_en(false); + return true; + } #else #if defined(MY_GATEWAY_ESP8266) // ESP8266: Go over list of clients and stop any that are no longer connected. @@ -356,7 +409,7 @@ bool gatewayTransportAvailable() } } } - #endif + #endif /* MY_GATEWAY_ESP8266 */ #endif _w5100_spi_en(false); return false; @@ -393,4 +446,4 @@ void gatewayTransportRenewIP() _w5100_spi_en(false); next_time = now + MY_IP_RENEWAL_INTERVAL; } -#endif /* IP_ADDRESS_DHCP */ +#endif From d8c45e9f07c7900632d0c788617a155faca545c9 Mon Sep 17 00:00:00 2001 From: Tom Date: Thu, 29 Sep 2016 20:02:32 +0100 Subject: [PATCH 083/167] V_Light Deprecated Change V_Light for V_Status as V_Light is deprecated as per is ttps://www.mysensors.org/download/serial_api_20 Change S_Light for S_Binary generic. --- examples/RelayActuator/RelayActuator.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/RelayActuator/RelayActuator.ino b/examples/RelayActuator/RelayActuator.ino index 7f82c711c..908cb9b17 100644 --- a/examples/RelayActuator/RelayActuator.ino +++ b/examples/RelayActuator/RelayActuator.ino @@ -65,7 +65,7 @@ void presentation() for (int sensor=1, pin=RELAY_1; sensor<=NUMBER_OF_RELAYS;sensor++, pin++) { // Register all sensors to gw (they will be created as child devices) - present(sensor, S_LIGHT); + present(sensor, S_BINARY); } } @@ -77,7 +77,7 @@ void loop() void receive(const MyMessage &message) { // We only expect one type of message from controller. But we better check anyway. - if (message.type==V_LIGHT) { + if (message.type==V_STATUS) { // Change relay state digitalWrite(message.sensor-1+RELAY_1, message.getBool()?RELAY_ON:RELAY_OFF); // Store state in eeprom From 0a9351988faf56efbf90d0e3ab5c158718add591 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Fri, 30 Sep 2016 17:04:40 -0300 Subject: [PATCH 084/167] Update configure script Add options to set status leds. Support controller ip address separated by dots. Fix controller url address option set. --- configure | 29 ++++++++++++++++++++++------- examples_linux/mysGateway.cpp | 6 +++--- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/configure b/configure index b2b2dc83b..570eddeae 100755 --- a/configure +++ b/configure @@ -14,8 +14,8 @@ Help: Building options: --soc=[BCM2835|BCM2836|AM33XX|A10|A13|A20|H3] SoC type to be used. [configure autodetected] - --cpu-flags= CPU defining/optimizing flags to be used. [configure autodetected] - --extra-cxxflags= Extra C flags passed to C/C++ compilation. [] + --cpu-flags= CPU defining/optimizing flags to be used. [configure autodetected] + --extra-cxxflags= Extra C flags passed to C/C++ compilation. [] --extra-ldflags= Extra C flags passed to linking. [] --cxx_compiler= C++ compiler [arm-linux-gnueabihf-g++][g++] --no-clean Don't clean previous build artifacts. @@ -25,8 +25,7 @@ Installation options: --gateway-dir= Gateway files installation directory. [PREFIX/bin] MySensors options: - --my-debug=[enable|disable] - Enables or disables MySensors core debugging. [enable] + --my-debug=[enable|disable] Enables or disables MySensors core debugging. [enable] --my-config-file= Config file path. [/etc/mysensors.dat] --my-gateway=[none|ethernet|serial|mqtt] Gateway type, set to none to disable gateway feature. [ethernet] @@ -34,7 +33,6 @@ MySensors options: Controller or MQTT broker url. --my-controller-ip-address= Controller or MQTT broker ip. - Use commas instead of points. Example: 127,0,0,1 --my-port= The port to keep open on gateway mode. If gateway is set to mqtt, it sets the broker port. --my-serial-port= Serial port. [/dev/ttyACM0] @@ -56,6 +54,10 @@ MySensors options: --my-rf24-irq-pin= Pin number connected to nRF24L01 IRQ pin. --my-rx-message-buffer-size= Buffer size for incoming messages when using rf24 interrupts. [20] + --my-leds-err-pin= Error LED pin. + --my-leds-rx-pin= Receive LED pin. + --my-leds-tx-pin= Transmit LED pin. + --my-leds-blinking-inverse Inverse the blinking feature. EOF } @@ -263,10 +265,11 @@ for opt do CXXFLAGS="-DMY_RF24_PA_LEVEL=${optarg} $CXXFLAGS" ;; --my-controller-url-address=*) - CXXFLAGS="-DMY_CONTROLLER_URL_ADDRESS=${optarg} $CXXFLAGS" + CXXFLAGS="-DMY_CONTROLLER_URL_ADDRESS=\\\"${optarg}\\\" $CXXFLAGS" ;; --my-controller-ip-address=*) - CXXFLAGS="-DMY_CONTROLLER_IP_ADDRESS=${optarg} $CXXFLAGS" + controller_ip=`echo ${optarg//./,}` + CXXFLAGS="-DMY_CONTROLLER_IP_ADDRESS=${controller_ip} $CXXFLAGS" ;; --my-port=*) CXXFLAGS="-DMY_PORT=${optarg} $CXXFLAGS" @@ -286,6 +289,18 @@ for opt do --my-rx-message-buffer-size=*) CXXFLAGS="-DMY_RX_MESSAGE_BUFFER_SIZE=${optarg} $CXXFLAGS" ;; + --my-leds-err-pin=*) + CXXFLAGS="-DMY_DEFAULT_ERR_LED_PIN=${optarg} $CXXFLAGS" + ;; + --my-leds-rx-pin=*) + CXXFLAGS="-DMY_DEFAULT_RX_LED_PIN=${optarg} $CXXFLAGS" + ;; + --my-leds-tx-pin=*) + CXXFLAGS="-DMY_DEFAULT_TX_LED_PIN=${optarg} $CXXFLAGS" + ;; + --my-leds-blinking-inverse*) + CXXFLAGS="-DMY_WITH_LEDS_BLINKING_INVERSE $CXXFLAGS" + ;; *) echo "[WARNING] Unknown option detected:$opt, ignored" ;; diff --git a/examples_linux/mysGateway.cpp b/examples_linux/mysGateway.cpp index de508bcb9..c0c69c2c2 100644 --- a/examples_linux/mysGateway.cpp +++ b/examples_linux/mysGateway.cpp @@ -51,9 +51,9 @@ //#define MY_MQTT_PASSWORD "password" // Flash leds on rx/tx/err -//#define MY_DEFAULT_ERR_LED_PIN 12 // Error led pin -//#define MY_DEFAULT_RX_LED_PIN 16 // Receive led pin -//#define MY_DEFAULT_TX_LED_PIN 18 // the PCB, on board +//#define MY_DEFAULT_ERR_LED_PIN 12 // Error LED pin +//#define MY_DEFAULT_RX_LED_PIN 16 // Receive LED pin +//#define MY_DEFAULT_TX_LED_PIN 18 // Transmit LED pin // Inverse the blinking feature //#define MY_WITH_LEDS_BLINKING_INVERSE From 025e197ba852ca36b1d694fffcfe38d2a2424ea1 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Sat, 1 Oct 2016 13:59:56 +0200 Subject: [PATCH 085/167] Fix include for case sensitive systems Fix proposed by @RB3rg in #559 --- examples/GatewayESP8266/GatewayESP8266.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/GatewayESP8266/GatewayESP8266.ino b/examples/GatewayESP8266/GatewayESP8266.ino index f4f6fd83f..4e7f38dd2 100644 --- a/examples/GatewayESP8266/GatewayESP8266.ino +++ b/examples/GatewayESP8266/GatewayESP8266.ino @@ -126,11 +126,11 @@ #define MY_DEFAULT_TX_LED_PIN 16 // the PCB, on board LED #if defined(MY_USE_UDP) - #include -#else - #include + #include #endif +#include + #include void setup() { From 3c8ea78f453c89627ba3396ede7389a9a3e81b11 Mon Sep 17 00:00:00 2001 From: tekka007 Date: Sat, 1 Oct 2016 15:47:23 +0200 Subject: [PATCH 086/167] Build(): Remove obsolete parameter --- core/MyOTAFirmwareUpdate.cpp | 4 ++-- core/MySensorsCore.cpp | 34 +++++++++++++++++----------------- core/MySensorsCore.h | 6 +++--- core/MySigning.cpp | 8 +++----- core/MyTransport.cpp | 16 ++++++++-------- 5 files changed, 33 insertions(+), 35 deletions(-) diff --git a/core/MyOTAFirmwareUpdate.cpp b/core/MyOTAFirmwareUpdate.cpp index e30cf97a0..34e69e1c4 100644 --- a/core/MyOTAFirmwareUpdate.cpp +++ b/core/MyOTAFirmwareUpdate.cpp @@ -54,7 +54,7 @@ void firmwareOTAUpdateRequest() { firmwareRequest.version = _fc.version; firmwareRequest.block = (_fwBlock - 1); OTA_DEBUG(PSTR("OTA:FRQ:FW REQ,T=%04X,V=%04X,B=%04X\n"),_fc.type,_fc.version,_fwBlock - 1); // request FW update block - _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_REQUEST, false).set(&firmwareRequest,sizeof(RequestFWBlock))); + _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_REQUEST, false).set(&firmwareRequest,sizeof(RequestFWBlock))); } } @@ -137,7 +137,7 @@ void presentBootloaderInformation(){ // add bootloader information reqFWConfig->BLVersion = MY_OTA_BOOTLOADER_VERSION; _fwUpdateOngoing = false; - _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_CONFIG_REQUEST, false)); + _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_CONFIG_REQUEST, false)); } // do a crc16 on the whole received firmware bool transportIsValidFirmware() { diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index cf45f4908..d52e2c4e9 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -180,7 +180,7 @@ void _registerNode() { uint8_t counter = MY_REGISTRATION_RETRIES; // only proceed if register response received or retries exceeded do { - _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REGISTRATION_REQUEST, false).set(MY_CORE_VERSION)); + _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REGISTRATION_REQUEST, false).set(MY_CORE_VERSION)); } while (!wait(2000, C_INTERNAL, I_REGISTRATION_RESPONSE) && counter--); #else @@ -217,7 +217,7 @@ void presentNode() { // Send a configuration exchange request to controller // Node sends parent node. Controller answers with latest node configuration - _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CONFIG, false).set(_nc.parentNodeId)); + _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CONFIG, false).set(_nc.parentNodeId)); // Wait configuration reply. wait(2000, C_INTERNAL, I_CONFIG); @@ -280,31 +280,31 @@ bool send(MyMessage &message, bool enableAck) { } void sendBatteryLevel(uint8_t value, bool enableAck) { - _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL, enableAck).set(value)); + _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL, enableAck).set(value)); } void sendHeartbeat(void) { #if defined(MY_RADIO_FEATURE) uint32_t heartbeat = transportGetHeartbeat(); - _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_HEARTBEAT_RESPONSE, false).set(heartbeat)); + _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_HEARTBEAT_RESPONSE, false).set(heartbeat)); #endif } void present(uint8_t childSensorId, uint8_t sensorType, const char *description, bool enableAck) { - _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, enableAck).set(childSensorId==NODE_SENSOR_ID?MYSENSORS_LIBRARY_VERSION:description)); + _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, enableAck).set(childSensorId==NODE_SENSOR_ID?MYSENSORS_LIBRARY_VERSION:description)); } void sendSketchInfo(const char *name, const char *version, bool enableAck) { - if (name) _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME, enableAck).set(name)); - if (version) _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION, enableAck).set(version)); + if (name) _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME, enableAck).set(name)); + if (version) _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION, enableAck).set(version)); } void request(uint8_t childSensorId, uint8_t variableType, uint8_t destination) { - _sendRoute(build(_msgTmp, _nc.nodeId, destination, childSensorId, C_REQ, variableType, false).set("")); + _sendRoute(build(_msgTmp, destination, childSensorId, C_REQ, variableType, false).set("")); } void requestTime() { - _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_TIME, false).set("")); + _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_TIME, false).set("")); } // Message delivered through _msg @@ -349,7 +349,7 @@ bool _processInternalMessages() { // Clears child relay data for this node setIndication(INDICATION_CLEAR_ROUTING); transportClearRoutingTable(); - _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN, false).set("ok")); + _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN, false).set("ok")); } #endif } @@ -363,23 +363,23 @@ bool _processInternalMessages() { if (route != BROADCAST_ADDRESS) { debug(PSTR("MCO:PIM:ROUTE N=%d,R=%d\n"), cnt, route); uint8_t outBuf[2] = { (uint8_t)cnt,route }; - _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set(outBuf, 2)); + _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set(outBuf, 2)); wait(200); } } #endif } else if (debug_msg == 'V') { // CPU voltage - _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set(hwCPUVoltage())); + _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set(hwCPUVoltage())); } else if (debug_msg == 'F') { // CPU frequency in 1/10Mhz - _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set(hwCPUFrequency())); + _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set(hwCPUFrequency())); } else if (debug_msg == 'M') { // free memory - _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set(hwFreeMem())); + _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set(hwFreeMem())); } else if (debug_msg == 'E') { // clear MySensors eeprom area and reboot - _sendRoute(build(_msgTmp, _nc.nodeId, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set("ok")); + _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set("ok")); for (int i = EEPROM_START; i MY_TRANSPORT_DISCOVERY_INTERVAL_MS) { _lastNetworkDiscovery = hwMillis(); TRANSPORT_DEBUG(PSTR("TSM:READY:NWD REQ\n")); // send transport network discovery - (void)transportRouteMessage(build(_msgTmp, GATEWAY_ADDRESS, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DISCOVER_REQUEST, false).set("")); + (void)transportRouteMessage(build(_msgTmp, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DISCOVER_REQUEST, false).set("")); } #else if (_transportSM.failedUplinkTransmissions > MY_TRANSPORT_MAX_TX_FAILURES) { @@ -507,7 +507,7 @@ uint8_t transportPingNode(const uint8_t targetId) { else { _transportSM.pingActive = true; _transportSM.pingResponse = INVALID_HOPS; - (void)transportRouteMessage(build(_msgTmp, _nc.nodeId, targetId, NODE_SENSOR_ID, C_INTERNAL, I_PING, false).set((uint8_t)1)); + (void)transportRouteMessage(build(_msgTmp, targetId, NODE_SENSOR_ID, C_INTERNAL, I_PING, false).set((uint8_t)1)); // Wait for ping reply or timeout (void)transportWait(2000, C_INTERNAL, I_PONG); } @@ -647,7 +647,7 @@ void transportProcessMessage(void) { // delay for fast GW and slow nodes delay(5); #endif - (void)transportRouteMessage(build(_msgTmp, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_PONG, false).set((uint8_t)1)); + (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, I_PONG, false).set((uint8_t)1)); return; // no further processing required } if (type == I_PONG) { @@ -700,7 +700,7 @@ void transportProcessMessage(void) { TRANSPORT_DEBUG(PSTR("TSF:MSG:GWL OK\n")); // GW uplink ok // random delay minimizes collisions delay(hwMillis() & 0x3ff); - (void)transportRouteMessage(build(_msgTmp, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(_nc.distance)); + (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(_nc.distance)); } else { TRANSPORT_DEBUG(PSTR("!TSF:MSG:GWL FAIL\n")); // GW uplink fail, do not respond to parent request @@ -718,7 +718,7 @@ void transportProcessMessage(void) { if (last == _nc.parentNodeId) { // random wait to minimize collisions delay(hwMillis() & 0x3ff); - (void)transportRouteMessage(build(_msgTmp, _nc.nodeId, sender, NODE_SENSOR_ID, C_INTERNAL, I_DISCOVER_RESPONSE, false).set(_nc.parentNodeId)); + (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, I_DISCOVER_RESPONSE, false).set(_nc.parentNodeId)); // no return here (for fwd if repeater) } } From f6f4e6dde46744648c7f9a59796fca7f8257092e Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Sat, 1 Oct 2016 12:03:14 -0300 Subject: [PATCH 087/167] Fix compilation errors on RPi (#594) --- core/MyTransport.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/MyTransport.cpp b/core/MyTransport.cpp index 72005586b..74a4a2a20 100644 --- a/core/MyTransport.cpp +++ b/core/MyTransport.cpp @@ -532,7 +532,7 @@ void transportProcessMessage(void) { setIndication(INDICATION_RX); const uint8_t payloadLength = transportReceive((uint8_t *)&_msg); // get message length and limit size - const uint8_t msgLength = min(mGetLength(_msg), MAX_PAYLOAD); + const uint8_t msgLength = min(mGetLength(_msg), (uint8_t)MAX_PAYLOAD); // calculate expected length const uint8_t expectedMessageLength = HEADER_SIZE + (mGetSigned(_msg) ? MAX_PAYLOAD : msgLength); const uint8_t command = mGetCommand(_msg); @@ -823,7 +823,7 @@ bool transportSendWrite(const uint8_t to, MyMessage &message) { // send setIndication(INDICATION_TX); - bool result = transportSend(to, &message, min(MAX_MESSAGE_LENGTH, totalMsgLength)); + bool result = transportSend(to, &message, min((uint8_t)MAX_MESSAGE_LENGTH, totalMsgLength)); // broadcasting (workaround counterfeits) result |= (to == BROADCAST_ADDRESS); From dc6f6e3691bcafe0dc262019d701a1fd32b578ce Mon Sep 17 00:00:00 2001 From: tekka007 Date: Sat, 1 Oct 2016 19:05:09 +0200 Subject: [PATCH 088/167] Reset wdt during init --- core/MySensorsCore.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index cf45f4908..9e5083c5f 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -72,6 +72,8 @@ void _infiniteLoop() { } void _begin() { + hwWatchdogReset(); + if (preHwInit) preHwInit(); @@ -169,6 +171,8 @@ void _begin() { } debug(PSTR("MCO:BGN:INIT OK,ID=%d,PAR=%d,DIS=%d,REG=%d\n"), _nc.nodeId, _nc.parentNodeId, _nc.distance, _nodeRegistered); + + hwWatchdogReset(); } From fc09763c492891aca0c5d101560749db3c2a24fa Mon Sep 17 00:00:00 2001 From: tekka007 Date: Sat, 1 Oct 2016 19:36:52 +0200 Subject: [PATCH 089/167] Fix payload length return --- core/MyTransportRFM69.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/MyTransportRFM69.cpp b/core/MyTransportRFM69.cpp index b5aec3325..b3b22de78 100644 --- a/core/MyTransportRFM69.cpp +++ b/core/MyTransportRFM69.cpp @@ -64,11 +64,13 @@ bool transportSanityCheck() { uint8_t transportReceive(void* data) { memcpy(data,(const void *)_radio.DATA, _radio.DATALEN); + // save payload length + const uint8_t dataLen = _radio.DATALEN; // Send ack back if this message wasn't a broadcast if (_radio.TARGETID != RF69_BROADCAST_ADDR) _radio.ACKRequested(); _radio.sendACK(); - return _radio.DATALEN; + return dataLen; } void transportPowerDown() { From 32596676e5f915aeb6b48d5673a8dcd91b6fcf71 Mon Sep 17 00:00:00 2001 From: Embedded Innovation Date: Mon, 3 Oct 2016 20:44:04 +0200 Subject: [PATCH 090/167] Fix detach pin interrupt in hwSleep (#599) Fix issue #598 Pin interrupts used as wakeup source for hwSleep now get detached correctly, also when the interrupts did not occur. --- core/MyHwATMega328.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/core/MyHwATMega328.cpp b/core/MyHwATMega328.cpp index 567f2cfff..2a130c771 100644 --- a/core/MyHwATMega328.cpp +++ b/core/MyHwATMega328.cpp @@ -30,11 +30,19 @@ volatile uint8_t _wakeUp2Interrupt = INVALID_INTERRUPT_NUM; // Interrupt num void wakeUp1() //place to send the interrupts { detachInterrupt(_wakeUp1Interrupt); + if (_wakeUp2Interrupt != INVALID_INTERRUPT_NUM) + { + detachInterrupt(_wakeUp2Interrupt); + } _wokeUpByInterrupt = _wakeUp1Interrupt; } void wakeUp2() //place to send the second interrupts { detachInterrupt(_wakeUp2Interrupt); + if (_wakeUp1Interrupt != INVALID_INTERRUPT_NUM) + { + detachInterrupt(_wakeUp1Interrupt); + } _wokeUpByInterrupt = _wakeUp2Interrupt; } @@ -129,7 +137,11 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo // sleep until ext interrupt triggered hwPowerDown(SLEEP_FOREVER); } - + + // Assure any interrupts attached, will get detached when they did not occur. + if (interrupt1 != INVALID_INTERRUPT_NUM) detachInterrupt(interrupt1); + if (interrupt2 != INVALID_INTERRUPT_NUM) detachInterrupt(interrupt2); + // Return what woke the mcu. int8_t ret = MY_WAKE_UP_BY_TIMER; // default: no interrupt triggered, timer wake up if (interruptWakeUp()) ret = static_cast(_wokeUpByInterrupt); From a66a469174353cacce8cc47c47f2772df66248ba Mon Sep 17 00:00:00 2001 From: petewill Date: Sat, 8 Oct 2016 07:15:40 -0600 Subject: [PATCH 091/167] Updated LED documentation Changed the comments for the LEDs to reflect the 2.0 code changes. --- examples/GatewayW5100/GatewayW5100.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/GatewayW5100/GatewayW5100.ino b/examples/GatewayW5100/GatewayW5100.ino index 0339c5203..99d0ac2b4 100644 --- a/examples/GatewayW5100/GatewayW5100.ino +++ b/examples/GatewayW5100/GatewayW5100.ino @@ -32,7 +32,7 @@ * The GW code is designed for Arduino 328p / 16MHz. ATmega168 does not have enough memory to run this program. * * LED purposes: - * - To use the feature, uncomment WITH_LEDS_BLINKING in MyConfig.h + * - To use the feature, uncomment MY_DEFAULT_xxx_LED_PIN in the sketch below * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly * - ERR (red) - fast blink on error during transmission error or recieve crc error @@ -106,7 +106,7 @@ // Uncomment to override default HW configurations //#define MY_DEFAULT_ERR_LED_PIN 7 // Error led pin //#define MY_DEFAULT_RX_LED_PIN 8 // Receive led pin -//#define MY_DEFAULT_TX_LED_PIN 9 // the PCB, on board LED +//#define MY_DEFAULT_TX_LED_PIN 9 // Transmit led pin #if defined(MY_USE_UDP) From fe3199ef6b774296c98b56c3cf5392ad72005fba Mon Sep 17 00:00:00 2001 From: Olivier Date: Sun, 9 Oct 2016 12:18:15 +0200 Subject: [PATCH 092/167] Fix routing table dump (#604) --- core/MyTransport.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/MyTransport.cpp b/core/MyTransport.cpp index 3762efba8..8187ed38b 100644 --- a/core/MyTransport.cpp +++ b/core/MyTransport.cpp @@ -851,7 +851,7 @@ void transportLoadRoutingTable(void) { void transportSaveRoutingTable(void) { #if defined(MY_RAM_ROUTING_TABLE_ENABLED) - hwWriteConfigBlock((void*)EEPROM_ROUTES_ADDRESS, (void*)&_transportRoutingTable.route, SIZE_ROUTES); + hwWriteConfigBlock((void*)&_transportRoutingTable.route, (void*)EEPROM_ROUTES_ADDRESS, SIZE_ROUTES); TRANSPORT_DEBUG(PSTR("TSF:SRT:OK\n")); // save routing table #endif } From 54489577a9c3ca70943bec0c6da6f21445722dd4 Mon Sep 17 00:00:00 2001 From: Olivier Date: Sun, 9 Oct 2016 13:22:20 +0200 Subject: [PATCH 093/167] Fix RFM69 ACK (#597) --- core/MyTransportRFM69.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/MyTransportRFM69.cpp b/core/MyTransportRFM69.cpp index b3b22de78..6ed728364 100644 --- a/core/MyTransportRFM69.cpp +++ b/core/MyTransportRFM69.cpp @@ -67,9 +67,9 @@ uint8_t transportReceive(void* data) { // save payload length const uint8_t dataLen = _radio.DATALEN; // Send ack back if this message wasn't a broadcast - if (_radio.TARGETID != RF69_BROADCAST_ADDR) - _radio.ACKRequested(); - _radio.sendACK(); + if(_radio.ACKRequested()) { + _radio.sendACK(); + } return dataLen; } From d05d0dad2a68ed1fa4c8b3641bd03e1968dfe2cf Mon Sep 17 00:00:00 2001 From: Olivier Date: Sun, 9 Oct 2016 15:31:44 +0200 Subject: [PATCH 094/167] Fix HAL inconsistency --- core/MyHwATMega328.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/MyHwATMega328.h b/core/MyHwATMega328.h index 29352d438..45a7f5988 100644 --- a/core/MyHwATMega328.h +++ b/core/MyHwATMega328.h @@ -80,7 +80,7 @@ do { \ // #define hwReadConfigBlock(__buf, __pos, __length) (eeprom_read_block((__buf), (void*)(__pos), (__length))) -#define hwWriteConfigBlock(__pos, __buf, __length) (eeprom_write_block((void*)(__pos), (void*)__buf, (__length))) +#define hwWriteConfigBlock(__buf, __pos, __length) (eeprom_write_block((void*)(__buf), (void*)(__pos), (__length))) From 351845205c8f64c73a49e786a2de9d8c0ea46077 Mon Sep 17 00:00:00 2001 From: Olivier Date: Sun, 9 Oct 2016 11:27:04 +0200 Subject: [PATCH 095/167] Code harmonization --- MySensors.h | 10 +- core/MyGatewayTransport.cpp | 2 +- core/MySensorsCore.cpp | 213 +++++++++++++++++------------------- core/MySensorsCore.h | 97 ++++++++-------- core/MySigning.cpp | 6 +- core/MyTransport.cpp | 24 ++-- core/MyTransport.h | 2 +- 7 files changed, 176 insertions(+), 178 deletions(-) diff --git a/MySensors.h b/MySensors.h index 01ab39a74..91affc1c6 100644 --- a/MySensors.h +++ b/MySensors.h @@ -54,7 +54,7 @@ // Enable radio "feature" if one of the radio types was enabled #if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) || defined(MY_RS485) - #define MY_RADIO_FEATURE + #define MY_SENSOR_NETWORK #endif // HARDWARE @@ -167,7 +167,7 @@ #endif #if defined(MY_GATEWAY_MQTT_CLIENT) - #if defined(MY_RADIO_FEATURE) + #if defined(MY_SENSOR_NETWORK) // We assume that a gateway having a radio also should act as repeater #define MY_REPEATER_FEATURE #endif @@ -205,7 +205,7 @@ #include "core/MyProtocolMySensors.cpp" // GATEWAY - CONFIGURATION - #if defined(MY_RADIO_FEATURE) + #if defined(MY_SENSOR_NETWORK) // We assume that a gateway having a radio also should act as repeater #define MY_REPEATER_FEATURE #endif @@ -308,7 +308,7 @@ #endif // Make sure to disable child features when parent feature is disabled -#if !defined(MY_RADIO_FEATURE) +#if !defined(MY_SENSOR_NETWORK) #undef MY_OTA_FIRMWARE_FEATURE #undef MY_REPEATER_FEATURE #undef MY_SIGNING_NODE_WHITELISTING @@ -321,7 +321,7 @@ #endif #if !defined(MY_CORE_ONLY) - #if !defined(MY_GATEWAY_FEATURE) && !defined(MY_RADIO_FEATURE) + #if !defined(MY_GATEWAY_FEATURE) && !defined(MY_SENSOR_NETWORK) #error No forward link or gateway feature activated. This means nowhere to send messages! Pretty pointless. #endif #endif diff --git a/core/MyGatewayTransport.cpp b/core/MyGatewayTransport.cpp index f4e98f413..fcf2b5391 100644 --- a/core/MyGatewayTransport.cpp +++ b/core/MyGatewayTransport.cpp @@ -61,7 +61,7 @@ inline void gatewayTransportProcess() { } } } else { - #if defined(MY_RADIO_FEATURE) + #if defined(MY_SENSOR_NETWORK) transportSendRoute(_msg); #endif } diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index f2b15e154..af58a88b8 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -19,10 +19,10 @@ #include "MySensorsCore.h" -ControllerConfig _cc; // Configuration coming from controller -NodeConfig _nc; // Essential settings for node to work -MyMessage _msg; // Buffer for incoming messages. -MyMessage _msgTmp; // Buffer for temporary messages (acks and nonces among others). +ControllerConfig _cc; // Configuration coming from controller +NodeConfig _nc; // Essential settings for node to work +MyMessage _msg; // Buffer for incoming messages +MyMessage _msgTmp; // Buffer for temporary messages (acks and nonces among others) bool _nodeRegistered = false; @@ -32,7 +32,7 @@ bool _nodeRegistered = false; void (*_timeCallback)(unsigned long); // Callback for requested time messages -void _process() { +void _process(void) { hwWatchdogReset(); #if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) @@ -47,7 +47,7 @@ void _process() { gatewayTransportProcess(); #endif - #if defined(MY_RADIO_FEATURE) + #if defined(MY_SENSOR_NETWORK) transportProcess(); #endif @@ -57,11 +57,9 @@ void _process() { #endif } -void _infiniteLoop() { +void _infiniteLoop(void) { while(1) { - #if defined(ARDUINO_ARCH_ESP8266) - yield(); - #endif + yield(); #if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) ledsProcess(); #endif @@ -71,7 +69,7 @@ void _infiniteLoop() { } } -void _begin() { +void _begin(void) { hwWatchdogReset(); if (preHwInit) @@ -102,16 +100,14 @@ void _begin() { readFirmwareSettings(); #endif - #if defined(MY_RADIO_FEATURE) + #if defined(MY_SENSOR_NETWORK) // Save static parent id in eeprom (used by bootloader) hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, MY_PARENT_NODE_ID); transportInitialise(); while (!isTransportReady()) { hwWatchdogReset(); transportProcess(); - #if defined(ARDUINO_ARCH_ESP8266) - yield(); - #endif + yield(); } #endif @@ -176,7 +172,7 @@ void _begin() { } -void _registerNode() { +void _registerNode(void) { #if defined (MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE) debug(PSTR("MCO:REG:REQ\n")); // registration request setIndication(INDICATION_REQ_REGISTRATION); @@ -184,7 +180,7 @@ void _registerNode() { uint8_t counter = MY_REGISTRATION_RETRIES; // only proceed if register response received or retries exceeded do { - _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REGISTRATION_REQUEST, false).set(MY_CORE_VERSION)); + (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REGISTRATION_REQUEST).set(MY_CORE_VERSION)); } while (!wait(2000, C_INTERNAL, I_REGISTRATION_RESPONSE) && counter--); #else @@ -193,20 +189,20 @@ void _registerNode() { #endif } -void presentNode() { +void presentNode(void) { setIndication(INDICATION_PRESENT); // Present node and request config #if defined(MY_GATEWAY_FEATURE) // Send presentation for this gateway device #if defined(MY_REPEATER_FEATURE) - present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE); + (void)present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE); #else - present(NODE_SENSOR_ID, S_ARDUINO_NODE); + (void)present(NODE_SENSOR_ID, S_ARDUINO_NODE); #endif #else #if defined(MY_OTA_FIRMWARE_FEATURE) - presentBootloaderInformation(); + presentBootloaderInformation(); #endif // Send signing preferences for this node to the GW @@ -214,17 +210,17 @@ void presentNode() { // Send presentation for this radio node #if defined(MY_REPEATER_FEATURE) - present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE); + (void)present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE); #else - present(NODE_SENSOR_ID, S_ARDUINO_NODE); + (void)present(NODE_SENSOR_ID, S_ARDUINO_NODE); #endif // Send a configuration exchange request to controller // Node sends parent node. Controller answers with latest node configuration - _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CONFIG, false).set(_nc.parentNodeId)); + (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CONFIG).set(_nc.parentNodeId)); // Wait configuration reply. - wait(2000, C_INTERNAL, I_CONFIG); + (void)wait(2000, C_INTERNAL, I_CONFIG); #endif @@ -234,15 +230,15 @@ void presentNode() { } -uint8_t getNodeId() { +uint8_t getNodeId(void) { return _nc.nodeId; } -uint8_t getParentNodeId() { +uint8_t getParentNodeId(void) { return _nc.parentNodeId; } -ControllerConfig getConfig() { +ControllerConfig getConfig(void) { return _cc; } @@ -258,14 +254,14 @@ bool _sendRoute(MyMessage &message) { return gatewayTransportSend(message); } #endif - #if defined(MY_RADIO_FEATURE) + #if defined(MY_SENSOR_NETWORK) return transportSendRoute(message); #else return false; #endif } -bool send(MyMessage &message, bool enableAck) { +bool send(MyMessage &message, const bool enableAck) { message.sender = _nc.nodeId; mSetCommand(message, C_SET); mSetRequestAck(message, enableAck); @@ -283,37 +279,42 @@ bool send(MyMessage &message, bool enableAck) { #endif } -void sendBatteryLevel(uint8_t value, bool enableAck) { - _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL, enableAck).set(value)); +bool sendBatteryLevel(const uint8_t value, const bool ack) { + return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL, ack).set(value)); } -void sendHeartbeat(void) { - #if defined(MY_RADIO_FEATURE) - uint32_t heartbeat = transportGetHeartbeat(); - _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_HEARTBEAT_RESPONSE, false).set(heartbeat)); +bool sendHeartbeat(const bool ack) { + #if defined(MY_SENSOR_NETWORK) + const uint32_t heartbeat = transportGetHeartbeat(); + return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_HEARTBEAT_RESPONSE, ack).set(heartbeat)); + #else + (void)ack; + return false; #endif } -void present(uint8_t childSensorId, uint8_t sensorType, const char *description, bool enableAck) { - _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, enableAck).set(childSensorId==NODE_SENSOR_ID?MYSENSORS_LIBRARY_VERSION:description)); +bool present(const uint8_t childSensorId, const uint8_t sensorType, const char *description, const bool ack) { + return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, ack).set(childSensorId==NODE_SENSOR_ID?MYSENSORS_LIBRARY_VERSION:description)); } -void sendSketchInfo(const char *name, const char *version, bool enableAck) { - if (name) _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME, enableAck).set(name)); - if (version) _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION, enableAck).set(version)); +bool sendSketchInfo(const char *name, const char *version, const bool ack) { + bool result = true; + if (name) result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME, ack).set(name)); + if (version) result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION, ack).set(version)); + return result; } -void request(uint8_t childSensorId, uint8_t variableType, uint8_t destination) { - _sendRoute(build(_msgTmp, destination, childSensorId, C_REQ, variableType, false).set("")); +bool request(const uint8_t childSensorId, const uint8_t variableType, const uint8_t destination) { + return _sendRoute(build(_msgTmp, destination, childSensorId, C_REQ, variableType).set("")); } -void requestTime() { - _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_TIME, false).set("")); +bool requestTime(const bool ack) { + return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_TIME, ack).set("")); } // Message delivered through _msg -bool _processInternalMessages() { - uint8_t type = _msg.type; +bool _processInternalMessages(void) { + const uint8_t type = _msg.type; if (_msg.sender == GATEWAY_ADDRESS) { if (type == I_REBOOT) { @@ -340,7 +341,7 @@ bool _processInternalMessages() { presentNode(); } else if (type == I_HEARTBEAT_REQUEST) { - sendHeartbeat(); + (void)sendHeartbeat(); } else if (type == I_TIME) { // Deliver time to callback @@ -353,7 +354,7 @@ bool _processInternalMessages() { // Clears child relay data for this node setIndication(INDICATION_CLEAR_ROUTING); transportClearRoutingTable(); - _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN, false).set("ok")); + (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN).set("OK")); } #endif } @@ -367,23 +368,23 @@ bool _processInternalMessages() { if (route != BROADCAST_ADDRESS) { debug(PSTR("MCO:PIM:ROUTE N=%d,R=%d\n"), cnt, route); uint8_t outBuf[2] = { (uint8_t)cnt,route }; - _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set(outBuf, 2)); + (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG).set(outBuf, 2)); wait(200); } } #endif } else if (debug_msg == 'V') { // CPU voltage - _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set(hwCPUVoltage())); + (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG).set(hwCPUVoltage())); } else if (debug_msg == 'F') { // CPU frequency in 1/10Mhz - _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set(hwCPUFrequency())); + (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG).set(hwCPUFrequency())); } else if (debug_msg == 'M') { // free memory - _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set(hwFreeMem())); + (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG).set(hwFreeMem())); } else if (debug_msg == 'E') { // clear MySensors eeprom area and reboot - _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG, false).set("ok")); + (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG).set("OK")); for (int i = EEPROM_START; i MY_TRANSPORT_DISCOVERY_INTERVAL_MS) { _lastNetworkDiscovery = hwMillis(); TRANSPORT_DEBUG(PSTR("TSM:READY:NWD REQ\n")); // send transport network discovery - (void)transportRouteMessage(build(_msgTmp, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DISCOVER_REQUEST, false).set("")); + (void)transportRouteMessage(build(_msgTmp, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DISCOVER_REQUEST).set("")); } #else if (_transportSM.failedUplinkTransmissions > MY_TRANSPORT_MAX_TX_FAILURES) { @@ -298,7 +298,7 @@ void stFailureTransition(void) { _transportSM.uplinkOk = false; // uplink nok _transportSM.transportActive = false; // transport inactive setIndication(INDICATION_ERR_INIT_TRANSPORT); - #if defined(MY_RADIO_FEATURE) + #if defined(MY_SENSOR_NETWORK) TRANSPORT_DEBUG(PSTR("TSM:FAIL:PDT\n")); // power down transport, no need until re-init transportPowerDown(); #endif @@ -344,11 +344,11 @@ bool isTransportSearchingParent(void) { } bool isMessageReceived(void) { - return _transportSM.MsgReceived; + return _transportSM.msgReceived; } void resetMessageReceived(void) { - _transportSM.MsgReceived = false; + _transportSM.msgReceived = false; } @@ -507,7 +507,7 @@ uint8_t transportPingNode(const uint8_t targetId) { else { _transportSM.pingActive = true; _transportSM.pingResponse = INVALID_HOPS; - (void)transportRouteMessage(build(_msgTmp, targetId, NODE_SENSOR_ID, C_INTERNAL, I_PING, false).set((uint8_t)1)); + (void)transportRouteMessage(build(_msgTmp, targetId, NODE_SENSOR_ID, C_INTERNAL, I_PING).set((uint8_t)1)); // Wait for ping reply or timeout (void)transportWait(2000, C_INTERNAL, I_PONG); } @@ -579,7 +579,7 @@ void transportProcessMessage(void) { #endif // set message received flag - _transportSM.MsgReceived = true; + _transportSM.msgReceived = true; // Is message addressed to this node? if (destination == _nc.nodeId) { @@ -647,7 +647,7 @@ void transportProcessMessage(void) { // delay for fast GW and slow nodes delay(5); #endif - (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, I_PONG, false).set((uint8_t)1)); + (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, I_PONG).set((uint8_t)1)); return; // no further processing required } if (type == I_PONG) { @@ -700,7 +700,7 @@ void transportProcessMessage(void) { TRANSPORT_DEBUG(PSTR("TSF:MSG:GWL OK\n")); // GW uplink ok // random delay minimizes collisions delay(hwMillis() & 0x3ff); - (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE, false).set(_nc.distance)); + (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE).set(_nc.distance)); } else { TRANSPORT_DEBUG(PSTR("!TSF:MSG:GWL FAIL\n")); // GW uplink fail, do not respond to parent request @@ -718,7 +718,7 @@ void transportProcessMessage(void) { if (last == _nc.parentNodeId) { // random wait to minimize collisions delay(hwMillis() & 0x3ff); - (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, I_DISCOVER_RESPONSE, false).set(_nc.parentNodeId)); + (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, I_DISCOVER_RESPONSE).set(_nc.parentNodeId)); // no return here (for fwd if repeater) } } diff --git a/core/MyTransport.h b/core/MyTransport.h index 0cd350e61..305b53ffb 100644 --- a/core/MyTransport.h +++ b/core/MyTransport.h @@ -236,7 +236,7 @@ typedef struct { // 8 bits uint8_t failedUplinkTransmissions : 4; //!< counter failed uplink transmissions (max 15) uint8_t failureCounter : 3; //!< counter for TSM failures (max 7) - bool MsgReceived : 1; //!< flag message received + bool msgReceived : 1; //!< flag message received // 8 bits uint8_t pingResponse; //!< stores I_PONG hops } transportSM; From ccabd224a834a7a8dbcb08085ca81be1af9cae97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Thu, 13 Oct 2016 11:05:55 +0200 Subject: [PATCH 096/167] Updated comments to reflect HW better --- .../SensebenderGatewaySerial.ino | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino b/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino index 5e9c89c2f..d5492f576 100644 --- a/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino +++ b/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino @@ -22,19 +22,17 @@ * The ArduinoGateway prints data received from sensors on the serial link. * The gateway accepts input on seral which will be sent out on radio network. * -the last one is meant for the end user to break up into the various connectors used on the board. - - * This GW code is designed for Sensebender GateWay / Arduino Zero + * This GW code is designed for Sensebender GateWay / (Arduino Zero variant) * * Wire connections (OPTIONAL): - * - Inclusion button should be connected between digital pin 3 and GND - * - RX/TX/ERR leds need to be connected between +5V (anode) and digital pin 6/5/4 with resistor 270-330R in a series + * - Inclusion button should be connected to SW2 * - * LEDs (OPTIONAL): - * - To use the feature, uncomment any of the MY_DEFAULT_xx_LED_PINs - * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved - * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly - * - ERR (red) - fast blink on error during transmission error or recieve crc error + * LEDs on board (default assignments): + * - Orange: USB RX/TX - Blink when receiving / transmitting on USB CDC device + * - Yellow: RX - Blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved + * - Green : TX - Blink fast on radio message transmitted. In inclusion mode will blink slowly + * - Red : ERR - Fast blink on error during transmission error or recieve crc error + * - Blue : free - (use with LED_BLUE macro) * */ @@ -268,5 +266,3 @@ bool testAnalog() { Serial.println(" Passed"); return true; } - - From 80659ddb00b4811f8e6f9d90221ec796722b79b5 Mon Sep 17 00:00:00 2001 From: Olivier Date: Sun, 16 Oct 2016 10:12:24 +0200 Subject: [PATCH 097/167] HAL for digitalRead/Write() and pinMode() (#607) --- MySensors.h | 1 + core/MyGatewayTransportEthernet.cpp | 8 +- core/MyHwATMega328.h | 6 +- core/MyHwESP8266.h | 5 +- core/MyHwLinuxGeneric.h | 7 +- core/MyHwSAMD.h | 11 ++- core/MyInclusionMode.cpp | 6 +- core/MyTransportRS485.cpp | 12 +-- .../AVR/DigitalWriteFast/digitalWriteFast.h | 95 +++++++++++++++++++ drivers/AltSoftSerial/AltSoftSerial.cpp | 6 +- drivers/RF24/RF24.cpp | 10 +- drivers/RFM69/RFM69.cpp | 22 ++--- drivers/SPIFlash/SPIFlash.cpp | 6 +- 13 files changed, 149 insertions(+), 46 deletions(-) create mode 100644 drivers/AVR/DigitalWriteFast/digitalWriteFast.h diff --git a/MySensors.h b/MySensors.h index 91affc1c6..508bb31c0 100644 --- a/MySensors.h +++ b/MySensors.h @@ -66,6 +66,7 @@ //#define F(x) (x) #include "core/MyHwESP8266.cpp" #elif defined(ARDUINO_ARCH_AVR) + #include "drivers/AVR/DigitalWriteFast/digitalWriteFast.h" #include "core/MyHwATMega328.cpp" #elif defined(ARDUINO_ARCH_SAMD) #include "core/MyHwSAMD.cpp" diff --git a/core/MyGatewayTransportEthernet.cpp b/core/MyGatewayTransportEthernet.cpp index 692fbc7b8..2a03df9a4 100644 --- a/core/MyGatewayTransportEthernet.cpp +++ b/core/MyGatewayTransportEthernet.cpp @@ -87,14 +87,14 @@ typedef struct if (enable) { // Pull up pin - pinMode(MY_W5100_SPI_EN, INPUT); - digitalWrite(MY_W5100_SPI_EN, HIGH); + hwPinMode(MY_W5100_SPI_EN, INPUT); + hwDigitalWrite(MY_W5100_SPI_EN, HIGH); } else { // Ground pin - pinMode(MY_W5100_SPI_EN, OUTPUT); - digitalWrite(MY_W5100_SPI_EN, LOW); + hwPinMode(MY_W5100_SPI_EN, OUTPUT); + hwDigitalWrite(MY_W5100_SPI_EN, LOW); } } #else diff --git a/core/MyHwATMega328.h b/core/MyHwATMega328.h index 45a7f5988..b8e64d108 100644 --- a/core/MyHwATMega328.h +++ b/core/MyHwATMega328.h @@ -58,7 +58,10 @@ do { \ // Define these as macros to save valuable space -#define hwDigitalWrite(__pin, __value) (digitalWrite(__pin, __value)) +#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() @@ -78,7 +81,6 @@ do { \ #define hwWriteConfig(__pos, __value) (eeprom_update_byte((uint8_t*)(__pos), (__value))) #endif -// #define hwReadConfigBlock(__buf, __pos, __length) (eeprom_read_block((__buf), (void*)(__pos), (__length))) #define hwWriteConfigBlock(__buf, __pos, __length) (eeprom_write_block((void*)(__buf), (void*)(__pos), (__length))) diff --git a/core/MyHwESP8266.h b/core/MyHwESP8266.h index 5489e62c8..0f53cedbc 100644 --- a/core/MyHwESP8266.h +++ b/core/MyHwESP8266.h @@ -33,8 +33,9 @@ // Define these as macros to save valuable space - -#define hwDigitalWrite(__pin, __value) (digitalWrite(__pin, __value)) +#define hwDigitalWrite(__pin, __value) digitalWrite(__pin, __value) +#define hwDigitalRead(__pin) digitalRead(__pin) +#define hwPinMode(__pin, __value) pinMode(__pin, __value) #if defined(MY_DISABLED_SERIAL) #define hwInit() diff --git a/core/MyHwLinuxGeneric.h b/core/MyHwLinuxGeneric.h index 067b93a06..3d39203ad 100644 --- a/core/MyHwLinuxGeneric.h +++ b/core/MyHwLinuxGeneric.h @@ -33,8 +33,11 @@ #define MY_SERIALDEVICE Serial -// Define these as macros (do nothing) -#define hwDigitalWrite(__pin, __value) +// Define these as macros +#define hwDigitalWrite(__pin, __value) digitalWrite(__pin, __value) +#define hwDigitalRead(__pin) digitalRead(__pin) +#define hwPinMode(__pin, __value) pinMode(__pin, __value) + #define hwWatchdogReset() #define hwReboot() #define hwMillis() millis() diff --git a/core/MyHwSAMD.h b/core/MyHwSAMD.h index 6df31621e..00ac1d612 100644 --- a/core/MyHwSAMD.h +++ b/core/MyHwSAMD.h @@ -34,17 +34,18 @@ #define max(a,b) ((a)>(b)?(a):(b)) #define snprintf_P(s, f, ...) snprintf((s), (f), __VA_ARGS__) +uint8_t configBlock[1024]; // Define these as macros to save valuable space +#define hwDigitalWrite(__pin, __value) digitalWrite(__pin, __value) +#define hwDigitalRead(__pin) digitalRead(__pin) +#define hwPinMode(__pin, __value) pinMode(__pin, __value) +#define hwMillis() millis() +#define hwRandomNumberInit() randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)) -uint8_t configBlock[1024]; -#define hwDigitalWrite(__pin, __value) (digitalWrite(__pin, __value)) void hwInit(); void hwWatchdogReset(); void hwReboot(); -#define hwMillis() millis() -#define hwRandomNumberInit() randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)) - void hwReadConfigBlock(void* buf, void* adr, size_t length); void hwWriteConfigBlock(void* buf, void* adr, size_t length); void hwWriteConfig(int adr, uint8_t value); diff --git a/core/MyInclusionMode.cpp b/core/MyInclusionMode.cpp index ea2198c57..c9dbfa67d 100644 --- a/core/MyInclusionMode.cpp +++ b/core/MyInclusionMode.cpp @@ -29,8 +29,8 @@ inline void inclusionInit() { _inclusionMode = false; #if defined(MY_INCLUSION_BUTTON_FEATURE) // Setup digital in that triggers inclusion mode - pinMode(MY_INCLUSION_MODE_BUTTON_PIN, INPUT); - digitalWrite(MY_INCLUSION_MODE_BUTTON_PIN, HIGH); + hwPinMode(MY_INCLUSION_MODE_BUTTON_PIN, INPUT); + hwDigitalWrite(MY_INCLUSION_MODE_BUTTON_PIN, HIGH); #endif } @@ -49,7 +49,7 @@ void inclusionModeSet(bool newMode) { inline void inclusionProcess() { #ifdef MY_INCLUSION_BUTTON_FEATURE - if (!_inclusionMode && digitalRead(MY_INCLUSION_MODE_BUTTON_PIN) == MY_INCLUSION_BUTTON_PRESSED) { + if (!_inclusionMode && hwDigitalRead(MY_INCLUSION_MODE_BUTTON_PIN) == MY_INCLUSION_BUTTON_PRESSED) { // Start inclusion mode inclusionModeSet(true); } diff --git a/core/MyTransportRS485.cpp b/core/MyTransportRS485.cpp index 285c1d1c9..92a140c08 100644 --- a/core/MyTransportRS485.cpp +++ b/core/MyTransportRS485.cpp @@ -63,8 +63,8 @@ #if defined(MY_RS485_DE_PIN) - #define assertDE() digitalWrite(MY_RS485_DE_PIN, HIGH); delayMicroseconds(5) - #define deassertDE() digitalWrite(MY_RS485_DE_PIN, LOW) + #define assertDE() hwDigitalWrite(MY_RS485_DE_PIN, HIGH); delayMicroseconds(5) + #define deassertDE() hwDigitalWrite(MY_RS485_DE_PIN, LOW) #else #define assertDE() @@ -258,7 +258,7 @@ bool transportSend(uint8_t to, const void* data, uint8_t len) } #if defined(MY_RS485_DE_PIN) - digitalWrite(MY_RS485_DE_PIN, HIGH); + hwDigitalWrite(MY_RS485_DE_PIN, HIGH); delayMicroseconds(5); #endif @@ -300,7 +300,7 @@ bool transportSend(uint8_t to, const void* data, uint8_t len) #endif #endif #endif - digitalWrite(MY_RS485_DE_PIN, LOW); + hwDigitalWrite(MY_RS485_DE_PIN, LOW); #endif return true; } @@ -312,8 +312,8 @@ bool transportInit() { _dev.begin(MY_RS485_BAUD_RATE); _serialReset(); #if defined(MY_RS485_DE_PIN) - pinMode(MY_RS485_DE_PIN, OUTPUT); - digitalWrite(MY_RS485_DE_PIN, LOW); + hwPinMode(MY_RS485_DE_PIN, OUTPUT); + hwDigitalWrite(MY_RS485_DE_PIN, LOW); #endif return true; } diff --git a/drivers/AVR/DigitalWriteFast/digitalWriteFast.h b/drivers/AVR/DigitalWriteFast/digitalWriteFast.h new file mode 100644 index 000000000..a76834712 --- /dev/null +++ b/drivers/AVR/DigitalWriteFast/digitalWriteFast.h @@ -0,0 +1,95 @@ +/* + * Optimized digital functions for AVR microcontrollers + * based on http://code.google.com/p/digitalwritefast + */ + +#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__) + #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(__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))) + #define __digitalPinToPINReg(__pin) (((__pin) <= 7) ? &PIND : (((__pin) >= 8 && (__pin) <= 13) ? &PINB : (((__pin) >= 14 && (__pin) <= 19) ? &PINC : &PINE))) + #define __digitalPinToBit(__pin) (((__pin) <= 7) ? (__pin) : (((__pin) >= 8 && (__pin) <= 13) ? (__pin) - 8 : (((__pin) >= 14 && (__pin) <= 19) ? (__pin) - 14 : (((__pin) >= 20 && (__pin) <= 21) ? (__pin) - 18 : (__pin) - 22)))) + #else + #define __digitalPinToPortReg(__pin) (((__pin) <= 7) ? &PORTD : (((__pin) >= 8 && (__pin) <= 13) ? &PORTB : &PORTC)) + #define __digitalPinToDDRReg(__pin) (((__pin) <= 7) ? &DDRD : (((__pin) >= 8 && (__pin) <= 13) ? &DDRB : &DDRC)) + #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(digitalWriteFast) + #define digitalWriteFast(__pin, __value) do { if (__builtin_constant_p(__pin) && __builtin_constant_p(__value)) { bitWrite(*__digitalPinToPortReg(__pin), __digitalPinToBit(__pin), (__value)); } else { digitalWrite((__pin), (__value)); } } while (0) + #endif + #if !defined(pinModeFast) + #define pinModeFast(__pin, __value) do { if (__builtin_constant_p(__pin) && __builtin_constant_p(__value)) { bitWrite(*__digitalPinToDDRReg(__pin), __digitalPinToBit(__pin), (__value)); } else { pinMode((__pin), (__value)); } } while (0) + #endif + #if !defined(digitalReadFast) + #define digitalReadFast(__pin) ( (bool) (__builtin_constant_p(__pin) ) ? (( bitRead(*__digitalPinToPINReg(__pin), __digitalPinToBit(__pin))) ) : digitalRead((__pin)) ) + #endif +#endif + +#endif \ No newline at end of file diff --git a/drivers/AltSoftSerial/AltSoftSerial.cpp b/drivers/AltSoftSerial/AltSoftSerial.cpp index 8dedae780..de9b1ebeb 100644 --- a/drivers/AltSoftSerial/AltSoftSerial.cpp +++ b/drivers/AltSoftSerial/AltSoftSerial.cpp @@ -76,9 +76,9 @@ void AltSoftSerial::init(uint32_t cycles_per_bit) } ticks_per_bit = cycles_per_bit; rx_stop_ticks = cycles_per_bit * 37 / 4; - pinMode(INPUT_CAPTURE_PIN, INPUT_PULLUP); - digitalWrite(OUTPUT_COMPARE_A_PIN, HIGH); - pinMode(OUTPUT_COMPARE_A_PIN, OUTPUT); + hwPinMode(INPUT_CAPTURE_PIN, INPUT_PULLUP); + hwDigitalWrite(OUTPUT_COMPARE_A_PIN, HIGH); + hwPinMode(OUTPUT_COMPARE_A_PIN, OUTPUT); rx_state = 0; rx_buffer_head = 0; rx_buffer_tail = 0; diff --git a/drivers/RF24/RF24.cpp b/drivers/RF24/RF24.cpp index aea2bd702..6f872e009 100644 --- a/drivers/RF24/RF24.cpp +++ b/drivers/RF24/RF24.cpp @@ -35,11 +35,11 @@ LOCAL uint8_t MY_RF24_NODE_ADDRESS = AUTO; #endif LOCAL void RF24_csn(bool level) { - digitalWrite(MY_RF24_CS_PIN, level); + hwDigitalWrite(MY_RF24_CS_PIN, level); } LOCAL void RF24_ce(bool level) { - digitalWrite(MY_RF24_CE_PIN, level); + hwDigitalWrite(MY_RF24_CE_PIN, level); } LOCAL uint8_t RF24_spiMultiByteTransfer(uint8_t cmd, uint8_t* buf, uint8_t len, bool aReadMode) { @@ -338,10 +338,10 @@ LOCAL bool RF24_initialize(void) { (void)RF24_getObserveTX; // Initialize pins - pinMode(MY_RF24_CE_PIN,OUTPUT); - pinMode(MY_RF24_CS_PIN,OUTPUT); + hwPinMode(MY_RF24_CE_PIN,OUTPUT); + hwPinMode(MY_RF24_CS_PIN,OUTPUT); #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) - pinMode(MY_RF24_IRQ_PIN,INPUT); + hwPinMode(MY_RF24_IRQ_PIN,INPUT); #endif // Initialize SPI _SPI.begin(); diff --git a/drivers/RFM69/RFM69.cpp b/drivers/RFM69/RFM69.cpp index a8edbab41..b9bf7f9a7 100644 --- a/drivers/RFM69/RFM69.cpp +++ b/drivers/RFM69/RFM69.cpp @@ -87,8 +87,8 @@ bool RFM69::initialize(uint8_t freqBand, uint8_t nodeID, uint8_t networkID) {255, 0} }; - digitalWrite(_slaveSelectPin, HIGH); - pinMode(_slaveSelectPin, OUTPUT); + hwDigitalWrite(_slaveSelectPin, HIGH); + hwPinMode(_slaveSelectPin, OUTPUT); SPI.begin(); unsigned long start = millis(); uint8_t timeout = 50; @@ -318,15 +318,15 @@ void RFM69::sendFrame(uint8_t toAddress, const void* buffer, uint8_t bufferSize, // no need to wait for transmit mode to be ready since its handled by the radio setMode(RF69_MODE_TX); uint32_t txStart = millis(); - while (digitalRead(_interruptPin) == 0 && millis() - txStart < RF69_TX_LIMIT_MS); // wait for DIO0 to turn HIGH signalling transmission finish + while (hwDigitalRead(_interruptPin) == 0 && millis() - txStart < RF69_TX_LIMIT_MS); // wait for DIO0 to turn HIGH signalling transmission finish //while (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PACKETSENT == 0x00); // wait for ModeReady setMode(RF69_MODE_STANDBY); } // internal function - interrupt gets called when a packet is received void RFM69::interruptHandler() { - //pinMode(4, OUTPUT); - //digitalWrite(4, 1); + //hwPinMode(4, OUTPUT); + //hwDigitalWrite(4, 1); if (_mode == RF69_MODE_RX && (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY)) { //RSSI = readRSSI(); @@ -342,7 +342,7 @@ void RFM69::interruptHandler() { PAYLOADLEN = 0; unselect(); receiveBegin(); - //digitalWrite(4, 0); + //hwDigitalWrite(4, 0); return; } @@ -364,7 +364,7 @@ void RFM69::interruptHandler() { setMode(RF69_MODE_RX); } RSSI = readRSSI(); - //digitalWrite(4, 0); + //hwDigitalWrite(4, 0); } // internal function @@ -464,12 +464,12 @@ void RFM69::select() { SPI.setDataMode(SPI_MODE0); SPI.setBitOrder(MSBFIRST); SPI.setClockDivider(SPI_CLOCK_DIV4); // decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present - digitalWrite(_slaveSelectPin, LOW); + hwDigitalWrite(_slaveSelectPin, LOW); } // unselect the RFM69 transceiver (set CS high, restore SPI settings) void RFM69::unselect() { - digitalWrite(_slaveSelectPin, HIGH); + hwDigitalWrite(_slaveSelectPin, HIGH); // restore SPI settings to what they were before talking to RFM69 #if defined (SPCR) && defined (SPSR) SPCR = _SPCR; @@ -504,8 +504,8 @@ void RFM69::setHighPowerRegs(bool onOff) { // set the slave select (CS) pin void RFM69::setCS(uint8_t newSPISlaveSelect) { _slaveSelectPin = newSPISlaveSelect; - digitalWrite(_slaveSelectPin, HIGH); - pinMode(_slaveSelectPin, OUTPUT); + hwDigitalWrite(_slaveSelectPin, HIGH); + hwPinMode(_slaveSelectPin, OUTPUT); } //for debugging diff --git a/drivers/SPIFlash/SPIFlash.cpp b/drivers/SPIFlash/SPIFlash.cpp index 1d4205ccc..547a703ac 100644 --- a/drivers/SPIFlash/SPIFlash.cpp +++ b/drivers/SPIFlash/SPIFlash.cpp @@ -72,12 +72,12 @@ void SPIFlash::select() { SPI.setClockDivider(SPI_CLOCK_DIV4); //decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present SPI.begin(); #endif - digitalWrite(_slaveSelectPin, LOW); + hwDigitalWrite(_slaveSelectPin, LOW); } /// UNselect the flash chip void SPIFlash::unselect() { - digitalWrite(_slaveSelectPin, HIGH); + hwDigitalWrite(_slaveSelectPin, HIGH); //restore SPI settings to what they were before talking to the FLASH chip #ifdef SPI_HAS_TRANSACTION SPI.endTransaction(); @@ -97,7 +97,7 @@ boolean SPIFlash::initialize() _SPCR = SPCR; _SPSR = SPSR; #endif - pinMode(_slaveSelectPin, OUTPUT); + hwPinMode(_slaveSelectPin, OUTPUT); #ifdef SPI_HAS_TRANSACTION _settings = SPISettings(4000000, MSBFIRST, SPI_MODE0); #endif From 54776a45205f2e1019b41fe84abac5b5f9c78c6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Sun, 16 Oct 2016 12:46:42 +0200 Subject: [PATCH 098/167] Added {} to control structures for clarity (#600) --- core/MyGatewayTransportEthernet.cpp | 7 +- core/MyGatewayTransportMQTTClient.cpp | 12 +- core/MyHwATMega328.cpp | 55 ++++---- core/MyHwSAMD.cpp | 4 +- core/MyIndication.cpp | 5 +- core/MyLeds.cpp | 15 ++- core/MyMainDefault.cpp | 27 +++- core/MyMainESP8266.cpp | 25 +++- core/MyMainLinux.cpp | 24 +++- core/MyMessage.cpp | 14 +- core/MyOTAFirmwareUpdate.cpp | 18 +-- core/MyOTAFirmwareUpdate.h | 6 +- core/MyProtocolMySensors.cpp | 28 ++-- core/MySensorsCore.cpp | 26 ++-- core/MySigningAtsha204.cpp | 22 ++-- core/MySigningAtsha204Soft.cpp | 72 ++++++---- core/MyTransport.cpp | 57 ++++---- core/MyTransportRS485.cpp | 10 +- core/Version.h | 18 +++ drivers/AES/AES.cpp | 52 ++++---- drivers/ATSHA204/ATSHA204.cpp | 115 ++++++++++------ drivers/ATSHA204/sha256.cpp | 22 +++- drivers/AltSoftSerial/AltSoftSerial.cpp | 59 ++++++--- drivers/Linux/EthernetClient.cpp | 24 ++-- drivers/Linux/EthernetServer.cpp | 4 +- drivers/Linux/Print.cpp | 24 ++-- drivers/Linux/SerialPort.cpp | 4 +- drivers/Linux/Stream.cpp | 82 ++++++++---- drivers/Linux/noniso.cpp | 10 +- drivers/PubSubClient/PubSubClient.cpp | 20 ++- drivers/RF24/RF24.cpp | 33 ++--- drivers/RFM69/RFM69.cpp | 167 ++++++++++++++---------- drivers/RPi/SPI.cpp | 12 +- drivers/SPIFlash/SPIFlash.cpp | 73 ++++++----- 34 files changed, 740 insertions(+), 406 deletions(-) diff --git a/core/MyGatewayTransportEthernet.cpp b/core/MyGatewayTransportEthernet.cpp index 2a03df9a4..498850ff6 100644 --- a/core/MyGatewayTransportEthernet.cpp +++ b/core/MyGatewayTransportEthernet.cpp @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Tomas Hozza - * Copyright (C) 2015 Tomas Hozza + * Copyright (C) 2015 Tomas Hozza * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -135,7 +135,7 @@ bool gatewayTransportInit() { _w5100_spi_en(false); return false; } - #endif + #endif MY_SERIALDEVICE.print(F("IP: ")); MY_SERIALDEVICE.println(Ethernet.localIP()); // give the Ethernet interface a second to initialize @@ -437,8 +437,9 @@ void gatewayTransportRenewIP() unsigned long now = hwMillis(); // http://playground.arduino.cc/Code/TimingRollover - if ((long)(now - next_time) < 0) + if ((long)(now - next_time) < 0) { return; + } if (Ethernet.maintain() & ~(0x06)) { debug(PSTR("IP was not renewed correctly\n")); /* Error occured -> IP was not renewed */ diff --git a/core/MyGatewayTransportMQTTClient.cpp b/core/MyGatewayTransportMQTTClient.cpp index 90fa9f0ed..ea98f076e 100644 --- a/core/MyGatewayTransportMQTTClient.cpp +++ b/core/MyGatewayTransportMQTTClient.cpp @@ -49,8 +49,9 @@ static bool _MQTT_available = false; static MyMessage _MQTT_msg; bool gatewayTransportSend(MyMessage &message) { - if (!_MQTT_client.connected()) + if (!_MQTT_client.connected()) { return false; + } setIndication(INDICATION_GW_TX); char *topic = protocolFormatMQTTTopic(MY_MQTT_PUBLISH_TOPIC_PREFIX, message); debug(PSTR("Sending message on topic: %s\n"), topic); @@ -134,7 +135,7 @@ bool gatewayTransportInit() { (void)WiFi.begin(MY_ESP8266_SSID, MY_ESP8266_PASSWORD); #ifdef MY_IP_ADDRESS WiFi.config(_MQTT_clientIp, _gatewayIp, _subnetIp); - #endif + #endif #endif gatewayTransportConnect(); @@ -144,15 +145,16 @@ bool gatewayTransportInit() { } bool gatewayTransportAvailable() { - if (_MQTT_connecting) + if (_MQTT_connecting) { return false; - + } //keep lease on dhcp address //Ethernet.maintain(); if (!_MQTT_client.connected()) { //reinitialise client - if (gatewayTransportConnect()) + if (gatewayTransportConnect()) { reconnectMQTT(); + } return false; } _MQTT_client.loop(); diff --git a/core/MyHwATMega328.cpp b/core/MyHwATMega328.cpp index 2a130c771..b0f9eadda 100644 --- a/core/MyHwATMega328.cpp +++ b/core/MyHwATMega328.cpp @@ -81,7 +81,7 @@ void hwPowerDown(period_t period) { sei(); // Directly sleep CPU, to prevent race conditions! (see chapter 7.7 of ATMega328P datasheet) sleep_cpu(); - sleep_disable(); + sleep_disable(); // restore previous WDT settings cli(); wdt_reset(); @@ -124,12 +124,16 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo // Disable interrupts until going to sleep, otherwise interrupts occurring between attachInterrupt() // and sleep might cause the ATMega to not wakeup from sleep as interrupt has already be handled! cli(); - // attach interrupts + // attach interrupts _wakeUp1Interrupt = interrupt1; _wakeUp2Interrupt = interrupt2; - if (interrupt1 != INVALID_INTERRUPT_NUM) attachInterrupt(interrupt1, wakeUp1, mode1); - if (interrupt2 != INVALID_INTERRUPT_NUM) attachInterrupt(interrupt2, wakeUp2, mode2); - + if (interrupt1 != INVALID_INTERRUPT_NUM) { + attachInterrupt(interrupt1, wakeUp1, mode1); + } + if (interrupt2 != INVALID_INTERRUPT_NUM) { + attachInterrupt(interrupt2, wakeUp2, mode2); + } + if (ms>0) { // sleep for defined time hwInternalSleep(ms); @@ -137,15 +141,20 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo // sleep until ext interrupt triggered hwPowerDown(SLEEP_FOREVER); } - + // Assure any interrupts attached, will get detached when they did not occur. - if (interrupt1 != INVALID_INTERRUPT_NUM) detachInterrupt(interrupt1); - if (interrupt2 != INVALID_INTERRUPT_NUM) detachInterrupt(interrupt2); + if (interrupt1 != INVALID_INTERRUPT_NUM) { + detachInterrupt(interrupt1); + } + if (interrupt2 != INVALID_INTERRUPT_NUM) { + detachInterrupt(interrupt2); + } // Return what woke the mcu. - int8_t ret = MY_WAKE_UP_BY_TIMER; // default: no interrupt triggered, timer wake up - if (interruptWakeUp()) ret = static_cast(_wokeUpByInterrupt); - + int8_t ret = MY_WAKE_UP_BY_TIMER; // default: no interrupt triggered, timer wake up + if (interruptWakeUp()) { + ret = static_cast(_wokeUpByInterrupt); + } // Clear woke-up-by-interrupt flag, so next sleeps won't return immediately. _wokeUpByInterrupt = INVALID_INTERRUPT_NUM; @@ -153,7 +162,7 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo } uint16_t hwCPUVoltage() { - // Measure Vcc against 1.1V Vref + // Measure Vcc against 1.1V Vref #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) ADMUX = (_BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1)); #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) @@ -162,12 +171,12 @@ uint16_t hwCPUVoltage() { ADMUX = (_BV(MUX3) | _BV(MUX2)); #else ADMUX = (_BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1)); - #endif + #endif // Vref settle - delay(70); + delay(70); // Do conversion ADCSRA |= _BV(ADSC); - while (bit_is_set(ADCSRA,ADSC)); + while (bit_is_set(ADCSRA,ADSC)) {}; // return Vcc in mV return (1125300UL) / ADC; } @@ -175,8 +184,8 @@ uint16_t hwCPUVoltage() { uint16_t hwCPUFrequency() { cli(); // setup timer1 - TIFR1 = 0xFF; - TCNT1 = 0; + TIFR1 = 0xFF; + TCNT1 = 0; TCCR1A = 0; TCCR1C = 0; // save WDT settings @@ -186,24 +195,24 @@ uint16_t hwCPUFrequency() { WDTCSR |= (1 << WDIE); wdt_reset(); // start timer1 with 1024 prescaling - TCCR1B = _BV(CS12) | _BV(CS10); + TCCR1B = _BV(CS12) | _BV(CS10); // wait until wdt interrupt - while (bit_is_clear(WDTCSR,WDIF)); + while (bit_is_clear(WDTCSR,WDIF)) {}; // stop timer TCCR1B = 0; // restore WDT settings wdt_reset(); WDTCSR |= (1 << WDCE) | (1 << WDE); WDTCSR = WDTsave; - sei(); + sei(); // return frequency in 1/10MHz (accuracy +- 10%) return TCNT1 * 2048UL / 100000UL; } uint16_t hwFreeMem() { - extern int __heap_start, *__brkval; - int v; - return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); + extern int __heap_start, *__brkval; + int v; + return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); } diff --git a/core/MyHwSAMD.cpp b/core/MyHwSAMD.cpp index 976d4cd25..9e11e5d3b 100644 --- a/core/MyHwSAMD.cpp +++ b/core/MyHwSAMD.cpp @@ -58,7 +58,9 @@ byte i2c_eeprom_read_byte(unsigned int eeaddress ) { Wire.write((int)(eeaddress & 0xFF)); // LSB Wire.endTransmission(); Wire.requestFrom(I2C_EEP_ADDRESS,1); - if (Wire.available()) rdata = Wire.read(); + if (Wire.available()) { + rdata = Wire.read(); + } return rdata; } diff --git a/core/MyIndication.cpp b/core/MyIndication.cpp index 6eb5b45fe..94478235e 100644 --- a/core/MyIndication.cpp +++ b/core/MyIndication.cpp @@ -43,6 +43,7 @@ void setIndication( const indication_t ind ) ledsBlinkErr(ind-INDICATION_ERR_START); } #endif - if (indication) - indication(ind); + if (indication) { + indication(ind); + } } diff --git a/core/MyLeds.cpp b/core/MyLeds.cpp index 33f1eedfc..e8c42a1dd 100644 --- a/core/MyLeds.cpp +++ b/core/MyLeds.cpp @@ -51,8 +51,9 @@ inline void ledsInit() void ledsProcess() { // Just return if it is not the time... - if ((hwMillis() - prevTime) < LED_PROCESS_INTERVAL_MS) + if ((hwMillis() - prevTime) < LED_PROCESS_INTERVAL_MS) { return; + } prevTime += LED_PROCESS_INTERVAL_MS; @@ -63,19 +64,25 @@ void ledsProcess() { #if defined(MY_DEFAULT_RX_LED_PIN) state = (countRx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF; hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, state); - if (countRx) --countRx; + if (countRx) { + --countRx; + } #endif #if defined(MY_DEFAULT_TX_LED_PIN) state = (countTx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF; hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, state); - if (countTx) --countTx; + if (countTx) { + --countTx; + } #endif #if defined(MY_DEFAULT_ERR_LED_PIN) state = (countErr & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF; hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, state); - if (countErr) --countErr; + if (countErr) { + --countErr; + } #endif } diff --git a/core/MyMainDefault.cpp b/core/MyMainDefault.cpp index b1934b94e..56388362b 100644 --- a/core/MyMainDefault.cpp +++ b/core/MyMainDefault.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-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. + */ + // Initialize library and handle sketch functions like we want to int main(void) { @@ -12,8 +31,12 @@ int main(void) { for(;;) { _process(); // Process incoming data - if (loop) loop(); // Call sketch loop - if (serialEventRun) serialEventRun(); + if (loop) { + loop(); // Call sketch loop + } + if (serialEventRun) { + serialEventRun(); + } } return 0; } diff --git a/core/MyMainESP8266.cpp b/core/MyMainESP8266.cpp index ee800a0a7..2b76eec41 100644 --- a/core/MyMainESP8266.cpp +++ b/core/MyMainESP8266.cpp @@ -1,4 +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-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. + */ + //This may be used to change user task stack size: //#define CONT_STACKSIZE 4096 #include "Schedule.h" @@ -109,8 +127,9 @@ static void loop_task(os_event_t *events) { static void do_global_ctors(void) { void(**p)(void) = &__init_array_end; - while (p != &__init_array_start) + while (p != &__init_array_start) { (*--p)(); + } } extern "C" void __gdb_init() {} @@ -144,4 +163,4 @@ extern "C" void user_init(void) { LOOP_QUEUE_SIZE); system_init_done_cb(&init_done); -} \ No newline at end of file +} diff --git a/core/MyMainLinux.cpp b/core/MyMainLinux.cpp index 56a2d47d6..5d70e4798 100644 --- a/core/MyMainLinux.cpp +++ b/core/MyMainLinux.cpp @@ -1,4 +1,22 @@ -// Initialize library and handle sketch functions like we want to +/** + * 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. + */ + // Initialize library and handle sketch functions like we want to #include #include @@ -129,7 +147,9 @@ int main(int argc, char *argv[]) for (;;) { _process(); // Process incoming data - if (loop) loop(); // Call sketch loop + if (loop) { + loop(); // Call sketch loop + } } return 0; } diff --git a/core/MyMessage.cpp b/core/MyMessage.cpp index d2891094f..bce0ae88a 100644 --- a/core/MyMessage.cpp +++ b/core/MyMessage.cpp @@ -75,10 +75,12 @@ const char* MyMessage::getString() const { // handles single character hex (0 - 15) char MyMessage::i2h(uint8_t i) const { uint8_t k = i & 0x0F; - if (k <= 9) + if (k <= 9) { return '0' + k; - else + } + else { return 'A' + k - 10; + } } char* MyMessage::getCustomString(char *buffer) const { @@ -173,7 +175,7 @@ uint32_t MyMessage::getULong() const { } int16_t MyMessage::getInt() const { - if (miGetPayloadType() == P_INT16) { + if (miGetPayloadType() == P_INT16) { return iValue; } else if (miGetPayloadType() == P_STRING) { return atoi(data); @@ -183,7 +185,7 @@ int16_t MyMessage::getInt() const { } uint16_t MyMessage::getUInt() const { - if (miGetPayloadType() == P_UINT16) { + if (miGetPayloadType() == P_UINT16) { return uiValue; } else if (miGetPayloadType() == P_STRING) { return atoi(data); @@ -211,7 +213,7 @@ MyMessage& MyMessage::setDestination(uint8_t _destination) { // Set payload MyMessage& MyMessage::set(void* value, uint8_t length) { uint8_t payloadLength = value == NULL ? 0 : min(length, (uint8_t)MAX_PAYLOAD); - miSetLength(payloadLength); + miSetLength(payloadLength); miSetPayloadType(P_CUSTOM); memcpy(data, value, payloadLength); return *this; @@ -221,7 +223,7 @@ MyMessage& MyMessage::set(const char* value) { uint8_t length = value == NULL ? 0 : min(strlen(value), (size_t)MAX_PAYLOAD); miSetLength(length); miSetPayloadType(P_STRING); - if (length) { + if (length) { strncpy(data, value, length); } // null terminate string diff --git a/core/MyOTAFirmwareUpdate.cpp b/core/MyOTAFirmwareUpdate.cpp index 34e69e1c4..af0338e1e 100644 --- a/core/MyOTAFirmwareUpdate.cpp +++ b/core/MyOTAFirmwareUpdate.cpp @@ -16,7 +16,7 @@ * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. */ - + #include "MyOTAFirmwareUpdate.h" // global variables @@ -76,7 +76,7 @@ bool firmwareOTAUpdateProcess() { // erase lower 32K -> max flash size for ATMEGA328 _flash.blockErase32K(0); // wait until flash erased - while ( _flash.busy() ); + while ( _flash.busy() ) {} _fwBlock = _fc.blocks; _fwUpdateOngoing = true; // reset flags @@ -96,7 +96,7 @@ bool firmwareOTAUpdateProcess() { // write to flash _flash.writeBytes( ((_fwBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE); // wait until flash written - while ( _flash.busy() ); + while ( _flash.busy() ) {} _fwBlock--; if (!_fwBlock) { // We're finished! Do a checksum and reboot. @@ -137,7 +137,7 @@ void presentBootloaderInformation(){ // add bootloader information reqFWConfig->BLVersion = MY_OTA_BOOTLOADER_VERSION; _fwUpdateOngoing = false; - _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_CONFIG_REQUEST, false)); + _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_CONFIG_REQUEST, false)); } // do a crc16 on the whole received firmware bool transportIsValidFirmware() { @@ -146,10 +146,12 @@ bool transportIsValidFirmware() { for (uint16_t i = 0; i < _fc.blocks * FIRMWARE_BLOCK_SIZE; ++i) { crc ^= _flash.readByte(i + FIRMWARE_START_OFFSET); for (int8_t j = 0; j < 8; ++j) { - if (crc & 1) - crc = (crc >> 1) ^ 0xA001; - else - crc = (crc >> 1); + if (crc & 1) { + crc = (crc >> 1) ^ 0xA001; + } + else { + crc = (crc >> 1); + } } } return crc == _fc.crc; diff --git a/core/MyOTAFirmwareUpdate.h b/core/MyOTAFirmwareUpdate.h index 7153eac3e..1f76540fc 100644 --- a/core/MyOTAFirmwareUpdate.h +++ b/core/MyOTAFirmwareUpdate.h @@ -36,7 +36,7 @@ * * |E| SYS | SUB | Message | Comment * |-|------|-------|-------------------------------------------|---------------------------------------------------------------------------- - * | | OTA | FWP | UPDATE | FW update initiated + * | | OTA | FWP | UPDATE | FW update initiated * |!| 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) @@ -132,10 +132,10 @@ bool firmwareOTAUpdateProcess(); */ bool transportIsValidFirmware(); /** - * @brief Present bootloader/FW information upon startup + * @brief Present bootloader/FW information upon startup */ void presentBootloaderInformation(); #endif -/** @}*/ \ No newline at end of file +/** @}*/ diff --git a/core/MyProtocolMySensors.cpp b/core/MyProtocolMySensors.cpp index 8c96b4279..f5302b482 100644 --- a/core/MyProtocolMySensors.cpp +++ b/core/MyProtocolMySensors.cpp @@ -70,10 +70,12 @@ bool protocolParse(MyMessage &message, char *inputString) { value = str; // Remove trailing carriage return and newline character (if it exists) uint8_t lastCharacter = strlen(value)-1; - if (value[lastCharacter] == '\r') + if (value[lastCharacter] == '\r') { value[lastCharacter] = 0; - if (value[lastCharacter] == '\n') + } + if (value[lastCharacter] == '\n') { value[lastCharacter] = 0; + } } break; } @@ -81,16 +83,18 @@ bool protocolParse(MyMessage &message, char *inputString) { } //debug(PSTR("Received %d"), i); // Check for invalid input - if (i < 5) + if (i < 5) { return false; - + } message.sender = GATEWAY_ADDRESS; message.last = GATEWAY_ADDRESS; mSetAck(message, false); - if (command == C_STREAM) + if (command == C_STREAM) { message.set(bvalue, blen); - else + } + else { message.set(value); + } return true; } @@ -158,8 +162,9 @@ bool protocolMQTTParse(MyMessage &message, char* topic, uint8_t* payload, unsign i++; } - if (i != 6) + if (i != 6) { return false; + } message.sender = GATEWAY_ADDRESS; message.last = GATEWAY_ADDRESS; @@ -190,11 +195,14 @@ bool protocolMQTTParse(MyMessage &message, char* topic, uint8_t* payload, unsign uint8_t protocolH2i(char c) { uint8_t i = 0; - if (c <= '9') + if (c <= '9') { i += c - '0'; - else if (c >= 'a') + } + else if (c >= 'a') { i += c - 'a' + 10; - else + } + else { i += c - 'A' + 10; + } return i; } diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index af58a88b8..11eadad16 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -72,8 +72,9 @@ void _infiniteLoop(void) { void _begin(void) { hwWatchdogReset(); - if (preHwInit) + if (preHwInit) { preHwInit(); + } hwInit(); @@ -120,7 +121,7 @@ void _begin(void) { pinMode(MY_NODE_UNLOCK_PIN, INPUT_PULLUP); // Make a short delay so we are sure any large external nets are fully pulled unsigned long enter = hwMillis(); - while (hwMillis() - enter < 2); + while (hwMillis() - enter < 2) {} if (digitalRead(MY_NODE_UNLOCK_PIN) == 0) { // Pin is grounded, reset lock counter hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, MY_NODE_LOCK_COUNTER_MAX); @@ -224,9 +225,9 @@ void presentNode(void) { #endif - if (presentation) + if (presentation) { presentation(); - + } } @@ -299,8 +300,12 @@ bool present(const uint8_t childSensorId, const uint8_t sensorType, const char * bool sendSketchInfo(const char *name, const char *version, const bool ack) { bool result = true; - if (name) result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME, ack).set(name)); - if (version) result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION, ack).set(version)); + if (name) { + result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME, ack).set(name)); + } + if (version) { + result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION, ack).set(version)); + } return result; } @@ -345,8 +350,9 @@ bool _processInternalMessages(void) { } else if (type == I_TIME) { // Deliver time to callback - if (receiveTime) + if (receiveTime) { receiveTime(_msg.getULong()); + } } else if (type == I_CHILDREN) { #if defined(MY_REPEATER_FEATURE) @@ -385,7 +391,9 @@ bool _processInternalMessages(void) { } else if (debug_msg == 'E') { // clear MySensors eeprom area and reboot (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG).set("OK")); - for (int i = EEPROM_START; i= MY_CORE_MIN_VERSION); #endif - + #if (F_CPU>16000000) // delay for fast GW and slow nodes delay(5); diff --git a/core/MySigningAtsha204.cpp b/core/MySigningAtsha204.cpp index 94dd91a88..3b53069fa 100644 --- a/core/MySigningAtsha204.cpp +++ b/core/MySigningAtsha204.cpp @@ -52,10 +52,12 @@ static uint8_t* signerSha256(const uint8_t* data, size_t sz); static char i2h(uint8_t i) { uint8_t k = i & 0x0F; - if (k <= 9) + if (k <= 9) { return '0' + k; - else + } + else { return 'A' + k - 10; + } } static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, uint8_t sz) { @@ -98,7 +100,7 @@ bool signerAtsha204CheckTimer(void) { memset(_signing_signing_nonce, 0x00, NONCE_NUMIN_SIZE_PASSTHROUGH); memset(_signing_verifying_nonce, 0x00, NONCE_NUMIN_SIZE_PASSTHROUGH); _signing_verification_ongoing = false; - return false; + return false; } } return true; @@ -132,7 +134,9 @@ bool signerAtsha204GetNonce(MyMessage &msg) { // Be a little fancy to handle turnover (prolong the time allowed to timeout after turnover) // Note that if message is "too" quick, and arrives before turnover, it will be rejected // but this is consider such a rare case that it is accepted and rejects are 'safe' - if (_signing_timestamp + MY_VERIFICATION_TIMEOUT_MS < hwMillis()) _signing_timestamp = 0; + if (_signing_timestamp + MY_VERIFICATION_TIMEOUT_MS < hwMillis()) { + _signing_timestamp = 0; + } return true; } @@ -148,7 +152,7 @@ bool signerAtsha204SignMsg(MyMessage &msg) { // If we cannot fit any signature in the message, refuse to sign it if (mGetLength(msg) > MAX_PAYLOAD-2) { DEBUG_SIGNING_PRINTBUF(F("Message too large"), NULL, 0); - return false; + return false; } // Calculate signature of message @@ -180,18 +184,18 @@ bool signerAtsha204SignMsg(MyMessage &msg) { bool signerAtsha204VerifyMsg(MyMessage &msg) { if (!_signing_verification_ongoing) { DEBUG_SIGNING_PRINTBUF(F("No active verification session"), NULL, 0); - return false; + return false; } else { // Make sure we have not expired if (!signerCheckTimer()) { - return false; + return false; } _signing_verification_ongoing = false; if (msg.data[mGetLength(msg)] != SIGNING_IDENTIFIER) { DEBUG_SIGNING_PRINTBUF(F("Incorrect signing identifier"), NULL, 0); - return false; + return false; } DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)], MAX_PAYLOAD-mGetLength(msg)); @@ -230,7 +234,7 @@ bool signerAtsha204VerifyMsg(MyMessage &msg) { #ifdef MY_SIGNING_NODE_WHITELISTING DEBUG_SIGNING_PRINTBUF(F("Is the sender whitelisted and serial correct?"), NULL, 0); #endif - return false; + return false; } else { DEBUG_SIGNING_PRINTBUF(F("Signature OK"), NULL, 0); return true; diff --git a/core/MySigningAtsha204Soft.cpp b/core/MySigningAtsha204Soft.cpp index 740db9dae..3c0b4b5e2 100644 --- a/core/MySigningAtsha204Soft.cpp +++ b/core/MySigningAtsha204Soft.cpp @@ -56,10 +56,12 @@ static void signerCalculateSignature(MyMessage &msg, bool signing); static char i2h(uint8_t i) { uint8_t k = i & 0x0F; - if (k <= 9) + if (k <= 9) { return '0' + k; - else + } + else { return 'A' + k - 10; + } } static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, uint8_t sz) { @@ -106,7 +108,7 @@ bool signerAtsha204SoftCheckTimer(void) { memset(_signing_signing_nonce, 0xAA, 32); memset(_signing_verifying_nonce, 0xAA, 32); _signing_verification_ongoing = false; - return false; + return false; } } return true; @@ -115,7 +117,7 @@ bool signerAtsha204SoftCheckTimer(void) { bool signerAtsha204SoftGetNonce(MyMessage &msg) { DEBUG_SIGNING_PRINTBUF(F("Signing backend: ATSHA204Soft"), NULL, 0); - // We used a basic whitening technique that XORs a random byte with the current hwMillis() counter and then the byte is + // We used a basic whitening technique that XORs a random byte with the current hwMillis() counter and then the byte is // hashed (SHA256) to produce the resulting nonce _signing_sha256.init(); for (int i = 0; i < 32; i++) { @@ -134,7 +136,9 @@ bool signerAtsha204SoftGetNonce(MyMessage &msg) { // Be a little fancy to handle turnover (prolong the time allowed to timeout after turnover) // Note that if message is "too" quick, and arrives before turnover, it will be rejected // but this is consider such a rare case that it is accepted and rejects are 'safe' - if (_signing_timestamp + MY_VERIFICATION_TIMEOUT_MS < hwMillis()) _signing_timestamp = 0; + if (_signing_timestamp + MY_VERIFICATION_TIMEOUT_MS < hwMillis()) { + _signing_timestamp = 0; + } return true; } @@ -150,7 +154,7 @@ bool signerAtsha204SoftSignMsg(MyMessage &msg) { // If we cannot fit any signature in the message, refuse to sign it if (mGetLength(msg) > MAX_PAYLOAD-2) { DEBUG_SIGNING_PRINTBUF(F("Message too large"), NULL, 0); - return false; + return false; } // Calculate signature of message @@ -160,9 +164,13 @@ bool signerAtsha204SoftSignMsg(MyMessage &msg) { if (DO_WHITELIST(msg.destination)) { // Salt the signature with the senders nodeId and the (hopefully) unique serial The Creator has provided _signing_sha256.init(); - for (int i=0; i<32; i++) _signing_sha256.write(_signing_hmac[i]); + for (int i=0; i<32; i++) { + _signing_sha256.write(_signing_hmac[i]); + } _signing_sha256.write(msg.sender); - for (int i=0; i MY_TRANSPORT_STATE_TIMEOUT_MS) { // timeout @@ -261,7 +261,7 @@ void stReadyTransition(void) { // stReadyUpdate: monitors link void stReadyUpdate(void) { - #if defined(MY_GATEWAY_FEATURE) + #if defined(MY_GATEWAY_FEATURE) if (hwMillis() - _lastNetworkDiscovery > MY_TRANSPORT_DISCOVERY_INTERVAL_MS) { _lastNetworkDiscovery = hwMillis(); TRANSPORT_DEBUG(PSTR("TSM:READY:NWD REQ\n")); // send transport network discovery @@ -319,7 +319,9 @@ void transportSwitchSM(transportState& newState) { else { _transportSM.stateRetries++; // increment retries } - if (_transportSM.currentState->Transition) _transportSM.currentState->Transition(); // State transition + if (_transportSM.currentState->Transition) { + _transportSM.currentState->Transition(); // State transition + } _transportSM.stateEnter = hwMillis(); // save time } @@ -328,7 +330,9 @@ uint32_t transportTimeInState(void) { } void transportUpdateSM(void) { - if (_transportSM.currentState->Update) _transportSM.currentState->Update(); + if (_transportSM.currentState->Update) { + _transportSM.currentState->Update(); + } } bool isTransportReady(void) { @@ -363,7 +367,7 @@ void transportInitialise(void) { // update TSM and process incoming messages void transportProcess(void) { // update state machine - transportUpdateSM(); + transportUpdateSM(); // process transport FIFO transportProcessFIFO(); } @@ -415,7 +419,7 @@ bool transportAssignNodeID(const uint8_t newNodeId) { bool transportRouteMessage(MyMessage &message) { const uint8_t destination = message.destination; uint8_t route = _nc.parentNodeId; // by default, all traffic is routed via parent node - + if (_transportSM.findingParentNode && destination != BROADCAST_ADDRESS) { TRANSPORT_DEBUG(PSTR("!TSF:RTE:FPAR ACTIVE\n")); // find parent active, message not sent // request to send a non-BC message while finding parent active, abort @@ -438,7 +442,7 @@ bool transportRouteMessage(MyMessage &message) { if (message.last != _nc.parentNodeId) { // message not from parent, i.e. child node - route it to parent route = _nc.parentNodeId; - } + } else { // route unknown and msg received from parent, send it to destination assuming in rx radius route = destination; @@ -464,7 +468,9 @@ bool transportRouteMessage(MyMessage &message) { else _transportSM.failedUplinkTransmissions = 0u; } #else - if(!result) setIndication(INDICATION_ERR_TX); + if(!result) { + setIndication(INDICATION_ERR_TX); + } #endif return result; @@ -532,7 +538,7 @@ void transportProcessMessage(void) { setIndication(INDICATION_RX); const uint8_t payloadLength = transportReceive((uint8_t *)&_msg); // get message length and limit size - const uint8_t msgLength = min(mGetLength(_msg), (uint8_t)MAX_PAYLOAD); + const uint8_t msgLength = min(mGetLength(_msg), (uint8_t)MAX_PAYLOAD); // calculate expected length const uint8_t expectedMessageLength = HEADER_SIZE + (mGetSigned(_msg) ? MAX_PAYLOAD : msgLength); const uint8_t command = mGetCommand(_msg); @@ -557,12 +563,12 @@ void transportProcessMessage(void) { TRANSPORT_DEBUG(PSTR("!TSF:MSG:PVER,%d=%d\n"), mGetVersion(_msg), PROTOCOL_VERSION); // protocol version mismatch return; } - + // Reject messages that do not pass verification if (!signerVerifyMsg(_msg)) { setIndication(INDICATION_ERR_SIGN); TRANSPORT_DEBUG(PSTR("!TSF:MSG:SIGN VERIFY FAIL\n")); - return; + return; } // update routing table if msg not from parent @@ -580,7 +586,7 @@ void transportProcessMessage(void) { // set message received flag _transportSM.msgReceived = true; - + // Is message addressed to this node? if (destination == _nc.nodeId) { // prevent buffer overflow by limiting max. possible message length (5 bits=31 bytes max) to MAX_PAYLOAD (25 bytes) @@ -590,14 +596,14 @@ void transportProcessMessage(void) { // Check if sender requests an ack back. if (mGetRequestAck(_msg)) { TRANSPORT_DEBUG(PSTR("TSF:MSG:ACK REQ\n")); // ACK requested - _msgTmp = _msg; // Copy message + _msgTmp = _msg; // Copy message mSetRequestAck(_msgTmp, false); // Reply without ack flag (otherwise we would end up in an eternal loop) mSetAck(_msgTmp, true); // set ACK flag _msgTmp.sender = _nc.nodeId; _msgTmp.destination = sender; // send ACK, use transportSendRoute since ACK reply is not internal, i.e. if !transportOK do not reply (void)transportSendRoute(_msgTmp); - } + } if(!mGetAck(_msg)) { // only process if not ACK if (command == C_INTERNAL) { @@ -683,7 +689,7 @@ void transportProcessMessage(void) { if (receive) { receive(_msg); } - } + } else if (destination == BROADCAST_ADDRESS) { TRANSPORT_DEBUG(PSTR("TSF:MSG:BC\n")); // broadcast msg if (command == C_INTERNAL) { @@ -707,7 +713,7 @@ void transportProcessMessage(void) { } } #endif - return; // no further processing required, do not forward + return; // no further processing required, do not forward } } // isTransportReady if (type == I_FIND_PARENT_RESPONSE) { @@ -732,12 +738,14 @@ void transportProcessMessage(void) { (void)transportRouteMessage(_msg); } #endif - + // Callback for BC, only for non-internal messages if (command != C_INTERNAL) { #if !defined(MY_GATEWAY_FEATURE) // only proceed if message received from parent - if (last != _nc.parentNodeId) return; + if (last != _nc.parentNodeId) { + return; + } #endif #if defined(MY_GATEWAY_FEATURE) // Hand over message to controller @@ -747,10 +755,10 @@ void transportProcessMessage(void) { receive(_msg); } } - - } + + } else { - // msg not to us and not BC, relay msg + // msg not to us and not BC, relay msg #if defined(MY_REPEATER_FEATURE) if (isTransportReady()) { TRANSPORT_DEBUG(PSTR("TSF:MSG:REL MSG\n")); // relay msg @@ -817,7 +825,7 @@ bool transportSendWrite(const uint8_t to, MyMessage &message) { setIndication(INDICATION_ERR_SIGN); return false; } - + // msg length changes if signed const uint8_t totalMsgLength = HEADER_SIZE + ( mGetSigned(message) ? MAX_PAYLOAD : mGetLength(message) ); @@ -873,6 +881,3 @@ uint8_t transportGetRoute(const uint8_t node) { #endif return result; } - - -// EOF MyTransport.cpp \ No newline at end of file diff --git a/core/MyTransportRS485.cpp b/core/MyTransportRS485.cpp index 92a140c08..a7990ae1b 100644 --- a/core/MyTransportRS485.cpp +++ b/core/MyTransportRS485.cpp @@ -125,7 +125,9 @@ bool _serialProcess() { char inch; unsigned char i; - if (!_dev.available()) return false; + if (!_dev.available()) { + return false; + } while(_dev.available()) { inch = _dev.read(); @@ -263,7 +265,9 @@ bool transportSend(uint8_t to, const void* data, uint8_t len) #endif // Start of header by writing multiple SOH - for(byte w=0;w<1;w++) _dev.write(SOH); + for(byte w=0;w<1;w++) { + _dev.write(SOH); + } _dev.write(to); // Destination address cs += to; _dev.write(_nodeId); // Source address @@ -351,5 +355,3 @@ uint8_t transportReceive(void* data) { void transportPowerDown() { // Nothing to shut down here } - - diff --git a/core/Version.h b/core/Version.h index e91949fe7..b279f564d 100644 --- a/core/Version.h +++ b/core/Version.h @@ -1,3 +1,21 @@ +/** + * 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. + */ /*** * This file defines the Sensor library version number * Normally, contributors should not modify this directly diff --git a/drivers/AES/AES.cpp b/drivers/AES/AES.cpp index cd5d3067f..02fbfd8d7 100644 --- a/drivers/AES/AES.cpp +++ b/drivers/AES/AES.cpp @@ -36,13 +36,13 @@ /* This version derived by Mark Tillotson 2012-01-23, tidied up, slimmed down and tailored to 8-bit microcontroller abilities and Arduino datatypes. - The s-box and inverse s-box were retained as tables (0.5kB PROGMEM) but all - the other transformations are coded to save table space. Many efficiency + The s-box and inverse s-box were retained as tables (0.5kB PROGMEM) but all + the other transformations are coded to save table space. Many efficiency improvments to the routines mix_sub_columns() and inv_mix_sub_columns() (mainly common sub-expression elimination). Only the routines with precalculated subkey schedule are retained (together - with set_key() - this does however mean each AES object takes 240 bytes of + with set_key() - this does however mean each AES object takes 240 bytes of RAM, alas) The CBC routines side-effect the iv argument (so that successive calls work @@ -218,7 +218,7 @@ static void inv_mix_sub_columns (byte dt[N_BLOCK], byte st[N_BLOCK]) byte a8 = f2(a4), b8 = f2(b4), c8 = f2(c4), d8 = f2(d4) ; byte a9 = a8 ^ a1,b9 = b8 ^ b1,c9 = c8 ^ c1,d9 = d8 ^ d1 ; byte ac = a8 ^ a4,bc = b8 ^ b4,cc = c8 ^ c4,dc = d8 ^ d4 ; - + dt[i] = is_box (ac^a2 ^ b9^b2 ^ cc^c1 ^ d9) ; dt[(i+5)&15] = is_box (a9 ^ bc^b2 ^ c9^c2 ^ dc^d1) ; dt[(i+10)&15] = is_box (ac^a1 ^ b9 ^ cc^c2 ^ d9^d2) ; @@ -257,32 +257,33 @@ byte AES::set_key (byte key [], int keylen) switch (keylen) { case 16: - case 128: + case 128: keylen = 16; // 10 rounds round = 10 ; break; case 24: - case 192: + case 192: keylen = 24; // 12 rounds round = 12 ; break; case 32: - case 256: + case 256: keylen = 32; // 14 rounds round = 14 ; break; - default: - round = 0; + default: + round = 0; return AES_FAILURE; } hi = (round + 1) << 4 ; copy_n_bytes (key_sched, key, keylen) ; byte t[4] ; byte next = keylen ; - for (byte cc = keylen, rc = 1 ; cc < hi ; cc += N_COL) + for (byte cc = keylen, rc = 1 ; cc < hi ; cc += N_COL) { - for (byte i = 0 ; i < N_COL ; i++) + for (byte i = 0 ; i < N_COL ; i++) { t[i] = key_sched [cc-4+i] ; + } if (cc == next) { next += keylen ; @@ -295,12 +296,14 @@ byte AES::set_key (byte key [], int keylen) } else if (keylen == 32 && (cc & 31) == 16) { - for (byte i = 0 ; i < 4 ; i++) + for (byte i = 0 ; i < 4 ; i++) { t[i] = s_box (t[i]) ; + } } byte tt = cc - keylen ; - for (byte i = 0 ; i < N_COL ; i++) + for (byte i = 0 ; i < N_COL ; i++) { key_sched [cc + i] = key_sched [tt + i] ^ t[i] ; + } } return AES_SUCCESS ; } @@ -309,8 +312,9 @@ byte AES::set_key (byte key [], int keylen) void AES::clean () { - for (byte i = 0 ; i < KEY_SCHEDULE_BYTES ; i++) + for (byte i = 0 ; i < KEY_SCHEDULE_BYTES ; i++) { key_sched [i] = 0 ; + } round = 0 ; } @@ -340,7 +344,7 @@ byte AES::encrypt (byte plain [N_BLOCK], byte cipher [N_BLOCK]) copy_and_key (s1, plain, (byte*) (key_sched)) ; for (r = 1 ; r < round ; r++) - { + { byte s2 [N_BLOCK] ; mix_sub_columns (s2, s1) ; copy_and_key (s1, s2, (byte*) (key_sched + r * N_BLOCK)) ; @@ -360,8 +364,9 @@ byte AES::cbc_encrypt (byte * plain, byte * cipher, int n_block, byte iv [N_BLOC while (n_block--) { xor_block (iv, plain) ; - if (encrypt (iv, iv) != AES_SUCCESS) + if (encrypt (iv, iv) != AES_SUCCESS) { return AES_FAILURE ; + } copy_n_bytes (cipher, iv, N_BLOCK) ; plain += N_BLOCK ; cipher += N_BLOCK ; @@ -376,8 +381,9 @@ byte AES::cbc_encrypt (byte * plain, byte * cipher, int n_block) while (n_block--) { xor_block (iv, plain) ; - if (encrypt (iv, iv) != AES_SUCCESS) + if (encrypt (iv, iv) != AES_SUCCESS) { return AES_FAILURE ; + } copy_n_bytes (cipher, iv, N_BLOCK) ; plain += N_BLOCK ; cipher += N_BLOCK ; @@ -411,13 +417,14 @@ byte AES::decrypt (byte plain [N_BLOCK], byte cipher [N_BLOCK]) /******************************************************************************/ byte AES::cbc_decrypt (byte * cipher, byte * plain, int n_block, byte iv [N_BLOCK]) -{ +{ while (n_block--) { byte tmp [N_BLOCK] ; copy_n_bytes (tmp, cipher, N_BLOCK) ; - if (decrypt (cipher, plain) != AES_SUCCESS) + if (decrypt (cipher, plain) != AES_SUCCESS) { return AES_FAILURE ; + } xor_block (plain, iv) ; copy_n_bytes (iv, tmp, N_BLOCK) ; plain += N_BLOCK ; @@ -429,13 +436,14 @@ byte AES::cbc_decrypt (byte * cipher, byte * plain, int n_block, byte iv [N_BLOC /******************************************************************************/ byte AES::cbc_decrypt (byte * cipher, byte * plain, int n_block) -{ +{ while (n_block--) { byte tmp [N_BLOCK] ; copy_n_bytes (tmp, cipher, N_BLOCK) ; - if (decrypt (cipher, plain) != AES_SUCCESS) + if (decrypt (cipher, plain) != AES_SUCCESS) { return AES_FAILURE ; + } xor_block (plain, iv) ; copy_n_bytes (iv, tmp, N_BLOCK) ; plain += N_BLOCK ; @@ -505,7 +513,7 @@ void AES::padPlaintext(void* in,byte* out) /******************************************************************************/ bool AES::CheckPad(byte* in,int lsize){ - if (in[lsize-1] <= 0x0f){ + if (in[lsize-1] <= 0x0f){ int lpad = (int)in[lsize-1]; for (int i = lsize - 1; i >= lsize-lpad; i--){ if (arr_pad[lpad - 1] != in[i]){ diff --git a/drivers/ATSHA204/ATSHA204.cpp b/drivers/ATSHA204/ATSHA204.cpp index 0c7de2352..ff7d250a7 100644 --- a/drivers/ATSHA204/ATSHA204.cpp +++ b/drivers/ATSHA204/ATSHA204.cpp @@ -24,10 +24,12 @@ static void swi_set_signal_pin(uint8_t is_high) { SHA204_SET_OUTPUT(); - if (is_high) - SHA204_POUT_HIGH(); - else - SHA204_POUT_LOW(); + if (is_high) { + SHA204_POUT_HIGH(); + } + else { + SHA204_POUT_LOW(); + } } static uint8_t swi_send_bytes(uint8_t count, uint8_t *buffer) @@ -109,8 +111,9 @@ static uint8_t swi_receive_bytes(uint8_t count, uint8_t *buffer) while (--timeout_count > 0) { // Wait for falling edge. - if (SHA204_PIN_READ() == 0) + if (SHA204_PIN_READ() == 0) { break; + } } if (timeout_count == 0) @@ -159,8 +162,9 @@ static uint8_t swi_receive_bytes(uint8_t count, uint8_t *buffer) { do { - if (SHA204_PIN_READ() != 0) + if (SHA204_PIN_READ() != 0) { break; + } } while (timeout_count-- > 0); } @@ -169,16 +173,18 @@ static uint8_t swi_receive_bytes(uint8_t count, uint8_t *buffer) buffer[i] |= bit_mask; // received "one" bit } - if (status != SWI_FUNCTION_RETCODE_SUCCESS) + if (status != SWI_FUNCTION_RETCODE_SUCCESS) { break; + } } interrupts(); //swi_enable_interrupts(); if (status == SWI_FUNCTION_RETCODE_TIMEOUT) { - if (i > 0) - // Indicate that we timed out after having received at least one byte. - status = SWI_FUNCTION_RETCODE_RX_FAIL; + if (i > 0) { + // Indicate that we timed out after having received at least one byte. + status = SWI_FUNCTION_RETCODE_RX_FAIL; + } } return status; } @@ -191,8 +197,9 @@ static uint8_t sha204p_receive_response(uint8_t size, uint8_t *response) uint8_t i; uint8_t ret_code; - for (i = 0; i < size; i++) + for (i = 0; i < size; i++) { response[i] = 0; + } (void) swi_send_byte(SHA204_SWI_FLAG_TX); @@ -200,8 +207,9 @@ static uint8_t sha204p_receive_response(uint8_t size, uint8_t *response) if (ret_code == SWI_FUNCTION_RETCODE_SUCCESS || ret_code == SWI_FUNCTION_RETCODE_RX_FAIL) { count_byte = response[SHA204_BUFFER_POS_COUNT]; - if ((count_byte < SHA204_RSP_SIZE_MIN) || (count_byte > size)) + if ((count_byte < SHA204_RSP_SIZE_MIN) || (count_byte > size)) { return SHA204_INVALID_SIZE; + } return SHA204_SUCCESS; } @@ -209,10 +217,12 @@ static uint8_t sha204p_receive_response(uint8_t size, uint8_t *response) // Translate error so that the Communication layer // can distinguish between a real error or the // device being busy executing a command. - if (ret_code == SWI_FUNCTION_RETCODE_TIMEOUT) + if (ret_code == SWI_FUNCTION_RETCODE_TIMEOUT) { return SHA204_RX_NO_RESPONSE; - else + } + else { return SHA204_RX_FAIL; + } } /* Communication functions */ @@ -223,8 +233,9 @@ static uint8_t sha204c_resync(uint8_t size, uint8_t *response) // (step 1 of the re-synchronization process). delay(SHA204_SYNC_TIMEOUT); uint8_t ret_code = sha204p_receive_response(size, response); - if (ret_code == SHA204_SUCCESS) + if (ret_code == SHA204_SUCCESS) { return ret_code; + } // We lost communication. Send a Wake pulse and try // to receive a response (steps 2 and 3 of the @@ -261,17 +272,21 @@ static uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uin { // Send command. ret_code = swi_send_byte(SHA204_SWI_FLAG_CMD); - if (ret_code != SWI_FUNCTION_RETCODE_SUCCESS) + if (ret_code != SWI_FUNCTION_RETCODE_SUCCESS) { ret_code = SHA204_COMM_FAIL; - else + } + else { ret_code = swi_send_bytes(count, tx_buffer); + } if (ret_code != SHA204_SUCCESS) { - if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE) + if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE) { return ret_code; // The device seems to be dead in the water. - else + } + else { continue; + } } // Wait minimum command execution time and then start polling for a response. @@ -282,8 +297,9 @@ static uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uin while (n_retries_receive-- > 0) { // Reset response buffer. - for (i = 0; i < rx_size; i++) + for (i = 0; i < rx_size; i++) { rx_buffer[i] = 0; + } // Poll for response. timeout_countdown = execution_timeout_us; @@ -297,11 +313,13 @@ static uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uin if (ret_code == SHA204_RX_NO_RESPONSE) { // We did not receive a response. Re-synchronize and send command again. - if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE) + if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE) { // The device seems to be dead in the water. return ret_code; - else + } + else { break; + } } // Check whether we received a valid response. @@ -309,16 +327,19 @@ static uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uin { // We see 0xFF for the count when communication got out of sync. ret_code_resync = sha204c_resync(rx_size, rx_buffer); - if (ret_code_resync == SHA204_SUCCESS) + if (ret_code_resync == SHA204_SUCCESS) { // We did not have to wake up the device. Try receiving response again. continue; - if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP) + } + if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP) { // We could re-synchronize, but only after waking up the device. // Re-send command. break; - else + } + else { // We failed to re-synchronize. return ret_code; + } } // We received a response of valid size. @@ -327,19 +348,22 @@ static uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uin if (ret_code == SHA204_SUCCESS) { // Received valid response. - if (rx_buffer[SHA204_BUFFER_POS_COUNT] > SHA204_RSP_SIZE_MIN) + if (rx_buffer[SHA204_BUFFER_POS_COUNT] > SHA204_RSP_SIZE_MIN) { // Received non-status response. We are done. return ret_code; + } // Received status response. status_byte = rx_buffer[SHA204_BUFFER_POS_STATUS]; // Translate the three possible device status error codes // into library return codes. - if (status_byte == SHA204_STATUS_BYTE_PARSE) + if (status_byte == SHA204_STATUS_BYTE_PARSE) { return SHA204_PARSE_ERROR; - if (status_byte == SHA204_STATUS_BYTE_EXEC) + } + if (status_byte == SHA204_STATUS_BYTE_EXEC) { return SHA204_CMD_FAIL; + } if (status_byte == SHA204_STATUS_BYTE_COMM) { // In case of the device status byte indicating a communication @@ -359,16 +383,19 @@ static uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uin { // Received response with incorrect CRC. ret_code_resync = sha204c_resync(rx_size, rx_buffer); - if (ret_code_resync == SHA204_SUCCESS) + if (ret_code_resync == SHA204_SUCCESS) { // We did not have to wake up the device. Try receiving response again. continue; - if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP) + } + if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP) { // We could re-synchronize, but only after waking up the device. // Re-send command. break; - else + } + else { // We failed to re-synchronize. return ret_code; + } } // block end of check response consistency } // block end of receive retry loop @@ -418,8 +445,9 @@ static void sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc) // Shift CRC to the left by 1. crc_register <<= 1; - if ((data_bit ^ crc_bit) != 0) + if ((data_bit ^ crc_bit) != 0) { crc_register ^= polynom; + } } } crc[0] = (uint8_t) (crc_register & 0x00FF); @@ -475,22 +503,27 @@ uint8_t atsha204_wakeup(uint8_t *response) delay(SHA204_WAKEUP_DELAY); uint8_t ret_code = sha204p_receive_response(SHA204_RSP_SIZE_MIN, response); - if (ret_code != SHA204_SUCCESS) + if (ret_code != SHA204_SUCCESS) { return ret_code; + } // Verify status response. - if (response[SHA204_BUFFER_POS_COUNT] != SHA204_RSP_SIZE_MIN) + if (response[SHA204_BUFFER_POS_COUNT] != SHA204_RSP_SIZE_MIN) { ret_code = SHA204_INVALID_SIZE; - else if (response[SHA204_BUFFER_POS_STATUS] != SHA204_STATUS_BYTE_WAKEUP) + } + else if (response[SHA204_BUFFER_POS_STATUS] != SHA204_STATUS_BYTE_WAKEUP) { ret_code = SHA204_COMM_FAIL; + } else { if ((response[SHA204_RSP_SIZE_MIN - SHA204_CRC_SIZE] != 0x33) - || (response[SHA204_RSP_SIZE_MIN + 1 - SHA204_CRC_SIZE] != 0x43)) + || (response[SHA204_RSP_SIZE_MIN + 1 - SHA204_CRC_SIZE] != 0x43)) { ret_code = SHA204_BAD_CRC; + } } - if (ret_code != SHA204_SUCCESS) + if (ret_code != SHA204_SUCCESS) { delay(SHA204_COMMAND_EXEC_MAX); + } return ret_code; } @@ -580,14 +613,16 @@ uint8_t atsha204_getSerialNumber(uint8_t * response) uint8_t returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN03); if (!returnCode) { - for (int i=0; i<4; i++) // store bytes 0-3 into respones array - response[i] = readResponse[SHA204_BUFFER_POS_DATA+i]; + for (int i=0; i<4; i++) {// store bytes 0-3 into respones array + response[i] = readResponse[SHA204_BUFFER_POS_DATA+i]; + } /* read from bytes 8->11 of config zone */ returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN47); - for (int i=4; i<8; i++) // store bytes 4-7 of SN into response array + for (int i=4; i<8; i++) {// store bytes 4-7 of SN into response array response[i] = readResponse[SHA204_BUFFER_POS_DATA+(i-4)]; + } if (!returnCode) { /* Finally if last two reads were successful, read byte 8 of the SN */ diff --git a/drivers/ATSHA204/sha256.cpp b/drivers/ATSHA204/sha256.cpp index 511d78a97..ac89f8e76 100644 --- a/drivers/ATSHA204/sha256.cpp +++ b/drivers/ATSHA204/sha256.cpp @@ -54,7 +54,7 @@ void Sha256Class::hashBlock() { f=state.w[5]; g=state.w[6]; h=state.w[7]; - + for (i=0; i<64; i++) { if (i>=16) { t1 = buffer.w[i&15] + buffer.w[(i-7)&15]; @@ -102,7 +102,9 @@ void Sha256Class::pad() { // Pad with 0x80 followed by 0x00 until the end of the block addUncounted(0x80); - while (bufferOffset != 56) addUncounted(0x00); + while (bufferOffset != 56) { + addUncounted(0x00); + } // Append length in the last 8 bytes addUncounted(0); // We're only using 32 bit lengths @@ -119,7 +121,7 @@ void Sha256Class::pad() { uint8_t* Sha256Class::result(void) { // Pad to complete the last block pad(); - + // Swap byte order back for (int i=0; i<8; i++) { uint32_t a,b; @@ -130,7 +132,7 @@ uint8_t* Sha256Class::result(void) { b|=a>>24; state.w[i]=b; } - + // Return pointer to hash (20 characters) return state.b; } @@ -147,7 +149,9 @@ void Sha256Class::initHmac(const uint8_t* key, int keyLength) { if (keyLength > BLOCK_LENGTH) { // Hash long keys init(); - for (;keyLength--;) write(*key++); + for (;keyLength--;) { + write(*key++); + } memcpy(keyBuffer,result(),HASH_LENGTH); } else { // Block length keys are used as is @@ -166,7 +170,11 @@ uint8_t* Sha256Class::resultHmac(void) { memcpy(innerHash,result(),HASH_LENGTH); // Calculate outer hash init(); - for (i=0; i= TX_BUFFER_SIZE) head = 0; - while (tx_buffer_tail == head) ; // wait until space in buffer + if (head >= TX_BUFFER_SIZE) { + head = 0; + } + while (tx_buffer_tail == head) {} // wait until space in buffer intr_state = SREG; cli(); if (tx_state) { @@ -168,7 +170,9 @@ ISR(COMPARE_A_INTERRUPT) DISABLE_INT_COMPARE_A(); } else { tx_state = 1; - if (++tail >= TX_BUFFER_SIZE) tail = 0; + if (++tail >= TX_BUFFER_SIZE) { + tail = 0; + } tx_buffer_tail = tail; tx_byte = tx_buffer[tail]; tx_bit = 0; @@ -180,7 +184,7 @@ ISR(COMPARE_A_INTERRUPT) void AltSoftSerial::flushOutput(void) { - while (tx_state) /* wait */ ; + while (tx_state) {}/* wait */ } @@ -216,14 +220,18 @@ ISR(CAPTURE_INTERRUPT) target = rx_target; while (1) { offset = capture - target; - if (offset < 0) break; + if (offset < 0) { + break; + } rx_byte = (rx_byte >> 1) | rx_bit; target += ticks_per_bit; state++; if (state >= 9) { DISABLE_INT_COMPARE_B(); head = rx_buffer_head + 1; - if (head >= RX_BUFFER_SIZE) head = 0; + if (head >= RX_BUFFER_SIZE) { + head = 0; + } if (head != rx_buffer_tail) { rx_buffer[head] = rx_byte; rx_buffer_head = head; @@ -253,7 +261,9 @@ ISR(COMPARE_B_INTERRUPT) state++; } head = rx_buffer_head + 1; - if (head >= RX_BUFFER_SIZE) head = 0; + if (head >= RX_BUFFER_SIZE) { + head = 0; + } if (head != rx_buffer_tail) { rx_buffer[head] = rx_byte; rx_buffer_head = head; @@ -271,8 +281,12 @@ int AltSoftSerial::read(void) head = rx_buffer_head; tail = rx_buffer_tail; - if (head == tail) return -1; - if (++tail >= RX_BUFFER_SIZE) tail = 0; + if (head == tail) { + return -1; + } + if (++tail >= RX_BUFFER_SIZE) { + tail = 0; + } out = rx_buffer[tail]; rx_buffer_tail = tail; return out; @@ -284,7 +298,9 @@ int AltSoftSerial::peek(void) head = rx_buffer_head; tail = rx_buffer_tail; - if (head == tail) return -1; + if (head == tail) { + return -1; + } return rx_buffer[tail]; } @@ -294,7 +310,9 @@ int AltSoftSerial::available(void) head = rx_buffer_head; tail = rx_buffer_tail; - if (head >= tail) return head - tail; + if (head >= tail) { + return head - tail; + } return RX_BUFFER_SIZE + head - tail; } @@ -309,9 +327,14 @@ void ftm0_isr(void) { uint32_t flags = FTM0_STATUS; FTM0_STATUS = 0; - if (flags & (1<<5)) altss_capture_interrupt(); - if (flags & (1<<6)) altss_compare_a_interrupt(); - if (flags & (1<<0)) altss_compare_b_interrupt(); + if (flags & (1<<5)) { + altss_capture_interrupt(); + } + if (flags & (1<<6)) { + altss_compare_a_interrupt(); + } + if (flags & (1<<0)) { + altss_compare_b_interrupt(); + } } #endif - diff --git a/drivers/Linux/EthernetClient.cpp b/drivers/Linux/EthernetClient.cpp index 9a9e65b1e..718d47786 100644 --- a/drivers/Linux/EthernetClient.cpp +++ b/drivers/Linux/EthernetClient.cpp @@ -120,7 +120,9 @@ size_t EthernetClient::write(const uint8_t *buf, size_t size) { } size_t EthernetClient::write(const char *str) { - if (str == NULL) return 0; + if (str == NULL) { + return 0; + } return write((const uint8_t *)str, strlen(str)); } size_t EthernetClient::write(const char *buffer, size_t size) { @@ -165,8 +167,9 @@ void EthernetClient::flush() { } void EthernetClient::stop() { - if (_sock == -1) + if (_sock == -1) { return; + } // attempt to close the connection gracefully (send a FIN to other side) shutdown(_sock, SHUT_RDWR); @@ -178,21 +181,24 @@ void EthernetClient::stop() { uint8_t s; do { s = status(); - if (s == ETHERNETCLIENT_W5100_CLOSED) + if (s == ETHERNETCLIENT_W5100_CLOSED) { break; // exit the loop + } usleep(1000); gettimeofday(&curTime, NULL); } while (((curTime.tv_sec - startTime.tv_sec) * 1000000) + (curTime.tv_usec - startTime.tv_usec) < 1000000); // if it hasn't closed, close it forcefully - if (s != ETHERNETCLIENT_W5100_CLOSED) + if (s != ETHERNETCLIENT_W5100_CLOSED) { close(_sock); - + } _sock = -1; } uint8_t EthernetClient::status() { - if (_sock == -1) return ETHERNETCLIENT_W5100_CLOSED; + if (_sock == -1) { + return ETHERNETCLIENT_W5100_CLOSED; + } struct tcp_info tcp_info; int tcp_info_length = sizeof(tcp_info); @@ -227,8 +233,10 @@ uint8_t EthernetClient::status() { } uint8_t EthernetClient::connected() { - if (_sock == -1) return 0; - + if (_sock == -1) { + return 0; + } + if (peek() < 0) { if (errno == EAGAIN) { return 1; diff --git a/drivers/Linux/EthernetServer.cpp b/drivers/Linux/EthernetServer.cpp index 7ac89f485..9d0012c1b 100644 --- a/drivers/Linux/EthernetServer.cpp +++ b/drivers/Linux/EthernetServer.cpp @@ -151,7 +151,9 @@ size_t EthernetServer::write(const uint8_t *buffer, size_t size) size_t EthernetServer::write(const char *str) { - if (str == NULL) return 0; + if (str == NULL) { + return 0; + } return write((const uint8_t *)str, strlen(str)); } diff --git a/drivers/Linux/Print.cpp b/drivers/Linux/Print.cpp index 94eb81448..4c8d670a3 100644 --- a/drivers/Linux/Print.cpp +++ b/drivers/Linux/Print.cpp @@ -105,10 +105,12 @@ size_t Print::print(long n, int base) { } size_t Print::print(unsigned long n, int base) { - if(base == 0) + if(base == 0) { return write(n); - else + } + else { return printNumber(n, base); + } } size_t Print::print(double n, int digits) { @@ -182,8 +184,9 @@ size_t Print::printNumber(unsigned long n, uint8_t base) { *str = '\0'; // prevent crash if called with base == 1 - if(base < 2) + if(base < 2) { base = 10; + } do { unsigned long m = n; @@ -198,14 +201,18 @@ size_t Print::printNumber(unsigned long n, uint8_t base) { size_t Print::printFloat(double number, uint8_t digits) { size_t n = 0; - if(std::isnan(number)) + if(std::isnan(number)) { return print("nan"); - if(std::isinf(number)) + } + if(std::isinf(number)) { return print("inf"); - if(number > 4294967040.0) + } + if(number > 4294967040.0) { return print("ovf"); // constant determined empirically - if(number < -4294967040.0) + } + if(number < -4294967040.0) { return print("ovf"); // constant determined empirically + } // Handle negative numbers if(number < 0.0) { @@ -215,8 +222,9 @@ size_t Print::printFloat(double number, uint8_t digits) { // Round correctly so that print(1.999, 2) prints as "2.00" double rounding = 0.5; - for(uint8_t i = 0; i < digits; ++i) + for(uint8_t i = 0; i < digits; ++i) { rounding /= 10.0; + } number += rounding; diff --git a/drivers/Linux/SerialPort.cpp b/drivers/Linux/SerialPort.cpp index 79b8484c8..25082a122 100644 --- a/drivers/Linux/SerialPort.cpp +++ b/drivers/Linux/SerialPort.cpp @@ -212,7 +212,9 @@ int SerialPort::peek() { FILE * f = fdopen(sd, "r+"); int c = getc(f); - if (c == EOF) return -1; + if (c == EOF) { + return -1; + } ungetc(c, f); return c; } diff --git a/drivers/Linux/Stream.cpp b/drivers/Linux/Stream.cpp index 1817083fc..62f9f6162 100644 --- a/drivers/Linux/Stream.cpp +++ b/drivers/Linux/Stream.cpp @@ -33,8 +33,9 @@ int Stream::timedRead() { _startMillis = millis(); do { c = read(); - if(c >= 0) - return c; + if(c >= 0) { + return c; + } yield(); } while(millis() - _startMillis < _timeout); return -1; // -1 indicates timeout @@ -46,8 +47,9 @@ int Stream::timedPeek() { _startMillis = millis(); do { c = peek(); - if(c >= 0) + if(c >= 0) { return c; + } yield(); } while(millis() - _startMillis < _timeout); return -1; // -1 indicates timeout @@ -59,12 +61,15 @@ int Stream::peekNextDigit() { int c; while(1) { c = timedPeek(); - if(c < 0) + if(c < 0) { return c; // timeout - if(c == '-') + } + if(c == '-') { return c; - if(c >= '0' && c <= '9') + } + if(c >= '0' && c <= '9') { return c; + } read(); // discard non-numeric } } @@ -101,13 +106,14 @@ bool Stream::findUntil(const char *target, size_t targetLen, const char *termina size_t termIndex = 0; int c; - if(*target == 0) + if(*target == 0) { return true; // return true if target is a null string + } while((c = timedRead()) > 0) { - if(c != target[index]) + if(c != target[index]) { index = 0; // reset index if any char does not match - + } if(c == target[index]) { //////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1); if(++index >= targetLen) { // return true if all chars in the target match @@ -116,10 +122,12 @@ bool Stream::findUntil(const char *target, size_t targetLen, const char *termina } if(termLen > 0 && c == terminator[termIndex]) { - if(++termIndex >= termLen) + if(++termIndex >= termLen) { return false; // return false if terminate string found before target string - } else + } + } else { termIndex = 0; + } } return false; } @@ -140,22 +148,27 @@ long Stream::parseInt(char skipChar) { c = peekNextDigit(); // ignore non numeric leading characters - if(c < 0) + if(c < 0) { return 0; // zero returned if timeout + } do { - if(c == skipChar) - ; // ignore this charactor - else if(c == '-') + if(c == skipChar) { + // ignore this charactor + } + else if(c == '-') { isNegative = true; - else if(c >= '0' && c <= '9') // is c a digit? + } + else if(c >= '0' && c <= '9') { // is c a digit? value = value * 10 + c - '0'; + } read(); // consume the character we got with peek c = timedPeek(); } while((c >= '0' && c <= '9') || c == skipChar); - if(isNegative) + if(isNegative) { value = -value; + } return value; } @@ -175,31 +188,39 @@ float Stream::parseFloat(char skipChar) { c = peekNextDigit(); // ignore non numeric leading characters - if(c < 0) + if(c < 0) { return 0; // zero returned if timeout + } do { - if(c == skipChar) - ; // ignore - else if(c == '-') + if(c == skipChar) { + // ignore + } + else if(c == '-') { isNegative = true; - else if(c == '.') + } + else if(c == '.') { isFraction = true; + } else if(c >= '0' && c <= '9') { // is c a digit? value = value * 10 + c - '0'; - if(isFraction) + if(isFraction) { fraction *= 0.1; + } } read(); // consume the character we got with peek c = timedPeek(); } while((c >= '0' && c <= '9') || c == '.' || c == skipChar); - if(isNegative) + if(isNegative) { value = -value; - if(isFraction) + } + if(isFraction) { return value * fraction; - else + } + else { return value; + } } // read characters from stream into buffer @@ -211,8 +232,9 @@ size_t Stream::readBytes(char *buffer, size_t length) { size_t count = 0; while(count < length) { int c = timedRead(); - if(c < 0) + if(c < 0) { break; + } *buffer++ = (char) c; count++; } @@ -224,13 +246,15 @@ size_t Stream::readBytes(char *buffer, size_t length) { // returns the number of characters placed in the buffer (0 means no valid data found) size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) { - if(length < 1) + if(length < 1) { return 0; + } size_t index = 0; while(index < length) { int c = timedRead(); - if(c < 0 || c == terminator) + if(c < 0 || c == terminator) { break; + } *buffer++ = (char) c; index++; } diff --git a/drivers/Linux/noniso.cpp b/drivers/Linux/noniso.cpp index f628aa733..04ee6f3ed 100644 --- a/drivers/Linux/noniso.cpp +++ b/drivers/Linux/noniso.cpp @@ -1,14 +1,14 @@ /* noniso.cpp - replacements for non-ISO functions used by Arduino core Copyright © 2016 Ivan Grokhotkov - + Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - + The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. @@ -61,8 +61,9 @@ char* itoa(int value, char* result, int base) { } while(quotient); // Apply negative sign - if(value < 0) + if(value < 0) { *out++ = '-'; + } reverse(result, out); *out = 0; @@ -112,8 +113,9 @@ char* ltoa(long value, char* result, int base) { } while(quotient); // Apply negative sign - if(value < 0) + if(value < 0) { *out++ = '-'; + } reverse(result, out); *out = 0; diff --git a/drivers/PubSubClient/PubSubClient.cpp b/drivers/PubSubClient/PubSubClient.cpp index e66c9e09b..d4a86c54f 100644 --- a/drivers/PubSubClient/PubSubClient.cpp +++ b/drivers/PubSubClient/PubSubClient.cpp @@ -231,7 +231,9 @@ boolean PubSubClient::readByte(uint8_t * result, uint16_t * index){ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) { uint16_t len = 0; - if(!readByte(buffer, &len)) return 0; + if(!readByte(buffer, &len)) { + return 0; + } bool isPublish = (buffer[0]&0xF0) == MQTTPUBLISH; uint32_t multiplier = 1; uint16_t length = 0; @@ -240,7 +242,9 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) { uint8_t start = 0; do { - if(!readByte(&digit)) return 0; + if(!readByte(&digit)) { + return 0; + } buffer[len++] = digit; length += (digit & 127) * multiplier; multiplier *= 128; @@ -249,8 +253,12 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) { if (isPublish) { // Read in topic length to calculate bytes to skip over for Stream writing - if(!readByte(buffer, &len)) return 0; - if(!readByte(buffer, &len)) return 0; + if(!readByte(buffer, &len)) { + return 0; + } + if(!readByte(buffer, &len)) { + return 0; + } skip = (buffer[*lengthLength+1]<<8)+buffer[*lengthLength+2]; start = 2; if (buffer[0]&MQTTQOS1) { @@ -260,7 +268,9 @@ uint16_t PubSubClient::readPacket(uint8_t* lengthLength) { } for (uint16_t i = start;istream) { if (isPublish && len-*lengthLength-2>skip) { this->stream->write(digit); diff --git a/drivers/RF24/RF24.cpp b/drivers/RF24/RF24.cpp index 6f872e009..2a9d27fa6 100644 --- a/drivers/RF24/RF24.cpp +++ b/drivers/RF24/RF24.cpp @@ -71,7 +71,7 @@ LOCAL uint8_t RF24_spiMultiByteTransfer(uint8_t cmd, uint8_t* buf, uint8_t len, } else { status = *prx++; // status is 1st byte of receive buffer // decrement before to skip status byte - while (--size) { *buf++ = *prx++; } + while (--size) { *buf++ = *prx++; } } } else { status = *prx; // status is 1st byte of receive buffer @@ -79,9 +79,11 @@ LOCAL uint8_t RF24_spiMultiByteTransfer(uint8_t cmd, uint8_t* buf, uint8_t len, #else status = _SPI.transfer( cmd ); while ( len-- ) { - if (aReadMode) { + if (aReadMode) { status = _SPI.transfer( NOP ); - if (buf != NULL) *current++ = status; + if (buf != NULL) { + *current++ = status; + } } else status = _SPI.transfer(*current++); } #endif @@ -92,7 +94,7 @@ LOCAL uint8_t RF24_spiMultiByteTransfer(uint8_t cmd, uint8_t* buf, uint8_t len, // timing delayMicroseconds(10); return status; -} +} LOCAL uint8_t RF24_spiByteTransfer(uint8_t cmd) { return RF24_spiMultiByteTransfer( cmd, NULL, 0, false); @@ -182,8 +184,8 @@ LOCAL void RF24_enableFeatures(void) { RF24_RAW_writeByteRegister(ACTIVATE, 0x73); } -LOCAL void RF24_openWritingPipe(uint8_t recipient) { - RF24_DEBUG(PSTR("RF24:open writing pipe, recipient=%d\n"), recipient); +LOCAL void RF24_openWritingPipe(uint8_t recipient) { + RF24_DEBUG(PSTR("RF24:open writing pipe, recipient=%d\n"), recipient); // only write LSB of RX0 and TX pipe RF24_setPipeLSB(RX_ADDR_P0, recipient); RF24_setPipeLSB(TX_ADDR, recipient); @@ -191,10 +193,12 @@ LOCAL void RF24_openWritingPipe(uint8_t recipient) { LOCAL void RF24_startListening(void) { RF24_DEBUG(PSTR("RF24:start listening\n")); - // toggle PRX + // toggle PRX RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(PWR_UP) | _BV(PRIM_RX) ); // all RX pipe addresses must be unique, therefore skip if node ID is 0xFF - if(MY_RF24_NODE_ADDRESS!=AUTO) RF24_setPipeLSB(RX_ADDR_P0, MY_RF24_NODE_ADDRESS); + if(MY_RF24_NODE_ADDRESS!=AUTO) { + RF24_setPipeLSB(RX_ADDR_P0, MY_RF24_NODE_ADDRESS); + } // start listening RF24_ce(HIGH); } @@ -219,7 +223,7 @@ LOCAL bool RF24_sendMessage( uint8_t recipient, const void* buf, uint8_t len ) { uint8_t status; RF24_stopListening(); - RF24_openWritingPipe( recipient ); + RF24_openWritingPipe( recipient ); RF24_DEBUG(PSTR("RF24:send message to %d, len=%d\n"),recipient,len); // flush TX FIFO RF24_flushTX(); @@ -251,10 +255,10 @@ LOCAL bool RF24_sendMessage( uint8_t recipient, const void* buf, uint8_t len ) { LOCAL uint8_t RF24_getDynamicPayloadSize(void) { uint8_t result = RF24_spiMultiByteTransfer(R_RX_PL_WID, NULL, 1, true); // check if payload size invalid - if(result > 32) { + if(result > 32) { RF24_DEBUG(PSTR("RF24:invalid payload length = %d\n"),result); - RF24_flushRX(); - result = 0; + RF24_flushRX(); + result = 0; } return result; } @@ -267,7 +271,7 @@ LOCAL bool RF24_isDataAvailable() { LOCAL uint8_t RF24_readMessage( void* buf) { const uint8_t len = RF24_getDynamicPayloadSize(); RF24_DEBUG(PSTR("RF24:read message, len=%d\n"), len); - RF24_spiMultiByteTransfer( R_RX_PAYLOAD , (uint8_t*)buf, len, true ); + RF24_spiMultiByteTransfer( R_RX_PAYLOAD , (uint8_t*)buf, len, true ); // clear RX interrupt RF24_setStatus(_BV(RX_DR) ); return len; @@ -314,7 +318,7 @@ LOCAL void RF24_irqHandler( void ) // for a message we've already read. while (RF24_isDataAvailable()) { RF24_receiveCallback(); // Must call RF24_readMessage(), which will clear RX_DR IRQ ! - } + } // Restore our interrupt handler. #if defined(MY_GATEWAY_SERIAL) && !defined(__linux__) noInterrupts(); @@ -395,4 +399,3 @@ LOCAL bool RF24_initialize(void) { RF24_setStatus(_BV(TX_DS) | _BV(MAX_RT) | _BV(RX_DR)); return true; } - diff --git a/drivers/RFM69/RFM69.cpp b/drivers/RFM69/RFM69.cpp index b9bf7f9a7..f967c0929 100644 --- a/drivers/RFM69/RFM69.cpp +++ b/drivers/RFM69/RFM69.cpp @@ -6,23 +6,23 @@ // ********************************************************************************** // License // ********************************************************************************** -// This program is free software; you can redistribute it -// and/or modify it under the terms of the GNU General -// Public License as published by the Free Software -// Foundation; either version 3 of the License, or -// (at your option) any later version. -// -// This program 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 General Public -// License for more details. -// -// You should have received a copy of the GNU General +// This program is free software; you can redistribute it +// and/or modify it under the terms of the GNU General +// Public License as published by the Free Software +// Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public +// License for more details. +// +// You should have received a copy of the GNU General // Public License along with this program. // If not, see . -// -// Licence can be viewed at +// +// Licence can be viewed at // http://www.gnu.org/licenses/gpl-3.0.txt // // Please maintain this license information along with authorship @@ -93,17 +93,18 @@ bool RFM69::initialize(uint8_t freqBand, uint8_t nodeID, uint8_t networkID) unsigned long start = millis(); uint8_t timeout = 50; do { - writeReg(REG_SYNCVALUE1, 0xAA); + writeReg(REG_SYNCVALUE1, 0xAA); yield(); } while (readReg(REG_SYNCVALUE1) != 0xaa && millis()-start < timeout); start = millis(); do { - writeReg(REG_SYNCVALUE1, 0x55); + writeReg(REG_SYNCVALUE1, 0x55); yield(); } while (readReg(REG_SYNCVALUE1) != 0x55 && millis()-start < timeout); - for (uint8_t i = 0; CONFIG[i][0] != 255; i++) + for (uint8_t i = 0; CONFIG[i][0] != 255; i++) { writeReg(CONFIG[i][0], CONFIG[i][1]); + } // Encryption is persistent between resets and can trip you up during debugging. // Disable it during initialization so we always start from a known state. @@ -113,10 +114,11 @@ bool RFM69::initialize(uint8_t freqBand, uint8_t nodeID, uint8_t networkID) setMode(RF69_MODE_STANDBY); start = millis(); while (((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00) && millis()-start < timeout) { - yield(); + yield(); } // wait for ModeReady - if (millis()-start >= timeout) + if (millis()-start >= timeout) { return false; + } attachInterrupt(_interruptNum, RFM69::isr0, RISING); selfPointer = this; @@ -149,17 +151,22 @@ void RFM69::setFrequency(uint32_t freqHz) void RFM69::setMode(uint8_t newMode) { - if (newMode == _mode) + if (newMode == _mode) { return; + } switch (newMode) { case RF69_MODE_TX: writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_TRANSMITTER); - if (_isRFM69HW) setHighPowerRegs(true); + if (_isRFM69HW) { + setHighPowerRegs(true); + } break; case RF69_MODE_RX: writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_RECEIVER); - if (_isRFM69HW) setHighPowerRegs(false); + if (_isRFM69HW) { + setHighPowerRegs(false); + } break; case RF69_MODE_SYNTH: writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_SYNTHESIZER); @@ -209,7 +216,9 @@ void RFM69::setNetwork(uint8_t networkID) void RFM69::setPowerLevel(uint8_t powerLevel) { _powerLevel = (powerLevel > 31 ? 31 : powerLevel); - if (_isRFM69HW) _powerLevel /= 2; + if (_isRFM69HW) { + _powerLevel /= 2; + } writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0xE0) | _powerLevel); } @@ -227,7 +236,9 @@ void RFM69::send(uint8_t toAddress, const void* buffer, uint8_t bufferSize, bool { writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART); // avoid RX deadlocks uint32_t now = millis(); - while (!canSend() && millis() - now < RF69_CSMA_LIMIT_MS) receiveDone(); + while (!canSend() && millis() - now < RF69_CSMA_LIMIT_MS) { + receiveDone(); + } sendFrame(toAddress, buffer, bufferSize, requestACK, false); } @@ -258,8 +269,9 @@ bool RFM69::sendWithRetry(uint8_t toAddress, const void* buffer, uint8_t bufferS // should be polled immediately after sending a packet with ACK request bool RFM69::ACKReceived(uint8_t fromNodeID) { - if (receiveDone()) + if (receiveDone()) { return (SENDERID == fromNodeID || fromNodeID == RF69_BROADCAST_ADDR) && ACK_RECEIVED; + } return false; } @@ -287,21 +299,25 @@ void RFM69::sendACK(const void* buffer, uint8_t bufferSize) { void RFM69::interruptHook(uint8_t CTLbyte) { (void)CTLbyte; }; - + // internal function void RFM69::sendFrame(uint8_t toAddress, const void* buffer, uint8_t bufferSize, bool requestACK, bool sendACK) { setMode(RF69_MODE_STANDBY); // turn off receiver to prevent reception while filling fifo - while ((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // wait for ModeReady + while ((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00) {} // wait for ModeReady writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_00); // DIO0 is "Packet Sent" - if (bufferSize > RF69_MAX_DATA_LEN) bufferSize = RF69_MAX_DATA_LEN; + if (bufferSize > RF69_MAX_DATA_LEN) { + bufferSize = RF69_MAX_DATA_LEN; + } // control byte uint8_t CTLbyte = 0x00; - if (sendACK) + if (sendACK) { CTLbyte = RFM69_CTL_SENDACK; - else if (requestACK) + } + else if (requestACK) { CTLbyte = RFM69_CTL_REQACK; + } // write to FIFO select(); @@ -311,14 +327,15 @@ void RFM69::sendFrame(uint8_t toAddress, const void* buffer, uint8_t bufferSize, SPI.transfer(_address); SPI.transfer(CTLbyte); - for (uint8_t i = 0; i < bufferSize; i++) + for (uint8_t i = 0; i < bufferSize; i++) { SPI.transfer(((uint8_t*) buffer)[i]); + } unselect(); // no need to wait for transmit mode to be ready since its handled by the radio setMode(RF69_MODE_TX); uint32_t txStart = millis(); - while (hwDigitalRead(_interruptPin) == 0 && millis() - txStart < RF69_TX_LIMIT_MS); // wait for DIO0 to turn HIGH signalling transmission finish + while (hwDigitalRead(_interruptPin) == 0 && millis() - txStart < RF69_TX_LIMIT_MS) {} // wait for DIO0 to turn HIGH signalling transmission finish //while (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PACKETSENT == 0x00); // wait for ModeReady setMode(RF69_MODE_STANDBY); } @@ -352,14 +369,16 @@ void RFM69::interruptHandler() { ACK_RECEIVED = CTLbyte & RFM69_CTL_SENDACK; // extract ACK-received flag ACK_REQUESTED = CTLbyte & RFM69_CTL_REQACK; // extract ACK-requested flag - + interruptHook(CTLbyte); // TWS: hook to derived class interrupt function for (uint8_t i = 0; i < DATALEN; i++) { DATA[i] = SPI.transfer(0); } - if (DATALEN < RF69_MAX_DATA_LEN) DATA[DATALEN] = 0; // add null at end of string + if (DATALEN < RF69_MAX_DATA_LEN) { + DATA[DATALEN] = 0; // add null at end of string + } unselect(); setMode(RF69_MODE_RX); } @@ -379,8 +398,9 @@ void RFM69::receiveBegin() { ACK_REQUESTED = 0; ACK_RECEIVED = 0; RSSI = 0; - if (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY) + if (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY) { writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART); // avoid RX deadlocks + } writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01); // set DIO0 to "PAYLOADREADY" in receive mode setMode(RF69_MODE_RX); } @@ -414,8 +434,9 @@ void RFM69::encrypt(const char* key) { { select(); SPI.transfer(REG_AESKEY1 | 0x80); - for (uint8_t i = 0; i < 16; i++) + for (uint8_t i = 0; i < 16; i++) { SPI.transfer(key[i]); + } unselect(); } writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFE) | (key ? 1 : 0)); @@ -428,7 +449,7 @@ int16_t RFM69::readRSSI(bool forceTrigger) { { // RSSI trigger not needed if DAGC is in continuous mode writeReg(REG_RSSICONFIG, RF_RSSI_START); - while ((readReg(REG_RSSICONFIG) & RF_RSSI_DONE) == 0x00); // wait for RSSI_Ready + while ((readReg(REG_RSSICONFIG) & RF_RSSI_DONE) == 0x00) {} // wait for RSSI_Ready } rssi = -readReg(REG_RSSIVALUE); rssi >>= 1; @@ -489,10 +510,12 @@ void RFM69::promiscuous(bool onOff) { void RFM69::setHighPower(bool onOff) { _isRFM69HW = onOff; writeReg(REG_OCP, _isRFM69HW ? RF_OCP_OFF : RF_OCP_ON); - if (_isRFM69HW) // turning ON + if (_isRFM69HW) { // turning ON writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0x1F) | RF_PALEVEL_PA1_ON | RF_PALEVEL_PA2_ON); // enable P1 & P2 amplifier stages - else + } + else { writeReg(REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | _powerLevel); // enable P0 only + } } // internal function @@ -501,7 +524,7 @@ void RFM69::setHighPowerRegs(bool onOff) { writeReg(REG_TESTPA2, onOff ? 0x7C : 0x70); } -// set the slave select (CS) pin +// set the slave select (CS) pin void RFM69::setCS(uint8_t newSPISlaveSelect) { _slaveSelectPin = newSPISlaveSelect; hwDigitalWrite(_slaveSelectPin, HIGH); @@ -519,7 +542,9 @@ void SerialWrite ( uint8_t c ) { } void SerialPrint_P(PGM_P str, void (*f)(uint8_t) = SerialWrite ) { - for (uint8_t c; (c = pgm_read_byte(str)); str++) (*f)(c); + for (uint8_t c; (c = pgm_read_byte(str)); str++) { + (*f)(c); + } } #endif @@ -527,7 +552,7 @@ void RFM69::readAllRegs() { uint8_t regVal; -#if REGISTER_DETAIL +#if REGISTER_DETAIL int capVal; //... State Variables for intelligent decoding @@ -536,7 +561,7 @@ void RFM69::readAllRegs() int freqDev = 0; long freqCenter = 0; #endif - + Serial.println("Address - HEX - BIN"); for (uint8_t regAddr = 1; regAddr <= 0x4F; regAddr++) { @@ -551,8 +576,8 @@ void RFM69::readAllRegs() Serial.print(" - "); Serial.println(regVal,BIN); -#if REGISTER_DETAIL - switch ( regAddr ) +#if REGISTER_DETAIL + switch ( regAddr ) { case 0x1 : { SerialPrint ( "Controls the automatic Sequencer ( see section 4.2 )\nSequencerOff : " ); @@ -561,19 +586,19 @@ void RFM69::readAllRegs() } else { SerialPrint ( "0 -> Operating mode as selected with Mode bits in RegOpMode is automatically reached with the Sequencer\n" ); } - + SerialPrint( "\nEnables Listen mode, should be enabled whilst in Standby mode:\nListenOn : " ); if ( 0x40 & regVal ) { SerialPrint ( "1 -> On\n" ); } else { SerialPrint ( "0 -> Off ( see section 4.3)\n" ); } - + SerialPrint( "\nAborts Listen mode when set together with ListenOn=0 See section 4.3.4 for details (Always reads 0.)\n" ); if ( 0x20 & regVal ) { SerialPrint ( "ERROR - ListenAbort should NEVER return 1 this is a write only register\n" ); } - + SerialPrint("\nTransceiver's operating modes:\nMode : "); capVal = (regVal >> 2) & 0x7; if ( capVal == 0b000 ) { @@ -593,9 +618,9 @@ void RFM69::readAllRegs() SerialPrint ( "\n" ); break; } - + case 0x2 : { - + SerialPrint("Data Processing mode:\nDataMode : "); capVal = (regVal >> 5) & 0x3; if ( capVal == 0b00 ) { @@ -607,7 +632,7 @@ void RFM69::readAllRegs() } else if ( capVal == 0b11 ) { SerialPrint ( "11 -> Continuous mode without bit synchronizer\n" ); } - + SerialPrint("\nModulation scheme:\nModulation Type : "); capVal = (regVal >> 3) & 0x3; if ( capVal == 0b00 ) { @@ -620,7 +645,7 @@ void RFM69::readAllRegs() } else if ( capVal == 0b11 ) { SerialPrint ( "11 -> reserved\n" ); } - + SerialPrint("\nData shaping: "); if ( modeFSK ) { SerialPrint( "in FSK:\n" ); @@ -650,16 +675,16 @@ void RFM69::readAllRegs() SerialPrint ( "ERROR - 11 is reserved\n" ); } } - + SerialPrint ( "\n" ); break; } - + case 0x3 : { bitRate = (regVal << 8); break; } - + case 0x4 : { bitRate |= regVal; SerialPrint ( "Bit Rate (Chip Rate when Manchester encoding is enabled)\nBitRate : "); @@ -668,12 +693,12 @@ void RFM69::readAllRegs() SerialPrint( "\n" ); break; } - + case 0x5 : { freqDev = ( (regVal & 0x3f) << 8 ); break; } - + case 0x6 : { freqDev |= regVal; SerialPrint( "Frequency deviation\nFdev : " ); @@ -682,20 +707,20 @@ void RFM69::readAllRegs() SerialPrint ( "\n" ); break; } - + case 0x7 : { unsigned long tempVal = regVal; freqCenter = ( tempVal << 16 ); break; } - + case 0x8 : { unsigned long tempVal = regVal; freqCenter = freqCenter | ( tempVal << 8 ); break; } - case 0x9 : { + case 0x9 : { freqCenter = freqCenter | regVal; SerialPrint ( "RF Carrier frequency\nFRF : " ); unsigned long val = 61UL * freqCenter; @@ -711,7 +736,7 @@ void RFM69::readAllRegs() } else { SerialPrint ( "0 -> RC calibration is in progress\n" ); } - + SerialPrint ( "\n" ); break; } @@ -726,7 +751,7 @@ void RFM69::readAllRegs() SerialPrint ( "\n" ); break; } - + case 0xc : { SerialPrint ( "Reserved\n\n" ); break; @@ -745,7 +770,7 @@ void RFM69::readAllRegs() } else if ( val == 0b11 ) { SerialPrint ( "11 -> 262 ms\n" ); } - + SerialPrint ( "\nResolution of Listen mode Rx time (calibrated RC osc):\nListenResolRx : " ); val = (regVal >> 4) & 0x3; if ( val == 0b00 ) { @@ -764,7 +789,7 @@ void RFM69::readAllRegs() } else { SerialPrint ( "0 -> signal strength is above RssiThreshold\n" ); } - + SerialPrint ( "\nAction taken after acceptance of a packet in Listen mode:\nListenEnd : " ); val = (regVal >> 1 ) & 0x3; if ( val == 0b00 ) { @@ -776,12 +801,12 @@ void RFM69::readAllRegs() } else if ( val == 0b11 ) { SerialPrint ( "11 -> Reserved\n" ); } - - + + SerialPrint ( "\n" ); break; } - + default : { } } @@ -794,12 +819,12 @@ uint8_t RFM69::readTemperature(uint8_t calFactor) // returns centigrade { setMode(RF69_MODE_STANDBY); writeReg(REG_TEMP1, RF_TEMP1_MEAS_START); - while ((readReg(REG_TEMP1) & RF_TEMP1_MEAS_RUNNING)); + while ((readReg(REG_TEMP1) & RF_TEMP1_MEAS_RUNNING)) {} return ~readReg(REG_TEMP2) + COURSE_TEMP_COEF + calFactor; // 'complement' corrects the slope, rising temp = rising val } // COURSE_TEMP_COEF puts reading in the ballpark, user can add additional correction void RFM69::rcCalibration() { writeReg(REG_OSC1, RF_OSC1_RCCAL_START); - while ((readReg(REG_OSC1) & RF_OSC1_RCCAL_DONE) == 0x00); -} \ No newline at end of file + while ((readReg(REG_OSC1) & RF_OSC1_RCCAL_DONE) == 0x00) {} +} diff --git a/drivers/RPi/SPI.cpp b/drivers/RPi/SPI.cpp index 8431daf4a..0b854223b 100644 --- a/drivers/RPi/SPI.cpp +++ b/drivers/RPi/SPI.cpp @@ -79,9 +79,15 @@ void SPIClass::setClockDivider(uint16_t divider) { } void SPIClass::chipSelect(int csn_pin) { - if (csn_pin == RPI_GPIO_P1_26) csn_pin = BCM2835_SPI_CS1; - else if (csn_pin == RPI_GPIO_P1_24) csn_pin = BCM2835_SPI_CS0; - else csn_pin = BCM2835_SPI_CS0; + if (csn_pin == RPI_GPIO_P1_26) { + csn_pin = BCM2835_SPI_CS1; + } + else if (csn_pin == RPI_GPIO_P1_24) { + csn_pin = BCM2835_SPI_CS0; + } + else { + csn_pin = BCM2835_SPI_CS0; + } bcm2835_spi_chipSelect(csn_pin); delayMicroseconds(5); } diff --git a/drivers/SPIFlash/SPIFlash.cpp b/drivers/SPIFlash/SPIFlash.cpp index 547a703ac..52bf06ce3 100644 --- a/drivers/SPIFlash/SPIFlash.cpp +++ b/drivers/SPIFlash/SPIFlash.cpp @@ -7,28 +7,28 @@ // > Updated Jan. 5, 2015, TomWS1, modified writeBytes to allow blocks > 256 bytes and handle page misalignment. // > Updated Feb. 26, 2015 TomWS1, added support for SPI Transactions (Arduino 1.5.8 and above) // > Selective merge by Felix after testing in IDE 1.0.6, 1.6.4 -// > Updated May 19, 2016 D-H-R, added support for SST25/Microchip Flash which does not support Page programming with OPCode 0x02, +// > Updated May 19, 2016 D-H-R, added support for SST25/Microchip Flash which does not support Page programming with OPCode 0x02, // > use define MY_SPIFLASH_SST25TYPE for SST25 Type Flash Memory // ********************************************************************************** // License // ********************************************************************************** -// This program is free software; you can redistribute it -// and/or modify it under the terms of the GNU General -// Public License as published by the Free Software -// Foundation; either version 3 of the License, or -// (at your option) any later version. -// -// This program 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 General Public -// License for more details. -// -// You should have received a copy of the GNU General +// This program is free software; you can redistribute it +// and/or modify it under the terms of the GNU General +// Public License as published by the Free Software +// Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public +// License for more details. +// +// You should have received a copy of the GNU General // Public License along with this program. // If not, see . -// -// Licence can be viewed at +// +// Licence can be viewed at // http://www.gnu.org/licenses/gpl-3.0.txt // // Please maintain this license information along with authorship @@ -81,7 +81,7 @@ void SPIFlash::unselect() { //restore SPI settings to what they were before talking to the FLASH chip #ifdef SPI_HAS_TRANSACTION SPI.endTransaction(); -#else +#else interrupts(); #endif #ifndef ESP8266 @@ -104,7 +104,7 @@ boolean SPIFlash::initialize() unselect(); wakeup(); - + if (_jedecID == 0 || readDeviceId() == _jedecID) { command(SPIFLASH_STATUSWRITE, true); // Write Status Register SPI.transfer(0); // Global Unprotect @@ -142,8 +142,9 @@ uint8_t* SPIFlash::readUniqueId() SPI.transfer(0); SPI.transfer(0); SPI.transfer(0); - for (uint8_t i=0;i<8;i++) + for (uint8_t i=0;i<8;i++) { UNIQUEID[i] = SPI.transfer(0); + } unselect(); return UNIQUEID; } @@ -166,8 +167,9 @@ void SPIFlash::readBytes(uint32_t addr, void* buf, uint16_t len) { SPI.transfer(addr >> 8); SPI.transfer(addr); SPI.transfer(0); //"dont care" - for (uint16_t i = 0; i < len; ++i) + for (uint16_t i = 0; i < len; ++i) { ((uint8_t*) buf)[i] = SPI.transfer(0); + } unselect(); } @@ -239,12 +241,12 @@ void SPIFlash::writeBytes(uint32_t addr, const void* buf, uint16_t len) { uint16_t i=0; uint8_t oddAdr=0; char s[5]; - + command(SPIFLASH_AAIWORDPROGRAM, true); // Byte/Page Program SPI.transfer(addr >> 16); SPI.transfer(addr >> 8); SPI.transfer(addr); - + if (addr%2){ //start address is not even, i.e. first byte of word must be 0xff SPI.transfer(0xff); @@ -252,25 +254,31 @@ void SPIFlash::writeBytes(uint32_t addr, const void* buf, uint16_t len) { unselect(); oddAdr=1; //following addresses must all be shifted one off len--; - if (len > 0) command(SPIFLASH_AAIWORDPROGRAM); //If for loop will run issue Wordprogram command + if (len > 0) { + command(SPIFLASH_AAIWORDPROGRAM); //If for loop will run issue Wordprogram command + } } - + for (i=0;i<(len/2);i++){ //AAI command must be set before every new word - if (i>0) command(SPIFLASH_AAIWORDPROGRAM); //Wordprogram command for first write has been issued before + if (i>0) { + command(SPIFLASH_AAIWORDPROGRAM); //Wordprogram command for first write has been issued before + } SPI.transfer(((uint8_t*) buf)[i*2+oddAdr]); SPI.transfer(((uint8_t*) buf)[i*2+1+oddAdr]); unselect(); } - + if (len-i*2 == 1){ //There is one byte (i.e. half word) left. This happens if len was odd or (len was even and addr odd) - if (i>0) command(SPIFLASH_AAIWORDPROGRAM); //if for loop had not run wordprogram command from before is still valid + if (i>0) { + command(SPIFLASH_AAIWORDPROGRAM); //if for loop had not run wordprogram command from before is still valid + } SPI.transfer(((uint8_t*) buf)[i*2+oddAdr]); SPI.transfer(0xff); unselect(); } - + command(SPIFLASH_WRITEDISABLE); //end AAI programming unselect(); #else @@ -284,11 +292,12 @@ void SPIFlash::writeBytes(uint32_t addr, const void* buf, uint16_t len) { SPI.transfer(addr >> 16); SPI.transfer(addr >> 8); SPI.transfer(addr); - - for (uint16_t i = 0; i < n; i++) - SPI.transfer(((uint8_t*) buf)[offset + i]); + + for (uint16_t i = 0; i < n; i++) { + SPI.transfer(((uint8_t*) buf)[offset + i]); + } unselect(); - + addr+=n; // adjust the addresses and remaining bytes by what we've just transferred. offset +=n; len -= n; From 5e9ae99a3435fb10029d468910d39b36b0df2bc5 Mon Sep 17 00:00:00 2001 From: Olivier Date: Sun, 16 Oct 2016 13:05:19 +0200 Subject: [PATCH 099/167] Fix for latest SAMD board defs 1.6.8 --- core/MyMainDefault.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/MyMainDefault.cpp b/core/MyMainDefault.cpp index 56388362b..c4aa0e630 100644 --- a/core/MyMainDefault.cpp +++ b/core/MyMainDefault.cpp @@ -19,11 +19,14 @@ // Initialize library and handle sketch functions like we want to +extern "C" void __libc_init_array(void); + int main(void) { init(); #if defined(USBCON) #if defined(ARDUINO_ARCH_SAMD) - USBDevice.init(); + __libc_init_array(); + USBDevice.init(); #endif USBDevice.attach(); #endif From 69ac4b759aa03a101ab27adaef5eb44d84c21444 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Mon, 10 Oct 2016 22:35:13 -0300 Subject: [PATCH 100/167] RPi: Add support for I2C Add MyHw file for RaspberryPi. Fix compilation warnings in x86. Fix some error messages. --- MySensors.h | 18 +-- core/MyHw.h | 27 +++- core/MyHwATMega328.cpp | 4 +- core/MyHwESP8266.cpp | 2 + core/MyHwLinuxGeneric.cpp | 105 ++++----------- core/MyHwLinuxGeneric.h | 22 ++-- core/MyHwRPi.cpp | 151 ++++++++++++++++++++++ core/MyHwRPi.h | 34 +++++ core/MyHwSAMD.cpp | 2 + core/MyMainLinux.cpp | 19 ++- drivers/Linux/Arduino.h | 12 ++ drivers/Linux/EthernetServer.cpp | 6 +- drivers/Linux/Print.h | 9 ++ drivers/Linux/SerialPort.cpp | 22 +++- drivers/Linux/SoftEeprom.cpp | 129 +++++++++++++++++++ drivers/Linux/SoftEeprom.h | 81 ++++++++++++ drivers/RPi/SPI.cpp | 11 +- drivers/RPi/SPI.h | 11 +- drivers/RPi/Wire.cpp | 213 +++++++++++++++++++++++++++++++ drivers/RPi/Wire.h | 80 ++++++++++++ drivers/RPi/rpi_util.cpp | 6 +- 21 files changed, 817 insertions(+), 147 deletions(-) create mode 100644 core/MyHwRPi.cpp create mode 100644 core/MyHwRPi.h create mode 100644 drivers/Linux/SoftEeprom.cpp create mode 100644 drivers/Linux/SoftEeprom.h create mode 100644 drivers/RPi/Wire.cpp create mode 100644 drivers/RPi/Wire.h diff --git a/MySensors.h b/MySensors.h index 508bb31c0..cbeee9083 100644 --- a/MySensors.h +++ b/MySensors.h @@ -71,22 +71,10 @@ #elif defined(ARDUINO_ARCH_SAMD) #include "core/MyHwSAMD.cpp" #elif defined(__linux__) - // Remove PSTR macros from debug prints - #undef PSTR - #define PSTR(x) (x) - //#undef F - //#define F(x) (x) - #define PROGMEM - #define vsnprintf_P(...) vsnprintf( __VA_ARGS__ ) - #define snprintf_P(...) snprintf( __VA_ARGS__ ) - #define memcpy_P memcpy - #define pgm_read_dword(x) (*x) - #define pgm_read_byte_near(x) (*x) - #include "core/MyHwLinuxGeneric.cpp" - // Ugly hack #ifdef LINUX_ARCH_RASPBERRYPI - #undef hwDigitalWrite - #define hwDigitalWrite(__pin, __value) (digitalWrite(__pin, __value)) + #include "core/MyHwRPi.cpp" + #else + #include "core/MyHwLinuxGeneric.cpp" #endif #endif diff --git a/core/MyHw.h b/core/MyHw.h index f2b29c366..99bfcc653 100644 --- a/core/MyHw.h +++ b/core/MyHw.h @@ -36,12 +36,15 @@ // Implement these as functions or macros /* -#define hwDigitalWrite(__pin, __value) #define hwInit() MY_SERIALDEVICE.begin(BAUD_RATE) #define hwWatchdogReset() wdt_reset() #define hwReboot() wdt_enable(WDTO_15MS); while (1) #define hwMillis() millis() +#define hwDigitalWrite(__pin, __value) +#define hwDigitalRead(__pin) +#define hwPinMode(__pin, __value) + void hwReadConfigBlock(void* buf, void* adr, size_t length); void hwWriteConfigBlock(void* buf, void* adr, size_t length); void hwWriteConfig(int adr, uint8_t value); @@ -75,8 +78,28 @@ int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms); */ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms); +#if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG) +/** + * CPU voltage + * @return CPU voltage in mV + */ +uint16_t hwCPUVoltage(); + +/** + * CPU frequency + * @return CPU frequency in 1/10Mhz + */ +uint16_t hwCPUFrequency(); + +/** + * Free memory + * @return free memory in bytes + */ +uint16_t hwFreeMem(); +#endif + #ifdef MY_DEBUG - void hwDebugPrint(const char *fmt, ... ); +void hwDebugPrint(const char *fmt, ... ); #endif /** diff --git a/core/MyHwATMega328.cpp b/core/MyHwATMega328.cpp index b0f9eadda..570559022 100644 --- a/core/MyHwATMega328.cpp +++ b/core/MyHwATMega328.cpp @@ -161,6 +161,7 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo return ret; } +#if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG) uint16_t hwCPUVoltage() { // Measure Vcc against 1.1V Vref #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) @@ -214,8 +215,7 @@ uint16_t hwFreeMem() { int v; return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); } - - +#endif #ifdef MY_DEBUG void hwDebugPrint(const char *fmt, ... ) { diff --git a/core/MyHwESP8266.cpp b/core/MyHwESP8266.cpp index 1760b68e0..5c48a0bdc 100644 --- a/core/MyHwESP8266.cpp +++ b/core/MyHwESP8266.cpp @@ -114,6 +114,7 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo return MY_SLEEP_NOT_POSSIBLE; } +#if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG) ADC_MODE(ADC_VCC); uint16_t hwCPUVoltage() { @@ -129,6 +130,7 @@ uint16_t hwCPUFrequency() { uint16_t hwFreeMem() { return ESP.getFreeHeap(); } +#endif #ifdef MY_DEBUG void hwDebugPrint(const char *fmt, ... ) { diff --git a/core/MyHwLinuxGeneric.cpp b/core/MyHwLinuxGeneric.cpp index 76e202f3e..d632d3ff2 100644 --- a/core/MyHwLinuxGeneric.cpp +++ b/core/MyHwLinuxGeneric.cpp @@ -20,109 +20,43 @@ #include "MyHwLinuxGeneric.h" #include -#include -#include -#include -#include #include +#include "SoftEeprom.h" #include "log.h" -static const char* CONFIG_FILE = MY_LINUX_CONFIG_FILE; -static const size_t _length = 1024; // ATMega328 has 1024 bytes -static uint8_t _config[_length]; - -bool CheckConfigFile() -{ - struct stat fileInfo; - - if (stat(CONFIG_FILE, &fileInfo) != 0) { - //File does not exist. Create it. - debug("Config file %s does not exist, creating new config file.\n", CONFIG_FILE); - std::ofstream myFile(CONFIG_FILE, std::ios::out | std::ios::binary); - if (!myFile) { - debug("Unable to create config file %s.\n", CONFIG_FILE); - return false; - } - myFile.write((const char*)_config, _length); - myFile.close(); - } else if (fileInfo.st_size < 0 || (size_t)fileInfo.st_size != _length) { - debug("Config file %s is not the correct size of %i. Please remove the file and a new one will be created.\n", CONFIG_FILE, _length); - return false; - } else { - //Read config into local memory. - std::ifstream myFile(CONFIG_FILE, std::ios::in | std::ios::binary); - if (!myFile) { - debug("Unable to open config to file %s for reading.\n", CONFIG_FILE); - return false; - } - myFile.read((char*)_config, _length); - myFile.close(); - } - - return true; -} +static SoftEeprom eeprom = SoftEeprom(MY_LINUX_CONFIG_FILE, 1024); // ATMega328 has 1024 bytes void hwInit() { - for (size_t i = 0; i < _length; i++) { - _config[i] = 0xFF; - } - - if (!CheckConfigFile()) { - exit(1); - } - - #ifdef MY_GATEWAY_SERIAL - MY_SERIALDEVICE.begin(MY_BAUD_RATE); - #ifdef MY_LINUX_SERIAL_GROUPNAME - if (!MY_SERIALDEVICE.setGroupPerm(MY_LINUX_SERIAL_GROUPNAME)) { - debug("Unable to change permission for serial port device.\n"); - exit(1); - } - #endif +#ifdef MY_GATEWAY_SERIAL + MY_SERIALDEVICE.begin(MY_BAUD_RATE); + #ifdef MY_LINUX_SERIAL_GROUPNAME + if (!MY_SERIALDEVICE.setGroupPerm(MY_LINUX_SERIAL_GROUPNAME)) { + mys_log(LOG_ERR, "Unable to change permission for serial port device.\n"); + exit(1); + } #endif +#endif } void hwReadConfigBlock(void* buf, void* addr, size_t length) { - unsigned long int offs = reinterpret_cast(addr); - - if (length && offs + length <= _length) { - memcpy(buf, _config+offs, length); - } + eeprom.readBlock(buf, addr, length); } void hwWriteConfigBlock(void* buf, void* addr, size_t length) { - unsigned long int offs = reinterpret_cast(addr); - - if (length && offs + length <= _length) { - memcpy(_config+offs, buf, length); - - std::ofstream myFile(CONFIG_FILE, std::ios::out | std::ios::in | std::ios::binary); - if (!myFile) { - debug("Unable to write config to file %s.\n", CONFIG_FILE); - return; - } - myFile.seekp(offs); - myFile.write((const char*)buf, length); - myFile.close(); - } + eeprom.writeBlock(buf, addr, length); } -uint8_t hwReadConfig(int adr) +uint8_t hwReadConfig(int addr) { - uint8_t value = 0xFF; - hwReadConfigBlock(&value, reinterpret_cast(adr), 1); - return value; + return eeprom.readByte(addr); } -void hwWriteConfig(int adr, uint8_t value) +void hwWriteConfig(int addr, uint8_t value) { - uint8_t curr = hwReadConfig(adr); - if (curr != value) { - hwWriteConfigBlock(&value, reinterpret_cast(adr), 1); - } + eeprom.writeByte(addr, value); } void hwRandomNumberInit() @@ -130,6 +64,11 @@ void hwRandomNumberInit() randomSeed(time(NULL)); } +unsigned long hwMillis() +{ + return millis(); +} + // Not supported! int8_t hwSleep(unsigned long ms) { @@ -160,6 +99,7 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo return MY_SLEEP_NOT_POSSIBLE; } +#if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG) uint16_t hwCPUVoltage() { // TODO: Not supported! @@ -177,6 +117,7 @@ uint16_t hwFreeMem() // TODO: Not supported! return 0; } +#endif #ifdef MY_DEBUG void hwDebugPrint(const char *fmt, ...) diff --git a/core/MyHwLinuxGeneric.h b/core/MyHwLinuxGeneric.h index 3d39203ad..ff8b0083e 100644 --- a/core/MyHwLinuxGeneric.h +++ b/core/MyHwLinuxGeneric.h @@ -33,21 +33,21 @@ #define MY_SERIALDEVICE Serial -// Define these as macros -#define hwDigitalWrite(__pin, __value) digitalWrite(__pin, __value) -#define hwDigitalRead(__pin) digitalRead(__pin) -#define hwPinMode(__pin, __value) pinMode(__pin, __value) - +// Define these as macros (do nothing) #define hwWatchdogReset() #define hwReboot() -#define hwMillis() millis() + +#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\"") void hwInit(); -void hwReadConfigBlock(void* buf, void* adr, size_t length); -void hwWriteConfigBlock(void* buf, void* adr, size_t length); -uint8_t hwReadConfig(int adr); -void hwWriteConfig(int adr, uint8_t value); -void hwRandomNumberInit(); +inline void hwReadConfigBlock(void* buf, void* addr, size_t length); +inline void hwWriteConfigBlock(void* buf, void* addr, size_t length); +inline uint8_t hwReadConfig(int addr); +inline void hwWriteConfig(int addr, uint8_t value); +inline void hwRandomNumberInit(); +inline unsigned long hwMillis(); #ifdef MY_RF24_IRQ_PIN static pthread_mutex_t hw_mutex = PTHREAD_MUTEX_INITIALIZER; diff --git a/core/MyHwRPi.cpp b/core/MyHwRPi.cpp new file mode 100644 index 000000000..de100211c --- /dev/null +++ b/core/MyHwRPi.cpp @@ -0,0 +1,151 @@ +/** + * 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. + */ + +#include "MyHwRPi.h" + +#include +#include +#include "SoftEeprom.h" +#include "log.h" + +static SoftEeprom eeprom = SoftEeprom(MY_LINUX_CONFIG_FILE, 1024); // ATMega328 has 1024 bytes + +void hwInit() +{ + if (!bcm2835_init()) { + mys_log(LOG_ERR, "Failed to initialized bcm2835.\n"); + exit(1); + } + +#ifdef MY_GATEWAY_SERIAL + MY_SERIALDEVICE.begin(MY_BAUD_RATE); + #ifdef MY_LINUX_SERIAL_GROUPNAME + if (!MY_SERIALDEVICE.setGroupPerm(MY_LINUX_SERIAL_GROUPNAME)) { + mys_log(LOG_ERR, "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); + mys_log_v(LOG_DEBUG, 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/MyHwRPi.h b/core/MyHwRPi.h new file mode 100644 index 000000000..f6bbb8ece --- /dev/null +++ b/core/MyHwRPi.h @@ -0,0 +1,34 @@ +/** + * 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. + */ + +#ifndef MyHwRPi_h +#define MyHwRPi_h + +#include "MyHwLinuxGeneric.h" + +#undef hwDigitalWrite +inline void hwDigitalWrite(uint8_t, uint8_t); + +#undef hwDigitalRead +inline int hwDigitalRead(uint8_t); + +#undef hwPinMode +inline void hwPinMode(uint8_t, uint8_t); + +#endif diff --git a/core/MyHwSAMD.cpp b/core/MyHwSAMD.cpp index 9e11e5d3b..3d79a4826 100644 --- a/core/MyHwSAMD.cpp +++ b/core/MyHwSAMD.cpp @@ -140,6 +140,7 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo return MY_SLEEP_NOT_POSSIBLE; } +#if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG) uint16_t hwCPUVoltage() { // TODO: Not supported! return 0; @@ -154,6 +155,7 @@ uint16_t hwFreeMem() { // TODO: Not supported! return 0; } +#endif #ifdef MY_DEBUG void hwDebugPrint(const char *fmt, ... ) { diff --git a/core/MyMainLinux.cpp b/core/MyMainLinux.cpp index 5d70e4798..12687e8b6 100644 --- a/core/MyMainLinux.cpp +++ b/core/MyMainLinux.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -56,7 +57,7 @@ static int daemonize(void) /* Fork off the parent process */ pid = fork(); if (pid < 0) { - mys_log(LOG_ERR, "fork: %s", strerror(errno)); + mys_log(LOG_ERR, "fork: %s\n", strerror(errno)); return -1; } /* If we got a good PID, then we can exit the parent process. */ @@ -72,20 +73,26 @@ static int daemonize(void) /* Create a new SID for the child process */ sid = setsid(); if (sid < 0) { - mys_log(LOG_ERR, "setsid: %s", strerror(errno)); + mys_log(LOG_ERR, "setsid: %s\n", strerror(errno)); return -1; } /* Change the current working directory. This prevents the current directory from being locked; hence not being able to remove it. */ if ((chdir("/")) < 0) { - mys_log(LOG_ERR, "chdir(\"/\"): %s", strerror(errno)); + mys_log(LOG_ERR, "chdir(\"/\"): %s\n", strerror(errno)); return -1; } - freopen( "/dev/null", "r", stdin); - freopen( "/dev/null", "r", stdout); - freopen( "/dev/null", "r", stderr); + if (freopen( "/dev/null", "r", stdin) == NULL) { + mys_log(LOG_ERR, "freopen: %s\n", strerror(errno)); + } + if (freopen( "/dev/null", "r", stdout) == NULL) { + mys_log(LOG_ERR, "freopen: %s\n", strerror(errno)); + } + if (freopen( "/dev/null", "r", stderr) == NULL) { + mys_log(LOG_ERR, "freopen: %s\n", strerror(errno)); + } return 0; } diff --git a/drivers/Linux/Arduino.h b/drivers/Linux/Arduino.h index 41081d5a3..cb0cb72af 100644 --- a/drivers/Linux/Arduino.h +++ b/drivers/Linux/Arduino.h @@ -18,6 +18,18 @@ using namespace rpi_util; #endif +#undef PSTR +#define PSTR(x) (x) +#undef F +#define F(x) (x) +#define PROGMEM __attribute__(( section(".progmem.data") )) +#define vsnprintf_P(...) vsnprintf( __VA_ARGS__ ) +#define snprintf_P(...) snprintf( __VA_ARGS__ ) +#define memcpy_P memcpy +#define pgm_read_byte(p) (*(p)) +#define pgm_read_dword(p) (*(p)) +#define pgm_read_byte_near(p) (*(p)) + #define PI 3.1415926535897932384626433832795 #define HALF_PI 1.5707963267948966192313216916398 #define TWO_PI 6.283185307179586476925286766559 diff --git a/drivers/Linux/EthernetServer.cpp b/drivers/Linux/EthernetServer.cpp index 9d0012c1b..7598bd1ec 100644 --- a/drivers/Linux/EthernetServer.cpp +++ b/drivers/Linux/EthernetServer.cpp @@ -84,7 +84,7 @@ void EthernetServer::begin(IPAddress address) } if (p == NULL) { - mys_log(LOG_ERR, "failed to bind\n"); + mys_log(LOG_ERR, "Failed to bind!\n"); freeaddrinfo(servinfo); return; } @@ -142,7 +142,7 @@ size_t EthernetServer::write(const uint8_t *buffer, size_t size) client.stop(); clients[i] = clients.back(); clients.pop_back(); - mys_log(LOG_DEBUG, "Client disconnected."); + mys_log(LOG_DEBUG, "Client disconnected.\n"); } } @@ -194,7 +194,7 @@ void EthernetServer::_accept() } } if (no_free_slots) { - mys_log(LOG_DEBUG, "Max number of ethernet clients reached."); + mys_log(LOG_DEBUG, "Max number of ethernet clients reached.\n"); return; } } diff --git a/drivers/Linux/Print.h b/drivers/Linux/Print.h index b63e7a171..e59900e20 100644 --- a/drivers/Linux/Print.h +++ b/drivers/Linux/Print.h @@ -34,10 +34,19 @@ class Print { private: + int write_error; size_t printNumber(unsigned long n, uint8_t base); size_t printFloat(double number, uint8_t digits); + protected: + void setWriteError(int err = 1) { write_error = err; } + public: + Print() : write_error(0) {} + + int getWriteError() { return write_error; } + void clearWriteError() { setWriteError(0); } + virtual size_t write(uint8_t) = 0; size_t write(const char *str) { if (str == NULL) diff --git a/drivers/Linux/SerialPort.cpp b/drivers/Linux/SerialPort.cpp index 25082a122..bd16e107b 100644 --- a/drivers/Linux/SerialPort.cpp +++ b/drivers/Linux/SerialPort.cpp @@ -194,18 +194,32 @@ int SerialPort::read() { unsigned char c; - ::read(sd, &c, 1); - return c; + int ret = ::read(sd, &c, 1); + if (ret < 0) { + mys_log(LOG_ERR, "Serial - read failed: %s\n", strerror(errno)); + } else if (ret == 1) { + return c; + } + + return -1; } size_t SerialPort::write(uint8_t b) { - return ::write(sd, &b, 1); + int ret = ::write(sd, &b, 1); + if (ret < 0) { + mys_log(LOG_ERR, "Serial - write failed: %s\n", strerror(errno)); + } + return ret; } size_t SerialPort::write(const uint8_t *buffer, size_t size) { - return ::write(sd, buffer, size); + int ret = ::write(sd, buffer, size); + if (ret < 0) { + mys_log(LOG_ERR, "Serial - write failed: %s\n", strerror(errno)); + } + return ret; } int SerialPort::peek() diff --git a/drivers/Linux/SoftEeprom.cpp b/drivers/Linux/SoftEeprom.cpp new file mode 100644 index 000000000..4e22d778b --- /dev/null +++ b/drivers/Linux/SoftEeprom.cpp @@ -0,0 +1,129 @@ +/** + * 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. + */ + +#include +#include +#include +#include +#include +#include "log.h" +#include "SoftEeprom.h" + +SoftEeprom::SoftEeprom(const char *fileName, size_t length) +{ + struct stat fileInfo; + + _fileName = strdup(fileName); + if (_fileName == NULL) { + perror("Error: "); + exit(1); + } + + _length = length; + _values = new uint8_t[_length]; + for (size_t i = 0; i < _length; ++i) { + _values[i] = 0xFF; + } + + if (stat(_fileName, &fileInfo) != 0) { + //File does not exist. Create it. + mys_log(LOG_INFO, "Config file %s does not exist, creating new config file.\n", _fileName); + std::ofstream myFile(_fileName, std::ios::out | std::ios::binary); + if (!myFile) { + mys_log(LOG_ERR, "Unable to create config file %s.\n", _fileName); + exit(1); + } + myFile.write((const char*)_values, _length); + myFile.close(); + } else if (fileInfo.st_size < 0 || (size_t)fileInfo.st_size != _length) { + mys_log(LOG_ERR, "Config file %s is not the correct size of %zu. Please remove the file and a new one will be created.\n", _fileName, _length); + exit(1); + } else { + //Read config into local memory. + std::ifstream myFile(_fileName, std::ios::in | std::ios::binary); + if (!myFile) { + mys_log(LOG_ERR, "Unable to open config to file %s for reading.\n", _fileName); + exit(1); + } + myFile.read((char*)_values, _length); + myFile.close(); + } +} + +SoftEeprom::~SoftEeprom() +{ + delete[] _values; + free(_fileName); +} + +void SoftEeprom::readBlock(void* buf, void* addr, size_t length) +{ + static bool config_to_mem = false; + unsigned long int offs = reinterpret_cast(addr); + + if (!config_to_mem) { + //Read config into local memory. + std::ifstream myFile(_fileName, std::ios::in | std::ios::binary); + if (!myFile) { + mys_log(LOG_ERR, "Unable to open config to file %s for reading.\n", _fileName); + exit(1); + } + myFile.read((char*)_values, _length); + myFile.close(); + + config_to_mem = true; + } + + if (length && offs + length <= _length) { + memcpy(buf, _values+offs, length); + } +} + +void SoftEeprom::writeBlock(void* buf, void* addr, size_t length) +{ + unsigned long int offs = reinterpret_cast(addr); + + if (length && offs + length <= _length) { + memcpy(_values+offs, buf, length); + + std::ofstream myFile(_fileName, std::ios::out | std::ios::in | std::ios::binary); + if (!myFile) { + mys_log(LOG_ERR, "Unable to write config to file %s.\n", _fileName); + return; + } + myFile.seekp(offs); + myFile.write((const char*)buf, length); + myFile.close(); + } +} + +uint8_t SoftEeprom::readByte(int addr) +{ + uint8_t value = 0xFF; + readBlock(&value, reinterpret_cast(addr), 1); + return value; +} + +void SoftEeprom::writeByte(int addr, uint8_t value) +{ + uint8_t curr = readByte(addr); + if (curr != value) { + writeBlock(&value, reinterpret_cast(addr), 1); + } +} diff --git a/drivers/Linux/SoftEeprom.h b/drivers/Linux/SoftEeprom.h new file mode 100644 index 000000000..e623773ab --- /dev/null +++ b/drivers/Linux/SoftEeprom.h @@ -0,0 +1,81 @@ +/** + * 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. + */ + +/** +* This a software emulation of EEPROM that uses a file for data storage. +* A copy of the eeprom values are also held in memory for faster reading. +*/ + +#ifndef SoftEeprom_h +#define SoftEeprom_h + +#include + +/** + * SoftEeprom class + */ +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. + */ + SoftEeprom(const char *fileName, size_t length); + /** + * @brief SoftEeprom destructor. + */ + ~SoftEeprom(); + /** + * @brief Read a block of bytes from eeprom. + * + * @param buf buffer to copy to. + * @param addr eeprom address to read from. + * @param length number of bytes to read. + */ + void readBlock(void* buf, void* addr, size_t length); + /** + * @brief Write a block of bytes to eeprom. + * + * @param buf buffer to read from. + * @param addr eeprom address to write to. + * @param length number of bytes to write. + */ + void writeBlock(void* buf, void* addr, size_t length); + /** + * @brief Read a byte from eeprom. + * + * @param addr eeprom address to read from. + * @return the read byte. + */ + uint8_t readByte(int addr); + /** + * @brief Write a byte to eeprom. + * + * @param addr eeprom address to write to. + * @param value to write. + */ + void writeByte(int addr, uint8_t value); +}; + +#endif diff --git a/drivers/RPi/SPI.cpp b/drivers/RPi/SPI.cpp index 0b854223b..997991dae 100644 --- a/drivers/RPi/SPI.cpp +++ b/drivers/RPi/SPI.cpp @@ -31,16 +31,7 @@ SPIClass SPI = SPIClass(); uint8_t SPIClass::initialized = 0; -SPIClass::SPIClass() { - if (!bcm2835_init()) { - mys_log(LOG_ERR, "Failed to initialized bcm2835.\n"); - exit(1); - } -} - -SPIClass::~SPIClass() {} - -uint8_t SPIClass::isInitialized() { +uint8_t SPIClass::is_initialized() { return initialized; } diff --git a/drivers/RPi/SPI.h b/drivers/RPi/SPI.h index 84a411740..d83a5405a 100644 --- a/drivers/RPi/SPI.h +++ b/drivers/RPi/SPI.h @@ -18,6 +18,7 @@ * * Based on TMRh20 RF24 library, Copyright (c) 2015 Charles-Henri Hallard */ + #ifndef _SPI_H_ #define _SPI_H_ @@ -122,20 +123,12 @@ class SPIClass { static uint8_t initialized; //!< @brief SPI initialized flag. public: - /** - * @brief SPIClass constructor. - */ - SPIClass(); - /** - * @brief SPIClass destructor. - */ - virtual ~SPIClass(); /** * @brief Checks if SPI was initialized. * * @return 0 if wasn't initialized, else 1 or more. */ - static uint8_t isInitialized(); + static uint8_t is_initialized(); /** * @brief Send and receive a byte. * diff --git a/drivers/RPi/Wire.cpp b/drivers/RPi/Wire.cpp new file mode 100644 index 000000000..bf78da1af --- /dev/null +++ b/drivers/RPi/Wire.cpp @@ -0,0 +1,213 @@ +/* + TwoWire.h - TWI/I2C library for Arduino & Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts + Modified December 2014 by Ivan Grokhotkov (ivan@esp8266.com) - esp8266 support + Modified April 2015 by Hrsto Gochkov (ficeto@ficeto.com) - alternative esp8266 support + Modified October 2016 by Marcelo Aquino for Raspberry Pi +*/ + +#include "Wire.h" +#include +#include +#include "bcm2835.h" +#include "log.h" + +static pthread_mutex_t i2cMutex = PTHREAD_MUTEX_INITIALIZER; + +uint8_t TwoWire::rxBuffer[BUFFER_LENGTH]; +uint8_t TwoWire::rxBufferIndex = 0; +uint8_t TwoWire::rxBufferLength = 0; + +uint8_t TwoWire::txAddress = 0; +uint8_t TwoWire::txBuffer[BUFFER_LENGTH]; +uint8_t TwoWire::txBufferIndex = 0; +uint8_t TwoWire::txBufferLength = 0; + +uint8_t TwoWire::transmitting = 0; + +void TwoWire::begin() +{ + if (!bcm2835_i2c_begin()) { + mys_log(LOG_ERR, "You need to be root to use I2C.\n"); + exit(1); + } +} + +void TwoWire::begin(uint8_t address) +{ + begin(); + bcm2835_i2c_setSlaveAddress(address); +} + +void TwoWire::begin(int address) +{ + begin(static_cast(address)); +} + +void TwoWire::end() +{ + bcm2835_i2c_end(); +} + +void TwoWire::setClock(uint32_t clock) +{ + bcm2835_i2c_set_baudrate(clock); +} + +void TwoWire::beginTransmission(uint8_t address) +{ + pthread_mutex_lock(&i2cMutex); + // indicate that we are transmitting + transmitting = 1; + // set address of targeted slave + txAddress = address; + // reset tx buffer iterator vars + txBufferIndex = 0; + txBufferLength = 0; +} + +void TwoWire::beginTransmission(int address) +{ + beginTransmission(static_cast(address)); +} + +uint8_t TwoWire::endTransmission(void) +{ + // transmit buffer + bcm2835_i2c_setSlaveAddress(txAddress); + uint8_t ret = bcm2835_i2c_write(reinterpret_cast(txBuffer), txBufferLength); + + // reset tx buffer iterator vars + txBufferIndex = 0; + txBufferLength = 0; + // indicate that we are done transmitting + transmitting = 0; + + pthread_mutex_unlock(&i2cMutex); + + if (ret == BCM2835_I2C_REASON_OK) { + return 0; // success + } else if (ret == BCM2835_I2C_REASON_ERROR_NACK) { + return 3; // error: data send, nack received + } + return 4; // other error +} + +size_t TwoWire::requestFrom(uint8_t address, size_t quantity) +{ + // clamp to buffer length + if (quantity > BUFFER_LENGTH) { + quantity = BUFFER_LENGTH; + } + + rxBufferIndex = 0; + rxBufferLength = 0; + + bcm2835_i2c_setSlaveAddress(address); + uint8_t ret = bcm2835_i2c_read(reinterpret_cast(rxBuffer), quantity); + if (ret == BCM2835_I2C_REASON_OK) { + rxBufferLength = quantity; + } + + return rxBufferLength; +} + +uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity) +{ + return requestFrom(address, static_cast(quantity)); +} + +uint8_t TwoWire::requestFrom(int address, int quantity) +{ + return requestFrom(static_cast(address), static_cast(quantity)); +} + +size_t TwoWire::write(uint8_t data) +{ + if (transmitting) { + // in master transmitter mode + // don't bother if buffer is full + if (txBufferLength >= BUFFER_LENGTH) { + setWriteError(); + return 0; + } + // put byte in tx buffer + txBuffer[txBufferIndex] = data; + ++txBufferIndex; + // update amount in buffer + txBufferLength = txBufferIndex; + + return 1; + } else { + return write(&data, 1); + } +} + +size_t TwoWire::write(const uint8_t *data, size_t quantity) +{ + if (transmitting) { + // in master transmitter mode + for (size_t i = 0; i < quantity; ++i) { + write(data[i]); + } + } else { + uint8_t rc = bcm2835_i2c_write(reinterpret_cast(data), quantity); + if (rc != BCM2835_I2C_REASON_OK) { + return 0; + } + } + + return quantity; +} + +int TwoWire::available() +{ + return rxBufferLength - rxBufferIndex; +} + +int TwoWire::read() +{ + int value = -1; + + if (rxBufferIndex < rxBufferLength) { + value = rxBuffer[rxBufferIndex]; + ++rxBufferIndex; + } + + return value; +} + +int TwoWire::peek() +{ + if (rxBufferIndex < rxBufferLength) { + return rxBuffer[rxBufferIndex]; + } + + return -1; +} + +void TwoWire::flush() +{ + rxBufferIndex = 0; + rxBufferLength = 0; + txBufferIndex = 0; + txBufferLength = 0; +} + +TwoWire Wire = TwoWire(); diff --git a/drivers/RPi/Wire.h b/drivers/RPi/Wire.h new file mode 100644 index 000000000..a82625b6c --- /dev/null +++ b/drivers/RPi/Wire.h @@ -0,0 +1,80 @@ +/* + TwoWire.h - TWI/I2C library for Arduino & Wiring + Copyright (c) 2006 Nicholas Zambetti. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts + Modified December 2014 by Ivan Grokhotkov (ivan@esp8266.com) - esp8266 support + Modified April 2015 by Hrsto Gochkov (ficeto@ficeto.com) - alternative esp8266 support + Modified October 2016 by Marcelo Aquino for Raspberry Pi +*/ + +#ifndef Wire_h +#define Wire_h + +#if !DOXYGEN +#include +#include "Stream.h" + +#define BUFFER_LENGTH 32 + +class TwoWire : public Stream { + +private: + static uint8_t rxBuffer[]; + static uint8_t rxBufferIndex; + static uint8_t rxBufferLength; + + static uint8_t txAddress; + static uint8_t txBuffer[]; + static uint8_t txBufferIndex; + static uint8_t txBufferLength; + + static uint8_t transmitting; + +public: + void begin(); + void begin(uint8_t address); + void begin(int address); + void end(); + void setClock(uint32_t clock); + + void beginTransmission(uint8_t address); + void beginTransmission(int address); + uint8_t endTransmission(void); + + size_t requestFrom(uint8_t address, size_t size); + uint8_t requestFrom(uint8_t address, uint8_t quantity); + uint8_t requestFrom(int address, int quantity); + + size_t write(uint8_t data); + size_t write(const uint8_t *data, size_t quantity); + int available(); + int read(); + int peek(); + void flush(); + + inline size_t write(unsigned long n) { return write((uint8_t)n); } + inline size_t write(long n) { return write((uint8_t)n); } + inline size_t write(unsigned int n) { return write((uint8_t)n); } + inline size_t write(int n) { return write((uint8_t)n); } + using Print::write; +}; + +extern TwoWire Wire; + +#endif +#endif diff --git a/drivers/RPi/rpi_util.cpp b/drivers/RPi/rpi_util.cpp index 5954fcc28..47f65bb32 100644 --- a/drivers/RPi/rpi_util.cpp +++ b/drivers/RPi/rpi_util.cpp @@ -167,7 +167,7 @@ void rpi_util::pinMode(uint8_t physPin, uint8_t mode) { return; } // Check if SPI is in use and target pin is related to SPI - if (SPIClass::isInitialized() && gpioPin >= RPI_GPIO_P1_26 && gpioPin <= RPI_GPIO_P1_23) { + if (SPIClass::is_initialized() && gpioPin >= RPI_GPIO_P1_26 && gpioPin <= RPI_GPIO_P1_23) { return; } else { bcm2835_gpio_fsel(gpioPin, mode); @@ -181,7 +181,7 @@ void rpi_util::digitalWrite(uint8_t physPin, uint8_t value) { return; } // Check if SPI is in use and target pin is related to SPI - if (SPIClass::isInitialized() && gpioPin >= RPI_GPIO_P1_26 && gpioPin <= RPI_GPIO_P1_23) { + 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); } @@ -199,7 +199,7 @@ uint8_t rpi_util::digitalRead(uint8_t physPin) { return 0; } // Check if SPI is in use and target pin is related to SPI - if (SPIClass::isInitialized() && gpioPin >= RPI_GPIO_P1_26 && gpioPin <= RPI_GPIO_P1_23) { + if (SPIClass::is_initialized() && gpioPin >= RPI_GPIO_P1_26 && gpioPin <= RPI_GPIO_P1_23) { return 0; } else { return bcm2835_gpio_lev(gpioPin); From 4a4eed295cde4412a10aae4cfc56955b86c58984 Mon Sep 17 00:00:00 2001 From: Olivier Date: Sun, 16 Oct 2016 16:07:24 +0200 Subject: [PATCH 101/167] Fix INPUT_PULLUP option for hwPinMode() --- drivers/AVR/DigitalWriteFast/digitalWriteFast.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/AVR/DigitalWriteFast/digitalWriteFast.h b/drivers/AVR/DigitalWriteFast/digitalWriteFast.h index a76834712..555d90305 100644 --- a/drivers/AVR/DigitalWriteFast/digitalWriteFast.h +++ b/drivers/AVR/DigitalWriteFast/digitalWriteFast.h @@ -81,11 +81,14 @@ #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), __digitalPinToBit(__pin), (__value)); } else { digitalWrite((__pin), (__value)); } } while (0) #endif #if !defined(pinModeFast) - #define pinModeFast(__pin, __value) do { if (__builtin_constant_p(__pin) && __builtin_constant_p(__value)) { bitWrite(*__digitalPinToDDRReg(__pin), __digitalPinToBit(__pin), (__value)); } else { pinMode((__pin), (__value)); } } while (0) + #define pinModeFast(__pin, __mode) do { if (__builtin_constant_p(__pin) && __builtin_constant_p(__mode) && (__mode!=INPUT_PULLUP)) { bitWrite(*__digitalPinToDDRReg(__pin), __digitalPinToBit(__pin), (__mode)); } else { pinMode((__pin), (__mode)); } } while (0) #endif #if !defined(digitalReadFast) #define digitalReadFast(__pin) ( (bool) (__builtin_constant_p(__pin) ) ? (( bitRead(*__digitalPinToPINReg(__pin), __digitalPinToBit(__pin))) ) : digitalRead((__pin)) ) From 2be804a1ef0dec28d839addd0efcfa3846a352b0 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Mon, 17 Oct 2016 22:55:48 -0200 Subject: [PATCH 102/167] RPi: Log refactor --- core/MyHwLinuxGeneric.cpp | 4 +- core/MyHwRPi.cpp | 6 +- core/MyMainLinux.cpp | 25 ++++--- drivers/Linux/EthernetClient.cpp | 12 ++-- drivers/Linux/EthernetServer.cpp | 22 +++--- drivers/Linux/SerialPort.cpp | 32 ++++----- drivers/Linux/SoftEeprom.cpp | 12 ++-- drivers/Linux/log.c | 112 +++++++++++++++++++++++++++++-- drivers/Linux/log.h | 19 +++++- drivers/RPi/SPI.cpp | 2 +- drivers/RPi/Wire.cpp | 2 +- drivers/RPi/bcm2835.c | 6 +- drivers/RPi/rpi_util.cpp | 22 +++--- 13 files changed, 196 insertions(+), 80 deletions(-) diff --git a/core/MyHwLinuxGeneric.cpp b/core/MyHwLinuxGeneric.cpp index d632d3ff2..a71c32309 100644 --- a/core/MyHwLinuxGeneric.cpp +++ b/core/MyHwLinuxGeneric.cpp @@ -32,7 +32,7 @@ void hwInit() MY_SERIALDEVICE.begin(MY_BAUD_RATE); #ifdef MY_LINUX_SERIAL_GROUPNAME if (!MY_SERIALDEVICE.setGroupPerm(MY_LINUX_SERIAL_GROUPNAME)) { - mys_log(LOG_ERR, "Unable to change permission for serial port device.\n"); + logError("Unable to change permission for serial port device.\n"); exit(1); } #endif @@ -125,7 +125,7 @@ void hwDebugPrint(const char *fmt, ...) va_list args; va_start(args, fmt); - mys_log_v(LOG_DEBUG, fmt, args); + vlogDebug(fmt, args); va_end(args); } #endif diff --git a/core/MyHwRPi.cpp b/core/MyHwRPi.cpp index de100211c..34c530fc5 100644 --- a/core/MyHwRPi.cpp +++ b/core/MyHwRPi.cpp @@ -29,7 +29,7 @@ static SoftEeprom eeprom = SoftEeprom(MY_LINUX_CONFIG_FILE, 1024); // ATMega328 void hwInit() { if (!bcm2835_init()) { - mys_log(LOG_ERR, "Failed to initialized bcm2835.\n"); + logError("Failed to initialized bcm2835.\n"); exit(1); } @@ -37,7 +37,7 @@ void hwInit() MY_SERIALDEVICE.begin(MY_BAUD_RATE); #ifdef MY_LINUX_SERIAL_GROUPNAME if (!MY_SERIALDEVICE.setGroupPerm(MY_LINUX_SERIAL_GROUPNAME)) { - mys_log(LOG_ERR, "Unable to change permission for serial port device.\n"); + logError("Unable to change permission for serial port device.\n"); exit(1); } #endif @@ -130,7 +130,7 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo va_list args; va_start(args, fmt); - mys_log_v(LOG_DEBUG, fmt, args); + vlogDebug(fmt, args); va_end(args); } #endif diff --git a/core/MyMainLinux.cpp b/core/MyMainLinux.cpp index 12687e8b6..09a5dc49e 100644 --- a/core/MyMainLinux.cpp +++ b/core/MyMainLinux.cpp @@ -32,9 +32,9 @@ void handle_sigint(int sig) { if (sig == SIGINT) { - mys_log(LOG_NOTICE, "Received SIGINT\n\n"); + logNotice("Received SIGINT\n\n"); } else if (sig == SIGTERM) { - mys_log(LOG_NOTICE, "Received SIGTERM\n\n"); + logNotice("Received SIGTERM\n\n"); } else { return; } @@ -47,6 +47,8 @@ void handle_sigint(int sig) MY_SERIALDEVICE.end(); #endif + closelog(); + exit(0); } @@ -57,7 +59,7 @@ static int daemonize(void) /* Fork off the parent process */ pid = fork(); if (pid < 0) { - mys_log(LOG_ERR, "fork: %s\n", strerror(errno)); + logError("fork: %s\n", strerror(errno)); return -1; } /* If we got a good PID, then we can exit the parent process. */ @@ -73,25 +75,25 @@ static int daemonize(void) /* Create a new SID for the child process */ sid = setsid(); if (sid < 0) { - mys_log(LOG_ERR, "setsid: %s\n", strerror(errno)); + logError("setsid: %s\n", strerror(errno)); return -1; } /* Change the current working directory. This prevents the current directory from being locked; hence not being able to remove it. */ if ((chdir("/")) < 0) { - mys_log(LOG_ERR, "chdir(\"/\"): %s\n", strerror(errno)); + logError("chdir(\"/\"): %s\n", strerror(errno)); return -1; } if (freopen( "/dev/null", "r", stdin) == NULL) { - mys_log(LOG_ERR, "freopen: %s\n", strerror(errno)); + logError("freopen: %s\n", strerror(errno)); } if (freopen( "/dev/null", "r", stdout) == NULL) { - mys_log(LOG_ERR, "freopen: %s\n", strerror(errno)); + logError("freopen: %s\n", strerror(errno)); } if (freopen( "/dev/null", "r", stderr) == NULL) { - mys_log(LOG_ERR, "freopen: %s\n", strerror(errno)); + logError("freopen: %s\n", strerror(errno)); } return 0; @@ -137,9 +139,10 @@ int main(int argc, char *argv[]) log_opts |= LOG_PERROR; } if (!debug) { + // Ignore debug type messages setlogmask(LOG_UPTO (LOG_INFO)); } - openlog(NULL, log_opts, LOG_USER); + logOpen(log_opts, LOG_USER); if (!foreground && !debug) { if (daemonize() != 0) { @@ -147,8 +150,8 @@ int main(int argc, char *argv[]) } } - mys_log(LOG_INFO, "Starting gateway...\n"); - mys_log(LOG_INFO, "Protocol version - %s\n", MYSENSORS_LIBRARY_VERSION); + logInfo("Starting gateway...\n"); + logInfo("Protocol version - %s\n", MYSENSORS_LIBRARY_VERSION); _begin(); // Startup MySensors library diff --git a/drivers/Linux/EthernetClient.cpp b/drivers/Linux/EthernetClient.cpp index 718d47786..ea69014a8 100644 --- a/drivers/Linux/EthernetClient.cpp +++ b/drivers/Linux/EthernetClient.cpp @@ -51,7 +51,7 @@ int EthernetClient::connect(const char* host, uint16_t port) { sprintf(port_str, "%hu", port); if ((rv = getaddrinfo(host, port_str, &hints, &servinfo)) != 0) { - mys_log(LOG_ERR, "getaddrinfo: %s\n", gai_strerror(rv)); + logError("getaddrinfo: %s\n", gai_strerror(rv)); return -1; } @@ -59,13 +59,13 @@ int EthernetClient::connect(const char* host, uint16_t port) { for (p = servinfo; p != NULL; p = p->ai_next) { if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { - mys_log(LOG_ERR, "socket: %s\n", strerror(errno)); + logError("socket: %s\n", strerror(errno)); continue; } if (::connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) { close(sockfd); - mys_log(LOG_ERR, "connect: %s\n", strerror(errno)); + logError("connect: %s\n", strerror(errno)); continue; } @@ -73,7 +73,7 @@ int EthernetClient::connect(const char* host, uint16_t port) { } if (p == NULL) { - mys_log(LOG_ERR, "failed to connect\n"); + logError("failed to connect\n"); return -1; } @@ -81,7 +81,7 @@ int EthernetClient::connect(const char* host, uint16_t port) { void *addr = &(((struct sockaddr_in*)p->ai_addr)->sin_addr); inet_ntop(p->ai_family, addr, s, sizeof s); - mys_log(LOG_DEBUG, "connected to %s\n", s); + logDebug("connected to %s\n", s); freeaddrinfo(servinfo); // all done with this structure @@ -107,7 +107,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); if (rc == -1) { - mys_log(LOG_ERR, "send: %s\n", strerror(errno)); + logError("send: %s\n", strerror(errno)); close(_sock); _sock = -1; break; diff --git a/drivers/Linux/EthernetServer.cpp b/drivers/Linux/EthernetServer.cpp index 7598bd1ec..311f315f8 100644 --- a/drivers/Linux/EthernetServer.cpp +++ b/drivers/Linux/EthernetServer.cpp @@ -57,26 +57,26 @@ void EthernetServer::begin(IPAddress address) sprintf(portstr, "%d", port); if ((rv = getaddrinfo(address.toString().c_str(), portstr, &hints, &servinfo)) != 0) { - mys_log(LOG_ERR, "getaddrinfo: %s\n", gai_strerror(rv)); + logError("getaddrinfo: %s\n", gai_strerror(rv)); return; } // loop through all the results and bind to the first we can for (p = servinfo; p != NULL; p = p->ai_next) { if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { - mys_log(LOG_ERR, "socket: %s\n", strerror(errno)); + logError("socket: %s\n", strerror(errno)); continue; } if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { - mys_log(LOG_ERR, "setsockopt: %s\n", strerror(errno)); + logError("setsockopt: %s\n", strerror(errno)); freeaddrinfo(servinfo); return; } if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { close(sockfd); - mys_log(LOG_ERR, "bind: %s\n", strerror(errno)); + logError("bind: %s\n", strerror(errno)); continue; } @@ -84,13 +84,13 @@ void EthernetServer::begin(IPAddress address) } if (p == NULL) { - mys_log(LOG_ERR, "Failed to bind!\n"); + logError("Failed to bind!\n"); freeaddrinfo(servinfo); return; } if (listen(sockfd, ETHERNETSERVER_BACKLOG) == -1) { - mys_log(LOG_ERR, "listen: %s\n", strerror(errno)); + logError("listen: %s\n", strerror(errno)); freeaddrinfo(servinfo); return; } @@ -102,7 +102,7 @@ void EthernetServer::begin(IPAddress address) struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr; void *addr = &(ipv4->sin_addr); inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr); - mys_log(LOG_DEBUG, "Listening for connections on %s:%s\n", ipstr, portstr); + logDebug("Listening for connections on %s:%s\n", ipstr, portstr); } bool EthernetServer::hasClient() @@ -142,7 +142,7 @@ size_t EthernetServer::write(const uint8_t *buffer, size_t size) client.stop(); clients[i] = clients.back(); clients.pop_back(); - mys_log(LOG_DEBUG, "Client disconnected.\n"); + logDebug("Client disconnected.\n"); } } @@ -194,7 +194,7 @@ void EthernetServer::_accept() } } if (no_free_slots) { - mys_log(LOG_DEBUG, "Max number of ethernet clients reached.\n"); + logDebug("Max number of ethernet clients reached.\n"); return; } } @@ -203,7 +203,7 @@ void EthernetServer::_accept() new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size); if (new_fd == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { - mys_log(LOG_ERR, "accept: %s\n", strerror(errno)); + logError("accept: %s\n", strerror(errno)); } return; } @@ -213,5 +213,5 @@ void EthernetServer::_accept() void *addr = &(((struct sockaddr_in*)&client_addr)->sin_addr); inet_ntop(client_addr.ss_family, addr, ipstr, sizeof ipstr); - mys_log(LOG_DEBUG, "New connection from %s\n", ipstr); + logDebug("New connection from %s\n", ipstr); } diff --git a/drivers/Linux/SerialPort.cpp b/drivers/Linux/SerialPort.cpp index bd16e107b..b1145cc3a 100644 --- a/drivers/Linux/SerialPort.cpp +++ b/drivers/Linux/SerialPort.cpp @@ -39,7 +39,7 @@ SerialPort::SerialPort(const char *port, bool isPty) : serialPort(std::string(po void SerialPort::begin(int bauds) { if (!open(bauds)) { - mys_log(LOG_ERR, "Failed to open serial port.\n"); + logError("Failed to open serial port.\n"); exit(1); } } @@ -52,29 +52,29 @@ bool SerialPort::open(int bauds) if (isPty) { sd = posix_openpt(O_RDWR | O_NOCTTY | O_NDELAY); if (sd < 0) { - mys_log(LOG_ERR, "Couldn't open a PTY: %s\n", strerror(errno)); + logError("Couldn't open a PTY: %s\n", strerror(errno)); return false; } if (grantpt(sd) != 0) { - mys_log(LOG_ERR, "Couldn't grant permission to the PTY: %s\n", strerror(errno)); + logError("Couldn't grant permission to the PTY: %s\n", strerror(errno)); return false; } if (unlockpt(sd) != 0) { - mys_log(LOG_ERR, "Couldn't unlock the PTY: %s\n", strerror(errno)); + logError("Couldn't unlock the PTY: %s\n", strerror(errno)); return false; } /* create a symlink with predictable name to the PTY device */ unlink(serialPort.c_str()); // remove the symlink if it already exists if (symlink(ptsname(sd), serialPort.c_str()) != 0) { - mys_log(LOG_ERR, "Couldn't create a symlink '%s' to PTY! (%d) %s\n", serialPort.c_str(), errno, strerror(errno)); + logError("Couldn't create a symlink '%s' to PTY! (%d) %s\n", serialPort.c_str(), errno, strerror(errno)); return false; } } else { if ((sd = ::open(serialPort.c_str(), O_RDWR | O_NOCTTY | O_NDELAY)) == -1) { - mys_log(LOG_ERR, "Unable to open the serial port %s\n", serialPort.c_str()); + logError("Unable to open the serial port %s\n", serialPort.c_str()); return false; } @@ -104,7 +104,7 @@ bool SerialPort::open(int bauds) // Get the current options of the port if (tcgetattr(sd, &options) < 0) { - mys_log(LOG_ERR, "Couldn't get term attributes: %s\n", strerror(errno)); + logError("Couldn't get term attributes: %s\n", strerror(errno)); return false; } @@ -127,13 +127,13 @@ bool SerialPort::open(int bauds) // Set parameters if (tcsetattr(sd, TCSANOW, &options) < 0) { - mys_log(LOG_ERR, "Couldn't set term attributes: %s\n", strerror(errno)); + logError("Couldn't set term attributes: %s\n", strerror(errno)); return false; } // flush if (tcflush(sd, TCIOFLUSH) < 0) { - mys_log(LOG_ERR, "Couldn't flush serial: %s\n", strerror(errno)); + logError("Couldn't flush serial: %s\n", strerror(errno)); return false; } @@ -152,7 +152,7 @@ bool SerialPort::setGroupPerm(const char *groupName) if (sd != -1 && groupName != NULL) { devGrp = getgrnam(groupName); if (devGrp == NULL) { - mys_log(LOG_ERR, "getgrnam: %s failed. (%d) %s\n", groupName, errno, strerror(errno)); + logError("getgrnam: %s failed. (%d) %s\n", groupName, errno, strerror(errno)); return false; } @@ -164,13 +164,13 @@ bool SerialPort::setGroupPerm(const char *groupName) ret = chown(dev, -1, devGrp->gr_gid); if (ret == -1) { - mys_log(LOG_ERR, "Could not change PTY owner! (%d) %s\n", errno, strerror(errno)); + logError("Could not change PTY owner! (%d) %s\n", errno, strerror(errno)); return false; } ret = chmod(dev, ttyPermissions); if (ret != 0) { - mys_log(LOG_ERR, "Could not change PTY permissions! (%d) %s\n", errno, strerror(errno)); + logError("Could not change PTY permissions! (%d) %s\n", errno, strerror(errno)); return false; } @@ -184,7 +184,7 @@ int SerialPort::available() int nbytes = 0; if (ioctl(sd, FIONREAD, &nbytes) < 0) { - mys_log(LOG_ERR, "Failed to get byte count on serial.\n"); + logError("Failed to get byte count on serial.\n"); exit(-1); } return nbytes; @@ -196,7 +196,7 @@ int SerialPort::read() int ret = ::read(sd, &c, 1); if (ret < 0) { - mys_log(LOG_ERR, "Serial - read failed: %s\n", strerror(errno)); + logError("Serial - read failed: %s\n", strerror(errno)); } else if (ret == 1) { return c; } @@ -208,7 +208,7 @@ size_t SerialPort::write(uint8_t b) { int ret = ::write(sd, &b, 1); if (ret < 0) { - mys_log(LOG_ERR, "Serial - write failed: %s\n", strerror(errno)); + logError("Serial - write failed: %s\n", strerror(errno)); } return ret; } @@ -217,7 +217,7 @@ size_t SerialPort::write(const uint8_t *buffer, size_t size) { int ret = ::write(sd, buffer, size); if (ret < 0) { - mys_log(LOG_ERR, "Serial - write failed: %s\n", strerror(errno)); + logError("Serial - write failed: %s\n", strerror(errno)); } return ret; } diff --git a/drivers/Linux/SoftEeprom.cpp b/drivers/Linux/SoftEeprom.cpp index 4e22d778b..bc1b497a9 100644 --- a/drivers/Linux/SoftEeprom.cpp +++ b/drivers/Linux/SoftEeprom.cpp @@ -43,22 +43,22 @@ SoftEeprom::SoftEeprom(const char *fileName, size_t length) if (stat(_fileName, &fileInfo) != 0) { //File does not exist. Create it. - mys_log(LOG_INFO, "Config file %s does not exist, creating new config file.\n", _fileName); + logInfo("Config file %s does not exist, creating new config file.\n", _fileName); std::ofstream myFile(_fileName, std::ios::out | std::ios::binary); if (!myFile) { - mys_log(LOG_ERR, "Unable to create config file %s.\n", _fileName); + logError("Unable to create config file %s.\n", _fileName); exit(1); } myFile.write((const char*)_values, _length); myFile.close(); } else if (fileInfo.st_size < 0 || (size_t)fileInfo.st_size != _length) { - mys_log(LOG_ERR, "Config file %s is not the correct size of %zu. Please remove the file and a new one will be created.\n", _fileName, _length); + logError("Config file %s is not the correct size of %zu. Please remove the file and a new one will be created.\n", _fileName, _length); exit(1); } else { //Read config into local memory. std::ifstream myFile(_fileName, std::ios::in | std::ios::binary); if (!myFile) { - mys_log(LOG_ERR, "Unable to open config to file %s for reading.\n", _fileName); + logError("Unable to open config to file %s for reading.\n", _fileName); exit(1); } myFile.read((char*)_values, _length); @@ -81,7 +81,7 @@ void SoftEeprom::readBlock(void* buf, void* addr, size_t length) //Read config into local memory. std::ifstream myFile(_fileName, std::ios::in | std::ios::binary); if (!myFile) { - mys_log(LOG_ERR, "Unable to open config to file %s for reading.\n", _fileName); + logError("Unable to open config to file %s for reading.\n", _fileName); exit(1); } myFile.read((char*)_values, _length); @@ -104,7 +104,7 @@ void SoftEeprom::writeBlock(void* buf, void* addr, size_t length) std::ofstream myFile(_fileName, std::ios::out | std::ios::in | std::ios::binary); if (!myFile) { - mys_log(LOG_ERR, "Unable to write config to file %s.\n", _fileName); + logError("Unable to write config to file %s.\n", _fileName); return; } myFile.seekp(offs); diff --git a/drivers/Linux/log.c b/drivers/Linux/log.c index b45df4e5a..a7650d149 100644 --- a/drivers/Linux/log.c +++ b/drivers/Linux/log.c @@ -1,22 +1,122 @@ +#include "log.h" #include +#include #include #include -#include "log.h" -void mys_log_v(int level, const char *fmt, va_list args) +// Default values +static const int log_opts = LOG_CONS | LOG_PERROR; // print syslog to stderror +static const int log_facility = LOG_USER; + +static uint8_t log_open = 0; + +void logOpen(int options, int facility) +{ + openlog(NULL, options, facility); + log_open = 1; +} + +void vlogInfo(const char *fmt, va_list args) +{ + if (!log_open) { + logOpen(log_opts, log_facility); + } + vsyslog(LOG_INFO, fmt, args); +} + +void +#ifdef __GNUC__ +__attribute__((format(printf, 1, 2))) +#endif +logInfo(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vlogInfo(fmt, args); + va_end(args); +} + +void vlogError(const char *fmt, va_list args) +{ + if (!log_open) { + logOpen(log_opts, log_facility); + } + vsyslog(LOG_ERR, fmt, args); +} + +void +#ifdef __GNUC__ +__attribute__((format(printf, 1, 2))) +#endif +logError(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vlogError(fmt, args); + va_end(args); +} + +void vlogNotice(const char *fmt, va_list args) +{ + if (!log_open) { + logOpen(log_opts, log_facility); + } + vsyslog(LOG_NOTICE, fmt, args); +} + +void +#ifdef __GNUC__ +__attribute__((format(printf, 1, 2))) +#endif +logNotice(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vlogNotice(fmt, args); + va_end(args); +} + +void vlogDebug(const char *fmt, va_list args) +{ + if (!log_open) { + logOpen(log_opts, log_facility); + } + vsyslog(LOG_DEBUG, fmt, args); +} + +void +#ifdef __GNUC__ +__attribute__((format(printf, 1, 2))) +#endif +logDebug(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vlogDebug(fmt, args); + va_end(args); +} + +void vlogWarning(const char *fmt, va_list args) { - vsyslog(level, fmt, args); + if (!log_open) { + logOpen(log_opts, log_facility); + } + vsyslog(LOG_WARNING, fmt, args); } void #ifdef __GNUC__ -__attribute__((format(printf, 2, 3))) +__attribute__((format(printf, 1, 2))) #endif -mys_log(int level, const char *fmt, ...) +logWarning(const char *fmt, ...) { va_list args; va_start(args, fmt); - mys_log_v(level, fmt, args); + vlogWarning(fmt, args); va_end(args); } diff --git a/drivers/Linux/log.h b/drivers/Linux/log.h index 5c93dcc68..db67cf349 100644 --- a/drivers/Linux/log.h +++ b/drivers/Linux/log.h @@ -2,14 +2,27 @@ #define LOG_H #include -#include #ifdef __cplusplus extern "C" { #endif -extern void mys_log_v(int level, const char *fmt, va_list args); -extern void mys_log(int level, const char *fmt, ...) __attribute__((format(printf,2,3))); +extern void logOpen(int options, int facility); + +extern void vlogInfo(const char *fmt, va_list args); +extern void logInfo(const char *fmt, ...) __attribute__((format(printf,1,2))); + +extern void vlogError(const char *fmt, va_list args); +extern void logError(const char *fmt, ...) __attribute__((format(printf,1,2))); + +extern void vlogNotice(const char *fmt, va_list args); +extern void logNotice(const char *fmt, ...) __attribute__((format(printf,1,2))); + +extern void vlogDebug(const char *fmt, va_list args); +extern void logDebug(const char *fmt, ...) __attribute__((format(printf,1,2))); + +extern void vlogWarning(const char *fmt, va_list args); +extern void logWarning(const char *fmt, ...) __attribute__((format(printf,1,2))); #ifdef __cplusplus } diff --git a/drivers/RPi/SPI.cpp b/drivers/RPi/SPI.cpp index 997991dae..9ec58572b 100644 --- a/drivers/RPi/SPI.cpp +++ b/drivers/RPi/SPI.cpp @@ -38,7 +38,7 @@ uint8_t SPIClass::is_initialized() { void SPIClass::begin() { if (!initialized) { if (!bcm2835_spi_begin()) { - mys_log(LOG_ERR, "You need to be root to use SPI.\n"); + logError("You need root privilege to use SPI.\n"); exit(1); } } diff --git a/drivers/RPi/Wire.cpp b/drivers/RPi/Wire.cpp index bf78da1af..69ac5a330 100644 --- a/drivers/RPi/Wire.cpp +++ b/drivers/RPi/Wire.cpp @@ -44,7 +44,7 @@ uint8_t TwoWire::transmitting = 0; void TwoWire::begin() { if (!bcm2835_i2c_begin()) { - mys_log(LOG_ERR, "You need to be root to use I2C.\n"); + logError("You need root privilege to use I2C.\n"); exit(1); } } diff --git a/drivers/RPi/bcm2835.c b/drivers/RPi/bcm2835.c index 84a0f0de2..26aa8d644 100644 --- a/drivers/RPi/bcm2835.c +++ b/drivers/RPi/bcm2835.c @@ -1290,7 +1290,7 @@ static void *mapmem(const char *msg, size_t size, int fd, off_t off) { void *map = mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, off); if (map == MAP_FAILED) - mys_log(LOG_ERR, "bcm2835_init: %s mmap failed: %s\n", msg, strerror(errno)); + logError("bcm2835_init: %s mmap failed: %s\n", msg, strerror(errno)); return map; } @@ -1351,7 +1351,7 @@ int bcm2835_init(void) /* Open the master /dev/mem device */ if ((memfd = open("/dev/mem", O_RDWR | O_SYNC) ) < 0) { - mys_log(LOG_ERR, "bcm2835_init: Unable to open /dev/mem: %s\n", + logError("bcm2835_init: Unable to open /dev/mem: %s\n", strerror(errno)) ; goto exit; } @@ -1381,7 +1381,7 @@ int bcm2835_init(void) /* Open the master /dev/mem device */ if ((memfd = open("/dev/gpiomem", O_RDWR | O_SYNC) ) < 0) { - mys_log(LOG_ERR, "bcm2835_init: Unable to open /dev/gpiomem: %s\n", + logError("bcm2835_init: Unable to open /dev/gpiomem: %s\n", strerror(errno)) ; goto exit; } diff --git a/drivers/RPi/rpi_util.cpp b/drivers/RPi/rpi_util.cpp index 47f65bb32..7ee1a9288 100644 --- a/drivers/RPi/rpi_util.cpp +++ b/drivers/RPi/rpi_util.cpp @@ -131,7 +131,7 @@ void *interruptHandler(void *args) { (void)piHiPri(55); // Only effective if we run as root if ((fd = sysFds[gpioPin]) == -1) { - mys_log(LOG_ERR, "Failed to attach interrupt for pin %d\n", gpioPin); + logError("Failed to attach interrupt for pin %d\n", gpioPin); return NULL; } @@ -143,7 +143,7 @@ void *interruptHandler(void *args) { // Wait for it ... ret = poll(&polls, 1, -1); if (ret < 0) { - mys_log(LOG_ERR, "Error waiting for interrupt: %s\n", strerror(errno)); + logError("Error waiting for interrupt: %s\n", strerror(errno)); break; } // Do a dummy read to clear the interrupt @@ -163,7 +163,7 @@ void *interruptHandler(void *args) { void rpi_util::pinMode(uint8_t physPin, uint8_t mode) { uint8_t gpioPin = (physPin > 63)? 255 : physToGpio[physPin]; if (gpioPin == 255) { - mys_log(LOG_ERR, "pinMode: invalid pin: %d\n", physPin); + logError("pinMode: invalid pin: %d\n", physPin); return; } // Check if SPI is in use and target pin is related to SPI @@ -177,7 +177,7 @@ void rpi_util::pinMode(uint8_t physPin, uint8_t mode) { void rpi_util::digitalWrite(uint8_t physPin, uint8_t value) { uint8_t gpioPin = (physPin > 63)? 255 : physToGpio[physPin]; if (gpioPin == 255) { - mys_log(LOG_ERR, "digitalWrite: invalid pin: %d\n", physPin); + logError("digitalWrite: invalid pin: %d\n", physPin); return; } // Check if SPI is in use and target pin is related to SPI @@ -195,7 +195,7 @@ void rpi_util::digitalWrite(uint8_t physPin, uint8_t value) { uint8_t rpi_util::digitalRead(uint8_t physPin) { uint8_t gpioPin = (physPin > 63)? 255 : physToGpio[physPin]; if (gpioPin == 255) { - mys_log(LOG_ERR, "digitalRead: invalid pin: %d\n", physPin); + logError("digitalRead: invalid pin: %d\n", physPin); return 0; } // Check if SPI is in use and target pin is related to SPI @@ -214,7 +214,7 @@ void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode) { uint8_t gpioPin = (physPin > 63)? 255 : physToGpio[physPin]; if (gpioPin == 255) { - mys_log(LOG_ERR, "attachInterrupt: invalid pin: %d\n", physPin); + logError("attachInterrupt: invalid pin: %d\n", physPin); return; } @@ -229,7 +229,7 @@ void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode) { // Export pin for interrupt if ((fd = fopen("/sys/class/gpio/export", "w")) == NULL) { - mys_log(LOG_ERR, "attachInterrupt: Unable to export pin %d for interrupt: %s\n", physPin, strerror(errno)); + logError("attachInterrupt: Unable to export pin %d for interrupt: %s\n", physPin, strerror(errno)); exit(1); } fprintf(fd, "%d\n", gpioPin); @@ -257,7 +257,7 @@ void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode) { case RISING: fprintf(fd, "rising\n"); break; case NONE: fprintf(fd, "none\n"); break; default: - mys_log(LOG_ERR, "attachInterrupt: Invalid mode\n"); + logError("attachInterrupt: Invalid mode\n"); fclose(fd); return; } @@ -275,7 +275,7 @@ void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode) { ioctl(sysFds[gpioPin], FIONREAD, &count); for (i = 0; i < count; ++i) { if (read(sysFds[gpioPin], &c, 1) == -1) { - mys_log(LOG_ERR, "attachInterrupt: failed to read pin status: %s\n", strerror(errno)); + logError("attachInterrupt: failed to read pin status: %s\n", strerror(errno)); } } @@ -290,7 +290,7 @@ void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode) { void rpi_util::detachInterrupt(uint8_t physPin) { uint8_t gpioPin = (physPin > 63)? 255 : physToGpio[physPin]; if (gpioPin == 255) { - mys_log(LOG_ERR, "detachInterrupt: invalid pin: %d\n", physPin); + logError("detachInterrupt: invalid pin: %d\n", physPin); return; } @@ -309,7 +309,7 @@ void rpi_util::detachInterrupt(uint8_t physPin) { FILE *fp = fopen("/sys/class/gpio/unexport", "w"); if (fp == NULL) { - mys_log(LOG_ERR, "Unable to unexport pin %d for interrupt\n", gpioPin); + logError("Unable to unexport pin %d for interrupt\n", gpioPin); exit(1); } fprintf(fp, "%d", gpioPin); From afd7b7abbbcfa60e4d0e8b5d877c0cad476c2bdb Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Tue, 27 Sep 2016 18:21:49 +0200 Subject: [PATCH 103/167] Add MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL flag This flag, when set in a gateway sketch will make the gateway require all nodes to sign messages sent to it. --- MyConfig.h | 10 ++++++++++ core/MySigning.cpp | 19 ++++++++++++++++--- core/MySigning.h | 10 ++++++---- keywords.txt | 1 + 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/MyConfig.h b/MyConfig.h index 214069b84..1fc059da7 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -365,6 +365,15 @@ */ //#define MY_SIGNING_REQUEST_SIGNATURES +/** + * @def MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL + * @brief Enable this to have gateway require all nodes in the network to sign messages sent to it. @ref MY_SIGNING_REQUEST_SIGNATURES must also be set. + * + * Use this for maximum security, but be aware that every single node will have to be personalized before they can be used. + * Note that if this is enabled, and whitelisting is also enabled, whitelisting will also be in effect for all nodes. + */ +//#define MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL + /** * @def MY_VERIFICATION_TIMEOUT_MS * @brief Define a suitable timeout for a signature verification session @@ -828,6 +837,7 @@ #define MY_SIGNING_ATSHA204 #define MY_SIGNING_SOFT #define MY_SIGNING_REQUEST_SIGNATURES +#define MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL #define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01}}} #define MY_IS_RFM69HW #define MY_PARENT_NODE_IS_STATIC diff --git a/core/MySigning.cpp b/core/MySigning.cpp index 738eae149..76ed69e70 100644 --- a/core/MySigning.cpp +++ b/core/MySigning.cpp @@ -33,6 +33,9 @@ #if defined(MY_SIGNING_REQUEST_SIGNATURES) && (!defined(MY_SIGNING_ATSHA204) && !defined(MY_SIGNING_SOFT)) #error You have to pick either MY_SIGNING_ATSHA204 or MY_SIGNING_SOFT in order to require signatures! #endif +#if defined(MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL) && !defined(MY_SIGNING_REQUEST_SIGNATURES) +#error You have to require signatures if you want to require signatures from all (also enable MY_SIGNING_REQUEST_SIGNATURES in your gateway) +#endif #ifdef MY_SIGNING_FEATURE uint8_t _doSign[32]; // Bitfield indicating which sensors require signed communication uint8_t _doWhitelist[32]; // Bitfield indicating which sensors require serial salted signatures @@ -231,20 +234,26 @@ bool signerProcessInternal(MyMessage &msg) { sizeof(_doWhitelist)); // Inform sender about our preference if we are a gateway, but only require signing if the sender - // required signing + // required signing unless we explicitly configure it to // We do not want a gateway to require signing from all nodes in a network just because it wants one node - // to sign it's messages + // to sign it's messages unless we explicitly configure it to #if defined(MY_GATEWAY_FEATURE) prepareSigningPresentation(msg, sender); #if defined(MY_SIGNING_REQUEST_SIGNATURES) if (DO_SIGN(sender)) { msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES; } +#if defined(MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL) + msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES; +#endif #endif #if defined(MY_SIGNING_NODE_WHITELISTING) if (DO_WHITELIST(sender)) { msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING; } +#if defined(MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL) + msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING; +#endif #endif if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_SIGNATURES) { SIGN_DEBUG(PSTR("Informing node %d that we require signatures\n"), sender); @@ -356,9 +365,13 @@ bool signerVerifyMsg(MyMessage &msg) { // (if it is signed and addressed to us) // Note that we do not care at all about any signature found if we do not require signing #if defined(MY_SIGNING_FEATURE) && defined(MY_SIGNING_REQUEST_SIGNATURES) - // If we are a node, or we are a gateway and the sender require signatures + // If we are a node, or we are a gateway and the sender require signatures (or just a strict gw) // and we are the destination... +#if defined(MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL) + if (msg.destination == _nc.nodeId) { +#else if ((!MY_IS_GATEWAY || DO_SIGN(msg.sender)) && msg.destination == _nc.nodeId) { +#endif // Internal messages of certain types are not verified if (skipSign(msg)) { verificationResult = true; diff --git a/core/MySigning.h b/core/MySigning.h index 135335322..761f3e38b 100644 --- a/core/MySigning.h +++ b/core/MySigning.h @@ -156,7 +156,8 @@ * This has to be set by at least one of the node in a "pair" or nobody will actually start calculating a signature for a message. * Just set the flag @ref MY_SIGNING_REQUEST_SIGNATURES and the node will inform the gateway that it expects the gateway to sign all * messages sent to the node. If this is set in a gateway, it will @b NOT force all nodes to sign messages to it. It will only require - * signatures from nodes that in turn require signatures.
+ * signatures from nodes that in turn require signatures. If it is desired that the gateway should require signatures from all nodes, + * @ref MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL can be set in the gateway sketch.
* If you want to have two nodes communicate securely directly with each other, the nodes that require signatures must send a presentation * message to all nodes it expect signed messages from (only the gateway is informed automatically). See @ref signerPresentation().
* A node can have three "states" with respect to signing: @@ -267,14 +268,15 @@ * * If a node does require signing, any unsigned message sent to the node will be rejected.
* This also applies to the gateway. However, the difference is that the gateway will only require signed messages from nodes it knows in turn - * require signed messages.
+ * require signed messages (unless @ref MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL is set).
* A node can also inform a different node that it expects to receive signed messages from it. This is done by transmitting an internal message * of type @ref I_SIGNING_PRESENTATION and provide flags as payload that inform the receiver of the signing preferences of the sender.
* All nodes and gateways in a network maintain a table where the signing preferences of all nodes are stored. This is also stored in EEPROM so * if the gateway reboots, the nodes does not have to retransmit a signing presentation to the gateway for the gateway to realize that the node * expect signed messages.
* Also, the nodes that do not require signed messages will also inform gateway of this, so if you reprogram a node to stop require signing, - * the gateway will adhere to this as soon as the new node has presented itself to the gateway. + * the gateway will adhere to this as soon as the new node has presented itself to the gateway. Note however, that if the gateway sets + * @ref MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL a node that does not support signing will be unable to send any data to the gateway. * * The following sequence diagram illustrate how messages are passed in a MySensors network with respect to signing: * @image html MySigning/signingsequence.png @@ -429,7 +431,7 @@ * ... * @endcode * - * The gateway needs to configured with a whitelist (and it have to have an entry for all nodes that send and/or require signed messages):
+ * The gateway needs to be configured with a whitelist (and it has to have an entry for all nodes that send and/or require signed messages):
* @code{.cpp} * #define MY_SIGNING_SOFT * #define MY_SIGNING_SOFT_RANDOMSEED_PIN 7 diff --git a/keywords.txt b/keywords.txt index 5d8da56a5..1e4617bd6 100644 --- a/keywords.txt +++ b/keywords.txt @@ -123,6 +123,7 @@ MY_GATEWAY_MQTT_CLIENT LITERAL1 MY_DISABLE_REMOTE_RESET LITERAL1 MY_RS485_DE_PIN LITERAL1 MY_SIGNING_REQUEST_SIGNATURES LITERAL1 +MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL LITERAL1 MY_SMART_SLEEP_WAIT_DURATION LITERAL1 MY_NODE_LOCK_FEATURE LITERAL1 MY_NODE_UNLOCK_PIN LITERAL1 From ec1c2096453a808fc33fe9ffd82a33d9929ee31f Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Sun, 16 Oct 2016 13:00:00 -0200 Subject: [PATCH 104/167] RPi: Add support for signing messages --- MySensors.h | 3 + core/MyMainLinux.cpp | 266 +++++++++++++++++++++++++++++++- core/MySensorsCore.cpp | 5 + core/MySigningAtsha204Soft.cpp | 18 +++ drivers/Linux/Arduino.h | 1 + drivers/Linux/compatibility.cpp | 13 ++ examples_linux/mysGateway.cpp | 10 ++ 7 files changed, 312 insertions(+), 4 deletions(-) diff --git a/MySensors.h b/MySensors.h index cbeee9083..8824e8d80 100644 --- a/MySensors.h +++ b/MySensors.h @@ -131,6 +131,9 @@ #if defined(MY_SIGNING_ATSHA204) && defined(MY_SIGNING_SOFT) #error Only one signing engine can be activated #endif + #if defined(MY_SIGNING_ATSHA204) && defined(__linux__) + #error No support for ATSHA204 on this platform + #endif #if defined(MY_SIGNING_ATSHA204) #include "core/MySigningAtsha204.cpp" diff --git a/core/MyMainLinux.cpp b/core/MyMainLinux.cpp index 12687e8b6..50c53255b 100644 --- a/core/MyMainLinux.cpp +++ b/core/MyMainLinux.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include "log.h" #include "MySensorsCore.h" @@ -101,20 +102,247 @@ void print_usage() { printf("Usage: mysGateway [options]\n\n" \ "Options:\n" \ - " -h Display a short summary of all program options.\n" \ - " -d Enable debug.\n" \ - " -b Become a daemon.\n"); + " -h, --help Display a short summary of all program options.\n" \ + " -d, --debug Enable debug.\n" \ + " -b, --background Run as a background process.\n" + " --gen-soft-hmac-key Generate and print a soft hmac key.\n" + " --gen-soft-serial-key Generate and print a soft serial key.\n" + " --gen-aes-key Generate and print an aes encryption key.\n" + " --print-soft-hmac-key Print the soft hmac key from the config file.\n" + " --print-soft-serial-key Print the soft serial key from the config file.\n" + " --print-aes-key Print the aes encryption key from the config file.\n" + " --set-soft-hmac-key Write a soft hmac key to the config file.\n" + " --set-soft-serial-key Write a soft serial key to the config file.\n" + " --set-aes-key Write an aes encryption key to the config file.\n"); +} + +void print_soft_sign_hmac_key() +{ + uint8_t key[32]; + + hwReadConfigBlock(&key, reinterpret_castEEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32); + + printf("SOFT_HMAC_KEY | "); + for (int i = 0; i < 32; i++) { + printf("%02X", key[i]); + } + printf("\n"); + + printf("The next line is intended to be used in SecurityPersonalizer.ino:\n"); + printf("#define MY_SOFT_HMAC_KEY "); + for (int i=0; i<32; i++) { + printf("%#02X", key[i]); + if (i < 31) printf(","); + } + printf("\n"); +} + +void generate_soft_sign_hmac_key() +{ + uint8_t key[32]; + + for (int i = 0; i < 32; i++) { + key[i] = random(256) ^ micros(); + unsigned long enter = hwMillis(); + while (hwMillis() - enter < (unsigned long)2); + } + + printf("SOFT_HMAC_KEY | "); + for (int i = 0; i < 32; i++) { + printf("%02X", key[i]); + } + printf("\n"); +} + +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) { + char c = key_str[i]; + if (c <= '9') + n = c - '0'; + else if (c >= 'a') + n = c - 'a' + 10; + else + n = c - 'A' + 10; + + if ((i & 0x1) == 0) { + key[i/2] = n * 16; + } else { + key[i/2] += n; + } + } + hwWriteConfigBlock(&key, reinterpret_castEEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32); + print_soft_sign_hmac_key(); + } +} + +void print_soft_sign_serial_key() +{ + uint8_t key[9]; + + hwReadConfigBlock(&key, reinterpret_castEEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9); + + printf("SOFT_SERIAL | "); + for (int i = 0; i < 9; i++) { + printf("%02X", key[i]); + } + printf("\n"); + + printf("The next line is intended to be used in SecurityPersonalizer.ino:\n"); + printf("#define MY_SOFT_SERIAL "); + for (int i=0; i<9; i++) { + printf("%#02X", key[i]); + if (i < 8) printf(","); + } + printf("\n"); +} + +void generate_soft_sign_serial_key() +{ + uint8_t key[9]; + + for (int i = 0; i < 9; i++) { + key[i] = random(256) ^ micros(); + unsigned long enter = hwMillis(); + while (hwMillis() - enter < (unsigned long)2); + } + + printf("SOFT_SERIAL | "); + for (int i = 0; i < 9; i++) { + printf("%02X", key[i]); + } + printf("\n"); +} + +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) { + char c = key_str[i]; + if (c <= '9') + n = c - '0'; + else if (c >= 'a') + n = c - 'a' + 10; + else + n = c - 'A' + 10; + + if ((i & 0x1) == 0) { + key[i/2] = n * 16; + } else { + key[i/2] += n; + } + } + hwWriteConfigBlock(&key, reinterpret_castEEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9); + print_soft_sign_serial_key(); + } +} + +void print_aes_key() +{ + uint8_t key[16]; + + hwReadConfigBlock(&key, reinterpret_castEEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); + + printf("AES_KEY | "); + for (int i = 0; i < 16; i++) { + printf("%02X", key[i]); + } + printf("\n"); + + printf("The next line is intended to be used in SecurityPersonalizer.ino:\n"); + printf("#define MY_AES_KEY "); + for (int i=0; i<16; i++) { + printf("%#02X", key[i]); + if (i < 15) printf(","); + } + printf("\n"); +} + +void generate_aes_key() +{ + uint8_t key[16]; + + for (int i = 0; i < 16; i++) { + key[i] = random(256) ^ micros(); + unsigned long enter = hwMillis(); + while (hwMillis() - enter < (unsigned long)2); + } + + printf("AES_KEY | "); + for (int i = 0; i < 16; i++) { + printf("%02X", key[i]); + } + printf("\n"); +} + +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) { + char c = key_str[i]; + if (c <= '9') + n = c - '0'; + else if (c >= 'a') + n = c - 'a' + 10; + else + n = c - 'A' + 10; + + if ((i & 0x1) == 0) { + key[i/2] = n * 16; + } else { + key[i/2] += n; + } + } + hwWriteConfigBlock(&key, reinterpret_castEEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); + print_aes_key(); + } } int main(int argc, char *argv[]) { int opt, log_opts, debug = 0, foreground = 1; + char *key = NULL; /* register the signal handler */ signal(SIGINT, handle_sigint); signal(SIGTERM, handle_sigint); - while ((opt = getopt(argc, argv, "hdb")) != -1) { + hwRandomNumberInit(); + + static struct option long_options[] = { + {"help", no_argument, 0, 'h'}, + {"debug", no_argument, 0, 'd'}, + {"background", no_argument, 0, 'b'}, + {"gen-soft-hmac-key", no_argument, 0, 'A'}, + {"gen-soft-serial-key", no_argument, 0, 'B'}, + {"gen-aes-key", no_argument, 0, 'C'}, + {"print-soft-hmac-key", no_argument, 0, 'D'}, + {"print-soft-serial-key", no_argument, 0, 'E'}, + {"print-aes-key", no_argument, 0, 'F'}, + {"set-soft-hmac-key", required_argument, 0, 'G'}, + {"set-soft-serial-key", required_argument, 0, 'H'}, + {"set-aes-key", required_argument, 0, 'I'}, + {0, 0, 0, 0} + }; + + int long_index = 0; + while ((opt = getopt_long(argc, argv,"hdbABCDEFGHI", long_options, &long_index )) != -1) { switch (opt) { case 'h': print_usage(); @@ -125,6 +353,36 @@ int main(int argc, char *argv[]) case 'b': foreground = 0; break; + case 'A': + generate_soft_sign_hmac_key(); + exit(0); + case 'B': + generate_soft_sign_serial_key(); + exit(0); + case 'C': + generate_aes_key(); + exit(0); + case 'D': + print_soft_sign_hmac_key(); + exit(0); + case 'E': + print_soft_sign_serial_key(); + exit(0); + case 'F': + print_aes_key(); + exit(0); + case 'G': + key = strdup(optarg); + set_soft_sign_hmac_key(key); + exit(0); + case 'H': + key = strdup(optarg); + set_soft_sign_serial_key(key); + exit(0); + case 'I': + key = strdup(optarg); + set_aes_key(key); + exit(0); default: print_usage(); exit(0); diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 11eadad16..8586b2a08 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -19,6 +19,11 @@ #include "MySensorsCore.h" +#if defined(__linux__) + #include + #include +#endif + ControllerConfig _cc; // Configuration coming from controller NodeConfig _nc; // Essential settings for node to work MyMessage _msg; // Buffer for incoming messages diff --git a/core/MySigningAtsha204Soft.cpp b/core/MySigningAtsha204Soft.cpp index 3c0b4b5e2..cec7ad6aa 100644 --- a/core/MySigningAtsha204Soft.cpp +++ b/core/MySigningAtsha204Soft.cpp @@ -64,6 +64,23 @@ static char i2h(uint8_t i) } } +#ifdef __linux__ +static void DEBUG_SIGNING_PRINTBUF(const char *str, uint8_t* buf, uint8_t sz) { + static char printBuffer[300]; + + for (int i=0; i> 4); + printBuffer[(i * 2) + 1] = i2h(buf[i]); + } + printBuffer[sz * 2] = '\0'; + debug(str); + if (sz > 0) + { + debug(printBuffer); + } +} +#else static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, uint8_t sz) { static char printBuffer[300]; #ifdef MY_GATEWAY_FEATURE @@ -88,6 +105,7 @@ static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, } MY_SERIALDEVICE.println(""); } +#endif /* __linux__ */ #else #define DEBUG_SIGNING_PRINTBUF(str, buf, sz) #endif diff --git a/drivers/Linux/Arduino.h b/drivers/Linux/Arduino.h index cb0cb72af..eaa4ed9a6 100644 --- a/drivers/Linux/Arduino.h +++ b/drivers/Linux/Arduino.h @@ -71,6 +71,7 @@ typedef string String; void yield(void); unsigned long millis(void); +unsigned long micros(void); void _delay_ms(unsigned int millis); void randomSeed(unsigned long seed); long randMax(long howbig); diff --git a/drivers/Linux/compatibility.cpp b/drivers/Linux/compatibility.cpp index b0ceee114..a19ce54a6 100644 --- a/drivers/Linux/compatibility.cpp +++ b/drivers/Linux/compatibility.cpp @@ -21,6 +21,19 @@ unsigned long millis(void) return ((curTime.tv_sec - millis_at_start) * 1000) + (curTime.tv_usec / 1000); } +unsigned long micros() +{ + timeval curTime; + + if (millis_at_start == 0) { + gettimeofday(&curTime, NULL); + millis_at_start = curTime.tv_sec; + } + + gettimeofday(&curTime, NULL); + return ((curTime.tv_sec - millis_at_start) * 1000000) + (curTime.tv_usec); +} + void _delay_ms(unsigned int millis) { struct timespec sleeper; diff --git a/examples_linux/mysGateway.cpp b/examples_linux/mysGateway.cpp index c0c69c2c2..c94d482a5 100644 --- a/examples_linux/mysGateway.cpp +++ b/examples_linux/mysGateway.cpp @@ -57,6 +57,16 @@ // Inverse the blinking feature //#define MY_WITH_LEDS_BLINKING_INVERSE +// Enable software signing +//#define MY_SIGNING_SOFT +// Enable signing related debug +//#define MY_DEBUG_VERBOSE_SIGNING +// Enable this to request signatures from nodes that in turn request signatures from gateway +//#define MY_SIGNING_REQUEST_SIGNATURES +// Enable this to have gateway require all nodes in the network to sign messages sent to it +// Note: MY_SIGNING_REQUEST_SIGNATURES must also be set +//#define MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL + #include void setup() { From 95318d05db8e891d8c355d04b312b78abc0c81c8 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Wed, 19 Oct 2016 15:25:58 -0200 Subject: [PATCH 105/167] RPi: Update messages for key generation This was suggested by the forum user NiklasO. --- core/MyMainLinux.cpp | 60 ++++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/core/MyMainLinux.cpp b/core/MyMainLinux.cpp index 4c74200e8..e6155baf9 100644 --- a/core/MyMainLinux.cpp +++ b/core/MyMainLinux.cpp @@ -118,25 +118,28 @@ void print_usage() " --set-aes-key Write an aes encryption key to the config file.\n"); } -void print_soft_sign_hmac_key() +void print_soft_sign_hmac_key(uint8_t *key_ptr = NULL) { uint8_t key[32]; - hwReadConfigBlock(&key, reinterpret_castEEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32); + if (key_ptr == NULL) { + hwReadConfigBlock(&key, reinterpret_castEEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32); + key_ptr = key; + } printf("SOFT_HMAC_KEY | "); for (int i = 0; i < 32; i++) { - printf("%02X", key[i]); + printf("%02X", key_ptr[i]); } - printf("\n"); + printf("\n\n"); printf("The next line is intended to be used in SecurityPersonalizer.ino:\n"); printf("#define MY_SOFT_HMAC_KEY "); for (int i=0; i<32; i++) { - printf("%#02X", key[i]); + printf("%#02X", key_ptr[i]); if (i < 31) printf(","); } - printf("\n"); + printf("\n\n"); } void generate_soft_sign_hmac_key() @@ -149,7 +152,10 @@ void generate_soft_sign_hmac_key() while (hwMillis() - enter < (unsigned long)2); } - printf("SOFT_HMAC_KEY | "); + print_soft_sign_hmac_key(key); + + printf("To use this key, run mysGateway with:\n" + " --set-soft-hmac-key="); for (int i = 0; i < 32; i++) { printf("%02X", key[i]); } @@ -184,25 +190,28 @@ void set_soft_sign_hmac_key(char *key_str) } } -void print_soft_sign_serial_key() +void print_soft_sign_serial_key(uint8_t *key_ptr = NULL) { uint8_t key[9]; - hwReadConfigBlock(&key, reinterpret_castEEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9); + if (key_ptr == NULL) { + hwReadConfigBlock(&key, reinterpret_castEEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9); + key_ptr = key; + } printf("SOFT_SERIAL | "); for (int i = 0; i < 9; i++) { - printf("%02X", key[i]); + printf("%02X", key_ptr[i]); } - printf("\n"); + printf("\n\n"); printf("The next line is intended to be used in SecurityPersonalizer.ino:\n"); printf("#define MY_SOFT_SERIAL "); for (int i=0; i<9; i++) { - printf("%#02X", key[i]); + printf("%#02X", key_ptr[i]); if (i < 8) printf(","); } - printf("\n"); + printf("\n\n"); } void generate_soft_sign_serial_key() @@ -215,7 +224,10 @@ void generate_soft_sign_serial_key() while (hwMillis() - enter < (unsigned long)2); } - printf("SOFT_SERIAL | "); + print_soft_sign_serial_key(key); + + printf("To use this key, run mysGateway with:\n" + " --set-soft-serial-key="); for (int i = 0; i < 9; i++) { printf("%02X", key[i]); } @@ -250,25 +262,28 @@ void set_soft_sign_serial_key(char *key_str) } } -void print_aes_key() +void print_aes_key(uint8_t *key_ptr = NULL) { uint8_t key[16]; - hwReadConfigBlock(&key, reinterpret_castEEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); + if (key_ptr == NULL) { + hwReadConfigBlock(&key, reinterpret_castEEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); + key_ptr = key; + } printf("AES_KEY | "); for (int i = 0; i < 16; i++) { - printf("%02X", key[i]); + printf("%02X", key_ptr[i]); } - printf("\n"); + printf("\n\n"); printf("The next line is intended to be used in SecurityPersonalizer.ino:\n"); printf("#define MY_AES_KEY "); for (int i=0; i<16; i++) { - printf("%#02X", key[i]); + printf("%#02X", key_ptr[i]); if (i < 15) printf(","); } - printf("\n"); + printf("\n\n"); } void generate_aes_key() @@ -281,7 +296,10 @@ void generate_aes_key() while (hwMillis() - enter < (unsigned long)2); } - printf("AES_KEY | "); + print_aes_key(key); + + printf("To use this key, run mysGateway with:\n" + " --set-aes-key="); for (int i = 0; i < 16; i++) { printf("%02X", key[i]); } From 76dea1532ce2bcf21a5a167e21b4e0ba4eeaa51a Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Thu, 20 Oct 2016 17:05:13 -0200 Subject: [PATCH 106/167] RPi: Add support for RS485 transport Remove serial print from MyTransportRS485.cpp to increase speed. --- MyConfig.h | 13 +++++++ MySensors.h | 7 +++- configure | 38 ++++++++++++++++--- core/MyTransportRS485.cpp | 19 +++++++--- drivers/Linux/SerialPort.cpp | 5 ++- .../GatewaySerialRS485/GatewaySerialRS485.ino | 9 ++++- .../MotionSensorRS485/MotionSensorRS485.ino | 11 +++++- keywords.txt | 1 + 8 files changed, 85 insertions(+), 18 deletions(-) diff --git a/MyConfig.h b/MyConfig.h index 1fc059da7..ff8ba7037 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -440,6 +440,18 @@ #define MY_RS485_MAX_MESSAGE_LENGTH 40 #endif +/** + * @def MY_RS485_DE_PIN + * @brief RS485 driver enable pin. + */ +//#define MY_RS485_DE_PIN 2 + +/** + * @def MY_RS485_HWSERIAL + * @brief Enable this if RS485 is connected to a hardware serial port. + */ +//#define MY_RS485_HWSERIAL Serial1 + /********************************** * NRF24L01P Driver Defaults ***********************************/ @@ -839,6 +851,7 @@ #define MY_SIGNING_REQUEST_SIGNATURES #define MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL #define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01}}} +#define MY_RS485_HWSERIAL #define MY_IS_RFM69HW #define MY_PARENT_NODE_IS_STATIC #define MY_REGISTRATION_CONTROLLER diff --git a/MySensors.h b/MySensors.h index 8824e8d80..1e6414d22 100644 --- a/MySensors.h +++ b/MySensors.h @@ -287,7 +287,12 @@ #include "drivers/RF24/RF24.cpp" #include "core/MyTransportNRF24.cpp" #elif defined(MY_RS485) - #include "drivers/AltSoftSerial/AltSoftSerial.cpp" + #if !defined(MY_RS485_HWSERIAL) + #if defined(__linux__) + #error You must specify MY_RS485_HWSERIAL for RS485 transport + #endif + #include "drivers/AltSoftSerial/AltSoftSerial.cpp" + #endif #include "core/MyTransportRS485.cpp" #elif defined(MY_RADIO_RFM69) #include "drivers/RFM69/RFM69.cpp" diff --git a/configure b/configure index 570eddeae..6d987af99 100755 --- a/configure +++ b/configure @@ -27,8 +27,9 @@ Installation options: MySensors options: --my-debug=[enable|disable] Enables or disables MySensors core debugging. [enable] --my-config-file= Config file path. [/etc/mysensors.dat] - --my-gateway=[none|ethernet|serial|mqtt] + --my-gateway=[ethernet|serial|mqtt] Gateway type, set to none to disable gateway feature. [ethernet] + --my-node-id= Disable gateway feature and run as a node with given id. --my-controller-url-address= Controller or MQTT broker url. --my-controller-ip-address= @@ -47,13 +48,20 @@ MySensors options: MQTT publish topic prefix. --my-mqtt-subscribe-topic-prefix= MQTT subscribe topic prefix. - --my-radio=[none|nrf24] Radio type, set to none to disable radio feature. [rf24] + --my-transport=[none|nrf24|rs485] + Transport type, set to none to disable transport feature. [nrf24] --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-irq-pin= Pin number connected to nRF24L01 IRQ pin. --my-rx-message-buffer-size= Buffer size for incoming messages when using rf24 interrupts. [20] + --my-rs485-serial-port= + RS485 serial port. You must provide a port. + --my-rs485-baudrate= RS485 baudrate. [9600] + --my-rs485-de-pin= Pin number connected to RS485 driver enable pin. + --my-rs485-max-msg-length= + The maximum message length used for RS485. --my-leds-err-pin= Error LED pin. --my-leds-rx-pin= Receive LED pin. --my-leds-tx-pin= Transmit LED pin. @@ -196,7 +204,7 @@ function gcc_cpu_flags { # Default values debug=enable gateway_type=ethernet -radio_type=nrf24 +transport_type=nrf24 params="SOC CXXFLAGS LDFLAGS PREFIX CXX GATEWAY_DIR INIT_SYSTEM" @@ -237,11 +245,15 @@ for opt do --my-gateway=*) gateway_type=${optarg} ;; + --my-node-id=*) + gateway_type="none"; + CXXFLAGS="-DMY_NODE_ID=${optarg} $CXXFLAGS" + ;; --my-config-file=*) CXXFLAGS="-DMY_LINUX_CONFIG_FILE=\\\"${optarg}\\\" $CXXFLAGS" ;; - --my-radio=*) - radio_type=${optarg} + --my-transport=*) + transport_type=${optarg} ;; --my-serial-port=*) CXXFLAGS="-DMY_LINUX_SERIAL_PORT=\\\"${optarg}\\\" $CXXFLAGS" @@ -289,6 +301,18 @@ for opt do --my-rx-message-buffer-size=*) CXXFLAGS="-DMY_RX_MESSAGE_BUFFER_SIZE=${optarg} $CXXFLAGS" ;; + --my-rs485-serial-port=*) + CXXFLAGS="-DMY_RS485_HWSERIAL=\\\"${optarg}\\\" $CXXFLAGS" + ;; + --my-rs485-baudrate=*) + CXXFLAGS="-DMY_RS485_BAUD_RATE=${optarg} $CXXFLAGS" + ;; + --my-rs485-de-pin=*) + CXXFLAGS="-DMY_RS485_DE_PIN=${optarg} $CXXFLAGS" + ;; + --my-rs485-max-msg-length=*) + CXXFLAGS="-DMY_RS485_MAX_MESSAGE_LENGTH=${optarg} $CXXFLAGS" + ;; --my-leds-err-pin=*) CXXFLAGS="-DMY_DEFAULT_ERR_LED_PIN=${optarg} $CXXFLAGS" ;; @@ -344,8 +368,10 @@ elif [[ ${gateway_type} == "mqtt" ]]; then CXXFLAGS="-DMY_GATEWAY_LINUX -DMY_GATEWAY_MQTT_CLIENT $CXXFLAGS" fi -if [[ ${radio_type} == "nrf24" ]]; then +if [[ ${transport_type} == "nrf24" ]]; then CXXFLAGS="-DMY_RADIO_NRF24 $CXXFLAGS" +elif [[ ${transport_type} == "rs485" ]]; then + CXXFLAGS="-DMY_RS485 $CXXFLAGS" fi LDFLAGS="-pthread $LDFLAGS" diff --git a/core/MyTransportRS485.cpp b/core/MyTransportRS485.cpp index a7990ae1b..780301ac4 100644 --- a/core/MyTransportRS485.cpp +++ b/core/MyTransportRS485.cpp @@ -61,6 +61,9 @@ #include "MyTransport.h" +#ifdef __linux__ + #include "SerialPort.h" +#endif #if defined(MY_RS485_DE_PIN) #define assertDE() hwDigitalWrite(MY_RS485_DE_PIN, HIGH); delayMicroseconds(5) @@ -87,8 +90,14 @@ unsigned char _recSender; unsigned char _recCS; unsigned char _recCalcCS; -AltSoftSerial _dev; +#if defined(__linux__) +SerialPort _dev = SerialPort(MY_RS485_HWSERIAL); +#elif defined(MY_RS485_HWSERIAL) +HardwareSerial& _dev = MY_RS485_HWSERIAL; +#else +AltSoftSerial _dev; +#endif unsigned char _nodeId; char _data[MY_RS485_MAX_MESSAGE_LENGTH]; @@ -160,10 +169,6 @@ bool _serialProcess() if ((_recSender == _nodeId) || (_recStation != _nodeId && _recStation != BROADCAST_ADDRESS)) { - _dev.print(" wrongid: "); - _dev.print(_recStation); - _dev.print(" - "); - _dev.println(_nodeId); _serialReset(); break; } @@ -302,7 +307,9 @@ bool transportSend(uint8_t to, const void* data, uint8_t len) _dev.flush(); delayMicroseconds((20000000UL/9600)+1); #endif - #endif + #elif defined(__linux__) + _dev.flush(); + #endif #endif hwDigitalWrite(MY_RS485_DE_PIN, LOW); #endif diff --git a/drivers/Linux/SerialPort.cpp b/drivers/Linux/SerialPort.cpp index b1145cc3a..0c9f1bb1d 100644 --- a/drivers/Linux/SerialPort.cpp +++ b/drivers/Linux/SerialPort.cpp @@ -235,7 +235,10 @@ int SerialPort::peek() void SerialPort::flush() { - tcflush(sd, TCIFLUSH); + // Waits until all output written to sd has been transmitted + if (tcdrain(sd) < 0) { + logError("Couldn't flush serial: %s\n", strerror(errno)); + } } void SerialPort::end() diff --git a/examples/GatewaySerialRS485/GatewaySerialRS485.ino b/examples/GatewaySerialRS485/GatewaySerialRS485.ino index 03c8996a3..2db67c9de 100644 --- a/examples/GatewaySerialRS485/GatewaySerialRS485.ino +++ b/examples/GatewaySerialRS485/GatewaySerialRS485.ino @@ -32,8 +32,10 @@ * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly * - ERR (red) - fast blink on error during transmission error or recieve crc error * - * The gateway uses AltSoftSerial to handle two serial links - * on one Arduino. Use the following pins for RS485 link + * If your Arduino board has additional serial ports + * you can use to connect the RS485 module. + * Otherwise, the gateway uses AltSoftSerial to handle two serial + * links on one Arduino. Use the following pins for RS485 link * * Board Transmit Receive PWM Unusable * ----- -------- ------- ------------ @@ -60,6 +62,9 @@ // Set RS485 baud rate to use #define MY_RS485_BAUD_RATE 9600 +// Enable this if RS485 is connected to a hardware serial port +//#define MY_RS485_HWSERIAL Serial1 + // Enable serial gateway #define MY_GATEWAY_SERIAL diff --git a/examples/MotionSensorRS485/MotionSensorRS485.ino b/examples/MotionSensorRS485/MotionSensorRS485.ino index 7af76d2f9..e034ab43f 100644 --- a/examples/MotionSensorRS485/MotionSensorRS485.ino +++ b/examples/MotionSensorRS485/MotionSensorRS485.ino @@ -27,8 +27,10 @@ * Motion Sensor example using HC-SR501 * http://www.mysensors.org/build/motion * - * The transport uses AltSoftSerial to handle two serial links - * on one Arduino. Use the following pins for RS485 link + * If your Arduino board has additional serial ports + * you can use to connect the RS485 module. + * Otherwise, the transport uses AltSoftSerial to handle two serial + * links on one Arduino. Use the following pins for RS485 link * * Board Transmit Receive PWM Unusable * ----- -------- ------- ------------ @@ -43,6 +45,8 @@ * */ +// Enable debug prints to serial monitor +#define MY_DEBUG // Enable RS485 transport layer #define MY_RS485 @@ -53,6 +57,9 @@ // Set RS485 baud rate to use #define MY_RS485_BAUD_RATE 9600 +// Enable this if RS485 is connected to a hardware serial port +//#define MY_RS485_HWSERIAL Serial1 + #include unsigned long SLEEP_TIME = 120000; // Sleep time between reports (in milliseconds) diff --git a/keywords.txt b/keywords.txt index 1e4617bd6..6f3146187 100644 --- a/keywords.txt +++ b/keywords.txt @@ -114,6 +114,7 @@ MY_W5100_SPI_EN LITERAL1 MY_RS485 LITERAL1 MY_RS485_BAUD_RATE LITERAL1 MY_RS485_MAX_MESSAGE_LENGTH LITERAL1 +MY_RS485_HWSERIAL LITERAL1 MY_INCLUSION_BUTTON_EXTERNAL_PULLUP LITERAL1 MY_W5100_SPI_EN LITERAL1 MY_MQTT_SUBSCRIBE_TOPIC_PREFIX LITERAL1 From 7a969670ac595fdf651376ed1d2801154b3eaa2d Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Fri, 21 Oct 2016 17:17:28 -0200 Subject: [PATCH 107/167] RPi: Add warning msg for deprecated option --- configure | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configure b/configure index 6d987af99..4d54aa157 100755 --- a/configure +++ b/configure @@ -255,6 +255,10 @@ for opt do --my-transport=*) transport_type=${optarg} ;; + --my-radio=*) + echo "Warning: --my-radio is deprecated, please use --my-transport" + transport_type=${optarg} + ;; --my-serial-port=*) CXXFLAGS="-DMY_LINUX_SERIAL_PORT=\\\"${optarg}\\\" $CXXFLAGS" ;; From c47a83f1daa808a105b4cab4587c19e755cc4959 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sun, 30 Oct 2016 11:26:23 +0100 Subject: [PATCH 108/167] Make stability improvements in message signing * Made delay waiting for GW to transmit signing preferences apply also if signing is disabled since nodes always sends a signing presentation, and GW always replies with it's own presentation. This can cause message collition if the node at the same time proceed with other presentation messages. * Made the signing backend "consume" signing presentation messages sent by GW when signing is disabled. These messages should not be forwarded to the "user". --- core/MySigning.cpp | 210 ++++++++++++++++++++++----------------------- 1 file changed, 105 insertions(+), 105 deletions(-) diff --git a/core/MySigning.cpp b/core/MySigning.cpp index 76ed69e70..a9be61fbd 100644 --- a/core/MySigning.cpp +++ b/core/MySigning.cpp @@ -148,158 +148,158 @@ void signerPresentation(MyMessage &msg, uint8_t destination) { #endif if (!_sendRoute(msg)) { - SIGN_DEBUG(PSTR("Failed to transmit signing presentation!")); + SIGN_DEBUG(PSTR("Failed to transmit signing presentation!\n")); } -#if defined(MY_SIGNING_FEATURE) - // If we do support signing, wait for the gateway to tell us how it prefer us to transmit our messages if (destination == GATEWAY_ADDRESS) { SIGN_DEBUG(PSTR("Waiting for GW to send signing preferences...\n")); wait(2000, C_INTERNAL, I_SIGNING_PRESENTATION); } -#endif } bool signerProcessInternal(MyMessage &msg) { uint8_t sender = msg.sender; (void)sender; - if (mGetCommand(msg) == C_INTERNAL) { -#if !defined(MY_SIGNING_FEATURE) && defined(MY_GATEWAY_FEATURE) +#if !defined(MY_SIGNING_FEATURE) + if (msg.type == I_SIGNING_PRESENTATION) { +#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 - if (msg.type == I_SIGNING_PRESENTATION) { - prepareSigningPresentation(msg, sender); - SIGN_DEBUG(PSTR("Informing node %d that we do not require signatures because we do not support it\n"), - sender); - if (!_sendRoute(msg)) { - SIGN_DEBUG(PSTR("Failed to transmit signing presentation!")); - } - return true; // No need to further process I_SIGNING_PRESENTATION in this case + prepareSigningPresentation(msg, sender); + SIGN_DEBUG(PSTR("Informing node %d that we do not require signatures because we do not support it\n"), + sender); + if (!_sendRoute(msg)) { + SIGN_DEBUG(PSTR("Failed to transmit signing presentation!\n")); } + return true; // No need to further process I_SIGNING_PRESENTATION in this case +#else + // If we act as a node and do not have the signing feature then we just silently drop any signing + // presentation messages received + SIGN_DEBUG(PSTR("Received signing presentation, but signing is not supported (message ignored)\n")); + return true; +#endif + } #elif defined(MY_SIGNING_FEATURE) - if (msg.type == I_NONCE_REQUEST) { + if (msg.type == I_NONCE_REQUEST) { #if defined(MY_NODE_LOCK_FEATURE) - nof_nonce_requests++; - SIGN_DEBUG(PSTR("Nonce requests left until lockdown: %d\n"), MY_NODE_LOCK_COUNTER_MAX-nof_nonce_requests); - if (nof_nonce_requests >= MY_NODE_LOCK_COUNTER_MAX) { - nodeLock("TMNR"); //Too many nonces requested - } + nof_nonce_requests++; + SIGN_DEBUG(PSTR("Nonce requests left until lockdown: %d\n"), MY_NODE_LOCK_COUNTER_MAX-nof_nonce_requests); + if (nof_nonce_requests >= MY_NODE_LOCK_COUNTER_MAX) { + nodeLock("TMNR"); //Too many nonces requested + } #endif #if defined(MY_SIGNING_SOFT) - if (signerAtsha204SoftGetNonce(msg)) { + if (signerAtsha204SoftGetNonce(msg)) { #endif #if defined(MY_SIGNING_ATSHA204) - if (signerAtsha204GetNonce(msg)) { + if (signerAtsha204GetNonce(msg)) { #endif - if (!_sendRoute(build(msg, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_NONCE_RESPONSE))) { - SIGN_DEBUG(PSTR("Failed to transmit nonce!\n")); - } else { - SIGN_DEBUG(PSTR("Transmitted nonce\n")); - } + if (!_sendRoute(build(msg, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_NONCE_RESPONSE))) { + SIGN_DEBUG(PSTR("Failed to transmit nonce!\n")); } else { - SIGN_DEBUG(PSTR("Failed to generate nonce!\n")); + SIGN_DEBUG(PSTR("Transmitted nonce\n")); } - return true; // No need to further process I_NONCE_REQUEST - } else if (msg.type == I_SIGNING_PRESENTATION) { - if (msg.data[0] != SIGNING_PRESENTATION_VERSION_1) { - SIGN_DEBUG(PSTR("Unsupported signing presentation version (%d)!\n"), msg.data[0]); - return true; // Just drop this presentation message - } - + } else { + SIGN_DEBUG(PSTR("Failed to generate nonce!\n")); + } + return true; // No need to further process I_NONCE_REQUEST + } else if (msg.type == I_SIGNING_PRESENTATION) { + if (msg.data[0] != SIGNING_PRESENTATION_VERSION_1) { + SIGN_DEBUG(PSTR("Unsupported signing presentation version (%d)!\n"), msg.data[0]); + return true; // Just drop this presentation message + } // 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); - } 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); - } - + 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); + } 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); + } 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); - } 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); - } + // 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); + } 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); + } - // Save updated tables - hwWriteConfigBlock((void*)_doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, - sizeof(_doSign)); - hwWriteConfigBlock((void*)_doWhitelist, (void*)EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS, - sizeof(_doWhitelist)); + // Save updated tables + hwWriteConfigBlock((void*)_doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, + sizeof(_doSign)); + hwWriteConfigBlock((void*)_doWhitelist, (void*)EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS, + sizeof(_doWhitelist)); - // 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 - // We do not want a gateway to require signing from all nodes in a network just because it wants one node - // to sign it's messages unless we explicitly configure it to + // 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 + // We do not want a gateway to require signing from all nodes in a network just because it wants one node + // to sign it's messages unless we explicitly configure it to #if defined(MY_GATEWAY_FEATURE) - prepareSigningPresentation(msg, sender); + prepareSigningPresentation(msg, sender); #if defined(MY_SIGNING_REQUEST_SIGNATURES) - if (DO_SIGN(sender)) { - msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES; - } -#if defined(MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL) + if (DO_SIGN(sender)) { msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES; + } +#if defined(MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL) + msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES; #endif #endif #if defined(MY_SIGNING_NODE_WHITELISTING) - if (DO_WHITELIST(sender)) { - msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING; - } -#if defined(MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL) + if (DO_WHITELIST(sender)) { msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING; + } +#if defined(MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL) + msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING; #endif #endif - if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_SIGNATURES) { - 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"), sender); - } - if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_WHITELISTING) { - 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"), sender); - } - if (!_sendRoute(msg)) { - SIGN_DEBUG(PSTR("Failed to transmit signing presentation!")); - } + if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_SIGNATURES) { + 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"), sender); + } + if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_WHITELISTING) { + 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"), sender); + } + if (!_sendRoute(msg)) { + SIGN_DEBUG(PSTR("Failed to transmit signing presentation!\n")); + } #endif // MY_GATEWAY_FEATURE - return true; // No need to further process I_SIGNING_PRESENTATION - } else if (msg.type == I_NONCE_RESPONSE) { - // Proceed with signing if nonce has been received - SIGN_DEBUG(PSTR("Nonce received from %d. Proceeding with signing...\n"), sender); - if (sender != _msgSign.destination) { - SIGN_DEBUG(PSTR("Nonce did not come from the destination (%d) of the message to be signed! " - "It came from %d.\n"), _msgSign.destination, sender); - SIGN_DEBUG(PSTR("Silently discarding this nonce\n")); - return true; // No need to further process I_NONCE_RESPONSE - } + return true; // No need to further process I_SIGNING_PRESENTATION + } else if (msg.type == I_NONCE_RESPONSE) { + // Proceed with signing if nonce has been received + SIGN_DEBUG(PSTR("Nonce received from %d. Proceeding with signing...\n"), sender); + if (sender != _msgSign.destination) { + SIGN_DEBUG(PSTR("Nonce did not come from the destination (%d) of the message to be signed! " + "It came from %d.\n"), _msgSign.destination, sender); + SIGN_DEBUG(PSTR("Silently discarding this nonce\n")); + return true; // No need to further process I_NONCE_RESPONSE + } #if defined(MY_SIGNING_SOFT) - signerAtsha204SoftPutNonce(msg); + signerAtsha204SoftPutNonce(msg); #endif #if defined(MY_SIGNING_ATSHA204) - signerAtsha204PutNonce(msg); + signerAtsha204PutNonce(msg); #endif #if defined(MY_SIGNING_SOFT) - if (!signerAtsha204SoftSignMsg(_msgSign)) { + if (!signerAtsha204SoftSignMsg(_msgSign)) { #endif #if defined(MY_SIGNING_ATSHA204) - if (!signerAtsha204SignMsg(_msgSign)) { + if (!signerAtsha204SignMsg(_msgSign)) { #endif - SIGN_DEBUG(PSTR("Failed to sign message!\n")); - } else { - SIGN_DEBUG(PSTR("Message signed\n")); - _signingNonceStatus = SIGN_OK; // _msgSign now contains the signed message pending transmission - } - return true; // No need to further process I_NONCE_RESPONSE + SIGN_DEBUG(PSTR("Failed to sign message!\n")); + } else { + SIGN_DEBUG(PSTR("Message signed\n")); + _signingNonceStatus = SIGN_OK; // _msgSign now contains the signed message pending transmission } -#endif // MY_SIGNING_FEATURE + return true; // No need to further process I_NONCE_RESPONSE } +#endif // MY_SIGNING_FEATURE return false; } From e21df6484553a6043a07336d7556dcc6e34cc6f7 Mon Sep 17 00:00:00 2001 From: frizzy Date: Thu, 3 Nov 2016 19:32:20 +0000 Subject: [PATCH 109/167] MQTT: Add support for slash in subscriber topic --- core/MyProtocolMySensors.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) mode change 100644 => 100755 core/MyProtocolMySensors.cpp diff --git a/core/MyProtocolMySensors.cpp b/core/MyProtocolMySensors.cpp old mode 100644 new mode 100755 index f5302b482..f3c9ac414 --- a/core/MyProtocolMySensors.cpp +++ b/core/MyProtocolMySensors.cpp @@ -120,40 +120,42 @@ bool protocolMQTTParse(MyMessage &message, char* topic, uint8_t* payload, unsign uint8_t bvalue[MAX_PAYLOAD]; uint8_t blen = 0; uint8_t command = 0; + uint8_t topiclen = strlen(topic) - strlen(MY_MQTT_SUBSCRIBE_TOPIC_PREFIX); + char topicTrimmed[topiclen]; - for (str = strtok_r(topic, "/", &p); str && i <= 5; + if (topic != strstr(topic, MY_MQTT_SUBSCRIBE_TOPIC_PREFIX)) { + // Prefix doesn't match incoming topic + return false; + } + // Extract the topic sans prefix + strncpy(topicTrimmed, &topic[strlen(MY_MQTT_SUBSCRIBE_TOPIC_PREFIX) + 1], topiclen); + topicTrimmed[topiclen] = (char)0; + + for (str = strtok_r(topicTrimmed, "/", &p); str && i <= 5; str = strtok_r(NULL, "/", &p)) { switch (i) { case 0: { - // Topic prefix - if (strcmp(str, MY_MQTT_SUBSCRIBE_TOPIC_PREFIX) != 0) { - // Message not for us or malformed! - return false; - } - break; - } - case 1: { // Node id message.destination = atoi(str); break; } - case 2: { + case 1: { // Sensor id message.sensor = atoi(str); break; } - case 3: { + case 2: { // Command type command = atoi(str); mSetCommand(message, command); break; } - case 4: { + case 3: { // Ack flag mSetRequestAck(message, atoi(str)?1:0); break; } - case 5: { + case 4: { // Sub type message.type = atoi(str); break; @@ -162,7 +164,7 @@ bool protocolMQTTParse(MyMessage &message, char* topic, uint8_t* payload, unsign i++; } - if (i != 6) { + if (i != 5) { return false; } From 2321c67ffa5903e6e473121fed32e239ac2beddc Mon Sep 17 00:00:00 2001 From: frizzy Date: Fri, 4 Nov 2016 19:42:34 +0000 Subject: [PATCH 110/167] MQTT: Removed need for new topic buffer --- core/MyProtocolMySensors.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/core/MyProtocolMySensors.cpp b/core/MyProtocolMySensors.cpp index f3c9ac414..d046e57f4 100755 --- a/core/MyProtocolMySensors.cpp +++ b/core/MyProtocolMySensors.cpp @@ -120,18 +120,11 @@ bool protocolMQTTParse(MyMessage &message, char* topic, uint8_t* payload, unsign uint8_t bvalue[MAX_PAYLOAD]; uint8_t blen = 0; uint8_t command = 0; - uint8_t topiclen = strlen(topic) - strlen(MY_MQTT_SUBSCRIBE_TOPIC_PREFIX); - char topicTrimmed[topiclen]; - if (topic != strstr(topic, MY_MQTT_SUBSCRIBE_TOPIC_PREFIX)) { // Prefix doesn't match incoming topic return false; } - // Extract the topic sans prefix - strncpy(topicTrimmed, &topic[strlen(MY_MQTT_SUBSCRIBE_TOPIC_PREFIX) + 1], topiclen); - topicTrimmed[topiclen] = (char)0; - - for (str = strtok_r(topicTrimmed, "/", &p); str && i <= 5; + for (str = strtok_r(topic + strlen(MY_MQTT_SUBSCRIBE_TOPIC_PREFIX) + 1, "/", &p); str && i <= 5; str = strtok_r(NULL, "/", &p)) { switch (i) { case 0: { From c6ff9122b4f68858c17b08692fbd05842960ce9e Mon Sep 17 00:00:00 2001 From: Olivier Date: Sat, 5 Nov 2016 09:50:18 +0100 Subject: [PATCH 111/167] Harmonize definition ins core (#628) --- MyConfig.h | 9 +++++++++ core/MyHwATMega328.cpp | 8 ++++---- core/MyHwATMega328.h | 14 ++++++-------- core/MyHwESP8266.cpp | 8 ++++---- core/MyHwESP8266.h | 1 - core/MyHwSAMD.cpp | 8 ++++---- core/MyHwSAMD.h | 9 --------- 7 files changed, 27 insertions(+), 30 deletions(-) diff --git a/MyConfig.h b/MyConfig.h index ff8ba7037..7002e846d 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -67,6 +67,15 @@ #ifndef MY_BAUD_RATE #define MY_BAUD_RATE 115200 #endif + /** + * @def MY_SERIAL_OUTPUT_SIZE + * @brief Max. characters for serial output. + */ +#ifndef MY_SERIAL_OUTPUT_SIZE +#define MY_SERIAL_OUTPUT_SIZE (120u) +#endif + + // Disables over-the-air reset of node //#define MY_DISABLE_REMOTE_RESET diff --git a/core/MyHwATMega328.cpp b/core/MyHwATMega328.cpp index 570559022..6619747bb 100644 --- a/core/MyHwATMega328.cpp +++ b/core/MyHwATMega328.cpp @@ -219,7 +219,7 @@ uint16_t hwFreeMem() { #ifdef MY_DEBUG void hwDebugPrint(const char *fmt, ... ) { - char fmtBuffer[MY_DEBUG_BUFFER_SIZE]; + char fmtBuffer[MY_SERIAL_OUTPUT_SIZE]; #ifdef MY_GATEWAY_FEATURE // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) snprintf_P(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); @@ -233,9 +233,9 @@ void hwDebugPrint(const char *fmt, ... ) { va_start (args, fmt ); #ifdef MY_GATEWAY_FEATURE // Truncate message if this is gateway node - vsnprintf_P(fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, fmt, args); - fmtBuffer[MY_GATEWAY_MAX_SEND_LENGTH-1] = '\n'; - fmtBuffer[MY_GATEWAY_MAX_SEND_LENGTH] = '\0'; + vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args); + fmtBuffer[sizeof(fmtBuffer) - 2] = '\n'; + fmtBuffer[sizeof(fmtBuffer) - 1] = '\0'; #else vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args); #endif diff --git a/core/MyHwATMega328.h b/core/MyHwATMega328.h index b8e64d108..bf38a24e5 100644 --- a/core/MyHwATMega328.h +++ b/core/MyHwATMega328.h @@ -35,7 +35,6 @@ #endif #define MY_SERIALDEVICE Serial -#define MY_DEBUG_BUFFER_SIZE 300 #if defined __AVR_ATmega328P__ #ifndef sleep_bod_disable @@ -73,21 +72,20 @@ do { \ #define hwReboot() wdt_enable(WDTO_15MS); while (1) #define hwMillis() millis() #define hwRandomNumberInit() randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)) -#define hwReadConfig(__pos) (eeprom_read_byte((uint8_t*)(__pos))) +#define hwReadConfig(__pos) eeprom_read_byte((uint8_t*)(__pos)) #ifndef eeprom_update_byte - #define hwWriteConfig(loc, val) if((uint8_t)(val) != eeprom_read_byte((uint8_t*)(loc))) { eeprom_write_byte((uint8_t*)(loc), (val)); } + #define hwWriteConfig(__loc, __val) if((uint8_t)(__val) != eeprom_read_byte((uint8_t*)(__loc))) { eeprom_write_byte((uint8_t*)(__loc), (__val)); } #else - #define hwWriteConfig(__pos, __value) (eeprom_update_byte((uint8_t*)(__pos), (__value))) + #define hwWriteConfig(__pos, __val) eeprom_update_byte((uint8_t*)(__pos), (__val)) #endif -#define hwReadConfigBlock(__buf, __pos, __length) (eeprom_read_block((__buf), (void*)(__pos), (__length))) -#define hwWriteConfigBlock(__buf, __pos, __length) (eeprom_write_block((void*)(__buf), (void*)(__pos), (__length))) +#define hwReadConfigBlock(__buf, __pos, __length) eeprom_read_block((void*)(__buf), (void*)(__pos), (__length)) +#define hwWriteConfigBlock(__buf, __pos, __length) eeprom_write_block((void*)(__buf), (void*)(__pos), (__length)) -enum period_t -{ +enum period_t { SLEEP_15MS, SLEEP_30MS, SLEEP_60MS, diff --git a/core/MyHwESP8266.cpp b/core/MyHwESP8266.cpp index 5c48a0bdc..7901e4dd5 100644 --- a/core/MyHwESP8266.cpp +++ b/core/MyHwESP8266.cpp @@ -134,7 +134,7 @@ uint16_t hwFreeMem() { #ifdef MY_DEBUG void hwDebugPrint(const char *fmt, ... ) { - char fmtBuffer[MY_DEBUG_BUFFER_SIZE]; + char fmtBuffer[MY_SERIAL_OUTPUT_SIZE]; #ifdef MY_GATEWAY_FEATURE // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) snprintf_P(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); @@ -144,9 +144,9 @@ void hwDebugPrint(const char *fmt, ... ) { va_start (args, fmt ); #ifdef MY_GATEWAY_FEATURE // Truncate message if this is gateway node - vsnprintf_P(fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, fmt, args); - fmtBuffer[MY_GATEWAY_MAX_SEND_LENGTH-1] = '\n'; - fmtBuffer[MY_GATEWAY_MAX_SEND_LENGTH] = '\0'; + vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args); + fmtBuffer[sizeof(fmtBuffer) - 2] = '\n'; + fmtBuffer[sizeof(fmtBuffer) - 1] = '\0'; #else vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args); #endif diff --git a/core/MyHwESP8266.h b/core/MyHwESP8266.h index 0f53cedbc..3b92169ee 100644 --- a/core/MyHwESP8266.h +++ b/core/MyHwESP8266.h @@ -26,7 +26,6 @@ #endif #define MY_SERIALDEVICE Serial -#define MY_DEBUG_BUFFER_SIZE 300 #define min(a,b) ((a)<(b)?(a):(b)) #define max(a,b) ((a)>(b)?(a):(b)) diff --git a/core/MyHwSAMD.cpp b/core/MyHwSAMD.cpp index 3d79a4826..ddd19193f 100644 --- a/core/MyHwSAMD.cpp +++ b/core/MyHwSAMD.cpp @@ -160,7 +160,7 @@ uint16_t hwFreeMem() { #ifdef MY_DEBUG void hwDebugPrint(const char *fmt, ... ) { if (MY_SERIALDEVICE) { - char fmtBuffer[MY_DEBUG_BUFFER_SIZE]; + char fmtBuffer[MY_SERIAL_OUTPUT_SIZE]; #ifdef MY_GATEWAY_FEATURE // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) snprintf(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); @@ -170,9 +170,9 @@ void hwDebugPrint(const char *fmt, ... ) { va_start (args, fmt ); #ifdef MY_GATEWAY_FEATURE // Truncate message if this is gateway node - vsnprintf(fmtBuffer, 60, fmt, args); - fmtBuffer[59] = '\n'; - fmtBuffer[60] = '\0'; + vsnprintf(fmtBuffer, sizeof(fmtBuffer), fmt, args); + fmtBuffer[sizeof(fmtBuffer) - 2] = '\n'; + fmtBuffer[sizeof(fmtBuffer) - 1] = '\0'; #else vsnprintf(fmtBuffer, sizeof(fmtBuffer), fmt, args); #endif diff --git a/core/MyHwSAMD.h b/core/MyHwSAMD.h index 00ac1d612..7d23e0712 100644 --- a/core/MyHwSAMD.h +++ b/core/MyHwSAMD.h @@ -52,15 +52,6 @@ void hwWriteConfig(int adr, uint8_t value); uint8_t hwReadConfig(int adr); #define MY_SERIALDEVICE SerialUSB -#define MY_DEBUG_BUFFER_SIZE 300 - - -/* -#define hwReadConfigBlock(__buf, __adr, __length) ( __length = __length) -#define hwWriteConfigBlock(__buf, __adr, __length) ( __length = __length) -#define hwWriteConfig(__adr, __value) ( __value = __value) -#define hwReadConfig(__adr) (0) -*/ /** * Disable all interrupts. From 6636a975625db3bde3997846b6eabed67db6709d Mon Sep 17 00:00:00 2001 From: Olivier Date: Sat, 5 Nov 2016 09:53:12 +0100 Subject: [PATCH 112/167] Harmonize RF24 definitions (#629) --- core/MyTransportNRF24.cpp | 179 +++++------ drivers/RF24/RF24.cpp | 637 ++++++++++++++++++++------------------ drivers/RF24/RF24.h | 262 ++++++++-------- 3 files changed, 560 insertions(+), 518 deletions(-) diff --git a/core/MyTransportNRF24.cpp b/core/MyTransportNRF24.cpp index e458eeefc..9a21a25a1 100644 --- a/core/MyTransportNRF24.cpp +++ b/core/MyTransportNRF24.cpp @@ -25,125 +25,128 @@ #include "drivers/CircularBuffer/CircularBuffer.h" #if defined(MY_RF24_ENABLE_ENCRYPTION) - #include "drivers/AES/AES.h" +#include "drivers/AES/AES.h" #endif #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) -typedef struct _transportQueuedMessage -{ - uint8_t m_len; // Length of the data - uint8_t m_data[MAX_MESSAGE_LENGTH]; // The raw data +typedef struct _transportQueuedMessage { + uint8_t m_len; // Length of the data + uint8_t m_data[MAX_MESSAGE_LENGTH]; // The raw data } transportQueuedMessage; /** Buffer to store queued messages in. */ static transportQueuedMessage transportRxQueueStorage[MY_RX_MESSAGE_BUFFER_SIZE]; /** Circular buffer, which uses the transportRxQueueStorage and administers stored messages. */ -static CircularBuffer transportRxQueue(transportRxQueueStorage, MY_RX_MESSAGE_BUFFER_SIZE); +static CircularBuffer transportRxQueue(transportRxQueueStorage, MY_RX_MESSAGE_BUFFER_SIZE); static volatile uint8_t transportLostMessageCount = 0; static void transportRxCallback(void) { - // Called for each message received by radio, from interrupt context. - // This function _must_ call RF24_readMessage() to de-assert interrupt line! - if (!transportRxQueue.full()) - { - transportQueuedMessage* msg = transportRxQueue.getFront(); - msg->m_len = RF24_readMessage(msg->m_data); // Read payload & clear RX_DR - (void)transportRxQueue.pushFront(msg); - } else { - // Queue is full. Discard message. - (void)RF24_readMessage(NULL); // Read payload & clear RX_DR - // Keep track of messages lost. Max 255, prevent wrapping. - if (transportLostMessageCount < 255) - { - ++transportLostMessageCount; - } - } + // Called for each message received by radio, from interrupt context. + // This function _must_ call RF24_readMessage() to de-assert interrupt line! + if (!transportRxQueue.full()) { + transportQueuedMessage* msg = transportRxQueue.getFront(); + msg->m_len = RF24_readMessage(msg->m_data); // Read payload & clear RX_DR + (void)transportRxQueue.pushFront(msg); + } else { + // Queue is full. Discard message. + (void)RF24_readMessage(NULL); // Read payload & clear RX_DR + // Keep track of messages lost. Max 255, prevent wrapping. + if (transportLostMessageCount < 255) { + ++transportLostMessageCount; + } + } } #endif #if defined(MY_RF24_ENABLE_ENCRYPTION) - AES _aes; - uint8_t _dataenc[32] = {0}; - uint8_t _psk[16]; +AES _aes; +uint8_t _dataenc[32] = {0}; +uint8_t _psk[16]; +#endif + +bool transportInit(void) +{ +#if defined(MY_RF24_ENABLE_ENCRYPTION) + hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); + //set up AES-key + _aes.set_key(_psk, 16); + // Make sure it is purged from memory when set + memset(_psk, 0, 16); #endif -bool transportInit() { - #if defined(MY_RF24_ENABLE_ENCRYPTION) - hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); - //set up AES-key - _aes.set_key(_psk, 16); - // Make sure it is purged from memory when set - memset(_psk, 0, 16); - #endif - - #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) - RF24_registerReceiveCallback( transportRxCallback ); - #endif - return RF24_initialize(); +#if defined(MY_RX_MESSAGE_BUFFER_FEATURE) + RF24_registerReceiveCallback( transportRxCallback ); +#endif + return RF24_initialize(); } -void transportSetAddress(uint8_t address) { - RF24_setNodeAddress(address); - RF24_startListening(); +void transportSetAddress(const uint8_t address) +{ + RF24_setNodeAddress(address); + RF24_startListening(); } -uint8_t transportGetAddress() { - return RF24_getNodeID(); +uint8_t transportGetAddress(void) +{ + return RF24_getNodeID(); } -bool transportSend(uint8_t recipient, const void* data, uint8_t len) { - #if defined(MY_RF24_ENABLE_ENCRYPTION) - // copy input data because it is read-only - memcpy(_dataenc,data,len); - // has to be adjusted, WIP! - _aes.set_IV(0); - len = len > 16 ? 32 : 16; - //encrypt data - _aes.cbc_encrypt(_dataenc, _dataenc, len/16); - bool status = RF24_sendMessage( recipient, _dataenc, len ); - #else - bool status = RF24_sendMessage( recipient, data, len ); - #endif - - return status; +bool transportSend(const uint8_t recipient, const void* data, uint8_t len) +{ +#if defined(MY_RF24_ENABLE_ENCRYPTION) + // copy input data because it is read-only + (void)memcpy(_dataenc,data,len); + // has to be adjusted, WIP! + _aes.set_IV(0); + len = len > 16 ? 32 : 16; + //encrypt data + _aes.cbc_encrypt(_dataenc, _dataenc, len/16); + return RF24_sendMessage(recipient, _dataenc, len); +#else + return RF24_sendMessage(recipient, data, len); +#endif } -bool transportAvailable() { - #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) - (void)RF24_isDataAvailable; // Prevent 'defined but not used' warning - return !transportRxQueue.empty(); - #else - return RF24_isDataAvailable(); - #endif +bool transportAvailable(void) +{ +#if defined(MY_RX_MESSAGE_BUFFER_FEATURE) + (void)RF24_isDataAvailable; // Prevent 'defined but not used' warning + return !transportRxQueue.empty(); +#else + return RF24_isDataAvailable(); +#endif } -bool transportSanityCheck() { - return RF24_sanityCheck(); +bool transportSanityCheck(void) +{ + return RF24_sanityCheck(); } -uint8_t transportReceive(void* data) { - uint8_t len = 0; - #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) - transportQueuedMessage* msg = transportRxQueue.getBack(); - if (msg) { - len = msg->m_len; - (void)memcpy(data, msg->m_data, len); - (void)transportRxQueue.popBack(); - } - #else - len = RF24_readMessage(data); - #endif - #if defined(MY_RF24_ENABLE_ENCRYPTION) - // has to be adjusted, WIP! - _aes.set_IV(0); - // decrypt data - _aes.cbc_decrypt((byte*)(data), (byte*)(data), len>16?2:1); - #endif - return len; +uint8_t transportReceive(void* data) +{ + uint8_t len = 0; +#if defined(MY_RX_MESSAGE_BUFFER_FEATURE) + transportQueuedMessage* msg = transportRxQueue.getBack(); + if (msg) { + len = msg->m_len; + (void)memcpy(data, msg->m_data, len); + (void)transportRxQueue.popBack(); + } +#else + len = RF24_readMessage(data); +#endif +#if defined(MY_RF24_ENABLE_ENCRYPTION) + // has to be adjusted, WIP! + _aes.set_IV(0); + // decrypt data + _aes.cbc_decrypt((byte*)(data), (byte*)(data), len>16?2:1); +#endif + return len; } -void transportPowerDown() { - RF24_powerDown(); +void transportPowerDown(void) +{ + RF24_powerDown(); } diff --git a/drivers/RF24/RF24.cpp b/drivers/RF24/RF24.cpp index 2a9d27fa6..606ad19f9 100644 --- a/drivers/RF24/RF24.cpp +++ b/drivers/RF24/RF24.cpp @@ -26,376 +26,415 @@ LOCAL uint8_t MY_RF24_BASE_ADDR[MY_RF24_ADDR_WIDTH] = { MY_RF24_BASE_RADIO_ID }; LOCAL uint8_t MY_RF24_NODE_ADDRESS = AUTO; #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) - LOCAL RF24_receiveCallbackType RF24_receiveCallback = NULL; +LOCAL RF24_receiveCallbackType RF24_receiveCallback = NULL; #endif #ifdef LINUX_ARCH_RASPBERRYPI - 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) +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 -LOCAL void RF24_csn(bool level) { - hwDigitalWrite(MY_RF24_CS_PIN, level); +LOCAL void RF24_csn(const bool level) +{ + hwDigitalWrite(MY_RF24_CS_PIN, level); } -LOCAL void RF24_ce(bool level) { - hwDigitalWrite(MY_RF24_CE_PIN, level); +LOCAL void RF24_ce(const bool level) +{ + hwDigitalWrite(MY_RF24_CE_PIN, level); } -LOCAL uint8_t RF24_spiMultiByteTransfer(uint8_t cmd, uint8_t* buf, uint8_t len, bool aReadMode) { - uint8_t status; - uint8_t* current = buf; - #if !defined(MY_SOFTSPI) - _SPI.beginTransaction(SPISettings(MY_RF24_SPI_MAX_SPEED, MY_RF24_SPI_DATA_ORDER, MY_RF24_SPI_DATA_MODE)); - #endif - RF24_csn(LOW); - // timing - delayMicroseconds(10); - #ifdef LINUX_ARCH_RASPBERRYPI - uint8_t * prx = spi_rxbuff; - uint8_t * ptx = spi_txbuff; - uint8_t size = len + 1; // Add register value to transmit buffer - - *ptx++ = cmd; - while ( len-- ) { - if (aReadMode) { - *ptx++ = NOP ; - } else { - *ptx++ = *current++; - } - } - _SPI.transfernb( (char *) spi_txbuff, (char *) spi_rxbuff, size); - if (aReadMode) { - if (size == 2) { - status = *++prx; // result is 2nd byte of receive buffer - } else { - status = *prx++; // status is 1st byte of receive buffer - // decrement before to skip status byte - while (--size) { *buf++ = *prx++; } - } - } else { - status = *prx; // status is 1st byte of receive buffer - } - #else - status = _SPI.transfer( cmd ); - while ( len-- ) { - if (aReadMode) { - status = _SPI.transfer( NOP ); - if (buf != NULL) { - *current++ = status; - } - } else status = _SPI.transfer(*current++); - } - #endif - RF24_csn(HIGH); - #if !defined(MY_SOFTSPI) - _SPI.endTransaction(); - #endif - // timing - delayMicroseconds(10); - return status; +LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_t len, const bool aReadMode) +{ + uint8_t status; + uint8_t* current = buf; +#if !defined(MY_SOFTSPI) + _SPI.beginTransaction(SPISettings(MY_RF24_SPI_MAX_SPEED, MY_RF24_SPI_DATA_ORDER, MY_RF24_SPI_DATA_MODE)); +#endif + RF24_csn(LOW); + // timing + delayMicroseconds(10); +#ifdef LINUX_ARCH_RASPBERRYPI + uint8_t * prx = spi_rxbuff; + uint8_t * ptx = spi_txbuff; + uint8_t size = len + 1; // Add register value to transmit buffer + + *ptx++ = cmd; + while ( len-- ) { + if (aReadMode) { + *ptx++ = NOP ; + } else { + *ptx++ = *current++; + } + } + _SPI.transfernb( (char *) spi_txbuff, (char *) spi_rxbuff, size); + if (aReadMode) { + if (size == 2) { + status = *++prx; // result is 2nd byte of receive buffer + } else { + status = *prx++; // status is 1st byte of receive buffer + // decrement before to skip status byte + while (--size) { + *buf++ = *prx++; + } + } + } else { + status = *prx; // status is 1st byte of receive buffer + } +#else + status = _SPI.transfer(cmd); + while ( len-- ) { + if (aReadMode) { + status = _SPI.transfer(RF24_NOP); + if (buf != NULL) { + *current++ = status; + } + } else { + status = _SPI.transfer(*current++); + } + } +#endif + RF24_csn(HIGH); +#if !defined(MY_SOFTSPI) + _SPI.endTransaction(); +#endif + // timing + delayMicroseconds(10); + return status; } -LOCAL uint8_t RF24_spiByteTransfer(uint8_t cmd) { - return RF24_spiMultiByteTransfer( cmd, NULL, 0, false); +LOCAL uint8_t RF24_spiByteTransfer(const uint8_t cmd) +{ + return RF24_spiMultiByteTransfer(cmd, NULL, 0, false); } -LOCAL uint8_t RF24_RAW_readByteRegister(uint8_t cmd) { - const uint8_t value = RF24_spiMultiByteTransfer( cmd, NULL, 1, true); - RF24_DEBUG(PSTR("RF24:read register, reg=%d, value=%d\n"), cmd & (R_REGISTER ^ 0xFF), value); - return value; +LOCAL uint8_t RF24_RAW_readByteRegister(const uint8_t cmd) +{ + const uint8_t value = RF24_spiMultiByteTransfer(cmd, NULL, 1, true); + RF24_DEBUG(PSTR("RF24:read register, reg=%d, value=%d\n"), cmd & RF24_REGISTER_MASK, value); + return value; } -LOCAL uint8_t RF24_RAW_writeByteRegister(uint8_t cmd, uint8_t value) { - RF24_DEBUG(PSTR("RF24:write register, reg=%d, value=%d\n"), cmd & (W_REGISTER ^ 0xFF), value); - return RF24_spiMultiByteTransfer( cmd , &value, 1, false); +LOCAL uint8_t RF24_RAW_writeByteRegister(const uint8_t cmd, uint8_t value) +{ + RF24_DEBUG(PSTR("RF24:write register, reg=%d, value=%d\n"), cmd & RF24_REGISTER_MASK, value); + return RF24_spiMultiByteTransfer( cmd , &value, 1, false); } -LOCAL void RF24_flushRX(void) { - RF24_DEBUG(PSTR("RF24:flushRX\n")); - RF24_spiByteTransfer( FLUSH_RX ); +LOCAL void RF24_flushRX(void) +{ + RF24_DEBUG(PSTR("RF24:flushRX\n")); + RF24_spiByteTransfer(RF24_FLUSH_RX); } -LOCAL void RF24_flushTX(void) { - RF24_DEBUG(PSTR("RF24:flushTX\n")); - RF24_spiByteTransfer( FLUSH_TX ); +LOCAL void RF24_flushTX(void) +{ + RF24_DEBUG(PSTR("RF24:flushTX\n")); + RF24_spiByteTransfer(RF24_FLUSH_TX); } -LOCAL uint8_t RF24_getStatus(void) { - return RF24_spiByteTransfer( NOP ); +LOCAL uint8_t RF24_getStatus(void) +{ + return RF24_spiByteTransfer(RF24_NOP); } -LOCAL uint8_t RF24_getFIFOStatus(void) { - return RF24_readByteRegister(FIFO_STATUS); +LOCAL uint8_t RF24_getFIFOStatus(void) +{ + return RF24_readByteRegister(RF24_FIFO_STATUS); } -LOCAL void RF24_setChannel(uint8_t channel) { - RF24_writeByteRegister(RF_CH, channel); +LOCAL void RF24_setChannel(const uint8_t channel) +{ + RF24_writeByteRegister(RF24_RF_CH,channel); } -LOCAL void RF24_setRetries(uint8_t retransmitDelay, uint8_t retransmitCount) { - RF24_writeByteRegister(SETUP_RETR, retransmitDelay << ARD | retransmitCount << ARC); +LOCAL void RF24_setRetries(const uint8_t retransmitDelay, const uint8_t retransmitCount) +{ + RF24_writeByteRegister(RF24_SETUP_RETR, retransmitDelay << RF24_ARD | retransmitCount << RF24_ARC); } -LOCAL void RF24_setAddressWidth(uint8_t width) { - RF24_writeByteRegister(SETUP_AW, width - 2); +LOCAL void RF24_setAddressWidth(const uint8_t width) +{ + RF24_writeByteRegister(RF24_SETUP_AW, width - 2); } -LOCAL void RF24_setRFSetup(uint8_t RFsetup) { - RF24_writeByteRegister(RF_SETUP, RFsetup); +LOCAL void RF24_setRFSetup(const uint8_t RFsetup) +{ + RF24_writeByteRegister(RF24_RF_SETUP, RFsetup); } -LOCAL void RF24_setFeature(uint8_t feature) { - RF24_writeByteRegister(FEATURE, feature); +LOCAL void RF24_setFeature(const uint8_t feature) +{ + RF24_writeByteRegister(RF24_FEATURE, feature); } -LOCAL void RF24_setPipe(uint8_t pipe) { - RF24_writeByteRegister(EN_RXADDR, pipe); +LOCAL void RF24_setPipe(const uint8_t pipe) +{ + RF24_writeByteRegister(RF24_EN_RXADDR, pipe); } -LOCAL void RF24_setAutoACK(uint8_t pipe) { - RF24_writeByteRegister(EN_AA, pipe); +LOCAL void RF24_setAutoACK(const uint8_t pipe) +{ + RF24_writeByteRegister(RF24_EN_AA, pipe); } -LOCAL void RF24_setDynamicPayload(uint8_t pipe) { - RF24_writeByteRegister(DYNPD, pipe); +LOCAL void RF24_setDynamicPayload(const uint8_t pipe) +{ + RF24_writeByteRegister(RF24_DYNPD, pipe); } -LOCAL void RF24_setRFConfiguration(uint8_t configuration) { - RF24_writeByteRegister(NRF_CONFIG, configuration); +LOCAL void RF24_setRFConfiguration(const uint8_t configuration) +{ + RF24_writeByteRegister(RF24_NRF_CONFIG, configuration); } -LOCAL void RF24_setPipeAddress(uint8_t pipe, uint8_t* address, uint8_t width) { - RF24_writeMultiByteRegister(pipe, address, width); +LOCAL void RF24_setPipeAddress(const uint8_t pipe, uint8_t* address, const uint8_t width) +{ + RF24_writeMultiByteRegister(pipe, address, width); } -LOCAL void RF24_setPipeLSB(uint8_t pipe, uint8_t LSB) { - RF24_writeByteRegister(pipe, LSB); +LOCAL void RF24_setPipeLSB(const uint8_t pipe, const uint8_t LSB) +{ + RF24_writeByteRegister(pipe, LSB); } -LOCAL uint8_t RF24_getObserveTX(void) { - return RF24_readByteRegister(OBSERVE_TX); +LOCAL uint8_t RF24_getObserveTX(void) +{ + return RF24_readByteRegister(RF24_OBSERVE_TX); } -LOCAL void RF24_setStatus(uint8_t status) { - RF24_writeByteRegister(RF24_STATUS, status); +LOCAL void RF24_setStatus(const uint8_t status) +{ + RF24_writeByteRegister(RF24_STATUS, status); } -LOCAL void RF24_enableFeatures(void) { - RF24_RAW_writeByteRegister(ACTIVATE, 0x73); +LOCAL void RF24_enableFeatures(void) +{ + RF24_RAW_writeByteRegister(RF24_ACTIVATE, 0x73); } -LOCAL void RF24_openWritingPipe(uint8_t recipient) { - RF24_DEBUG(PSTR("RF24:open writing pipe, recipient=%d\n"), recipient); - // only write LSB of RX0 and TX pipe - RF24_setPipeLSB(RX_ADDR_P0, recipient); - RF24_setPipeLSB(TX_ADDR, recipient); +LOCAL void RF24_openWritingPipe(const uint8_t recipient) +{ + RF24_DEBUG(PSTR("RF24:OPEN WPIPE,RCPT=%d\n"), recipient); // open writing pipe + // only write LSB of RX0 and TX pipe + RF24_setPipeLSB(RF24_RX_ADDR_P0, recipient); + RF24_setPipeLSB(RF24_TX_ADDR, recipient); } -LOCAL void RF24_startListening(void) { - RF24_DEBUG(PSTR("RF24:start listening\n")); - // toggle PRX - RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(PWR_UP) | _BV(PRIM_RX) ); - // all RX pipe addresses must be unique, therefore skip if node ID is 0xFF - if(MY_RF24_NODE_ADDRESS!=AUTO) { - RF24_setPipeLSB(RX_ADDR_P0, MY_RF24_NODE_ADDRESS); - } - // start listening - RF24_ce(HIGH); +LOCAL void RF24_startListening(void) +{ + RF24_DEBUG(PSTR("RF24:STRT LIS\n")); // start listening + // toggle PRX + RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(RF24_PWR_UP) | _BV(RF24_PRIM_RX) ); + // all RX pipe addresses must be unique, therefore skip if node ID is AUTO + if(MY_RF24_NODE_ADDRESS!=AUTO) { + RF24_setPipeLSB(RF24_RX_ADDR_P0, MY_RF24_NODE_ADDRESS); + } + // start listening + RF24_ce(HIGH); +} + +LOCAL void RF24_stopListening(void) +{ + RF24_DEBUG(PSTR("RF24:STP LIS\n")); // stop listening + RF24_ce(LOW); + // timing + delayMicroseconds(130); + RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(RF24_PWR_UP) ); + // timing + delayMicroseconds(100); +} + +LOCAL void RF24_powerDown(void) +{ + RF24_ce(LOW); + RF24_setRFConfiguration(MY_RF24_CONFIGURATION); + RF24_DEBUG(PSTR("RF24:PD\n")); // power down } -LOCAL void RF24_stopListening(void) { - RF24_DEBUG(PSTR("RF24:stop listening\n")); - RF24_ce(LOW); - // timing - delayMicroseconds(130); - RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(PWR_UP) ); - // timing - delayMicroseconds(100); +LOCAL bool RF24_sendMessage(const uint8_t recipient, const void* buf, const uint8_t len) +{ + uint8_t RF24_status; + RF24_stopListening(); + RF24_openWritingPipe( recipient ); + RF24_DEBUG(PSTR("RF24:SND:TO=%d,LEN=%d\n"),recipient,len); // send message + // flush TX FIFO + RF24_flushTX(); + // this command is affected in clones (e.g. Si24R1): flipped NoACK bit when using W_TX_PAYLOAD_NO_ACK / W_TX_PAYLOAD + // AutoACK is disabled on the broadcasting pipe - NO_ACK prevents resending + RF24_spiMultiByteTransfer(recipient == BROADCAST_ADDRESS ? RF24_WRITE_TX_PAYLOAD_NO_ACK : RF24_WRITE_TX_PAYLOAD, (uint8_t*)buf, len, false ); + // go, TX starts after ~10us + RF24_ce(HIGH); + // timeout counter to detect HW issues + uint16_t timeout = 0xFFFF; + do { + RF24_status = RF24_getStatus(); + } while (!(RF24_status & ( _BV(RF24_MAX_RT) | _BV(RF24_TX_DS) )) && timeout--); + // timeout value after successful TX on 16Mhz AVR ~ 65500, i.e. msg is transmitted after ~36 loop cycles + RF24_ce(LOW); + // reset interrupts + RF24_setStatus(_BV(RF24_TX_DS) | _BV(RF24_MAX_RT) ); + // Max retries exceeded + if(RF24_status & _BV(RF24_MAX_RT)) { + // flush packet + RF24_DEBUG(PSTR("!RF24:SND:MAX_RT\n")); // max retries, no ACK + RF24_flushTX(); + } + RF24_startListening(); + // true if message sent + return (RF24_status & _BV(RF24_TX_DS)); +} + +LOCAL uint8_t RF24_getDynamicPayloadSize(void) +{ + uint8_t result = RF24_spiMultiByteTransfer(RF24_READ_RX_PL_WID, NULL, 1, true); + // check if payload size invalid + if(result > 32) { + RF24_DEBUG(PSTR("!RF24:GDP:PAYL LEN INVALID=%d\n"),result); // payload len invalid + RF24_flushRX(); + result = 0; + } + return result; } -LOCAL void RF24_powerDown(void) { - RF24_ce(LOW); - RF24_setRFConfiguration(MY_RF24_CONFIGURATION); - RF24_DEBUG(PSTR("RF24:power down\n")); +LOCAL bool RF24_isDataAvailable() +{ + return (!(RF24_getFIFOStatus() & _BV(0)) ); } -LOCAL bool RF24_sendMessage( uint8_t recipient, const void* buf, uint8_t len ) { - uint8_t status; - RF24_stopListening(); - RF24_openWritingPipe( recipient ); - RF24_DEBUG(PSTR("RF24:send message to %d, len=%d\n"),recipient,len); - // flush TX FIFO - RF24_flushTX(); - // this command is affected in clones (e.g. Si24R1): flipped NoACK bit when using W_TX_PAYLOAD_NO_ACK / W_TX_PAYLOAD - // AutoACK is disabled on the broadcasting pipe - NO_ACK prevents resending - RF24_spiMultiByteTransfer(recipient == BROADCAST_ADDRESS ? W_TX_PAYLOAD_NO_ACK : W_TX_PAYLOAD, (uint8_t*)buf, len, false ); - // go, TX starts after ~10us - RF24_ce(HIGH); - // timeout counter to detect HW issues - uint16_t timeout = 0xFFFF; - do { - status = RF24_getStatus(); - } while (!(status & ( _BV(MAX_RT) | _BV(TX_DS) )) && timeout--); - // timeout value after successful TX on 16Mhz AVR ~ 65500, i.e. msg is transmitted after ~36 loop cycles - RF24_ce(LOW); - // reset interrupts - RF24_setStatus(_BV(TX_DS) | _BV(MAX_RT) ); - // Max retries exceeded - if( status & _BV(MAX_RT)){ - // flush packet - RF24_DEBUG(PSTR("RF24:MAX_RT\n")); - RF24_flushTX(); - } - RF24_startListening(); - // true if message sent - return ( status & _BV(TX_DS) ); +LOCAL uint8_t RF24_readMessage(void* buf) +{ + const uint8_t len = RF24_getDynamicPayloadSize(); + RF24_DEBUG(PSTR("RF24:RDM:MSG LEN=%d\n"), len); // read message + RF24_spiMultiByteTransfer(RF24_READ_RX_PAYLOAD,(uint8_t*)buf,len,true); + // clear RX interrupt + RF24_setStatus(_BV(RF24_RX_DR)); + return len; } -LOCAL uint8_t RF24_getDynamicPayloadSize(void) { - uint8_t result = RF24_spiMultiByteTransfer(R_RX_PL_WID, NULL, 1, true); - // check if payload size invalid - if(result > 32) { - RF24_DEBUG(PSTR("RF24:invalid payload length = %d\n"),result); - RF24_flushRX(); - result = 0; - } - return result; +LOCAL void RF24_setNodeAddress(const uint8_t address) +{ + if(address!=AUTO) { + MY_RF24_NODE_ADDRESS = address; + // enable node pipe + RF24_setPipe(_BV(RF24_ERX_P0 + RF24_BROADCAST_PIPE) | _BV(RF24_ERX_P0)); + // enable autoACK on pipe 0 + RF24_setAutoACK(_BV(RF24_ENAA_P0)); + } } -LOCAL bool RF24_isDataAvailable() { - return ( !(RF24_getFIFOStatus() & _BV(0)) ); +LOCAL uint8_t RF24_getNodeID(void) +{ + return MY_RF24_NODE_ADDRESS; } - -LOCAL uint8_t RF24_readMessage( void* buf) { - const uint8_t len = RF24_getDynamicPayloadSize(); - RF24_DEBUG(PSTR("RF24:read message, len=%d\n"), len); - RF24_spiMultiByteTransfer( R_RX_PAYLOAD , (uint8_t*)buf, len, true ); - // clear RX interrupt - RF24_setStatus(_BV(RX_DR) ); - return len; -} - -LOCAL void RF24_setNodeAddress(uint8_t address) { - if(address!=AUTO){ - MY_RF24_NODE_ADDRESS = address; - // enable node pipe - RF24_setPipe(_BV(ERX_P0 + BROADCAST_PIPE) | _BV(ERX_P0) ); - // enable autoACK on pipe 0 - RF24_setAutoACK(_BV(ENAA_P0) ); - } -} - -LOCAL uint8_t RF24_getNodeID(void) { - return MY_RF24_NODE_ADDRESS; -} - -LOCAL bool RF24_sanityCheck(void) { - // detect HW defect, configuration errors or interrupted SPI line, CE disconnect cannot be detected - return (RF24_readByteRegister(RF_SETUP) == MY_RF24_RF_SETUP) & (RF24_readByteRegister(RF_CH) == MY_RF24_CHANNEL); +LOCAL bool RF24_sanityCheck(void) +{ + // detect HW defect, configuration errors or interrupted SPI line, CE disconnect cannot be detected + return (RF24_readByteRegister(RF24_RF_SETUP) == MY_RF24_RF_SETUP) & (RF24_readByteRegister(RF24_RF_CH) == MY_RF24_CHANNEL); } #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) -LOCAL void RF24_irqHandler( void ) -{ - if (RF24_receiveCallback) - { - // Will stay for a while (several 100us) in this interrupt handler. Any interrupts from serial - // rx coming in during our stay will not be handled and will cause characters to be lost. - // As a workaround we re-enable interrupts to allow nested processing of other interrupts. - // Our own handler is disconnected to prevent recursive calling of this handler. - #if defined(MY_GATEWAY_SERIAL) && !defined(__linux__) - detachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN)); - interrupts(); - #endif - // Read FIFO until empty. - // Procedure acc. to datasheet (pg. 63): - // 1.Read payload, 2.Clear RX_DR IRQ, 3.Read FIFO_status, 4.Repeat when more data available. - // Datasheet (ch. 8.5) states, that the nRF de-asserts IRQ after reading STATUS. - - // Start checking if RX-FIFO is not empty, as we might end up here from an interrupt - // for a message we've already read. - while (RF24_isDataAvailable()) { - RF24_receiveCallback(); // Must call RF24_readMessage(), which will clear RX_DR IRQ ! - } - // Restore our interrupt handler. - #if defined(MY_GATEWAY_SERIAL) && !defined(__linux__) - noInterrupts(); - attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING); - #endif - } else { - // clear RX interrupt - RF24_setStatus(_BV(RX_DR)); - } -} - -LOCAL void RF24_registerReceiveCallback( RF24_receiveCallbackType cb ) { - MY_CRITICAL_SECTION { - RF24_receiveCallback = cb; - } +LOCAL void RF24_irqHandler(void) +{ + if (RF24_receiveCallback) { + // Will stay for a while (several 100us) in this interrupt handler. Any interrupts from serial + // rx coming in during our stay will not be handled and will cause characters to be lost. + // As a workaround we re-enable interrupts to allow nested processing of other interrupts. + // Our own handler is disconnected to prevent recursive calling of this handler. +#if defined(MY_GATEWAY_SERIAL) && !defined(__linux__) + detachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN)); + interrupts(); +#endif + // Read FIFO until empty. + // Procedure acc. to datasheet (pg. 63): + // 1.Read payload, 2.Clear RX_DR IRQ, 3.Read FIFO_status, 4.Repeat when more data available. + // Datasheet (ch. 8.5) states, that the nRF de-asserts IRQ after reading STATUS. + + // Start checking if RX-FIFO is not empty, as we might end up here from an interrupt + // for a message we've already read. + while (RF24_isDataAvailable()) { + RF24_receiveCallback(); // Must call RF24_readMessage(), which will clear RX_DR IRQ ! + } + // Restore our interrupt handler. +#if defined(MY_GATEWAY_SERIAL) && !defined(__linux__) + noInterrupts(); + attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING); +#endif + } else { + // clear RX interrupt + RF24_setStatus(_BV(RF24_RX_DR)); + } +} + +LOCAL void RF24_registerReceiveCallback(RF24_receiveCallbackType cb) +{ + MY_CRITICAL_SECTION { + RF24_receiveCallback = cb; + } } #endif -LOCAL bool RF24_initialize(void) { - // prevent warning - (void)RF24_getObserveTX; - - // Initialize pins - hwPinMode(MY_RF24_CE_PIN,OUTPUT); - hwPinMode(MY_RF24_CS_PIN,OUTPUT); - #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) - hwPinMode(MY_RF24_IRQ_PIN,INPUT); - #endif - // Initialize SPI - _SPI.begin(); - RF24_ce(LOW); - RF24_csn(HIGH); - #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) - // assure SPI can be used from interrupt context - // Note: ESP8266 & SoftSPI currently do not support interrupt usage for SPI, - // therefore it is unsafe to use MY_RF24_IRQ_PIN with ESP8266/SoftSPI! - _SPI.usingInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN)); - // attach interrupt - attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING); - #endif - // CRC and power up - RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(PWR_UP) ) ; - // settle >2ms - delay(5); - // set address width - RF24_setAddressWidth(MY_RF24_ADDR_WIDTH); - // auto retransmit delay 1500us, auto retransmit count 15 - RF24_setRetries(RF24_ARD, RF24_ARC); - // set channel - RF24_setChannel(MY_RF24_CHANNEL); - // set data rate and pa level - RF24_setRFSetup(MY_RF24_RF_SETUP); - // toggle features (necessary on some clones and non-P versions) - RF24_enableFeatures(); - // enable ACK payload and dynamic payload - RF24_setFeature(MY_RF24_FEATURE); - // sanity check (this function is P/non-P independent) - if (!RF24_sanityCheck()) { - RF24_DEBUG(PSTR("!RF24:Sanity check failed: configuration mismatch! Check wiring or replace module\n")); - return false; - } - // enable broadcasting pipe - RF24_setPipe(_BV(ERX_P0 + BROADCAST_PIPE)); - // disable AA on all pipes, activate when node pipe set - RF24_setAutoACK(0x00); - // enable dynamic payloads on used pipes - RF24_setDynamicPayload(_BV(DPL_P0 + BROADCAST_PIPE) | _BV(DPL_P0)); - // listen to broadcast pipe - MY_RF24_BASE_ADDR[0] = BROADCAST_ADDRESS; - RF24_setPipeAddress(RX_ADDR_P0 + BROADCAST_PIPE, (uint8_t*)&MY_RF24_BASE_ADDR, BROADCAST_PIPE > 1 ? 1 : MY_RF24_ADDR_WIDTH); - // pipe 0, set full address, later only LSB is updated - RF24_setPipeAddress(RX_ADDR_P0, (uint8_t*)&MY_RF24_BASE_ADDR, MY_RF24_ADDR_WIDTH); - RF24_setPipeAddress(TX_ADDR, (uint8_t*)&MY_RF24_BASE_ADDR, MY_RF24_ADDR_WIDTH); - // reset FIFO - RF24_flushRX(); - RF24_flushTX(); - // reset interrupts - RF24_setStatus(_BV(TX_DS) | _BV(MAX_RT) | _BV(RX_DR)); - return true; +LOCAL bool RF24_initialize(void) +{ + // prevent warning + (void)RF24_getObserveTX; + + // Initialize pins + hwPinMode(MY_RF24_CE_PIN,OUTPUT); + hwPinMode(MY_RF24_CS_PIN,OUTPUT); +#if defined(MY_RX_MESSAGE_BUFFER_FEATURE) + hwPinMode(MY_RF24_IRQ_PIN,INPUT); +#endif + // Initialize SPI + _SPI.begin(); + RF24_ce(LOW); + RF24_csn(HIGH); +#if defined(MY_RX_MESSAGE_BUFFER_FEATURE) + // assure SPI can be used from interrupt context + // Note: ESP8266 & SoftSPI currently do not support interrupt usage for SPI, + // therefore it is unsafe to use MY_RF24_IRQ_PIN with ESP8266/SoftSPI! + _SPI.usingInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN)); + // attach interrupt + attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING); +#endif + // CRC and power up + RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(RF24_PWR_UP)) ; + // settle >2ms + delay(5); + // set address width + RF24_setAddressWidth(MY_RF24_ADDR_WIDTH); + // auto retransmit delay 1500us, auto retransmit count 15 + RF24_setRetries(RF24_SET_ARD, RF24_SET_ARC); + // set channel + RF24_setChannel(MY_RF24_CHANNEL); + // set data rate and pa level + RF24_setRFSetup(MY_RF24_RF_SETUP); + // toggle features (necessary on some clones and non-P versions) + RF24_enableFeatures(); + // enable ACK payload and dynamic payload + RF24_setFeature(MY_RF24_FEATURE); + // sanity check (this function is P/non-P independent) + if (!RF24_sanityCheck()) { + RF24_DEBUG(PSTR("!RF24:INIT:SANCHK FAIL\n")); // sanity check failed, check wiring or replace module + return false; + } + // enable broadcasting pipe + RF24_setPipe(_BV(RF24_ERX_P0 + RF24_BROADCAST_PIPE)); + // disable AA on all pipes, activate when node pipe set + RF24_setAutoACK(0x00); + // enable dynamic payloads on used pipes + RF24_setDynamicPayload(_BV(RF24_DPL_P0 + RF24_BROADCAST_PIPE) | _BV(RF24_DPL_P0)); + // listen to broadcast pipe + MY_RF24_BASE_ADDR[0] = BROADCAST_ADDRESS; + RF24_setPipeAddress(RF24_RX_ADDR_P0 + RF24_BROADCAST_PIPE, (uint8_t*)&MY_RF24_BASE_ADDR, RF24_BROADCAST_PIPE > 1 ? 1 : MY_RF24_ADDR_WIDTH); + // pipe 0, set full address, later only LSB is updated + RF24_setPipeAddress(RF24_RX_ADDR_P0, (uint8_t*)&MY_RF24_BASE_ADDR, MY_RF24_ADDR_WIDTH); + RF24_setPipeAddress(RF24_TX_ADDR, (uint8_t*)&MY_RF24_BASE_ADDR, MY_RF24_ADDR_WIDTH); + // reset FIFO + RF24_flushRX(); + RF24_flushTX(); + // reset interrupts + RF24_setStatus(_BV(RF24_TX_DS) | _BV(RF24_MAX_RT) | _BV(RF24_RX_DR)); + return true; } diff --git a/drivers/RF24/RF24.h b/drivers/RF24/RF24.h index d1e8f57b5..ae98d9457 100644 --- a/drivers/RF24/RF24.h +++ b/drivers/RF24/RF24.h @@ -83,16 +83,16 @@ // RF24 settings #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) - #define MY_RF24_CONFIGURATION (uint8_t) ((RF24_CRC_16 << 2) | (1 << MASK_TX_DS) | (1 << MASK_MAX_RT)) + #define MY_RF24_CONFIGURATION (uint8_t) ((RF24_CRC_16 << 2) | (1 << RF24_MASK_TX_DS) | (1 << RF24_MASK_MAX_RT)) #else #define MY_RF24_CONFIGURATION (uint8_t) (RF24_CRC_16 << 2) #endif -#define MY_RF24_FEATURE (uint8_t)( _BV(EN_DPL) | _BV(EN_ACK_PAY) ) +#define MY_RF24_FEATURE (uint8_t)( _BV(RF24_EN_DPL) | _BV(RF24_EN_ACK_PAY) ) #define MY_RF24_RF_SETUP (uint8_t)( ((MY_RF24_DATARATE & 0b10 ) << 4) | ((MY_RF24_DATARATE & 0b01 ) << 3) | (MY_RF24_PA_LEVEL << 1) ) + 1 // +1 for Si24R1 // pipes -#define BROADCAST_PIPE 1 -#define NODE_PIPE 0 +#define RF24_BROADCAST_PIPE (1) +#define RF24_NODE_PIPE (0) // debug #if defined(MY_DEBUG_VERBOSE_RF24) @@ -102,146 +102,146 @@ #endif // PA levels -#define RF24_PA_MIN 0 -#define RF24_PA_LOW 1 -#define RF24_PA_HIGH 2 -#define RF24_PA_MAX 3 +#define RF24_PA_MIN (0) +#define RF24_PA_LOW (1) +#define RF24_PA_HIGH (2) +#define RF24_PA_MAX (3) // data rate -#define RF24_1MBPS 0 -#define RF24_2MBPS 1 -#define RF24_250KBPS 2 +#define RF24_1MBPS (0) +#define RF24_2MBPS (1) +#define RF24_250KBPS (2) // CRC -#define RF24_CRC_DISABLED 0 -#define RF24_CRC_8 2 -#define RF24_CRC_16 3 +#define RF24_CRC_DISABLED (0) +#define RF24_CRC_8 (2) +#define RF24_CRC_16 (3) // ARD, auto retry delay -#define RF24_ARD 5 //=1500us +#define RF24_SET_ARD (5) //=1500us // ARD, auto retry count -#define RF24_ARC 15 +#define RF24_SET_ARC (15) // nRF24L01(+) register definitions -#define NRF_CONFIG 0x00 -#define EN_AA 0x01 -#define EN_RXADDR 0x02 -#define SETUP_AW 0x03 -#define SETUP_RETR 0x04 -#define RF_CH 0x05 -#define RF_SETUP 0x06 -#define RF24_STATUS 0x07 -#define OBSERVE_TX 0x08 -#define CD 0x09 -#define RX_ADDR_P0 0x0A -#define RX_ADDR_P1 0x0B -#define RX_ADDR_P2 0x0C -#define RX_ADDR_P3 0x0D -#define RX_ADDR_P4 0x0E -#define RX_ADDR_P5 0x0F -#define TX_ADDR 0x10 -#define RX_PW_P0 0x11 -#define RX_PW_P1 0x12 -#define RX_PW_P2 0x13 -#define RX_PW_P3 0x14 -#define RX_PW_P4 0x15 -#define RX_PW_P5 0x16 -#define FIFO_STATUS 0x17 -#define DYNPD 0x1C -#define FEATURE 0x1D +#define RF24_NRF_CONFIG (0x00) +#define RF24_EN_AA (0x01) +#define RF24_EN_RXADDR (0x02) +#define RF24_SETUP_AW (0x03) +#define RF24_SETUP_RETR (0x04) +#define RF24_RF_CH (0x05) +#define RF24_RF_SETUP (0x06) +#define RF24_STATUS (0x07) +#define RF24_OBSERVE_TX (0x08) +#define RF24_CD (0x09) +#define RF24_RX_ADDR_P0 (0x0A) +#define RF24_RX_ADDR_P1 (0x0B) +#define RF24_RX_ADDR_P2 (0x0C) +#define RF24_RX_ADDR_P3 (0x0D) +#define RF24_RX_ADDR_P4 (0x0E) +#define RF24_RX_ADDR_P5 (0x0F) +#define RF24_TX_ADDR (0x10) +#define RF24_RX_PW_P0 (0x11) +#define RF24_RX_PW_P1 (0x12) +#define RF24_RX_PW_P2 (0x13) +#define RF24_RX_PW_P3 (0x14) +#define RF24_RX_PW_P4 (0x15) +#define RF24_RX_PW_P5 (0x16) +#define RF24_FIFO_STATUS (0x17) +#define RF24_DYNPD (0x1C) +#define RF24_FEATURE (0x1D) // instructions -#define R_REGISTER 0x00 -#define RPD 0x09 -#define W_REGISTER 0x20 -#define REGISTER_MASK 0x1F -#define ACTIVATE 0x50 -#define R_RX_PL_WID 0x60 -#define R_RX_PAYLOAD 0x61 -#define W_TX_PAYLOAD 0xA0 -#define W_ACK_PAYLOAD 0xA8 -#define W_TX_PAYLOAD_NO_ACK 0xB0 -#define FLUSH_TX 0xE1 -#define FLUSH_RX 0xE2 -#define REUSE_TX_PL 0xE3 -#define NOP 0xFF +#define RF24_READ_REGISTER (0x00) +#define RF24_RPD (0x09) +#define RF24_WRITE_REGISTER (0x20) +#define RF24_REGISTER_MASK (0x1F) +#define RF24_ACTIVATE (0x50) +#define RF24_READ_RX_PL_WID (0x60) +#define RF24_READ_RX_PAYLOAD (0x61) +#define RF24_WRITE_TX_PAYLOAD (0xA0) +#define RF24_WRITE_ACK_PAYLOAD (0xA8) +#define RF24_WRITE_TX_PAYLOAD_NO_ACK (0xB0) +#define RF24_FLUSH_TX (0xE1) +#define RF24_FLUSH_RX (0xE2) +#define RF24_REUSE_TX_PL (0xE3) +#define RF24_NOP (0xFF) // bit mnemonics -#define MASK_RX_DR 6 -#define MASK_TX_DS 5 -#define MASK_MAX_RT 4 -#define EN_CRC 3 -#define CRCO 2 -#define PWR_UP 1 -#define PRIM_RX 0 +#define RF24_MASK_RX_DR (6) +#define RF24_MASK_TX_DS (5) +#define RF24_MASK_MAX_RT (4) +#define RF24_EN_CRC (3) +#define RF24_CRCO (2) +#define RF24_PWR_UP (1) +#define RF24_PRIM_RX (0) // auto ACK -#define ENAA_P5 5 -#define ENAA_P4 4 -#define ENAA_P3 3 -#define ENAA_P2 2 -#define ENAA_P1 1 -#define ENAA_P0 0 +#define RF24_ENAA_P5 (5) +#define RF24_ENAA_P4 (4) +#define RF24_ENAA_P3 (3) +#define RF24_ENAA_P2 (2) +#define RF24_ENAA_P1 (1) +#define RF24_ENAA_P0 (0) // rx pipe -#define ERX_P5 5 -#define ERX_P4 4 -#define ERX_P3 3 -#define ERX_P2 2 -#define ERX_P1 1 -#define ERX_P0 0 +#define RF24_ERX_P5 (5) +#define RF24_ERX_P4 (4) +#define RF24_ERX_P3 (3) +#define RF24_ERX_P2 (2) +#define RF24_ERX_P1 (1) +#define RF24_ERX_P0 (0) // dynamic payload -#define DPL_P5 5 -#define DPL_P4 4 -#define DPL_P3 3 -#define DPL_P2 2 -#define DPL_P1 1 -#define DPL_P0 0 +#define RF24_DPL_P5 (5) +#define RF24_DPL_P4 (4) +#define RF24_DPL_P3 (3) +#define RF24_DPL_P2 (2) +#define RF24_DPL_P1 (1) +#define RF24_DPL_P0 (0) -#define AW 0 -#define ARD 4 -#define ARC 0 -#define PLL_LOCK 4 -#define RF_DR 3 -#define RF_PWR 6 -#define RX_DR 6 -#define TX_DS 5 -#define MAX_RT 4 -#define RX_P_NO 1 -#define TX_FULL 0 -#define PLOS_CNT 4 -#define ARC_CNT 0 -#define TX_REUSE 6 -#define FIFO_FULL 5 -#define TX_EMPTY 4 -#define RX_FULL 1 -#define RX_EMPTY 0 +#define RF24_AW (0) +#define RF24_ARD (4) +#define RF24_ARC (0) +#define RF24_PLL_LOCK (4) +#define RF24_RF_DR (3) +#define RF24_RF_PWR (6) +#define RF24_RX_DR (6) +#define RF24_TX_DS (5) +#define RF24_MAX_RT (4) +#define RF24_RX_P_NO (1) +#define RF24_TX_FULL (0) +#define RF24_PLOS_CNT (4) +#define RF24_ARC_CNT (0) +#define RF24_TX_REUSE (6) +#define RF24_FIFO_FULL (5) +#define RF24_TX_EMPTY (4) +#define RF24_RX_FULL (1) +#define RF24_RX_EMPTY (0) // features -#define EN_DPL 2 -#define EN_ACK_PAY 1 -#define EN_DYN_ACK 0 +#define RF24_EN_DPL (2) +#define RF24_EN_ACK_PAY (1) +#define RF24_EN_DYN_ACK (0) -#define LNA_HCURR 0 -#define RF_DR_LOW 5 -#define RF_DR_HIGH 3 -#define RF_PWR_LOW 1 -#define RF_PWR_HIGH 2 +#define RF24_LNA_HCURR (0) +#define RF24_RF_DR_LOW (5) +#define RF24_RF_DR_HIGH (3) +#define RF24_RF_PWR_LOW (1) +#define RF24_RF_PWR_HIGH (2) // functions -LOCAL void RF24_csn(bool level); -LOCAL void RF24_ce(bool level); -LOCAL uint8_t RF24_spiMultiByteTransfer(uint8_t cmd, uint8_t* buf, uint8_t len, bool aReadMode); -LOCAL uint8_t RF24_spiByteTransfer(uint8_t cmd); -LOCAL uint8_t RF24_RAW_readByteRegister(uint8_t cmd); -LOCAL uint8_t RF24_RAW_writeByteRegister(uint8_t cmd, uint8_t value); +LOCAL void RF24_csn(const bool level); +LOCAL void RF24_ce(const bool level); +LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, const uint8_t len, const bool aReadMode); +LOCAL uint8_t RF24_spiByteTransfer(const uint8_t cmd); +LOCAL uint8_t RF24_RAW_readByteRegister(const uint8_t cmd); +LOCAL uint8_t RF24_RAW_writeByteRegister(const uint8_t cmd, const uint8_t value); -#define RF24_readByteRegister(reg) RF24_RAW_readByteRegister( R_REGISTER | ( REGISTER_MASK & (reg) ) ) -#define RF24_writeByteRegister(reg, value) RF24_RAW_writeByteRegister( W_REGISTER | ( REGISTER_MASK & (reg) ), value ) -#define RF24_writeMultiByteRegister(reg, buf, len) RF24_spiMultiByteTransfer( W_REGISTER | ( REGISTER_MASK & (reg) ), (uint8_t*)buf, len, false ) +#define RF24_readByteRegister(__reg) RF24_RAW_readByteRegister(RF24_READ_REGISTER | (RF24_REGISTER_MASK & __reg)) +#define RF24_writeByteRegister(__reg,__value) RF24_RAW_writeByteRegister(RF24_WRITE_REGISTER | (RF24_REGISTER_MASK & __reg), __value) +#define RF24_writeMultiByteRegister(__reg,__buf,__len) RF24_spiMultiByteTransfer(RF24_WRITE_REGISTER | (RF24_REGISTER_MASK & __reg),(uint8_t*)__buf, __len,false) LOCAL void RF24_flushRX(void); LOCAL void RF24_flushTX(void); @@ -251,27 +251,27 @@ LOCAL void RF24_openWritingPipe(uint8_t recipient); LOCAL void RF24_startListening(void); LOCAL void RF24_stopListening(void); LOCAL void RF24_powerDown(void); -LOCAL bool RF24_sendMessage(uint8_t recipient, const void* buf, uint8_t len); +LOCAL bool RF24_sendMessage(const uint8_t recipient, const void* buf, const uint8_t len); LOCAL uint8_t RF24_getDynamicPayloadSize(void); LOCAL bool RF24_isDataAvailable(); LOCAL uint8_t RF24_readMessage(void* buf); -LOCAL void RF24_setNodeAddress(uint8_t address); +LOCAL void RF24_setNodeAddress(const uint8_t address); LOCAL uint8_t RF24_getNodeID(void); LOCAL bool RF24_sanityCheck(void); LOCAL bool RF24_initialize(void); -LOCAL void RF24_setChannel(uint8_t channel); -LOCAL void RF24_setRetries(uint8_t retransmitDelay, uint8_t retransmitCount); -LOCAL void RF24_setAddressWidth(uint8_t width); -LOCAL void RF24_setRFSetup(uint8_t RFsetup); -LOCAL void RF24_setFeature(uint8_t feature); -LOCAL void RF24_setPipe(uint8_t pipe); -LOCAL void RF24_setAutoACK(uint8_t pipe); -LOCAL void RF24_setDynamicPayload(uint8_t pipe); -LOCAL void RF24_setRFConfiguration(uint8_t configuration); -LOCAL void RF24_setPipeAddress(uint8_t pipe, uint8_t* address, uint8_t width); -LOCAL void RF24_setPipeLSB(uint8_t pipe, uint8_t LSB); +LOCAL void RF24_setChannel(const uint8_t channel); +LOCAL void RF24_setRetries(const uint8_t retransmitDelay, const uint8_t retransmitCount); +LOCAL void RF24_setAddressWidth(const uint8_t width); +LOCAL void RF24_setRFSetup(const uint8_t RFsetup); +LOCAL void RF24_setFeature(const uint8_t feature); +LOCAL void RF24_setPipe(const uint8_t pipe); +LOCAL void RF24_setAutoACK(const uint8_t pipe); +LOCAL void RF24_setDynamicPayload(const uint8_t pipe); +LOCAL void RF24_setRFConfiguration(const uint8_t configuration); +LOCAL void RF24_setPipeAddress(const uint8_t pipe, uint8_t* address, const uint8_t width); +LOCAL void RF24_setPipeLSB(const uint8_t pipe, const uint8_t LSB); LOCAL uint8_t RF24_getObserveTX(void); -LOCAL void RF24_setStatus(uint8_t status); +LOCAL void RF24_setStatus(const uint8_t status); LOCAL void RF24_enableFeatures(void); #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) @@ -282,7 +282,7 @@ LOCAL void RF24_enableFeatures(void); * by calling RF24_readMessage(). Otherwise the interrupt will not get deasserted * and message reception will stop. */ - LOCAL void RF24_registerReceiveCallback( RF24_receiveCallbackType cb ); + LOCAL void RF24_registerReceiveCallback(RF24_receiveCallbackType cb); #endif #endif // __RF24_H__ \ No newline at end of file From 6ad18b641e7ddd72adb4c73acf6b2dba7dd82e6e Mon Sep 17 00:00:00 2001 From: Olivier Date: Sun, 6 Nov 2016 10:55:32 +0100 Subject: [PATCH 113/167] Fixed missing RF24_NOP refactoring (#635) --- drivers/RF24/RF24.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/RF24/RF24.cpp b/drivers/RF24/RF24.cpp index 606ad19f9..34d1193e2 100644 --- a/drivers/RF24/RF24.cpp +++ b/drivers/RF24/RF24.cpp @@ -62,7 +62,7 @@ LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_t *ptx++ = cmd; while ( len-- ) { if (aReadMode) { - *ptx++ = NOP ; + *ptx++ = RF24_NOP; } else { *ptx++ = *current++; } From 30e447782edd397783ff7798b6532facebc1ff15 Mon Sep 17 00:00:00 2001 From: Olivier Date: Sun, 6 Nov 2016 14:07:21 +0100 Subject: [PATCH 114/167] Implement SAMD core functions: reboot, Vcc, freq --- core/MyHwSAMD.cpp | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/core/MyHwSAMD.cpp b/core/MyHwSAMD.cpp index ddd19193f..1cf3662e6 100644 --- a/core/MyHwSAMD.cpp +++ b/core/MyHwSAMD.cpp @@ -113,7 +113,8 @@ void hwWatchdogReset() { } void hwReboot() { - // TODO: Not supported! + NVIC_SystemReset(); + while (true); } int8_t hwSleep(unsigned long ms) { @@ -142,13 +143,44 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo #if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG) uint16_t hwCPUVoltage() { - // TODO: Not supported! - return 0; + + // disable ADC + while (ADC->STATUS.bit.SYNCBUSY); + ADC->CTRLA.bit.ENABLE = 0x00; + + // internal 1V reference (default) + analogReference(AR_INTERNAL1V0); + // 12 bit resolution (default) + analogWriteResolution(12); + // MUXp 0x1B = SCALEDIOVCC/4 => connected to Vcc + ADC->INPUTCTRL.bit.MUXPOS = 0x1B ; + + // enable ADC + while (ADC->STATUS.bit.SYNCBUSY); + ADC->CTRLA.bit.ENABLE = 0x01; + // start conversion + while (ADC->STATUS.bit.SYNCBUSY); + ADC->SWTRIG.bit.START = 1; + // clear the Data Ready flag + ADC->INTFLAG.bit.RESRDY = 1; + // start conversion again, since The first conversion after the reference is changed must not be used. + while (ADC->STATUS.bit.SYNCBUSY); + ADC->SWTRIG.bit.START = 1; + + // waiting for conversion to complete + while (!ADC->INTFLAG.bit.RESRDY); + const uint32_t valueRead = ADC->RESULT.reg; + + // disable ADC + while (ADC->STATUS.bit.SYNCBUSY); + ADC->CTRLA.bit.ENABLE = 0x00; + + return valueRead * 4; } uint16_t hwCPUFrequency() { - // TODO: Not supported! - return 0; + // TODO: currently reporting compile time frequency (in 1/10MHz) + return F_CPU / 100000UL; } uint16_t hwFreeMem() { From 15e2770347915b52881bb1050496de1ddc9a9e92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Sun, 6 Nov 2016 17:51:53 +0100 Subject: [PATCH 115/167] Fixes LED prevTime bug reported in forum (#636) --- core/MyLeds.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/MyLeds.cpp b/core/MyLeds.cpp index e8c42a1dd..4e28903ba 100644 --- a/core/MyLeds.cpp +++ b/core/MyLeds.cpp @@ -55,7 +55,7 @@ void ledsProcess() { return; } - prevTime += LED_PROCESS_INTERVAL_MS; + prevTime = hwMillis(); uint8_t state; From 9254b4515000516e2e95fddd3439af406f0c34e5 Mon Sep 17 00:00:00 2001 From: Embedded Innovation Date: Mon, 7 Nov 2016 21:28:25 +0100 Subject: [PATCH 116/167] Fix consistent yield usage & LED updates --- core/MyGatewayTransportEthernet.cpp | 3 +-- core/MyGatewayTransportMQTTClient.cpp | 2 +- core/MyLeds.cpp | 20 ++++++++++++------ core/MySensorsCore.cpp | 29 +++++++++++++-------------- core/MySensorsCore.h | 7 +++++++ core/MyTransport.cpp | 2 +- 6 files changed, 38 insertions(+), 25 deletions(-) diff --git a/core/MyGatewayTransportEthernet.cpp b/core/MyGatewayTransportEthernet.cpp index 498850ff6..a6abe9132 100644 --- a/core/MyGatewayTransportEthernet.cpp +++ b/core/MyGatewayTransportEthernet.cpp @@ -116,9 +116,8 @@ bool gatewayTransportInit() { (void)WiFi.begin(MY_ESP8266_SSID, MY_ESP8266_PASSWORD); while (WiFi.status() != WL_CONNECTED) { - delay(500); + wait(500); MY_SERIALDEVICE.print(F(".")); - yield(); } MY_SERIALDEVICE.print(F("IP: ")); MY_SERIALDEVICE.println(WiFi.localIP()); diff --git a/core/MyGatewayTransportMQTTClient.cpp b/core/MyGatewayTransportMQTTClient.cpp index ea98f076e..339d1aa7a 100644 --- a/core/MyGatewayTransportMQTTClient.cpp +++ b/core/MyGatewayTransportMQTTClient.cpp @@ -88,7 +88,7 @@ bool reconnectMQTT() { bool gatewayTransportConnect() { #if defined(MY_GATEWAY_ESP8266) while (WiFi.status() != WL_CONNECTED) { - delay(500); // delay calls yield + wait(500); MY_SERIALDEVICE.print("."); } MY_SERIALDEVICE.print("IP: "); diff --git a/core/MyLeds.cpp b/core/MyLeds.cpp index 4e28903ba..bbbcb6666 100644 --- a/core/MyLeds.cpp +++ b/core/MyLeds.cpp @@ -26,8 +26,7 @@ static uint8_t countRx; static uint8_t countTx; static uint8_t countErr; -static unsigned long prevTime = hwMillis() - LED_PROCESS_INTERVAL_MS; // Substract some, to make sure leds gets updated on first run. - +static unsigned long prevTime; inline void ledsInit() { @@ -46,6 +45,7 @@ inline void ledsInit() #if defined(MY_DEFAULT_ERR_LED_PIN) pinMode(MY_DEFAULT_ERR_LED_PIN, OUTPUT); #endif + prevTime = hwMillis() - LED_PROCESS_INTERVAL_MS; // Substract some, to make sure leds gets updated on first run. ledsProcess(); } @@ -54,7 +54,6 @@ void ledsProcess() { if ((hwMillis() - prevTime) < LED_PROCESS_INTERVAL_MS) { return; } - prevTime = hwMillis(); uint8_t state; @@ -87,13 +86,22 @@ void ledsProcess() { } void ledsBlinkRx(uint8_t cnt) { - if (!countRx) { countRx = cnt*LED_ON_OFF_RATIO; } + if (!countRx) { + countRx = cnt*LED_ON_OFF_RATIO; + } + ledsProcess(); } void ledsBlinkTx(uint8_t cnt) { - if(!countTx) { countTx = cnt*LED_ON_OFF_RATIO; } + if(!countTx) { + countTx = cnt*LED_ON_OFF_RATIO; + } + ledsProcess(); } void ledsBlinkErr(uint8_t cnt) { - if(!countErr) { countErr = cnt*LED_ON_OFF_RATIO; } + if(!countErr) { + countErr = cnt*LED_ON_OFF_RATIO; + } + ledsProcess(); } diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 8586b2a08..9f4170c3b 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -38,11 +38,7 @@ bool _nodeRegistered = false; void (*_timeCallback)(unsigned long); // Callback for requested time messages void _process(void) { - hwWatchdogReset(); - - #if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) - ledsProcess(); - #endif + doYield(); #if defined(MY_INCLUSION_MODE_FEATURE) inclusionProcess(); @@ -64,10 +60,7 @@ void _process(void) { void _infiniteLoop(void) { while(1) { - yield(); - #if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) - ledsProcess(); - #endif + doYield(); #if defined(__linux__) exit(1); #endif @@ -111,9 +104,8 @@ void _begin(void) { hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, MY_PARENT_NODE_ID); transportInitialise(); while (!isTransportReady()) { - hwWatchdogReset(); transportProcess(); - yield(); + doYield(); } #endif @@ -447,7 +439,6 @@ void wait(const uint32_t waitingMS) { const uint32_t enteringMS = hwMillis(); while (hwMillis() - enteringMS < waitingMS) { _process(); - yield(); } } @@ -458,12 +449,21 @@ bool wait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t msgtype) { bool expectedResponse = false; while ( (hwMillis() - enteringMS < waitingMS) && !expectedResponse ) { _process(); - yield(); expectedResponse = (mGetCommand(_msg) == cmd && _msg.type == msgtype); } return expectedResponse; } +void doYield(void) { + hwWatchdogReset(); + + yield(); + + #if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) + ledsProcess(); + #endif +} + int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep, const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, const uint8_t mode2) { debug(PSTR("MCO:SLP:MS=%lu,SMS=%d,I1=%d,M1=%d,I2=%d,M2=%d\n"), sleepingMS, smartSleep, interrupt1, mode1, interrupt2, mode2); // OTA FW feature: do not sleep if FW update ongoing @@ -495,7 +495,6 @@ int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep, const uint8_t in uint32_t sleepDeltaMS = 0; while (!isTransportReady() && (sleepDeltaMS < sleepingTimeMS) && (sleepDeltaMS < MY_SLEEP_TRANSPORT_RECONNECT_TIMEOUT_MS)) { _process(); - yield(); sleepDeltaMS = hwMillis() - sleepEnterMS; } // sleep remainder @@ -581,7 +580,7 @@ void nodeLock(const char* str) { while (1) { setIndication(INDICATION_ERR_LOCKED); debug(PSTR("MCO:NLK:NODE LOCKED. TO UNLOCK, GND PIN %d AND RESET\n"), MY_NODE_UNLOCK_PIN); - yield(); + doYield(); (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID,C_INTERNAL, I_LOCKED).set(str)); #if defined(MY_SENSOR_NETWORK) transportPowerDown(); diff --git a/core/MySensorsCore.h b/core/MySensorsCore.h index 56f04a176..094f37014 100644 --- a/core/MySensorsCore.h +++ b/core/MySensorsCore.h @@ -246,6 +246,13 @@ void wait(const uint32_t waitingMS); */ bool wait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t msgtype); +/** + * Function to allow scheduler to do some work. + * @remark Internally it will call yield, kick the watchdog and update led states. + */ +void doYield(void); + + /** * Sleep (PowerDownMode) the MCU and radio. Wake up on timer. * @param sleepingMS Number of milliseconds to sleep. diff --git a/core/MyTransport.cpp b/core/MyTransport.cpp index 129715de2..238918b6e 100644 --- a/core/MyTransport.cpp +++ b/core/MyTransport.cpp @@ -497,7 +497,7 @@ bool transportWait(const uint32_t ms, const uint8_t cmd, const uint8_t msgtype){ while ((hwMillis() - enter < ms) && !expectedResponse) { // process incoming messages transportProcessFIFO(); - yield(); // process esp8266 stack, ignored for AVR + doYield(); expectedResponse = (mGetCommand(_msg) == cmd && _msg.type == msgtype); } return expectedResponse; From 7f0e23b728ea14e209a2ff8986472a4983c697f6 Mon Sep 17 00:00:00 2001 From: Embedded Innovation Date: Tue, 8 Nov 2016 20:06:53 +0100 Subject: [PATCH 117/167] Finish LED pattern before low-power sleep Wait until no LEDs are blinking anymore before going to sleep. Decrement LED blink counter before acting on the value, otherwise LED state will always lag behind. --- core/MyLeds.cpp | 60 ++++++++++++++++++++++-------------------- core/MyLeds.h | 5 ++++ core/MySensorsCore.cpp | 7 +++++ 3 files changed, 44 insertions(+), 28 deletions(-) diff --git a/core/MyLeds.cpp b/core/MyLeds.cpp index bbbcb6666..0da662829 100644 --- a/core/MyLeds.cpp +++ b/core/MyLeds.cpp @@ -36,17 +36,17 @@ inline void ledsInit() countErr = 0; // Setup led pins -#if defined(MY_DEFAULT_RX_LED_PIN) - pinMode(MY_DEFAULT_RX_LED_PIN, OUTPUT); -#endif -#if defined(MY_DEFAULT_TX_LED_PIN) - pinMode(MY_DEFAULT_TX_LED_PIN, OUTPUT); -#endif -#if defined(MY_DEFAULT_ERR_LED_PIN) - pinMode(MY_DEFAULT_ERR_LED_PIN, OUTPUT); -#endif + #if defined(MY_DEFAULT_RX_LED_PIN) + pinMode(MY_DEFAULT_RX_LED_PIN, OUTPUT); + #endif + #if defined(MY_DEFAULT_TX_LED_PIN) + pinMode(MY_DEFAULT_TX_LED_PIN, OUTPUT); + #endif + #if defined(MY_DEFAULT_ERR_LED_PIN) + pinMode(MY_DEFAULT_ERR_LED_PIN, OUTPUT); + #endif prevTime = hwMillis() - LED_PROCESS_INTERVAL_MS; // Substract some, to make sure leds gets updated on first run. - ledsProcess(); + ledsProcess(); } void ledsProcess() { @@ -56,33 +56,33 @@ void ledsProcess() { } prevTime = hwMillis(); - uint8_t state; + uint8_t state; - // For an On/Off ratio of 4, the pattern repeated will be [on, on, on, off] - // until the counter becomes 0. -#if defined(MY_DEFAULT_RX_LED_PIN) - state = (countRx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF; - hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, state); - if (countRx) { + // For an On/Off ratio of 4, the pattern repeated will be [on, on, on, off] + // until the counter becomes 0. + #if defined(MY_DEFAULT_RX_LED_PIN) + if (countRx) { --countRx; } -#endif + state = (countRx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF; + hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, state); + #endif -#if defined(MY_DEFAULT_TX_LED_PIN) - state = (countTx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF; - hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, state); - if (countTx) { + #if defined(MY_DEFAULT_TX_LED_PIN) + if (countTx) { --countTx; } -#endif + state = (countTx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF; + hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, state); + #endif -#if defined(MY_DEFAULT_ERR_LED_PIN) - state = (countErr & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF; - hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, state); - if (countErr) { + #if defined(MY_DEFAULT_ERR_LED_PIN) + if (countErr) { --countErr; } -#endif + state = (countErr & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF; + hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, state); + #endif } void ledsBlinkRx(uint8_t cnt) { @@ -105,3 +105,7 @@ void ledsBlinkErr(uint8_t cnt) { } ledsProcess(); } + +bool ledsBlinking() { + return countRx || countTx || countErr; +} diff --git a/core/MyLeds.h b/core/MyLeds.h index e6f982d1d..e0fb121f4 100644 --- a/core/MyLeds.h +++ b/core/MyLeds.h @@ -43,6 +43,11 @@ void ledsBlinkTx(uint8_t cnt); void ledsBlinkErr(uint8_t cnt); void ledsProcess(); // do the actual blinking + /** + * Test if any LED is currently blinking. + * @return true when one or more LEDs are blinking, false otherwise. + */ + bool ledsBlinking(); #else // Remove led functions if feature is disabled diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 9f4170c3b..0c87a849d 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -520,6 +520,13 @@ int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep, const uint8_t in transportPowerDown(); #endif + #if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) + // Wait until leds finish their blinking pattern + while (ledsBlinking()) { + doYield(); + } + #endif + setIndication(INDICATION_SLEEP); int8_t result = MY_SLEEP_NOT_POSSIBLE; // default From 92cbd2ac8f49fe2f8cb25726e08aac9ecd597b84 Mon Sep 17 00:00:00 2001 From: Olivier Date: Sat, 5 Nov 2016 17:32:29 +0100 Subject: [PATCH 118/167] Allow node to enter loop() if transport is NOK --- MyConfig.h | 15 ++- MySensors.h | 22 +--- core/MyGatewayTransport.cpp | 4 +- core/MyOTAFirmwareUpdate.cpp | 1 - core/MySensorsCore.cpp | 239 +++++++++++++++++++++-------------- core/MySensorsCore.h | 61 ++++----- core/MySigning.cpp | 12 +- core/MyTransport.cpp | 134 ++++++++++++-------- core/MyTransport.h | 47 ++++++- 9 files changed, 315 insertions(+), 220 deletions(-) diff --git a/MyConfig.h b/MyConfig.h index ff8ba7037..cf737a1ad 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -123,12 +123,6 @@ */ //#define MY_TRANSPORT_UPLINK_CHECK_DISABLED -/** -*@def MY_TRANSPORT_DONT_CARE_MODE -*@brief If set, transport traffic is unmonitored and GW connection is optional -*/ -//#define MY_TRANSPORT_DONT_CARE_MODE - /** *@def MY_TRANSPORT_MAX_TX_FAILURES *@brief Set to override max. consecutive TX failures until SNP is initiated @@ -167,6 +161,12 @@ * @brief If enabled, library compatibility is checked during node registration. Incompatible libraries are unable to send sensor data. */ #define MY_CORE_COMPATIBILITY_CHECK + + /** + * @def MY_TRANSPORT_RELAX + * @brief If enabled, node enters main loop() even if transport / connection to GW is not established + */ +//#define MY_TRANSPORT_RELAX /** * @def MY_NODE_ID @@ -855,6 +855,8 @@ #define MY_IS_RFM69HW #define MY_PARENT_NODE_IS_STATIC #define MY_REGISTRATION_CONTROLLER +#define MY_TRANSPORT_UPLINK_CHECK_DISABLED +#define MY_TRANSPORT_RELAX #define MY_DEBUG_VERBOSE_RF24 #define MY_TRANSPORT_SANITY_CHECK #define MY_RF24_IRQ_PIN @@ -862,7 +864,6 @@ #define MY_RX_MESSAGE_BUFFER_SIZE #define MY_NODE_LOCK_FEATURE #define MY_REPEATER_FEATURE -#define MY_TRANSPORT_DONT_CARE_MODE #define MY_LINUX_SERIAL_GROUPNAME #define MY_IS_SERIAL_PTY #endif diff --git a/MySensors.h b/MySensors.h index 1e6414d22..bb596cb9d 100644 --- a/MySensors.h +++ b/MySensors.h @@ -239,26 +239,8 @@ #endif #endif -#if defined(MY_TRANSPORT_DONT_CARE_MODE) && !defined(MY_GATEWAY_FEATURE) - // enables transport don't care mode, i.e. transport link is not monitored and GW connection optional - #if !defined(MY_PARENT_NODE_ID) || MY_PARENT_NODE_ID==255 - #error MY_TRANSPORT_DONT_CARE_MODE requires MY_PARENT_NODE_ID set - #endif - #if !defined(MY_PARENT_NODE_IS_STATIC) - #define MY_PARENT_NODE_IS_STATIC - #endif - #ifdef MY_REGISTRATION_FEATURE - #undef MY_REGISTRATION_FEATURE - #endif - #ifdef MY_TRANSPORT_SANITY_CHECK - #undef MY_TRANSPORT_SANITY_CHECK - #endif - #ifndef MY_TRANSPORT_UPLINK_CHECK_DISABLED - #define MY_TRANSPORT_UPLINK_CHECK_DISABLED - #endif - #ifdef MY_REGISTRATION_FEATURE - #undef MY_REGISTRATION_FEATURE - #endif +#if defined(MY_TRANSPORT_DONT_CARE_MODE) + #error This directive is deprecated, use MY_TRANSPORT_RELAX instead! #endif diff --git a/core/MyGatewayTransport.cpp b/core/MyGatewayTransport.cpp index fcf2b5391..c4aad2715 100644 --- a/core/MyGatewayTransport.cpp +++ b/core/MyGatewayTransport.cpp @@ -24,8 +24,6 @@ extern bool transportSendRoute(MyMessage &message); // global variables extern MyMessage _msg; extern MyMessage _msgTmp; -extern NodeConfig _nc; - inline void gatewayTransportProcess() { if (gatewayTransportAvailable()) { @@ -38,7 +36,7 @@ inline void gatewayTransportProcess() { _msgTmp = _msg; mSetRequestAck(_msgTmp, false); // Reply without ack flag (otherwise we would end up in an eternal loop) mSetAck(_msgTmp, true); - _msgTmp.sender = _nc.nodeId; + _msgTmp.sender = getNodeId(); _msgTmp.destination = _msg.sender; gatewayTransportSend(_msgTmp); } diff --git a/core/MyOTAFirmwareUpdate.cpp b/core/MyOTAFirmwareUpdate.cpp index af0338e1e..e9f286c8d 100644 --- a/core/MyOTAFirmwareUpdate.cpp +++ b/core/MyOTAFirmwareUpdate.cpp @@ -22,7 +22,6 @@ // global variables extern MyMessage _msg; extern MyMessage _msgTmp; -extern NodeConfig _nc; // local variables SPIFlash _flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID); diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 8586b2a08..f84cfb507 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -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-2016 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -24,18 +24,34 @@ #include #endif -ControllerConfig _cc; // Configuration coming from controller -NodeConfig _nc; // Essential settings for node to work +// message buffers MyMessage _msg; // Buffer for incoming messages MyMessage _msgTmp; // Buffer for temporary messages (acks and nonces among others) -bool _nodeRegistered = false; +// core configuration +coreConfig_t coreConfig; #if defined(MY_DEBUG) char _convBuf[MAX_PAYLOAD*2+1]; #endif -void (*_timeCallback)(unsigned long); // Callback for requested time messages +// Callback for requested time messages +void (*_timeCallback)(unsigned long); + +// Callback for transport=ok transition +void _callbackTransportOk() +{ + if (!coreConfig.presentationSent) { + presentNode(); + coreConfig.presentationSent = true; + } +#if !defined(MY_GATEWAY_FEATURE) + if (!coreConfig.registrationRequested) { + _registerNode(); + coreConfig.registrationRequested = true; + } +#endif +} void _process(void) { hwWatchdogReset(); @@ -75,6 +91,7 @@ void _infiniteLoop(void) { } void _begin(void) { + // reset wdt hwWatchdogReset(); if (preHwInit) { @@ -83,11 +100,15 @@ void _begin(void) { hwInit(); - debug(PSTR("MCO:BGN:INIT " MY_NODE_TYPE ",CP=" MY_CAPABILITIES ",VER=" MYSENSORS_LIBRARY_VERSION "\n")); + CORE_DEBUG(PSTR("MCO:BGN:INIT " MY_NODE_TYPE ",CP=" MY_CAPABILITIES ",VER=" MYSENSORS_LIBRARY_VERSION "\n")); + // set defaults + coreConfig.presentationSent = false; + coreConfig.registrationRequested = false; + // Call before() in sketch (if it exists) if (before) { - debug(PSTR("MCO:BGN:BFR\n")); // before callback + CORE_DEBUG(PSTR("MCO:BGN:BFR\n")); // before callback before(); } @@ -99,7 +120,7 @@ void _begin(void) { // Read latest received controller configuration from EEPROM // Note: _cc.isMetric is bool, hence empty EEPROM (=0xFF) evaluates to true (default) - hwReadConfigBlock((void*)&_cc, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(ControllerConfig)); + hwReadConfigBlock((void*)&coreConfig.controllerConfig, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(controllerConfig_t)); #if defined(MY_OTA_FIRMWARE_FEATURE) // Read firmware config from EEPROM, i.e. type, version, CRC, blocks @@ -109,42 +130,26 @@ void _begin(void) { #if defined(MY_SENSOR_NETWORK) // Save static parent id in eeprom (used by bootloader) hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, MY_PARENT_NODE_ID); - transportInitialise(); - while (!isTransportReady()) { - hwWatchdogReset(); - transportProcess(); - yield(); - } - #endif - - + // Register for transport layer + transportRegisterTransportOkCallback(_callbackTransportOk); - #ifdef MY_NODE_LOCK_FEATURE - // Check if node has been locked down - if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER) == 0) { - // Node is locked, check if unlock pin is asserted, else hang the node - pinMode(MY_NODE_UNLOCK_PIN, INPUT_PULLUP); - // Make a short delay so we are sure any large external nets are fully pulled - unsigned long enter = hwMillis(); - while (hwMillis() - enter < 2) {} - if (digitalRead(MY_NODE_UNLOCK_PIN) == 0) { - // Pin is grounded, reset lock counter - hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, MY_NODE_LOCK_COUNTER_MAX); - // Disable pullup - pinMode(MY_NODE_UNLOCK_PIN, INPUT); - setIndication(INDICATION_ERR_LOCKED); - debug(PSTR("MCO:BGN:NODE UNLOCKED\n")); - } else { - // Disable pullup - pinMode(MY_NODE_UNLOCK_PIN, INPUT); - nodeLock("LDB"); //Locked during boot + // Initialise transport layer + transportInitialise(); + + #if !defined(MY_TRANSPORT_RELAX) + // check if transport ready + while (!isTransportReady()) { + hwWatchdogReset(); + transportProcess(); + yield(); } - } else if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER) == 0xFF) { - // Reset walue - hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, MY_NODE_LOCK_COUNTER_MAX); - } + #else + CORE_DEBUG(PSTR("MCO:BGN:MTR\n")); + #endif #endif - + + _checkNodeLock(); + #if defined(MY_GATEWAY_FEATURE) #if defined(MY_INCLUSION_BUTTON_FEATURE) inclusionInit(); @@ -153,46 +158,40 @@ void _begin(void) { // initialise the transport driver if (!gatewayTransportInit()) { setIndication(INDICATION_ERR_INIT_GWTRANSPORT); - debug(PSTR("!MCO:BGN:TSP FAIL\n")); + CORE_DEBUG(PSTR("!MCO:BGN:TSP FAIL\n")); // Nothing more we can do _infiniteLoop(); } #endif - #if !defined(MY_GATEWAY_FEATURE) - presentNode(); - #endif - - // register node - _registerNode(); - // Call sketch setup if (setup) { - debug(PSTR("MCO:BGN:STP\n")); // setup callback + CORE_DEBUG(PSTR("MCO:BGN:STP\n")); // setup callback setup(); } - debug(PSTR("MCO:BGN:INIT OK,ID=%d,PAR=%d,DIS=%d,REG=%d\n"), _nc.nodeId, _nc.parentNodeId, _nc.distance, _nodeRegistered); + CORE_DEBUG(PSTR("MCO:BGN:INIT OK,TSP=%d\n"), isTransportReady()); + // reset wdt before handing over to loop hwWatchdogReset(); } -void _registerNode(void) { - #if defined (MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE) - debug(PSTR("MCO:REG:REQ\n")); // registration request - setIndication(INDICATION_REQ_REGISTRATION); - _nodeRegistered = MY_REGISTRATION_DEFAULT; - uint8_t counter = MY_REGISTRATION_RETRIES; - // only proceed if register response received or retries exceeded - do { - (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REGISTRATION_REQUEST).set(MY_CORE_VERSION)); - } while (!wait(2000, C_INTERNAL, I_REGISTRATION_RESPONSE) && counter--); - - #else - _nodeRegistered = true; - debug(PSTR("MCO:REG:NOT NEEDED\n")); - #endif +void _registerNode(void) +{ +#if defined (MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE) + CORE_DEBUG(PSTR("MCO:REG:REQ\n")); // registration request + setIndication(INDICATION_REQ_REGISTRATION); + coreConfig.registered = MY_REGISTRATION_DEFAULT; + uint8_t counter = MY_REGISTRATION_RETRIES; + // only proceed if register response received or retries exceeded + do { + (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REGISTRATION_REQUEST).set(MY_CORE_VERSION)); + } while (!wait(2000, C_INTERNAL, I_REGISTRATION_RESPONSE) && counter--); +#else + coreConfig.registered = true; + CORE_DEBUG(PSTR("MCO:REG:NOT NEEDED\n")); +#endif } void presentNode(void) { @@ -223,7 +222,7 @@ void presentNode(void) { // Send a configuration exchange request to controller // Node sends parent node. Controller answers with latest node configuration - (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CONFIG).set(_nc.parentNodeId)); + (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CONFIG).set(getParentNodeId())); // Wait configuration reply. (void)wait(2000, C_INTERNAL, I_CONFIG); @@ -236,16 +235,35 @@ void presentNode(void) { } -uint8_t getNodeId(void) { - return _nc.nodeId; +uint8_t getNodeId(void) +{ +#if defined(MY_SENSOR_NETWORK) + return transportGetNodeId(); +#else + return 0xFF; +#endif +} + +uint8_t getParentNodeId(void) +{ +#if defined(MY_SENSOR_NETWORK) + return transportGetParentNodeId(); +#else + return 0xFF; +#endif } -uint8_t getParentNodeId(void) { - return _nc.parentNodeId; +uint8_t getDistanceGW(void) +{ +#if defined(MY_SENSOR_NETWORK) + return transportGetDistanceGW(); +#else + return 0xFF; +#endif } -ControllerConfig getConfig(void) { - return _cc; +controllerConfig_t getConfig(void) { + return coreConfig.controllerConfig; } @@ -254,7 +272,7 @@ bool _sendRoute(MyMessage &message) { (void)message; #endif #if defined(MY_GATEWAY_FEATURE) - if (message.destination == _nc.nodeId) { + if (message.destination == getNodeId()) { // This is a message sent from a sensor attached on the gateway node. // Pass it directly to the gateway transport layer. return gatewayTransportSend(message); @@ -268,16 +286,16 @@ bool _sendRoute(MyMessage &message) { } bool send(MyMessage &message, const bool enableAck) { - message.sender = _nc.nodeId; + message.sender = getNodeId(); mSetCommand(message, C_SET); mSetRequestAck(message, enableAck); #if defined(MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE) - if (_nodeRegistered) { + if (coreConfig.registered) { return _sendRoute(message); } else { - debug(PSTR("!MCO:SND:NODE NOT REG\n")); // node not registered + CORE_DEBUG(PSTR("!MCO:SND:NODE NOT REG\n")); // node not registered return false; } #else @@ -308,7 +326,7 @@ bool sendSketchInfo(const char *name, const char *version, const bool ack) { if (name) { result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME, ack).set(name)); } - if (version) { + if (version) { result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION, ack).set(version)); } return result; @@ -336,15 +354,15 @@ bool _processInternalMessages(void) { } else if (type == I_REGISTRATION_RESPONSE) { #if defined (MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE) - _nodeRegistered = _msg.getBool(); + coreConfig.registered = _msg.getBool(); setIndication(INDICATION_GOT_REGISTRATION); - debug(PSTR("MCO:PIM:NODE REG=%d\n"), _nodeRegistered); // node registration + CORE_DEBUG(PSTR("MCO:PIM:NODE REG=%d\n"), coreConfig.registered); // node registration #endif } else if (type == I_CONFIG) { // Pick up configuration from controller (currently only metric/imperial) and store it in eeprom if changed - _cc.isMetric = _msg.data[0] == 0x00 || _msg.data[0] == 'M'; // metric if null terminated or M - hwWriteConfig(EEPROM_CONTROLLER_CONFIG_ADDRESS, _cc.isMetric); + coreConfig.controllerConfig.isMetric = _msg.data[0] == 0x00 || _msg.data[0] == 'M'; // metric if null terminated or M + hwWriteConfigBlock((void*)&coreConfig.controllerConfig, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(controllerConfig_t)); } else if (type == I_PRESENTATION) { // Re-send node presentation to controller @@ -377,7 +395,7 @@ bool _processInternalMessages(void) { for (uint16_t cnt = 0; cnt < SIZE_ROUTES; cnt++) { const uint8_t route = transportGetRoute(cnt); if (route != BROADCAST_ADDRESS) { - debug(PSTR("MCO:PIM:ROUTE N=%d,R=%d\n"), cnt, route); + CORE_DEBUG(PSTR("MCO:PIM:ROUTE N=%d,R=%d\n"), cnt, route); uint8_t outBuf[2] = { (uint8_t)cnt,route }; (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG).set(outBuf, 2)); wait(200); @@ -465,11 +483,11 @@ bool wait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t msgtype) { } int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep, const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, const uint8_t mode2) { - debug(PSTR("MCO:SLP:MS=%lu,SMS=%d,I1=%d,M1=%d,I2=%d,M2=%d\n"), sleepingMS, smartSleep, interrupt1, mode1, interrupt2, mode2); + CORE_DEBUG(PSTR("MCO:SLP:MS=%lu,SMS=%d,I1=%d,M1=%d,I2=%d,M2=%d\n"), sleepingMS, smartSleep, interrupt1, mode1, interrupt2, mode2); // OTA FW feature: do not sleep if FW update ongoing #if defined(MY_OTA_FIRMWARE_FEATURE) if (_fwUpdateOngoing) { - debug(PSTR("!MCO:SLP:FWUPD\n")); // sleeping not possible, FW update ongoing + CORE_DEBUG(PSTR("!MCO:SLP:FWUPD\n")); // sleeping not possible, FW update ongoing wait(sleepingMS); return MY_SLEEP_NOT_POSSIBLE; } @@ -482,7 +500,7 @@ int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep, const uint8_t in (void)interrupt2; (void)mode2; - debug(PSTR("!MCO:SLP:REP\n")); // sleeping not possible, repeater feature enabled + CORE_DEBUG(PSTR("!MCO:SLP:REP\n")); // sleeping not possible, repeater feature enabled wait(sleepingMS); return MY_SLEEP_NOT_POSSIBLE; #else @@ -490,7 +508,7 @@ int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep, const uint8_t in #if defined(MY_SENSOR_NETWORK) // Do not sleep if transport not ready if (!isTransportReady()) { - debug(PSTR("!MCO:SLP:TNR\n")); // sleeping not possible, transport not ready + CORE_DEBUG(PSTR("!MCO:SLP:TNR\n")); // sleeping not possible, transport not ready const uint32_t sleepEnterMS = hwMillis(); uint32_t sleepDeltaMS = 0; while (!isTransportReady() && (sleepDeltaMS < sleepingTimeMS) && (sleepDeltaMS < MY_SLEEP_TRANSPORT_RECONNECT_TIMEOUT_MS)) { @@ -501,7 +519,7 @@ int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep, const uint8_t in // sleep remainder if (sleepDeltaMS < sleepingTimeMS) { sleepingTimeMS -= sleepDeltaMS; // calculate remaining sleeping time - debug(PSTR("MCO:SLP:MS=%lu\n"), sleepingTimeMS); + CORE_DEBUG(PSTR("MCO:SLP:MS=%lu\n"), sleepingTimeMS); } else { // no sleeping time left @@ -517,7 +535,7 @@ int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep, const uint8_t in } #if defined(MY_SENSOR_NETWORK) - debug(PSTR("MCO:SLP:TPD\n")); // sleep, power down transport + CORE_DEBUG(PSTR("MCO:SLP:TPD\n")); // sleep, power down transport transportPowerDown(); #endif @@ -539,7 +557,7 @@ int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep, const uint8_t in } setIndication(INDICATION_WAKEUP); - debug(PSTR("MCO:SLP:WUP=%d\n"), result); // sleep wake-up + CORE_DEBUG(PSTR("MCO:SLP:WUP=%d\n"), result); // sleep wake-up return result; #endif } @@ -574,22 +592,57 @@ int8_t smartSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t i } + +void _nodeLock(const char* str) +{ #ifdef MY_NODE_LOCK_FEATURE -void nodeLock(const char* str) { // Make sure EEPROM is updated to locked status hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, 0); while (1) { setIndication(INDICATION_ERR_LOCKED); - debug(PSTR("MCO:NLK:NODE LOCKED. TO UNLOCK, GND PIN %d AND RESET\n"), MY_NODE_UNLOCK_PIN); + CORE_DEBUG(PSTR("MCO:NLK:NODE LOCKED. TO UNLOCK, GND PIN %d AND RESET\n"), MY_NODE_UNLOCK_PIN); yield(); (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID,C_INTERNAL, I_LOCKED).set(str)); #if defined(MY_SENSOR_NETWORK) transportPowerDown(); - debug(PSTR("MCO:NLK:TPD\n")); // power down transport + CORE_DEBUG(PSTR("MCO:NLK:TPD\n")); // power down transport #endif setIndication(INDICATION_SLEEP); (void)hwSleep((unsigned long)1000*60*30); // Sleep for 30 min before resending LOCKED message setIndication(INDICATION_WAKEUP); } +#else + (void)str; +#endif } + +void _checkNodeLock(void) +{ +#ifdef MY_NODE_LOCK_FEATURE + // Check if node has been locked down + if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER) == 0) { + // Node is locked, check if unlock pin is asserted, else hang the node + hwPinMode(MY_NODE_UNLOCK_PIN, INPUT_PULLUP); + // Make a short delay so we are sure any large external nets are fully pulled + unsigned long enter = hwMillis(); + while (hwMillis() - enter < 2) {} + if (hwDigitalRead(MY_NODE_UNLOCK_PIN) == 0) { + // Pin is grounded, reset lock counter + hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, MY_NODE_LOCK_COUNTER_MAX); + // Disable pullup + hwPinMode(MY_NODE_UNLOCK_PIN, INPUT); + setIndication(INDICATION_ERR_LOCKED); + CORE_DEBUG(PSTR("MCO:BGN:NODE UNLOCKED\n")); + } + else { + // Disable pullup + hwPinMode(MY_NODE_UNLOCK_PIN, INPUT); + _nodeLock("LDB"); //Locked during boot + } + } + else if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER) == 0xFF) { + // Reset walue + hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, MY_NODE_LOCK_COUNTER_MAX); + } #endif +} diff --git a/core/MySensorsCore.h b/core/MySensorsCore.h index 56f04a176..927244866 100644 --- a/core/MySensorsCore.h +++ b/core/MySensorsCore.h @@ -41,8 +41,9 @@ * |-|------|-------|-----------------------------------------------|---------------------------------------------------------------------------- * | | MCO | BGN | INIT %%s,CP=%%s,LIB=%%s | Core initialization, capabilities (CP), library version (VER) * | | MCO | BGN | BFR | Callback before() + * | | MCO | BGN | MTR | MY_TRANSPORT_RELAX enabled * | | MCO | BGN | STP | Callback setup() - * | | MCO | BGN | INIT OK,ID=%%d,PAR=%%d,DIS=%%d,REG=%%d | Core initialized, parent ID (PAR), distance to GW (DIS), registration (REG) + * | | MCO | BGN | INIT OK,TSP=%%d | Core initialised, transport status (TSP), 1=initialised, 0=not initialised * | | MCO | BGN | NODE UNLOCKED | Node successfully unlocked (see signing chapter) * |!| MCO | BGN | TSP FAIL | Transport initialization failed * | | MCO | REG | REQ | Registration request @@ -85,37 +86,36 @@ #ifdef MY_DEBUG - #define debug(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug + #define debug(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug, to be removed (follow-up PR) + #define CORE_DEBUG(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug #else - #define debug(x,...) //!< debug NULL + #define debug(x,...) //!< debug NULL, to be removed (follow-up PR) + #define CORE_DEBUG(x,...) //!< debug NULL #endif -/** - * @brief Node configuration - * - * This structure stores node-related configurations - */ -struct NodeConfig { - uint8_t nodeId; //!< Current node id - uint8_t parentNodeId; //!< Where this node sends its messages - uint8_t distance; //!< This nodes distance to sensor net gateway (number of hops) -}; /** * @brief Controller configuration * - * This structure stores controllerrelated configurations + * This structure stores controller-related configurations */ -struct ControllerConfig { +typedef struct { uint8_t isMetric; //!< Flag indicating if metric or imperial measurements are used -}; +} controllerConfig_t; + +/** +* @brief Node core configuration +* +*/ +typedef struct { + controllerConfig_t controllerConfig; //!< Controller config + // 8 bit + bool registered : 1; //!< Flag node registered + bool presentationSent : 1; //!< Flag presentation sent + bool registrationRequested : 1; //!< Flag registration requested + uint8_t reserved : 5; //!< reserved +} coreConfig_t; -extern NodeConfig _nc; //!< Node config -extern MyMessage _msg; //!< Buffer for incoming messages -extern MyMessage _msgTmp; //!< Buffer for temporary messages (acks and nonces among others) -#ifdef MY_DEBUG - extern char _convBuf[MAX_PAYLOAD * 2 + 1]; -#endif // **** public functions ******** @@ -203,7 +203,7 @@ bool requestTime(const bool ack = false); /** * Returns the most recent node configuration received from controller */ -ControllerConfig getConfig(void); +controllerConfig_t getControllerConfig(void); /** * Save a state (in local EEPROM). Good for actuators to "remember" state between @@ -328,20 +328,23 @@ int8_t smartSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t i int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep = false, const uint8_t interrupt1 = INTERRUPT_NOT_DEFINED, const uint8_t mode1 = MODE_NOT_DEFINED, const uint8_t interrupt2 = INTERRUPT_NOT_DEFINED, const uint8_t mode2 = MODE_NOT_DEFINED); -#ifdef MY_NODE_LOCK_FEATURE /** * @ingroup MyLockgrp * @ingroup internals * @brief Lock a node and transmit provided message with 30m intervals * * This function is called if suspicious activity has exceeded the threshold (see - * @ref ATTACK_COUNTER_MAX). Unlocking with a normal Arduino bootloader require erasing the EEPROM - * while unlocking with a custom bootloader require holding @ref UNLOCK_PIN low during power on/reset. + * @ref MY_NODE_LOCK_COUNTER_MAX). Unlocking with a normal Arduino bootloader require erasing the EEPROM + * while unlocking with a custom bootloader require holding @ref MY_NODE_UNLOCK_PIN low during power on/reset. * * @param str The string to transmit. */ -void nodeLock(const char* str); -#endif +void _nodeLock(const char* str); + +/** + * @brief Check node lock status and prevent node execution if locked. + */ +void _checkNodeLock(void); // **** private functions ******** @@ -406,7 +409,7 @@ void loop(void) __attribute__((weak)); // Inline function and macros static inline MyMessage& build(MyMessage &msg, const uint8_t destination, const uint8_t sensor, const uint8_t command, const uint8_t type, const bool ack = false) { - msg.sender = _nc.nodeId; + msg.sender = getNodeId(); msg.destination = destination; msg.sensor = sensor; msg.type = type; diff --git a/core/MySigning.cpp b/core/MySigning.cpp index a9be61fbd..bdfa4e9cb 100644 --- a/core/MySigning.cpp +++ b/core/MySigning.cpp @@ -185,7 +185,7 @@ bool signerProcessInternal(MyMessage &msg) { nof_nonce_requests++; SIGN_DEBUG(PSTR("Nonce requests left until lockdown: %d\n"), MY_NODE_LOCK_COUNTER_MAX-nof_nonce_requests); if (nof_nonce_requests >= MY_NODE_LOCK_COUNTER_MAX) { - nodeLock("TMNR"); //Too many nonces requested + _nodeLock("TMNR"); //Too many nonces requested } #endif #if defined(MY_SIGNING_SOFT) @@ -317,7 +317,7 @@ bool signerSignMsg(MyMessage &msg) { #if defined(MY_SIGNING_FEATURE) // If destination is known to require signed messages and we are the sender, // sign this message unless it is a handshake message - if (DO_SIGN(msg.destination) && msg.sender == _nc.nodeId) { + if (DO_SIGN(msg.destination) && msg.sender == getNodeId()) { if (skipSign(msg)) { return true; } else { @@ -350,7 +350,7 @@ bool signerSignMsg(MyMessage &msg) { // After this point, only the 'last' member of the message structure is allowed to be altered if the // message has been signed, or signature will become invalid and the message rejected by the receiver } - } else if (_nc.nodeId == msg.sender) { + } else if (getNodeId() == msg.sender) { mSetSigned(msg, 0); // Message is not supposed to be signed, make sure it is marked unsigned } #else @@ -368,9 +368,9 @@ bool signerVerifyMsg(MyMessage &msg) { // If we are a node, or we are a gateway and the sender require signatures (or just a strict gw) // and we are the destination... #if defined(MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL) - if (msg.destination == _nc.nodeId) { + if (msg.destination == getNodeId()) { #else - if ((!MY_IS_GATEWAY || DO_SIGN(msg.sender)) && msg.destination == _nc.nodeId) { + if ((!MY_IS_GATEWAY || DO_SIGN(msg.sender)) && msg.destination == getNodeId()) { #endif // Internal messages of certain types are not verified if (skipSign(msg)) { @@ -399,7 +399,7 @@ bool signerVerifyMsg(MyMessage &msg) { nof_failed_verifications++; SIGN_DEBUG(PSTR("Failed verification attempts left until lockdown: %d\n"), MY_NODE_LOCK_COUNTER_MAX-nof_failed_verifications); if (nof_failed_verifications >= MY_NODE_LOCK_COUNTER_MAX) { - nodeLock("TMFV"); //Too many failed verifications + _nodeLock("TMFV"); //Too many failed verifications } } #endif diff --git a/core/MyTransport.cpp b/core/MyTransport.cpp index 129715de2..e921cadf7 100644 --- a/core/MyTransport.cpp +++ b/core/MyTransport.cpp @@ -20,20 +20,25 @@ #include "MyTransport.h" // SM: transitions and update states -static transportState stInit = { stInitTransition, stInitUpdate }; -static transportState stParent = { stParentTransition, stParentUpdate }; -static transportState stID = { stIDTransition, stIDUpdate }; -static transportState stUplink = { stUplinkTransition, stUplinkUpdate }; -static transportState stReady = { stReadyTransition, stReadyUpdate }; -static transportState stFailure = { stFailureTransition, stFailureUpdate }; +static transportState_t stInit = { stInitTransition, stInitUpdate }; +static transportState_t stParent = { stParentTransition, stParentUpdate }; +static transportState_t stID = { stIDTransition, stIDUpdate }; +static transportState_t stUplink = { stUplinkTransition, stUplinkUpdate }; +static transportState_t stReady = { stReadyTransition, stReadyUpdate }; +static transportState_t stFailure = { stFailureTransition, stFailureUpdate }; // transport SM variables -static transportSM _transportSM; +static transportSM_t _transportSM; + +// transport config +transportConfig_t transportConfig; + +// callbacks +transportCallback_t transportOk_cb = NULL; // global variables extern MyMessage _msg; // incoming message extern MyMessage _msgTmp; // outgoing message -extern NodeConfig _nc; // node config #if defined(MY_RAM_ROUTING_TABLE_ENABLED) static routingTable _transportRoutingTable; //!< routing table @@ -70,13 +75,10 @@ void stInitTransition(void) { #endif // Read node settings (ID, parent ID, GW distance) from EEPROM - hwReadConfigBlock((void*)&_nc, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(NodeConfig)); + hwReadConfigBlock((void*)&transportConfig, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(transportConfig_t)); } void stInitUpdate(void) { - #if defined(MY_TRANSPORT_DONT_CARE_MODE) - TRANSPORT_DEBUG(PSTR("TSM:INIT:TDC\n")); // transport don't care mode - #endif // initialise radio if (!transportInit()) { TRANSPORT_DEBUG(PSTR("!TSM:INIT:TSP FAIL\n")); @@ -89,9 +91,9 @@ void stInitUpdate(void) { #if defined(MY_GATEWAY_FEATURE) // Set configuration for gateway TRANSPORT_DEBUG(PSTR("TSM:INIT:GW MODE\n")); - _nc.parentNodeId = GATEWAY_ADDRESS; - _nc.distance = 0u; - _nc.nodeId = GATEWAY_ADDRESS; + transportConfig.parentNodeId = GATEWAY_ADDRESS; + transportConfig.distanceGW = 0u; + transportConfig.nodeId = GATEWAY_ADDRESS; transportSetAddress(GATEWAY_ADDRESS); // GW mode: skip FPAR,ID,UPL states transportSwitchSM(stReady); @@ -99,12 +101,12 @@ void stInitUpdate(void) { if ((uint8_t)MY_NODE_ID != AUTO) { TRANSPORT_DEBUG(PSTR("TSM:INIT:STATID=%d\n"),(uint8_t)MY_NODE_ID); // Set static ID - _nc.nodeId = (uint8_t)MY_NODE_ID; + transportConfig.nodeId = (uint8_t)MY_NODE_ID; // Save static ID to eeprom (for bootloader) hwWriteConfig(EEPROM_NODE_ID_ADDRESS, (uint8_t)MY_NODE_ID); } // assign ID if set - if (_nc.nodeId == AUTO || transportAssignNodeID(_nc.nodeId)) { + if (transportConfig.nodeId == AUTO || transportAssignNodeID(transportConfig.nodeId)) { // if node ID valid (>0 and <255), proceed to next state transportSwitchSM(stParent); } @@ -125,14 +127,14 @@ void stParentTransition(void) { #if defined(MY_PARENT_NODE_IS_STATIC) TRANSPORT_DEBUG(PSTR("TSM:FPAR:STATP=%d\n"), (uint8_t)MY_PARENT_NODE_ID); // static parent _transportSM.findingParentNode = false; - _nc.distance = 1u; // assumption, CHKUPL:GWDC will update this variable - _nc.parentNodeId = (uint8_t)MY_PARENT_NODE_ID; + transportConfig.distanceGW = 1u; // assumption, CHKUPL:GWDC will update this variable + transportConfig.parentNodeId = (uint8_t)MY_PARENT_NODE_ID; // save parent ID to eeprom (for bootloader) hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, (uint8_t)MY_PARENT_NODE_ID); #else _transportSM.findingParentNode = true; - _nc.distance = DISTANCE_INVALID; // Set distance to max and invalidate parent node ID - _nc.parentNodeId = AUTO; + transportConfig.distanceGW = DISTANCE_INVALID; // Set distance to max and invalidate parent node ID + transportConfig.parentNodeId = AUTO; // Broadcast find parent request (void)transportRouteMessage(build(_msgTmp, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_REQUEST).set("")); #endif @@ -147,7 +149,7 @@ void stParentUpdate(void) { #else if (transportTimeInState() > MY_TRANSPORT_STATE_TIMEOUT_MS || _transportSM.preferredParentFound) { // timeout or preferred parent found - if (_nc.parentNodeId != AUTO) { + if (transportConfig.parentNodeId != AUTO) { // parent assigned TRANSPORT_DEBUG(PSTR("TSM:FPAR:OK\n")); // find parent ok _transportSM.findingParentNode = false; @@ -177,7 +179,7 @@ void stParentUpdate(void) { // stID: verify and request ID if necessary void stIDTransition(void) { TRANSPORT_DEBUG(PSTR("TSM:ID\n")); // verify/request node ID - if (_nc.nodeId == AUTO) { + if (transportConfig.nodeId == AUTO) { // send ID request setIndication(INDICATION_REQ_NODEID); TRANSPORT_DEBUG(PSTR("TSM:ID:REQ\n")); // request node ID @@ -186,7 +188,7 @@ void stIDTransition(void) { } void stIDUpdate(void) { - if (_nc.nodeId != AUTO) { + if (transportConfig.nodeId != AUTO) { // current node ID is valid TRANSPORT_DEBUG(PSTR("TSM:ID:OK\n")); setIndication(INDICATION_GOT_NODEID); @@ -225,9 +227,9 @@ void stUplinkUpdate(void) { // uplink ok, i.e. GW replied TRANSPORT_DEBUG(PSTR("TSM:UPL:OK\n")); // uplink ok //_transportSM.pingActive = false; ==> set false upon receiving I_PONG - if (_transportSM.pingResponse != _nc.distance) { - TRANSPORT_DEBUG(PSTR("TSM:UPL:DGWC,O=%d,N=%d\n"), _nc.distance, _transportSM.pingResponse); // distance to GW changed - _nc.distance = _transportSM.pingResponse; + if (_transportSM.pingResponse != transportConfig.distanceGW) { + TRANSPORT_DEBUG(PSTR("TSM:UPL:DGWC,O=%d,N=%d\n"), transportConfig.distanceGW, _transportSM.pingResponse); // distance to GW changed + transportConfig.distanceGW = _transportSM.pingResponse; } transportSwitchSM(stReady); // proceed to next state } @@ -257,6 +259,11 @@ void stReadyTransition(void) { _transportSM.uplinkOk = true; _transportSM.failureCounter = 0u; // reset failure counter _transportSM.failedUplinkTransmissions = 0u; // reset failed uplink TX counter + // callback + if (transportOk_cb) { + transportOk_cb(); + } + TRANSPORT_DEBUG(PSTR("TSM:READY:PARAM,ID=%d,PAR=%d,DIS=%d\n"), transportConfig.nodeId, transportConfig.parentNodeId, transportConfig.distanceGW); } // stReadyUpdate: monitors link @@ -311,7 +318,7 @@ void stFailureUpdate(void) { } } -void transportSwitchSM(transportState& newState) { +void transportSwitchSM(transportState_t& newState) { if (_transportSM.currentState != &newState) { _transportSM.stateRetries = 0u; // state change, reset retry counter _transportSM.currentState = &newState; // change state @@ -386,9 +393,9 @@ bool transportCheckUplink(const bool force) { _transportSM.lastUplinkCheck = hwMillis(); TRANSPORT_DEBUG(PSTR("TSF:CKU:OK\n")); // did distance to GW change upstream, eg. re-routing of uplink nodes - if (hopsCount != _nc.distance) { - TRANSPORT_DEBUG(PSTR("TSF:CKU:DGWC,O=%d,N=%d\n"), _nc.distance, hopsCount); // distance to GW changed - _nc.distance = hopsCount; + if (hopsCount != transportConfig.distanceGW) { + TRANSPORT_DEBUG(PSTR("TSF:CKU:DGWC,O=%d,N=%d\n"), transportConfig.distanceGW, hopsCount); // distance to GW changed + transportConfig.distanceGW = hopsCount; } return true; } @@ -401,7 +408,7 @@ bool transportCheckUplink(const bool force) { bool transportAssignNodeID(const uint8_t newNodeId) { // verify if ID valid if (newNodeId != GATEWAY_ADDRESS && newNodeId != AUTO) { - _nc.nodeId = newNodeId; + transportConfig.nodeId = newNodeId; transportSetAddress(newNodeId); // Write ID to EEPROM hwWriteConfig(EEPROM_NODE_ID_ADDRESS, newNodeId); @@ -411,14 +418,14 @@ bool transportAssignNodeID(const uint8_t newNodeId) { else { TRANSPORT_DEBUG(PSTR("!TSF:SID:FAIL,ID=%d\n"),newNodeId); // ID is invalid, cannot assign ID setIndication(INDICATION_ERR_NET_FULL); - _nc.nodeId = AUTO; + transportConfig.nodeId = AUTO; return false; } } bool transportRouteMessage(MyMessage &message) { const uint8_t destination = message.destination; - uint8_t route = _nc.parentNodeId; // by default, all traffic is routed via parent node + uint8_t route = transportConfig.parentNodeId; // by default, all traffic is routed via parent node if (_transportSM.findingParentNode && destination != BROADCAST_ADDRESS) { TRANSPORT_DEBUG(PSTR("!TSF:RTE:FPAR ACTIVE\n")); // find parent active, message not sent @@ -427,7 +434,7 @@ bool transportRouteMessage(MyMessage &message) { } if (destination == GATEWAY_ADDRESS) { - route = _nc.parentNodeId; // message to GW always routes via parent + route = transportConfig.parentNodeId; // message to GW always routes via parent } else if (destination == BROADCAST_ADDRESS) { route = BROADCAST_ADDRESS; // message to BC does not require routing @@ -439,9 +446,9 @@ bool transportRouteMessage(MyMessage &message) { if (route == AUTO) { TRANSPORT_DEBUG(PSTR("!TSF:RTE:%d UNKNOWN\n"), destination); // route unknown #if !defined(MY_GATEWAY_FEATURE) - if (message.last != _nc.parentNodeId) { + if (message.last != transportConfig.parentNodeId) { // message not from parent, i.e. child node - route it to parent - route = _nc.parentNodeId; + route = transportConfig.parentNodeId; } else { // route unknown and msg received from parent, send it to destination assuming in rx radius @@ -453,14 +460,14 @@ bool transportRouteMessage(MyMessage &message) { #endif } #else - route = _nc.parentNodeId; // not a repeater, all traffic routed via parent + route = transportConfig.parentNodeId; // not a repeater, all traffic routed via parent #endif } // send message const bool result = transportSendWrite(route, message); #if !defined(MY_GATEWAY_FEATURE) // update counter - if (route == _nc.parentNodeId) { + if (route == transportConfig.parentNodeId) { if (!result) { setIndication(INDICATION_ERR_TX); _transportSM.failedUplinkTransmissions++; @@ -506,7 +513,7 @@ bool transportWait(const uint32_t ms, const uint8_t cmd, const uint8_t msgtype){ uint8_t transportPingNode(const uint8_t targetId) { if(!_transportSM.pingActive){ TRANSPORT_DEBUG(PSTR("TSF:PNG:SEND,TO=%d\n"), targetId); - if(targetId == _nc.nodeId) { + if(targetId == transportConfig.nodeId) { // pinging self _transportSM.pingResponse = 0u; } @@ -574,7 +581,7 @@ void transportProcessMessage(void) { // update routing table if msg not from parent #if defined(MY_REPEATER_FEATURE) #if !defined(MY_GATEWAY_FEATURE) - if (last != _nc.parentNodeId) { + if (last != transportConfig.parentNodeId) { #else // GW doesn't have parent { @@ -588,7 +595,7 @@ void transportProcessMessage(void) { _transportSM.msgReceived = true; // Is message addressed to this node? - if (destination == _nc.nodeId) { + if (destination == transportConfig.nodeId) { // prevent buffer overflow by limiting max. possible message length (5 bits=31 bytes max) to MAX_PAYLOAD (25 bytes) mSetLength(_msg, min(mGetLength(_msg),(uint8_t)MAX_PAYLOAD)); // null terminate data @@ -599,7 +606,7 @@ void transportProcessMessage(void) { _msgTmp = _msg; // Copy message mSetRequestAck(_msgTmp, false); // Reply without ack flag (otherwise we would end up in an eternal loop) mSetAck(_msgTmp, true); // set ACK flag - _msgTmp.sender = _nc.nodeId; + _msgTmp.sender = transportConfig.nodeId; _msgTmp.destination = sender; // send ACK, use transportSendRoute since ACK reply is not internal, i.e. if !transportOK do not reply (void)transportSendRoute(_msgTmp); @@ -627,15 +634,15 @@ void transportProcessMessage(void) { if (isValidDistance(distance)) { distance++; // Distance to gateway is one more for us w.r.t. parent // update settings if distance shorter or preferred parent found - if (((isValidDistance(distance) && distance < _nc.distance) || (!_autoFindParent && sender == (uint8_t)MY_PARENT_NODE_ID)) && !_transportSM.preferredParentFound) { + if (((isValidDistance(distance) && distance < transportConfig.distanceGW) || (!_autoFindParent && sender == (uint8_t)MY_PARENT_NODE_ID)) && !_transportSM.preferredParentFound) { // Found a neighbor closer to GW than previously found if (!_autoFindParent && sender == (uint8_t)MY_PARENT_NODE_ID) { _transportSM.preferredParentFound = true; TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR PREF\n")); // find parent, preferred parent found } - _nc.distance = distance; - _nc.parentNodeId = sender; - TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR OK,ID=%d,D=%d\n"), _nc.parentNodeId, _nc.distance); + transportConfig.distanceGW = distance; + transportConfig.parentNodeId = sender; + TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR OK,ID=%d,D=%d\n"), transportConfig.parentNodeId, transportConfig.distanceGW); } } } @@ -697,7 +704,7 @@ void transportProcessMessage(void) { // only reply if node is fully operational if (type == I_FIND_PARENT_REQUEST) { #if defined(MY_REPEATER_FEATURE) - if (sender != _nc.parentNodeId) { // no circular reference + if (sender != transportConfig.parentNodeId) { // no circular reference TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR REQ,ID=%d\n"), sender); // FPAR: find parent request // check if uplink functional - node can only be parent node if link to GW functional // this also prevents circular references in case GW ooo @@ -706,7 +713,7 @@ void transportProcessMessage(void) { TRANSPORT_DEBUG(PSTR("TSF:MSG:GWL OK\n")); // GW uplink ok // random delay minimizes collisions delay(hwMillis() & 0x3ff); - (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE).set(_nc.distance)); + (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE).set(transportConfig.distanceGW)); } else { TRANSPORT_DEBUG(PSTR("!TSF:MSG:GWL FAIL\n")); // GW uplink fail, do not respond to parent request @@ -721,10 +728,10 @@ void transportProcessMessage(void) { } #if !defined(MY_GATEWAY_FEATURE) if (type == I_DISCOVER_REQUEST) { - if (last == _nc.parentNodeId) { + if (last == transportConfig.parentNodeId) { // random wait to minimize collisions delay(hwMillis() & 0x3ff); - (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, I_DISCOVER_RESPONSE).set(_nc.parentNodeId)); + (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, I_DISCOVER_RESPONSE).set(transportConfig.parentNodeId)); // no return here (for fwd if repeater) } } @@ -733,7 +740,7 @@ void transportProcessMessage(void) { // controlled BC relay #if defined(MY_REPEATER_FEATURE) // controlled BC repeating: forward only if message received from parent and sender not self to prevent circular fwds - if(last == _nc.parentNodeId && sender != _nc.nodeId && isTransportReady()){ + if(last == transportConfig.parentNodeId && sender != transportConfig.nodeId && isTransportReady()){ TRANSPORT_DEBUG(PSTR("TSF:MSG:FWD BC MSG\n")); // controlled broadcast msg forwarding (void)transportRouteMessage(_msg); } @@ -743,7 +750,7 @@ void transportProcessMessage(void) { if (command != C_INTERNAL) { #if !defined(MY_GATEWAY_FEATURE) // only proceed if message received from parent - if (last != _nc.parentNodeId) { + if (last != transportConfig.parentNodeId) { return; } #endif @@ -818,7 +825,7 @@ void transportProcessFIFO(void) { } bool transportSendWrite(const uint8_t to, MyMessage &message) { - message.last = _nc.nodeId; // Update last + message.last = transportConfig.nodeId; // Update last // sign message if required if (!signerSignMsg(message)) { TRANSPORT_DEBUG(PSTR("!TSF:MSG:SIGN FAIL\n")); @@ -842,6 +849,25 @@ bool transportSendWrite(const uint8_t to, MyMessage &message) { return result; } +void transportRegisterTransportOkCallback(transportCallback_t cb) +{ + transportOk_cb = cb; +} + +uint8_t transportGetNodeId(void) +{ + return transportConfig.nodeId; +} +uint8_t transportGetParentNodeId(void) +{ + return transportConfig.parentNodeId; +} +uint8_t transportGetDistanceGW(void) +{ + return transportConfig.distanceGW; +} + + void transportClearRoutingTable(void) { for (uint16_t i = 0; i < SIZE_ROUTES; i++) { transportSetRoute((uint8_t)i, BROADCAST_ADDRESS); diff --git a/core/MyTransport.h b/core/MyTransport.h index 305b53ffb..edbf35df8 100644 --- a/core/MyTransport.h +++ b/core/MyTransport.h @@ -55,7 +55,6 @@ * |E| SYS | SUB | Message | Comment * |-|------|-----------|-----------------------|--------------------------------------------------------------------- * | | TSM | INIT | | Transition to stInit state - * | | TSM | INIT | TDC | Transport don't care mode * | | TSM | INIT | STATID=%%d | Node ID is static * | | TSM | INIT | TSP OK | Transport device configured and fully operational * | | TSM | INIT | GW MODE | Node is set up as GW, thus omitting ID and findParent states @@ -147,11 +146,13 @@ // debug #if defined(MY_DEBUG) - #define TRANSPORT_DEBUG(x,...) debug(x, ##__VA_ARGS__) //!< debug + #define TRANSPORT_DEBUG(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug + extern char _convBuf[MAX_PAYLOAD * 2 + 1]; #else #define TRANSPORT_DEBUG(x,...) //!< debug NULL #endif + #if defined(MY_REPEATER_FEATURE) #define MY_TRANSPORT_MAX_TX_FAILURES (10u) //!< search for a new parent node after this many transmission failures, higher threshold for repeating nodes #else @@ -204,16 +205,32 @@ #error Receive message buffering requires message buffering feature enabled! #endif +/** +* @brief Callback +* +*/ +typedef void(*transportCallback_t)(void); + +/** +* @brief Node configuration +* +* This structure stores node-related configurations +*/ +typedef struct { + uint8_t nodeId; //!< Current node id + uint8_t parentNodeId; //!< Where this node sends its messages + uint8_t distanceGW; //!< This nodes distance to sensor net gateway (number of hops) +} transportConfig_t; /** * @brief SM state * * This structure stores SM state definitions */ -struct transportState { +typedef struct { void(*Transition)(); //!< state transition function void(*Update)(); //!< state update function -}; +} transportState_t; /** * @brief Status variables and SM state @@ -222,7 +239,7 @@ struct transportState { */ typedef struct { // SM variables - transportState* currentState; //!< pointer to current fsm state + transportState_t* currentState; //!< pointer to current fsm state uint32_t stateEnter; //!< state enter timepoint // general transport variables uint32_t lastUplinkCheck; //!< last uplink check, required to prevent GW flooding @@ -239,7 +256,7 @@ typedef struct { bool msgReceived : 1; //!< flag message received // 8 bits uint8_t pingResponse; //!< stores I_PONG hops -} transportSM; +} transportSM_t; /** * @brief RAM routing table @@ -302,7 +319,7 @@ void stFailureUpdate(void); * @brief Switch SM state * @param newState New state to switch SM to */ -void transportSwitchSM(transportState& newState); +void transportSwitchSM(transportState_t& newState); /** * @brief Update SM state */ @@ -483,6 +500,22 @@ uint8_t transportReceive(void* data); */ void transportPowerDown(); +/** +* @brief Get node ID +* @return node ID +*/ +uint8_t transportGetNodeId(void); +/** +* @brief Get parent node ID +* @return parent node ID +*/ +uint8_t transportGetParentNodeId(void); +/** +* @brief Get distance to GW +* @return distance (=hops) to GW +*/ +uint8_t transportGetDistanceGW(void); + #endif // MyTransport_h /** @}*/ From 9ec97a6eaf8b1a3174d16d62c33cdfd8986cca2e Mon Sep 17 00:00:00 2001 From: tekka007 Date: Mon, 14 Nov 2016 15:19:54 +0100 Subject: [PATCH 119/167] Fix IO/HAL calls --- core/MyLeds.cpp | 8 ++++---- core/MySensorsCore.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/core/MyLeds.cpp b/core/MyLeds.cpp index 0da662829..3138be3a1 100644 --- a/core/MyLeds.cpp +++ b/core/MyLeds.cpp @@ -34,16 +34,16 @@ inline void ledsInit() countRx = 0; countTx = 0; countErr = 0; - + // Setup led pins #if defined(MY_DEFAULT_RX_LED_PIN) - pinMode(MY_DEFAULT_RX_LED_PIN, OUTPUT); + hwPinMode(MY_DEFAULT_RX_LED_PIN, OUTPUT); #endif #if defined(MY_DEFAULT_TX_LED_PIN) - pinMode(MY_DEFAULT_TX_LED_PIN, OUTPUT); + hwPinMode(MY_DEFAULT_TX_LED_PIN, OUTPUT); #endif #if defined(MY_DEFAULT_ERR_LED_PIN) - pinMode(MY_DEFAULT_ERR_LED_PIN, OUTPUT); + hwPinMode(MY_DEFAULT_ERR_LED_PIN, OUTPUT); #endif prevTime = hwMillis() - LED_PROCESS_INTERVAL_MS; // Substract some, to make sure leds gets updated on first run. ledsProcess(); diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 0c87a849d..80c32e3a9 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -115,20 +115,20 @@ void _begin(void) { // Check if node has been locked down if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER) == 0) { // Node is locked, check if unlock pin is asserted, else hang the node - pinMode(MY_NODE_UNLOCK_PIN, INPUT_PULLUP); + hwPinMode(MY_NODE_UNLOCK_PIN, INPUT_PULLUP); // Make a short delay so we are sure any large external nets are fully pulled unsigned long enter = hwMillis(); while (hwMillis() - enter < 2) {} - if (digitalRead(MY_NODE_UNLOCK_PIN) == 0) { + if (hwDigitalRead(MY_NODE_UNLOCK_PIN) == 0) { // Pin is grounded, reset lock counter hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, MY_NODE_LOCK_COUNTER_MAX); // Disable pullup - pinMode(MY_NODE_UNLOCK_PIN, INPUT); + hwPinMode(MY_NODE_UNLOCK_PIN, INPUT); setIndication(INDICATION_ERR_LOCKED); debug(PSTR("MCO:BGN:NODE UNLOCKED\n")); } else { // Disable pullup - pinMode(MY_NODE_UNLOCK_PIN, INPUT); + hwPinMode(MY_NODE_UNLOCK_PIN, INPUT); nodeLock("LDB"); //Locked during boot } } else if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER) == 0xFF) { From 144c7b9d2f92fdba4e7a0d905e99b6d7fc70bad0 Mon Sep 17 00:00:00 2001 From: Olivier Date: Tue, 18 Oct 2016 23:06:38 +0200 Subject: [PATCH 120/167] Implement RFM95 transport layer --- MyConfig.h | 86 +++++- MySensors.h | 7 +- core/MyCapabilities.h | 2 + core/MyTransportRFM95.cpp | 64 ++++ drivers/RFM95/RFM95.cpp | 468 ++++++++++++++++++++++++++++++ drivers/RFM95/RFM95.h | 593 ++++++++++++++++++++++++++++++++++++++ keywords.txt | 9 + 7 files changed, 1226 insertions(+), 3 deletions(-) create mode 100644 core/MyTransportRFM95.cpp create mode 100644 drivers/RFM95/RFM95.cpp create mode 100644 drivers/RFM95/RFM95.h diff --git a/MyConfig.h b/MyConfig.h index 214069b84..89853d9f8 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -79,6 +79,7 @@ //#define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 +//#define MY_RADIO_RFM95 //#define MY_RS485 /** @@ -641,7 +642,7 @@ */ #ifndef MY_RF69_IRQ_NUM #if defined(ARDUINO_ARCH_ESP8266) - #define MY_RF69_IRQ_NUM MY_RF69_IRQ_PIN + #define MY_RF69_IRQ_NUM RF69_IRQ_PIN #else #define MY_RF69_IRQ_NUM RF69_IRQ_NUM #endif @@ -650,6 +651,87 @@ // Enables RFM69 encryption (all nodes and gateway must have this enabled, and all must be personalized with the same AES key) //#define MY_RFM69_ENABLE_ENCRYPTION +/********************************** +* RFM95 driver defaults +***********************************/ + +/** + * @def MY_RFM95_FREQUENCY + * @brief RFM95 frequency + * + * This must match the hardware version of the RFM95 radio. + */ +#ifndef MY_RFM95_FREQUENCY + #define MY_RFM95_FREQUENCY (868.1f) +#endif + /** + * @def MY_RFM95_MODEM_CONFIGRUATION + * @brief RFM95 modem configuration, see table + * + * BW = Bandwidth in kHz + * CR = Error correction code + * SF = Spreading factor, chips / symbol + * + * | CONFIG | BW | CR | SF | Comment + * |------------------------|-------|-----|------|----------------------------- + * | RFM95_BW125CR45SF128 | 125 | 4/5 | 128 | Default, medium range + * | RFM95_BW500CR45SF128 | 500 | 4/5 | 128 | Fast, short range + * | RFM95_BW31_25CR48SF512 | 31.25 | 4/8 | 512 | Slow, long range + * | RFM95_BW125CR48SF4096 | 125 | 4/8 | 4096 | Slow, long range + * + */ + +#ifndef MY_RFM95_MODEM_CONFIGRUATION + // default + #define MY_RFM95_MODEM_CONFIGRUATION RFM95_BW125CR45SF128 +#endif + +/** + * @def MY_RFM95_RST_PIN + * @brief RFM95 reset pin, uncomment if used + */ +//#define MY_RFM95_RST_PIN RFM95_RST_PIN + +/** + * @def MY_RFM95_IRQ_PIN + * @brief RFM95 IRQ pin + */ +#ifndef MY_RFM95_IRQ_PIN + #define MY_RFM95_IRQ_PIN RFM95_IRQ_PIN +#endif + +/** + * @def MY_RFM95_SPI_CS + * @brief RFM95 SPI chip select pin + */ +#ifndef MY_RFM95_SPI_CS + #define MY_RFM95_SPI_CS RFM95_SPI_CS +#endif + +/** + * @def MY_RFM95_TX_POWER + * @brief RFM95 TX power level. + */ +#ifndef MY_RFM95_TX_POWER + #define MY_RFM95_TX_POWER 13 +#endif + + /** + * @def MY_RFM95_ATC_MODE_DISABLED + * @brief Enable to disable ATC mode + */ +//#define MY_RFM95_ATC_MODE_DISABLED + + /** + * @def MY_RFM95_ATC_TARGET_RSSI + * @brief Traget RSSI level for ATC mode + */ +#ifndef MY_RFM95_ATC_TARGET_RSSI + #define MY_RFM95_ATC_TARGET_RSSI (-60) +#endif + + + /************************************** * Ethernet Gateway Transport Defaults ***************************************/ @@ -842,4 +924,6 @@ #define MY_TRANSPORT_DONT_CARE_MODE #define MY_LINUX_SERIAL_GROUPNAME #define MY_IS_SERIAL_PTY +#define MY_RFM95_ATC_MODE_DISABLED +#define MY_RFM95_RST_PIN #endif diff --git a/MySensors.h b/MySensors.h index cbeee9083..3efe00063 100644 --- a/MySensors.h +++ b/MySensors.h @@ -53,7 +53,7 @@ #endif // Enable radio "feature" if one of the radio types was enabled -#if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) || defined(MY_RS485) +#if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) || defined(MY_RADIO_RFM95) || defined(MY_RS485) #define MY_SENSOR_NETWORK #endif @@ -260,7 +260,7 @@ // RADIO -#if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) || defined(MY_RS485) +#if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) || defined(MY_RADIO_RFM95) ||defined(MY_RS485) // SOFTSPI #ifdef MY_SOFTSPI #if defined(ARDUINO_ARCH_ESP8266) @@ -289,6 +289,9 @@ #elif defined(MY_RADIO_RFM69) #include "drivers/RFM69/RFM69.cpp" #include "core/MyTransportRFM69.cpp" + #elif defined(MY_RADIO_RFM95) + #include "drivers/RFM95/RFM95.cpp" + #include "core/MyTransportRFM95.cpp" #endif #endif diff --git a/core/MyCapabilities.h b/core/MyCapabilities.h index d861961c0..8b8abccec 100644 --- a/core/MyCapabilities.h +++ b/core/MyCapabilities.h @@ -38,6 +38,8 @@ #define MY_CAP_RADIO "N" #elif defined(MY_RADIO_RFM69) #define MY_CAP_RADIO "R" +#elif defined(MY_RADIO_RFM95) + #define MY_CAP_RADIO "L" #elif defined(MY_RS485) #define MY_CAP_RADIO "S" #else diff --git a/core/MyTransportRFM95.cpp b/core/MyTransportRFM95.cpp new file mode 100644 index 000000000..1d3ec333f --- /dev/null +++ b/core/MyTransportRFM95.cpp @@ -0,0 +1,64 @@ +/* + * 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/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 "MyConfig.h" +#include "MyTransport.h" +#include "drivers/RFM95/RFM95.h" + +bool transportInit(void) { + const bool result = RFM95_initialise(MY_RFM95_FREQUENCY); + #if !defined(MY_GATEWAY_FEATURE) && !defined(MY_RFM95_ATC_MODE_DISABLED) + // only enable ATC mode nodes + RFM95_ATCmode(true, MY_RFM95_ATC_TARGET_RSSI); + #endif + return result; +} + +void transportSetAddress(uint8_t address) { + RFM95_setAddress(address); +} + +uint8_t transportGetAddress(void) { + return RFM95_getAddress(); +} + +bool transportSend(uint8_t to, const void* data, uint8_t len) { + return RFM95_sendWithRetry(to, data, len); +} + +bool transportAvailable(void) { + return RFM95_available(); +} + +bool transportSanityCheck(void) { + return RFM95_sanityCheck(); +} + +uint8_t transportReceive(void* data) { + return RFM95_recv((uint8_t*)data); +} + +void transportPowerDown(void) { + (void)RFM95_sleep(); +} + +int16_t transportGetSignalStrength(void) { + return RFM95_getRSSI(); +} diff --git a/drivers/RFM95/RFM95.cpp b/drivers/RFM95/RFM95.cpp new file mode 100644 index 000000000..316040e7b --- /dev/null +++ b/drivers/RFM95/RFM95.cpp @@ -0,0 +1,468 @@ +/* + * 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/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 Mike McCauley's RFM95 library, Copyright (C) 2014 Mike McCauley + * Radiohead http://www.airspayce.com/mikem/arduino/RadioHead/index.html + * RFM95 driver refactored and optimized for MySensors, Copyright (C) 2016 Olivier Mauti + * + */ + +#include "RFM95.h" + +LOCAL void RFM95_csn(const bool level) { + hwDigitalWrite(MY_RFM95_SPI_CS, level); +} + +LOCAL uint8_t RFM95_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_t len, const bool aReadMode) { + uint8_t status; + uint8_t* current = buf; + noInterrupts(); + #if !defined(MY_SOFTSPI) + _SPI.beginTransaction(SPISettings(MY_RFM95_SPI_MAX_SPEED, MY_RFM95_SPI_DATA_ORDER, MY_RFM95_SPI_DATA_MODE)); + #endif + RFM95_csn(LOW); + status = _SPI.transfer(cmd); + while (len--) { + if (aReadMode) { + status = _SPI.transfer((uint8_t)0x00); + if (buf != NULL) { + *current++ = status; + } + } + else status = _SPI.transfer(*current++); + } + RFM95_csn(HIGH); + #if !defined(MY_SOFTSPI) + _SPI.endTransaction(); + #endif + interrupts(); + return status; +} + +// low level register access +LOCAL uint8_t RFM95_RAW_readByteRegister(const uint8_t address) { + return RFM95_spiMultiByteTransfer(address, NULL, 1, true); +} + +// low level register access +LOCAL uint8_t RFM95_RAW_writeByteRegister(const uint8_t address, uint8_t value) { + return RFM95_spiMultiByteTransfer(address, &value, 1, false); +} + +// macros, saves space +#define RFM95_readReg(__reg) RFM95_RAW_readByteRegister(__reg & RFM95_READ_REGISTER) +#define RFM95_writeReg(__reg, __value) RFM95_RAW_writeByteRegister((__reg | RFM95_WRITE_REGISTER), __value ) +#define RFM95_burstReadReg(__reg, __buf, __len) RFM95_spiMultiByteTransfer( __reg & RFM95_READ_REGISTER, (uint8_t*)__buf, __len, true ) +#define RFM95_burstWriteReg(__reg, __buf, __len) RFM95_spiMultiByteTransfer( __reg | RFM95_WRITE_REGISTER, (uint8_t*)__buf, __len, false ) + + +// check RegPktRssiValue (0x1A) vs. RegRssiValue (0x1B) + + +LOCAL bool RFM95_initialise(const float frequency) { + RFM95_DEBUG(PSTR("RFM95:INIT\n")); + // reset radio module if rst pin defined + #if defined(MY_RFM95_RST_PIN) + hwPinMode(MY_RFM95_RST_PIN, OUTPUT); + hwDigitalWrite(MY_RFM95_RST_PIN, HIGH); + // 100uS + delayMicroseconds(100); + hwDigitalWrite(MY_RFM95_RST_PIN, LOW); + // wait until chip ready + delay(5); + #endif + + // set variables + RFM95.address = RFM95_BROADCAST_ADDRESS; + RFM95.rxBufferValid = false; + RFM95.txSequenceNumber = 0; // initialise TX sequence counter + RFM95.powerLevel = 0; + RFM95.ATCenabled = false; + RFM95.ATCtargetRSSI = RFM95_TARGET_RSSI + RFM95_RSSI_OFFSET; + + // SPI init + hwDigitalWrite(MY_RFM95_SPI_CS, HIGH); + hwPinMode(MY_RFM95_SPI_CS, OUTPUT); + _SPI.begin(); + + // Set LoRa mode (during sleep mode) + RFM95_writeReg(RFM95_REG_01_OP_MODE, RFM95_MODE_SLEEP | RFM95_LONG_RANGE_MODE); + delay(10); // Wait for sleep mode to take over from say, CAD + // Check we are in sleep mode, with LORA set + if (RFM95_readReg(RFM95_REG_01_OP_MODE) != (RFM95_MODE_SLEEP | RFM95_LONG_RANGE_MODE)) { + return false; // No device present? + } + + // Set up FIFO, 256 bytes: LoRa max message 64 bytes, set half RX half TX (default) + RFM95_writeReg(RFM95_REG_0F_FIFO_RX_BASE_ADDR, RFM95_RX_FIFO_ADDR); + RFM95_writeReg(RFM95_REG_0E_FIFO_TX_BASE_ADDR, RFM95_TX_FIFO_ADDR); + RFM95_writeReg(RFM95_REG_23_MAX_PAYLOAD_LENGTH, RFM95_MAX_PACKET_LEN); + + (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); + const modemConfig_t configuration = { MY_RFM95_MODEM_CONFIGRUATION }; + RFM95_setModemRegisters(configuration); + RFM95_setPreambleLength(8); // default + RFM95_setFrequency(frequency); + // set power level + RFM95_setTxPower(MY_RFM95_TX_POWER); + + // IRQ + hwPinMode(MY_RFM95_IRQ_PIN, INPUT); + #if defined (SPI_HAS_TRANSACTION) && !defined (ESP8266) + _SPI.usingInterrupt(digitalPinToInterrupt(MY_RFM95_IRQ_PIN)); + #endif + attachInterrupt(digitalPinToInterrupt(MY_RFM95_IRQ_PIN), RFM95_interruptHandler, RISING); + + return true; +} + +// RxDone, TxDone, CADDone is mapped to DI0 +LOCAL void RFM95_interruptHandler(void) { + // Read the interrupt register + const uint8_t irq_flags = RFM95_readReg(RFM95_REG_12_IRQ_FLAGS); + if (RFM95.radioMode == RFM95_RADIO_MODE_RX && (irq_flags & (RFM95_RX_TIMEOUT | RFM95_PAYLOAD_CRC_ERROR)) ) { + // CRC error or timeout + // RXcontinuous mode: radio stays in RX mode, clearing IRQ needed + } + else if (RFM95.radioMode == RFM95_RADIO_MODE_RX && (irq_flags & RFM95_RX_DONE)) { + // set radio to STDBY (we are in RXcontinuous mode) + (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); + // Have received a packet + //In order to retrieve received data from FIFO the user must ensure that ValidHeader, PayloadCrcError, RxDone and RxTimeout interrupts in the status register RegIrqFlags are not asserted to ensure that packet reception has terminated successfully(i.e.no flags should be set). + const uint8_t bufLen = min(RFM95_readReg(RFM95_REG_13_RX_NB_BYTES), RFM95_MAX_PACKET_LEN); + if (bufLen >= RFM95_HEADER_LEN) { + // Reset the fifo read ptr to the beginning of the packet + RFM95_writeReg(RFM95_REG_0D_FIFO_ADDR_PTR, RFM95_readReg(RFM95_REG_10_FIFO_RX_CURRENT_ADDR)); + RFM95_burstReadReg(RFM95_REG_00_FIFO, RFM95.currentPacket.data, bufLen); + RFM95.currentPacket.RSSI = RFM95_readReg(RFM95_REG_1A_PKT_RSSI_VALUE); + RFM95.currentPacket.SNR = static_cast(RFM95_readReg(RFM95_REG_19_PKT_SNR_VALUE)); + RFM95.currentPacket.payloadLen = bufLen - RFM95_HEADER_LEN; + // Message for us + if ((RFM95.currentPacket.header.version >= RFM95_MIN_PACKET_HEADER_VERSION) && + (RFM95_PROMISCUOUS || RFM95.currentPacket.header.recipient == RFM95.address || RFM95.currentPacket.header.recipient == RFM95_BROADCAST_ADDRESS)) { + RFM95.rxBufferValid = true; + } + } + + } + else if (RFM95.radioMode == RFM95_RADIO_MODE_TX && (irq_flags & RFM95_TX_DONE) ) { + (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); + } + else if (RFM95.radioMode == RFM95_RADIO_MODE_CAD && (irq_flags & RFM95_CAD_DONE) ) { + RFM95.cad = irq_flags & RFM95_CAD_DETECTED; + (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); + } + + // Clear all IRQ flags + RFM95_writeReg(RFM95_REG_12_IRQ_FLAGS, 0xff); +} + +LOCAL bool RFM95_available(void) { + if (RFM95.radioMode == RFM95_RADIO_MODE_TX) { + return false; + } + (void)RFM95_setRadioMode(RFM95_RADIO_MODE_RX); + return RFM95.rxBufferValid; +} + +LOCAL void RFM95_clearRxBuffer(void) { + noInterrupts(); + RFM95.rxBufferValid = false; + interrupts(); +} + +LOCAL uint8_t RFM95_recv(uint8_t* buf) { + if (!RFM95_available()) { + return false; + } + + // atomic + noInterrupts(); + const uint8_t payloadLen = RFM95.currentPacket.payloadLen; + const uint8_t sender = RFM95.currentPacket.header.sender; + const rfm95_sequenceNumber_t sequenceNumber = RFM95.currentPacket.header.sequenceNumber; + const uint8_t controlFlags = RFM95.currentPacket.header.controlFlags; + const rfm95_RSSI_t RSSI = RFM95.currentPacket.RSSI; // of incoming packet + const rfm95_SNR_t SNR = RFM95.currentPacket.SNR; + if (buf != NULL) { + memcpy((void*)buf, (void*)RFM95.currentPacket.payload, payloadLen); + RFM95.rxBufferValid = false; + } + interrupts(); + + // ACK handling + if (RFM95_getACKRequested(controlFlags)) { + RFM95_DEBUG(PSTR("RFM95:RCV:SEND ACK\n")); + RFM95_sendACK(sender, sequenceNumber, RSSI, SNR); + } + + return payloadLen; +} + +LOCAL bool RFM95_send(rfm95_packet_t &packet) { + const uint8_t finalLen = packet.payloadLen + RFM95_HEADER_LEN; + // Make sure we dont interrupt an outgoing message + RFM95_waitPacketSent(); + (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); + + // Check channel activity + if (!RFM95_waitCAD()) { + return false; + } + packet.header.sequenceNumber = RFM95.txSequenceNumber++; + // Position at the beginning of the TX FIFO + RFM95_writeReg(RFM95_REG_0D_FIFO_ADDR_PTR, RFM95_TX_FIFO_ADDR); + // write packet + RFM95_burstWriteReg(RFM95_REG_00_FIFO, packet.data, finalLen); + // total payload length + RFM95_writeReg(RFM95_REG_22_PAYLOAD_LENGTH, finalLen); + // send message, if sent, irq fires and radio returns to standby + (void)RFM95_setRadioMode(RFM95_RADIO_MODE_TX); + return true; +} + +LOCAL bool RFM95_sendFrame(const uint8_t recipient, uint8_t* data, const uint8_t len, const rfm95_flag_t flags) { + rfm95_packet_t packet; + packet.header.version = RFM95_PACKET_HEADER_VERSION; + packet.header.sender = RFM95.address; + packet.header.recipient = recipient; + packet.header.controlFlags = 0x00; + packet.payloadLen = min(len, RFM95_MAX_PAYLOAD_LEN); + packet.header.controlFlags = flags; + memcpy(&packet.payload, data, packet.payloadLen); + return RFM95_send(packet); +} + +LOCAL void RFM95_setFrequency(const float centre) { + const uint32_t freq = (centre * 1000000.0) / RFM95_FSTEP; + RFM95_writeReg(RFM95_REG_06_FRF_MSB, (freq >> 16) & 0xff); + RFM95_writeReg(RFM95_REG_07_FRF_MID, (freq >> 8) & 0xff); + RFM95_writeReg(RFM95_REG_08_FRF_LSB, freq & 0xff); +} + +LOCAL bool RFM95_setTxPower(uint8_t powerLevel) { + // RFM95/96/97/98 does not have RFO pins connected to anything. Only PA_BOOST + powerLevel = max(RFM95_MIN_POWER_LEVEL_DBM, powerLevel); + powerLevel = min(RFM95_MAX_POWER_LEVEL_DBM, powerLevel); + if (powerLevel != RFM95.powerLevel) { + RFM95.powerLevel = powerLevel; + uint8_t val; + if (powerLevel > 20) { + // enable DAC, adds 3dBm + // The documentation is pretty confusing on this topic: PaSelect says the max power is 20dBm, + // but OutputPower claims it would be 17dBm. + // My measurements show 20dBm is correct + RFM95_writeReg(RFM95_REG_4D_PA_DAC, RFM95_PA_DAC_ENABLE); + val = powerLevel - 8; + } + else { + RFM95_writeReg(RFM95_REG_4D_PA_DAC, RFM95_PA_DAC_DISABLE); + val = powerLevel - 5; + } + RFM95_writeReg(RFM95_REG_09_PA_CONFIG, RFM95_PA_SELECT | val); + RFM95_DEBUG(PSTR("RFM95:PTX:LEVEL=%d\n"), powerLevel); + return true; + } + return false; + +} + +// Sets registers from a canned modem configuration structure +LOCAL void RFM95_setModemRegisters(const modemConfig_t config) { + RFM95_writeReg(RFM95_REG_1D_MODEM_CONFIG1, config.reg_1d); + RFM95_writeReg(RFM95_REG_1E_MODEM_CONFIG2, config.reg_1e); + RFM95_writeReg(RFM95_REG_26_MODEM_CONFIG3, config.reg_26); +} + +LOCAL void RFM95_setPreambleLength(const uint16_t preambleLength) { + RFM95_writeReg(RFM95_REG_20_PREAMBLE_MSB, preambleLength >> 8); + RFM95_writeReg(RFM95_REG_21_PREAMBLE_LSB, preambleLength & 0xff); +} + +LOCAL void RFM95_setAddress(const uint8_t addr) { + RFM95.address = addr; +} + +LOCAL uint8_t RFM95_getAddress(void) { + return RFM95.address; +} + + +LOCAL bool RFM95_isChannelActive(void) { + (void)RFM95_setRadioMode(RFM95_RADIO_MODE_CAD); + while (RFM95.radioMode == RFM95_RADIO_MODE_CAD) { + yield(); + } + + return RFM95.cad; +} + +LOCAL bool RFM95_setRadioMode(const rfm95_radio_mode_t newRadioMode) { + if (RFM95.radioMode == newRadioMode) { + return false; + } + uint8_t regMode; + + if (newRadioMode == RFM95_RADIO_MODE_STDBY) { + regMode = RFM95_MODE_STDBY; + } + else if (newRadioMode == RFM95_RADIO_MODE_SLEEP) { + regMode = RFM95_MODE_SLEEP; + } + else if (newRadioMode == RFM95_RADIO_MODE_CAD) { + regMode = RFM95_MODE_CAD; + RFM95_writeReg(RFM95_REG_40_DIO_MAPPING1, 0x80); // Interrupt on CadDone, DIO0 + } + else if (newRadioMode == RFM95_RADIO_MODE_RX) { + regMode = RFM95_MODE_RXCONTINUOUS; + RFM95_writeReg(RFM95_REG_40_DIO_MAPPING1, 0x00); // Interrupt on RxDone, DIO0 + } + else if (newRadioMode == RFM95_RADIO_MODE_TX) { + regMode = RFM95_MODE_TX; + RFM95_writeReg(RFM95_REG_40_DIO_MAPPING1, 0x40); // Interrupt on TxDone, DIO0 + } + else return false; + RFM95_writeReg(RFM95_REG_01_OP_MODE, regMode); + + RFM95.radioMode = newRadioMode; + return true; +} + +LOCAL bool RFM95_sleep(void) { + return RFM95_setRadioMode(RFM95_RADIO_MODE_SLEEP); +} + +// should be called immediately after reception in case sender wants ACK +LOCAL void RFM95_sendACK(const uint8_t recipient, const rfm95_sequenceNumber_t sequenceNumber, const rfm95_RSSI_t RSSI, const rfm95_RSSI_t SNR) { + RFM95_DEBUG(PSTR("RFM95:SAC:SEND ACK to=%d,RSSI=%d\n"),recipient,RSSI); + rfm95_ack_t ACK; + ACK.sequenceNumber = sequenceNumber; + ACK.RSSI = RSSI; + ACK.SNR = SNR; + rfm95_flag_t flags = 0x00; + RFM95_setACKReceived(flags, true); + RFM95_setACKRSSIReport(flags, true); + (void)RFM95_sendFrame(recipient, (uint8_t*)&ACK, sizeof(rfm95_ack_t), flags); +} + +LOCAL bool RFM95_executeATC(const rfm95_RSSI_t currentRSSI, const rfm95_RSSI_t targetRSSI) { + // allow +-5% + if (currentRSSI < (targetRSSI*1.05) && RFM95.powerLevel < RFM95_MAX_POWER_LEVEL_DBM) { + // increase transmitter power + RFM95.powerLevel++; + } + else if (currentRSSI > (targetRSSI*0.95) && RFM95.powerLevel > RFM95_MIN_POWER_LEVEL_DBM) { + // decrease transmitter power + RFM95.powerLevel--; + } + else { + // nothing to adjust + return false; + } + RFM95_DEBUG(PSTR("RFM95:ATC:ADJ TXL,cR=%d,tR=%d,TXL=%d\n"), currentRSSI - RFM95_RSSI_OFFSET, targetRSSI - RFM95_RSSI_OFFSET, RFM95.powerLevel); + return RFM95_setTxPower(RFM95.powerLevel);; +} + +LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, const uint8_t bufferSize, const uint8_t retries, const uint32_t retryWaitTime) { + for (uint8_t retry = 0; retry < retries; retry++) { + RFM95_DEBUG(PSTR("RFM95:SWR:SEND TO=%d,RETRY=%d\n"), recipient, retry); + rfm95_flag_t flags = 0x00; + RFM95_setACKRequested(flags, (recipient != RFM95_BROADCAST_ADDRESS)); + (void)RFM95_sendFrame(recipient, (uint8_t*)buffer, bufferSize, flags); + (void)RFM95_waitPacketSent(); + (void)RFM95_setRadioMode(RFM95_RADIO_MODE_RX); + if (recipient == RFM95_BROADCAST_ADDRESS) { + return true; + } + const uint32_t enterMS = hwMillis(); + while (hwMillis() - enterMS < 500) { + if (RFM95.rxBufferValid) { + const uint8_t sender = RFM95.currentPacket.header.sender; + const rfm95_sequenceNumber_t ACKsequenceNumber = RFM95.currentPacket.ACK.sequenceNumber; + const rfm95_flag_t flag = RFM95.currentPacket.header.controlFlags; + if (sender == recipient && RFM95_getACKReceived(flag) && (ACKsequenceNumber == RFM95.txSequenceNumber - 1)) { + RFM95_DEBUG(PSTR("RFM95:SWR:ACK FROM=%d,SEQ=%d,RSSI=%d,SNR=%d\n"),sender,ACKsequenceNumber, RFM95.currentPacket.ACK.RSSI-RFM95_RSSI_OFFSET, (int8_t)RFM95.currentPacket.ACK.SNR / 4); + RFM95_clearRxBuffer(); + + // ATC + if (RFM95.ATCenabled && RFM95_getACKRSSIReport(flag)) { + (void)RFM95_executeATC(RFM95.currentPacket.ACK.RSSI, RFM95.ATCtargetRSSI); + } // ATC + return true; + } // seq check + } + yield(); + } + RFM95_DEBUG(PSTR("!RFM95:SWR:NACK\n")); + if (RFM95.ATCenabled) { + // No ACK received, maybe out of reach: increase power level + RFM95_setTxPower(RFM95.powerLevel++); + } + } + return false; +} + + +// Wait until no channel activity detected or timeout +LOCAL bool RFM95_waitCAD(void) { + const uint32_t enterMS = hwMillis(); + while (RFM95_isChannelActive()) { + if (hwMillis() - enterMS > RFM95_CAD_TIMEOUT_MS) { + return false; + } + yield(); + } + return true; +} + +// Wait for any previous transmission to finish +LOCAL bool RFM95_waitPacketSent(void) { + while (RFM95.radioMode == RFM95_RADIO_MODE_TX) + yield(); + return true; +} + +LOCAL int16_t RFM95_getRSSI(void) { + return (int16_t)(RFM95.currentPacket.RSSI - RFM95_RSSI_OFFSET); +} +LOCAL int16_t RFM95_getSNR(void) { + return (int16_t)(RFM95.currentPacket.SNR / 4); +} + +LOCAL int8_t RFM95_getTxPower(void) { + return RFM95.powerLevel; +} + +LOCAL void RFM95_ATCmode(const bool OnOff, const int16_t targetRSSI) { + RFM95.ATCenabled = OnOff; + RFM95.ATCtargetRSSI = (uint8_t)(targetRSSI + RFM95_RSSI_OFFSET); +} + +LOCAL bool RFM95_sanityCheck(void) { + return true; +} + + + + + + + + + + diff --git a/drivers/RFM95/RFM95.h b/drivers/RFM95/RFM95.h new file mode 100644 index 000000000..c9f253fb0 --- /dev/null +++ b/drivers/RFM95/RFM95.h @@ -0,0 +1,593 @@ +/* + * 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/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 Mike McCauley's RFM95 library, Copyright (C) 2014 Mike McCauley + * Radiohead http://www.airspayce.com/mikem/arduino/RadioHead/index.html + * RFM95 driver refactored and optimized for MySensors, Copyright (C) 2016 Olivier Mauti + * + * Changelog: + * - ACK with sequenceNumber + * - ATC control + * + * Definitions for HopeRF LoRa radios: + * http://www.hoperf.com/upload/rf/RFM95_96_97_98W.pdf + * http://www.hoperf.cn/upload/rfchip/RF96_97_98.pdf + * + */ + + /** + * @file RFM95.h + * + * @defgroup RFM95grp RFM95 + * @ingroup internals + * @{ + * + * RFM95 driver-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE + * - [!] Exclamation mark is prepended in case of error + * + * This section is WIP! + * + * |E| SYS | SUB | Message | Comment + * |-|-------|----------|-----------------------------------|--------------------------------------------------------------------- + * | | RFM95 | INIT | | Initialise RFM95 radio + * | | RFM95 | RCV | SEND ACK | ACK request received, sending ACK back + * | | RFM95 | PTC | LEVEL=%d | Set TX power level + * | | RFM95 | SAC | SEND ACK TO=%d,RSSI=%d | Send ACK to node (TO), RSSI of received message (RSSI) + * | | RFM95 | ATC | ADJ TXL,cR=%d,tR=%d,TXL=%d | Adjust TX level, current RSSI (cR), target RSSI (tR), TX level (TXL) + * | | RFM95 | SWR | SEND TO=%d,RETRY=%d | Send message to (TO), NACK retry counter (RETRY) + * | | RFM95 | SWR | ACK FROM=%d,SEQ=%d,RSSI=%d,SNR=%d | ACK received from node (FROM), seq ID (SEQ), (RSSI), (SNR) + * |!| RFM95 | SWR | NACK | No ACK received + + * + * + * RFM95 modem configuration + * + * BW = Bandwidth in kHz + * CR = Error correction code + * SF = Spreading factor, chips / symbol + * + * | CONFIG | REG_1D | REG_1E | REG_26 | BW | CR | SF | Comment + * |------------------|--------|--------|--------|-------|-----|------|----------------------------- + * | BW125CR45SF128 | 0x72 | 0x74 | 0x04 | 125 | 4/5 | 128 | Default, medium range + * | BW500CR45SF128 | 0x92 | 0x74 | 0x04 | 500 | 4/5 | 128 | Fast, short range + * | BW31_25CR48SF512 | 0x48 | 0x94 | 0x04 | 31.25 | 4/8 | 512 | Slow, long range + * | BW125CR48SF4096 | 0x78 | 0xC4 | 0x0C | 125 | 4/8 | 4096 | Slow, long range + * + * @brief API declaration for RFM95 + * + */ + +#ifndef _RFM95_h +#define _RFM95_h + +#if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__) + #define RFM95_IRQ_PIN (2) + #define RFM95_RST_PIN (9) +#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) + #define RFM95_IRQ_PIN (2) + #define RFM95_RST_PIN (9) +#elif defined(__AVR_ATmega32U4__) + #define RFM95_IRQ_PIN (3) + #define RFM95_RST_PIN (9) +#elif defined(__arm__) + #define RFM95_IRQ_PIN (10) + #define RFM95_RST_PIN (27) +#else + #define RFM95_IRQ_PIN (2) //!< RFM95_IRQ_PIN + #define RFM95_RST_PIN (9) //!< RFM95_IRQ_PIN +#endif + +// SPI settings +#define RFM95_SPI_CS (SS) //!< SPI CS/SS pin + + +#if !defined(MY_RFM95_SPI_MAX_SPEED) + #define MY_RFM95_SPI_MAX_SPEED 4000000 //!< SPI speed +#endif +#define MY_RFM95_SPI_DATA_ORDER MSBFIRST //!< SPI data order +#define MY_RFM95_SPI_DATA_MODE SPI_MODE0 //!< SPI mode + + +#if defined (ARDUINO) && !defined (__arm__) && !defined (_SPI) + #include + #if defined(MY_SOFTSPI) + SoftSPI _SPI; + #else + #define _SPI SPI + #endif +#else + #if defined(__arm__) + #include + #else + extern HardwareSPI SPI; //!< SPI + #endif + + #if !defined(_SPI) + #define _SPI SPI //!< SPI + #endif +#endif + +// debug +#if defined(MY_DEBUG_VERBOSE_RFM95) + #define RFM95_DEBUG(x,...) debug(x, ##__VA_ARGS__) //!< Debug print +#else + #define RFM95_DEBUG(x,...) //!< Debug null +#endif + +#define RFM95_FIFO_SIZE (0xFFu) //!< Max number of bytes the LORA Rx/Tx FIFO can hold +#define RFM95_RX_FIFO_ADDR (0x00u) //!< RX FIFO addr pointer +#define RFM95_TX_FIFO_ADDR (0x80u) //!< TX FIFO addr pointer +#define RFM95_MAX_PACKET_LEN (0x40u) //!< This is the maximum number of bytes that can be carried by the LORA + +#define RFM95_CAD_TIMEOUT_MS (2*1000ul) //!< channel activity detection timeout +#define RFM95_FXOSC (32000000.0f) //!< The crystal oscillator frequency of the module +#define RFM95_FSTEP (RFM95_FXOSC / 524288ul) //!< The Frequency Synthesizer step = RFM95_FXOSC / + +#define RFM95_PACKET_HEADER_VERSION (1u) //!< RFM95 packet header version +#define RFM95_MIN_PACKET_HEADER_VERSION (1u) //!< Minimal RFM95 packet header version +#define RFM95_RETRIES (2u) //!< Retries in case of failed transmission +#define RFM95_RETRY_TIMEOUT_MS (500ul) //!< Timeout for ACK, adjustments needed if modem configuration changed (air time different) + +#define RFM95_BIT_ACK_REQUESTED (7u) //!< RFM95 header, controlFlag, bit 7 +#define RFM95_BIT_ACK_RECEIVED (6u) //!< RFM95 header, controlFlag, bit 6 +#define RFM95_BIT_ACK_RSSI_REPORT (5u) //!< RFM95 header, controlFlag, bit 5 + +#define RFM95_BROADCAST_ADDRESS (255u) //!< Broadcasting address +#define RFM95_RSSI_OFFSET (137u) //!< RSSI offset +#define RFM95_TARGET_RSSI (-60) //!< RSSI target +#define RFM95_PROMISCUOUS (false) //!< RFM95 promiscuous mode + +#define RFM95_getACKRequested(__value) ((bool)bitRead(__value, RFM95_BIT_ACK_REQUESTED)) //!< getACKRequested +#define RFM95_setACKRequested(__value, __flag) bitWrite(__value, RFM95_BIT_ACK_REQUESTED,__flag) //!< setACKRequested +#define RFM95_getACKReceived(__value) ((bool)bitRead(__value, RFM95_BIT_ACK_RECEIVED)) //!< getACKReceived +#define RFM95_setACKReceived(__value, __flag) bitWrite(__value, RFM95_BIT_ACK_RECEIVED,__flag) //!< setACKReceived +#define RFM95_setACKRSSIReport(__value, __flag) bitWrite(__value, RFM95_BIT_ACK_RSSI_REPORT,__flag) //!< setACKRSSIReport +#define RFM95_getACKRSSIReport(__value) ((bool)bitRead(__value, RFM95_BIT_ACK_RSSI_REPORT)) //!< getACKRSSIReport + +// RFM95 radio configurations: reg_1d, reg_1e, reg_26 (see datasheet) +#define RFM95_BW125CR45SF128 RFM95_BW_125KHZ | RFM95_CODING_RATE_4_5, RFM95_SPREADING_FACTOR_128CPS | RFM95_RX_PAYLOAD_CRC_ON, RFM95_AGC_AUTO_ON //!< 0x72,0x74,0x04 +#define RFM95_BW500CR45SF128 RFM95_BW_500KHZ | RFM95_CODING_RATE_4_5, RFM95_SPREADING_FACTOR_128CPS | RFM95_RX_PAYLOAD_CRC_ON, RFM95_AGC_AUTO_ON //!< 0x92,0x74,0x04 +#define RFM95_BW31_25CR48SF512 RFM95_BW_31_25KHZ | RFM95_CODING_RATE_4_8, RFM95_SPREADING_FACTOR_512CPS | RFM95_RX_PAYLOAD_CRC_ON, RFM95_AGC_AUTO_ON //!< 0x48,0x94,0x04 +#define RFM95_BW125CR48SF4096 RFM95_BW_125KHZ | RFM95_CODING_RATE_4_8, RFM95_SPREADING_FACTOR_4096CPS | RFM95_RX_PAYLOAD_CRC_ON, RFM95_AGC_AUTO_ON | RFM95_LOW_DATA_RATE_OPTIMIZE //!< 0x78,0xc4,0x0C + +#define RFM95_MIN_POWER_LEVEL_DBM (5u) //!< min. power level +#define RFM95_MAX_POWER_LEVEL_DBM (23u) //!< max. power level + +/** +* @brief Radio modes +*/ +typedef enum { + RFM95_RADIO_MODE_RX = 0, //!< RX mode + RFM95_RADIO_MODE_TX = 1, //!< TX mode + RFM95_RADIO_MODE_CAD = 2, //!< CAD mode + RFM95_RADIO_MODE_SLEEP = 3, //!< SLEEP mode + RFM95_RADIO_MODE_STDBY = 4 //!< STDBY mode +} rfm95_radio_mode_t; + +/** +* @brief RFM95 modem config registers +*/ +typedef struct { + uint8_t reg_1d; //!< Value for register REG_1D_MODEM_CONFIG1 + uint8_t reg_1e; //!< Value for register REG_1E_MODEM_CONFIG2 + uint8_t reg_26; //!< Value for register REG_26_MODEM_CONFIG3 +} modemConfig_t; + +/** +* @brief Sequence number data type +*/ +typedef uint16_t rfm95_sequenceNumber_t; +/** +* @brief RSSI data type +*/ +typedef uint8_t rfm95_RSSI_t; +/** +* @brief SNR data type +*/ +typedef int8_t rfm95_SNR_t; +/** +* @brief Control flag data type +*/ +typedef uint8_t rfm95_flag_t; +/** +* @brief RFM95 LoRa header +*/ +typedef struct { + uint8_t version; //!< Header version + uint8_t recipient; //!< Payload recipient + uint8_t sender; //!< Payload sender + rfm95_flag_t controlFlags; //!< Control flags, used for ACK + rfm95_sequenceNumber_t sequenceNumber; //!< Packet sequence number, used for ACK +} __attribute__((packed)) rfm95_header_t; + +/** +* @brief RFM95 LoRa ACK packet structure +*/ +typedef struct { + rfm95_sequenceNumber_t sequenceNumber; //!< sequence number + rfm95_RSSI_t RSSI; //!< RSSI + rfm95_SNR_t SNR; //!< SNR +} __attribute__((packed)) rfm95_ack_t; + + +#define RFM95_HEADER_LEN sizeof(rfm95_header_t) //!< Size header inside LoRa payload +#define RFM95_MAX_PAYLOAD_LEN (RFM95_MAX_PACKET_LEN - RFM95_HEADER_LEN) //!< Max payload length + +/** +* @brief LoRa packet structure +*/ +typedef struct { + union { + struct { + rfm95_header_t header; //!< LoRa header + union { + uint8_t payload[RFM95_MAX_PAYLOAD_LEN]; //!< Payload, i.e. MySensors message + rfm95_ack_t ACK; //!< Union: ACK + }; + }; + uint8_t data[RFM95_MAX_PACKET_LEN]; //!< RAW + }; + uint8_t payloadLen; //!< Length of payload (excluding header) + rfm95_RSSI_t RSSI; //!< RSSI of current packet, RSSI = value - 137 + rfm95_SNR_t SNR; //!< SNR of current packet +} __attribute__((packed)) rfm95_packet_t; + + +/** +* @brief RFM95 internal variables +*/ +typedef struct { + uint8_t address; //!< Node address + rfm95_packet_t currentPacket; //!< Buffer for current packet + rfm95_sequenceNumber_t txSequenceNumber; //!< RFM95_txSequenceNumber + uint8_t powerLevel; //!< TX power level dBm + uint8_t ATCtargetRSSI; //!< ATC: target RSSI + // 8 bit + rfm95_radio_mode_t radioMode : 3; //!< current transceiver state + bool cad : 1; //!< RFM95_cad + bool rxBufferValid : 1; //!< RX buffer valid + bool ATCenabled : 1; //!< ATC enabled + uint8_t reserved : 2; //!< reserved +} rfm95_internal_t; + +#define LOCAL static //!< static + +/** +* @brief Initialise the driver transport hardware and software +* @param frequency +* @return True if initialisation succeeded +*/ +LOCAL bool RFM95_initialise(const float frequency); +/** +* @brief Set the driver/node address +* @param addr +*/ +LOCAL void RFM95_setAddress(const uint8_t addr); +/** +* @brief Get driver/node address +* @return Node address +*/ +LOCAL uint8_t RFM95_getAddress(void); +/** +* @brief Sets all the registered required to configure the data modem in the RF95/96/97/98, including the +* bandwidth, spreading factor etc. +* @param config See modemConfig_t and references therein +*/ +LOCAL void RFM95_setModemRegisters(const modemConfig_t config); +/** +* @brief Tests whether a new message is available +* @return True if a new, complete, error-free uncollected message is available to be retreived by @ref RFM95_recv() +*/ +LOCAL bool RFM95_available(void); +/** +* @brief If a valid message is received, copy it to buf and return length. 0 byte messages are permitted. +* @param buf Location to copy the received message +* @return Number of bytes +*/ +LOCAL uint8_t RFM95_recv(uint8_t* buf); +/** +* @brief RFM95_send +* @param packet +* @return True if packet sent +*/ +LOCAL bool RFM95_send(rfm95_packet_t &packet); +/** +* @brief RFM95_sendFrame +* @param recipient +* @param data +* @param len +* @param flags +* @return True if frame sent +*/ +LOCAL bool RFM95_sendFrame(const uint8_t recipient, uint8_t* data, const uint8_t len, const rfm95_flag_t flags); +/** +* @brief RFM95_setPreambleLength +* @param preambleLength +*/ +LOCAL void RFM95_setPreambleLength(const uint16_t preambleLength); +/** +* @brief Sets the transmitter and receiver centre frequency +* @param centre Frequency in MHz (137.0 to 1020.0) +*/ +LOCAL void RFM95_setFrequency(const float centre); +/** +* @brief Sets the transmitter power output level, and configures the transmitter pin +* @param powerLevel Transmitter power level in dBm (+5 to +23) +* @return True power level adjusted +*/ +LOCAL bool RFM95_setTxPower(uint8_t powerLevel); +/** +* @brief Sets the radio into low-power sleep mode +* @return true if sleep mode was successfully entered +*/ +LOCAL bool RFM95_sleep(void); +/** +* @brief Use the radio's Channel Activity Detect (CAD) function to detect channel activity +* @return true if channel is in use +*/ +LOCAL bool RFM95_isChannelActive(void); +/** +* @brief RFM95_sendACK +* @param recipient +* @param sequenceNumber +* @param RSSI (rfm95_RSSI_t) +* @param SNR (rfm95_RSSI_t) +*/ +LOCAL void RFM95_sendACK(const uint8_t recipient, const rfm95_sequenceNumber_t sequenceNumber, const rfm95_RSSI_t RSSI, const rfm95_RSSI_t SNR); +/** +* @brief RFM95_sendWithRetry +* @param recipient +* @param buffer +* @param bufferSize +* @param retries +* @param retryWaitTime +* @return True if packet successfully sent +*/ +LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, const uint8_t bufferSize, const uint8_t retries = RFM95_RETRIES, const uint32_t retryWaitTime = RFM95_RETRY_TIMEOUT_MS); +/** +* @brief RFM95_waitCAD +* @return True if no channel activity detected +*/ +LOCAL bool RFM95_waitCAD(void); +/** +* @brief RFM95_waitPacketSent +* @return True if packet sent +*/ +LOCAL bool RFM95_waitPacketSent(void); +/** +* @brief RFM95_setRadioMode +* @param newRadioMode +* @return True if mode changed +*/ +LOCAL bool RFM95_setRadioMode(const rfm95_radio_mode_t newRadioMode); +/** +* @brief Low level interrupt handler +*/ +LOCAL void RFM95_interruptHandler(void); +/** +* @brief RFM95_clearRxBuffer +*/ +LOCAL void RFM95_clearRxBuffer(void); +/** +* @brief RFM95_getSNR +* @return SNR Signal strength of last packet +*/ +LOCAL int16_t RFM95_getSNR(void); +/** +* @brief RFM95_getRSSI +* @return RSSI Signal strength of last packet +*/ +LOCAL int16_t RFM95_getRSSI(void); +/** +* @brief RFM_executeATC +* @param currentRSSI +* @param targetRSSI +* @return True if power level adjusted +*/ +LOCAL bool RFM95_executeATC(const rfm95_RSSI_t currentRSSI, const rfm95_RSSI_t targetRSSI); +/** +* @brief RFM95_getTxPower +* @return Current power level +*/ +LOCAL int8_t RFM95_getTxPower(void); +/** +* @brief RFM95_ATCmode +* @param targetRSSI Target RSSI for transmitter (default -60) +* @param OnOff True to enable ATC +*/ +LOCAL void RFM95_ATCmode(const bool OnOff, const int16_t targetRSSI = RFM95_TARGET_RSSI); + +volatile rfm95_internal_t RFM95; //!< internal variables + +// Register access +#define RFM95_READ_REGISTER (0x7Fu) //!< reading register +#define RFM95_WRITE_REGISTER (0x80u) //!< writing register + +// Registers, available LoRa mode +#define RFM95_REG_00_FIFO 0x00 //!< REG_00_FIFO +#define RFM95_REG_01_OP_MODE 0x01 //!< REG_01_OP_MODE +#define RFM95_REG_02_RESERVED 0x02 //!< REG_02_RESERVED +#define RFM95_REG_03_RESERVED 0x03 //!< REG_03_RESERVED +#define RFM95_REG_04_RESERVED 0x04 //!< REG_04_RESERVED +#define RFM95_REG_05_RESERVED 0x05 //!< REG_05_RESERVED +#define RFM95_REG_06_FRF_MSB 0x06 //!< REG_06_FRF_MSB +#define RFM95_REG_07_FRF_MID 0x07 //!< REG_07_FRF_MID +#define RFM95_REG_08_FRF_LSB 0x08 //!< REG_08_FRF_LSB +#define RFM95_REG_09_PA_CONFIG 0x09 //!< REG_09_PA_CONFIG +#define RFM95_REG_0A_PA_RAMP 0x0a //!< REG_0A_PA_RAMP +#define RFM95_REG_0B_OCP 0x0b //!< REG_0B_OCP +#define RFM95_REG_0C_LNA 0x0c //!< REG_0C_LNA +#define RFM95_REG_0D_FIFO_ADDR_PTR 0x0d //!< REG_0D_FIFO_ADDR_PTR +#define RFM95_REG_0E_FIFO_TX_BASE_ADDR 0x0e //!< REG_0E_FIFO_TX_BASE_ADDR +#define RFM95_REG_0F_FIFO_RX_BASE_ADDR 0x0f //!< REG_0F_FIFO_RX_BASE_ADDR +#define RFM95_REG_10_FIFO_RX_CURRENT_ADDR 0x10 //!< REG_10_FIFO_RX_CURRENT_ADDR +#define RFM95_REG_11_IRQ_FLAGS_MASK 0x11 //!< REG_11_IRQ_FLAGS_MASK +#define RFM95_REG_12_IRQ_FLAGS 0x12 //!< REG_12_IRQ_FLAGS +#define RFM95_REG_13_RX_NB_BYTES 0x13 //!< REG_13_RX_NB_BYTES +#define RFM95_REG_14_RX_HEADER_CNT_VALUE_MSB 0x14 //!< REG_14_RX_HEADER_CNT_VALUE_MSB +#define RFM95_REG_15_RX_HEADER_CNT_VALUE_LSB 0x15 //!< REG_15_RX_HEADER_CNT_VALUE_LSB +#define RFM95_REG_16_RX_PACKET_CNT_VALUE_MSB 0x16 //!< REG_16_RX_PACKET_CNT_VALUE_MSB +#define RFM95_REG_17_RX_PACKET_CNT_VALUE_LSB 0x17 //!< REG_17_RX_PACKET_CNT_VALUE_LSB +#define RFM95_REG_18_MODEM_STAT 0x18 //!< REG_18_MODEM_STAT +#define RFM95_REG_19_PKT_SNR_VALUE 0x19 //!< REG_19_PKT_SNR_VALUE +#define RFM95_REG_1A_PKT_RSSI_VALUE 0x1a //!< REG_1A_PKT_RSSI_VALUE +#define RFM95_REG_1B_RSSI_VALUE 0x1b //!< REG_1B_RSSI_VALUE +#define RFM95_REG_1C_HOP_CHANNEL 0x1c //!< REG_1C_HOP_CHANNEL +#define RFM95_REG_1D_MODEM_CONFIG1 0x1d //!< REG_1D_MODEM_CONFIG1 +#define RFM95_REG_1E_MODEM_CONFIG2 0x1e //!< REG_1E_MODEM_CONFIG2 +#define RFM95_REG_1F_SYMB_TIMEOUT_LSB 0x1f //!< REG_1F_SYMB_TIMEOUT_LSB +#define RFM95_REG_20_PREAMBLE_MSB 0x20 //!< REG_20_PREAMBLE_MSB +#define RFM95_REG_21_PREAMBLE_LSB 0x21 //!< REG_21_PREAMBLE_LSB +#define RFM95_REG_22_PAYLOAD_LENGTH 0x22 //!< REG_22_PAYLOAD_LENGTH +#define RFM95_REG_23_MAX_PAYLOAD_LENGTH 0x23 //!< REG_23_MAX_PAYLOAD_LENGTH +#define RFM95_REG_24_HOP_PERIOD 0x24 //!< REG_24_HOP_PERIOD +#define RFM95_REG_25_FIFO_RX_BYTE_ADDR 0x25 //!< REG_25_FIFO_RX_BYTE_ADDR +#define RFM95_REG_26_MODEM_CONFIG3 0x26 //!< REG_26_MODEM_CONFIG3 + +// Reserved when in LoRa mode +#define RFM95_REG_40_DIO_MAPPING1 0x40 //!< REG_40_DIO_MAPPING1 +#define RFM95_REG_41_DIO_MAPPING2 0x41 //!< REG_41_DIO_MAPPING2 +#define RFM95_REG_42_VERSION 0x42 //!< REG_42_VERSION +#define RFM95_REG_4B_TCXO 0x4b //!< REG_4B_TCXO +#define RFM95_REG_4D_PA_DAC 0x4d //!< REG_4D_PA_DAC +#define RFM95_REG_5B_FORMER_TEMP 0x5b //!< REG_5B_FORMER_TEMP +#define RFM95_REG_61_AGC_REF 0x61 //!< REG_61_AGC_REF +#define RFM95_REG_62_AGC_THRESH1 0x62 //!< REG_62_AGC_THRESH1 +#define RFM95_REG_63_AGC_THRESH2 0x63 //!< REG_63_AGC_THRESH2 +#define RFM95_REG_64_AGC_THRESH3 0x64 //!< REG_64_AGC_THRESH3 + +// RFM95_REG_01_OP_MODE 0x01 +#define RFM95_LONG_RANGE_MODE 0x80 //!< LONG_RANGE_MODE +#define RFM95_ACCESS_SHARED_REG 0x40 //!< ACCESS_SHARED_REG + +#define RFM95_MODE_SLEEP 0x00 //!< MODE_SLEEP +#define RFM95_MODE_STDBY 0x01 //!< MODE_STDBY +#define RFM95_MODE_FSTX 0x02 //!< MODE_FSTX +#define RFM95_MODE_TX 0x03 //!< MODE_TX +#define RFM95_MODE_FSRX 0x04 //!< MODE_FSRX +#define RFM95_MODE_RXCONTINUOUS 0x05 //!< MODE_RXCONTINUOUS +#define RFM95_MODE_RXSINGLE 0x06 //!< MODE_RXSINGLE +#define RFM95_MODE_CAD 0x07 //!< MODE_CAD + +// RFM95_REG_09_PA_CONFIG 0x09 +#define RFM95_OUTPUT_POWER 0x0F //!< OUTPUT_POWER +#define RFM95_MAX_POWER 0x70 //!< MAX_POWER +#define RFM95_PA_SELECT 0x80 //!< PA_SELECT + +// RFM95_REG_0A_PA_RAMP 0x0a +#define RFM95_PA_RAMP_3_4MS 0x00 //!< PA_RAMP_3_4MS +#define RFM95_PA_RAMP_2MS 0x01 //!< PA_RAMP_2MS +#define RFM95_PA_RAMP_1MS 0x02 //!< PA_RAMP_1MS +#define RFM95_PA_RAMP_500US 0x03 //!< PA_RAMP_500US +#define RFM95_PA_RAMP_250US 0x04 //!< PA_RAMP_250US +#define RFM95_PA_RAMP_125US 0x05 //!< PA_RAMP_125US +#define RFM95_PA_RAMP_100US 0x06 //!< PA_RAMP_100US +#define RFM95_PA_RAMP_62US 0x07 //!< PA_RAMP_62US +#define RFM95_PA_RAMP_50US 0x08 //!< PA_RAMP_50US +#define RFM95_PA_RAMP_40US 0x09 //!< PA_RAMP_40US +#define RFM95_PA_RAMP_31US 0x0A //!< PA_RAMP_31US +#define RFM95_PA_RAMP_25US 0x0B //!< PA_RAMP_25US +#define RFM95_PA_RAMP_20US 0x0C //!< PA_RAMP_20US +#define RFM95_PA_RAMP_15US 0x0D //!< PA_RAMP_15US +#define RFM95_PA_RAMP_12US 0x0E //!< PA_RAMP_12US +#define RFM95_PA_RAMP_10US 0x0F //!< PA_RAMP_10US +#define RFM95_LOW_PN_TX_PLL_OFF 0x10 //! Date: Mon, 14 Nov 2016 15:16:01 +0100 Subject: [PATCH 121/167] Core optimizations --- MyConfig.h | 6 +-- core/MySensorsCore.cpp | 47 ++++++++---------- core/MySensorsCore.h | 7 ++- core/MyTransport.cpp | 108 ++++++++++++++++++++--------------------- core/MyTransport.h | 35 +++++++------ 5 files changed, 98 insertions(+), 105 deletions(-) diff --git a/MyConfig.h b/MyConfig.h index 22039d1f6..9bdf596d4 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -172,10 +172,10 @@ #define MY_CORE_COMPATIBILITY_CHECK /** - * @def MY_TRANSPORT_RELAX + * @def MY_TRANSPORT_RELAXED * @brief If enabled, node enters main loop() even if transport / connection to GW is not established */ -//#define MY_TRANSPORT_RELAX +//#define MY_TRANSPORT_RELAXED /** * @def MY_NODE_ID @@ -865,7 +865,7 @@ #define MY_PARENT_NODE_IS_STATIC #define MY_REGISTRATION_CONTROLLER #define MY_TRANSPORT_UPLINK_CHECK_DISABLED -#define MY_TRANSPORT_RELAX +#define MY_TRANSPORT_RELAXED #define MY_DEBUG_VERBOSE_RF24 #define MY_TRANSPORT_SANITY_CHECK #define MY_RF24_IRQ_PIN diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 1761b66d7..7a5e20a68 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -29,7 +29,7 @@ MyMessage _msg; // Buffer for incoming messages MyMessage _msgTmp; // Buffer for temporary messages (acks and nonces among others) // core configuration -coreConfig_t coreConfig; +static coreConfig_t _coreConfig; #if defined(MY_DEBUG) char _convBuf[MAX_PAYLOAD*2+1]; @@ -41,16 +41,13 @@ void (*_timeCallback)(unsigned long); // Callback for transport=ok transition void _callbackTransportOk() { - if (!coreConfig.presentationSent) { + if (!_coreConfig.presentationSent) { presentNode(); - coreConfig.presentationSent = true; - } #if !defined(MY_GATEWAY_FEATURE) - if (!coreConfig.registrationRequested) { _registerNode(); - coreConfig.registrationRequested = true; - } #endif + _coreConfig.presentationSent = true; + } } void _process(void) { @@ -96,8 +93,7 @@ void _begin(void) { CORE_DEBUG(PSTR("MCO:BGN:INIT " MY_NODE_TYPE ",CP=" MY_CAPABILITIES ",VER=" MYSENSORS_LIBRARY_VERSION "\n")); // set defaults - coreConfig.presentationSent = false; - coreConfig.registrationRequested = false; + _coreConfig.presentationSent = false; // Call before() in sketch (if it exists) if (before) { @@ -112,8 +108,8 @@ void _begin(void) { signerInit(); // Read latest received controller configuration from EEPROM - // Note: _cc.isMetric is bool, hence empty EEPROM (=0xFF) evaluates to true (default) - hwReadConfigBlock((void*)&coreConfig.controllerConfig, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(controllerConfig_t)); + // Note: _coreConfig.isMetric is bool, hence empty EEPROM (=0xFF) evaluates to true (default) + hwReadConfigBlock((void*)&_coreConfig.controllerConfig, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(controllerConfig_t)); #if defined(MY_OTA_FIRMWARE_FEATURE) // Read firmware config from EEPROM, i.e. type, version, CRC, blocks @@ -123,13 +119,12 @@ void _begin(void) { #if defined(MY_SENSOR_NETWORK) // Save static parent id in eeprom (used by bootloader) hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, MY_PARENT_NODE_ID); - // Register for transport layer - transportRegisterTransportOkCallback(_callbackTransportOk); - + // Register transport=OK callback + transportRegisterOkCallback(_callbackTransportOk); // Initialise transport layer transportInitialise(); - #if !defined(MY_TRANSPORT_RELAX) + #if !defined(MY_TRANSPORT_RELAXED) // check if transport ready while (!isTransportReady()) { transportProcess(); @@ -174,14 +169,14 @@ void _registerNode(void) #if defined (MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE) CORE_DEBUG(PSTR("MCO:REG:REQ\n")); // registration request setIndication(INDICATION_REQ_REGISTRATION); - coreConfig.registered = MY_REGISTRATION_DEFAULT; + _coreConfig.nodeRegistered = MY_REGISTRATION_DEFAULT; uint8_t counter = MY_REGISTRATION_RETRIES; // only proceed if register response received or retries exceeded do { (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REGISTRATION_REQUEST).set(MY_CORE_VERSION)); } while (!wait(2000, C_INTERNAL, I_REGISTRATION_RESPONSE) && counter--); #else - coreConfig.registered = true; + _coreConfig.registered = true; CORE_DEBUG(PSTR("MCO:REG:NOT NEEDED\n")); #endif } @@ -255,7 +250,7 @@ uint8_t getDistanceGW(void) } controllerConfig_t getConfig(void) { - return coreConfig.controllerConfig; + return _coreConfig.controllerConfig; } @@ -283,7 +278,7 @@ bool send(MyMessage &message, const bool enableAck) { mSetRequestAck(message, enableAck); #if defined(MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE) - if (coreConfig.registered) { + if (_coreConfig.nodeRegistered) { return _sendRoute(message); } else { @@ -346,15 +341,15 @@ bool _processInternalMessages(void) { } else if (type == I_REGISTRATION_RESPONSE) { #if defined (MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE) - coreConfig.registered = _msg.getBool(); + _coreConfig.nodeRegistered = _msg.getBool(); setIndication(INDICATION_GOT_REGISTRATION); - CORE_DEBUG(PSTR("MCO:PIM:NODE REG=%d\n"), coreConfig.registered); // node registration + CORE_DEBUG(PSTR("MCO:PIM:NODE REG=%d\n"), _coreConfig.nodeRegistered); // node registration #endif } else if (type == I_CONFIG) { // Pick up configuration from controller (currently only metric/imperial) and store it in eeprom if changed - coreConfig.controllerConfig.isMetric = _msg.data[0] == 0x00 || _msg.data[0] == 'M'; // metric if null terminated or M - hwWriteConfigBlock((void*)&coreConfig.controllerConfig, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(controllerConfig_t)); + _coreConfig.controllerConfig.isMetric = _msg.data[0] == 0x00 || _msg.data[0] == 'M'; // metric if null terminated or M + hwWriteConfigBlock((void*)&_coreConfig.controllerConfig, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(controllerConfig_t)); } else if (type == I_PRESENTATION) { // Re-send node presentation to controller @@ -460,14 +455,14 @@ void wait(const uint32_t waitingMS) { } } -bool wait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t msgtype) { +bool wait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t msgType) { const uint32_t enteringMS = hwMillis(); // invalidate msg type - _msg.type = !msgtype; + _msg.type = !msgType; bool expectedResponse = false; while ( (hwMillis() - enteringMS < waitingMS) && !expectedResponse ) { _process(); - expectedResponse = (mGetCommand(_msg) == cmd && _msg.type == msgtype); + expectedResponse = (mGetCommand(_msg) == cmd && _msg.type == msgType); } return expectedResponse; } diff --git a/core/MySensorsCore.h b/core/MySensorsCore.h index 06b6c17df..0d0ab60a7 100644 --- a/core/MySensorsCore.h +++ b/core/MySensorsCore.h @@ -41,7 +41,7 @@ * |-|------|-------|-----------------------------------------------|---------------------------------------------------------------------------- * | | MCO | BGN | INIT %%s,CP=%%s,LIB=%%s | Core initialization, capabilities (CP), library version (VER) * | | MCO | BGN | BFR | Callback before() - * | | MCO | BGN | MTR | MY_TRANSPORT_RELAX enabled + * | | MCO | BGN | MTR | MY_TRANSPORT_RELAXED enabled * | | MCO | BGN | STP | Callback setup() * | | MCO | BGN | INIT OK,TSP=%%d | Core initialised, transport status (TSP), 1=initialised, 0=not initialised * | | MCO | BGN | NODE UNLOCKED | Node successfully unlocked (see signing chapter) @@ -110,10 +110,9 @@ typedef struct { typedef struct { controllerConfig_t controllerConfig; //!< Controller config // 8 bit - bool registered : 1; //!< Flag node registered + bool nodeRegistered : 1; //!< Flag node registered bool presentationSent : 1; //!< Flag presentation sent - bool registrationRequested : 1; //!< Flag registration requested - uint8_t reserved : 5; //!< reserved + uint8_t reserved : 6; //!< reserved } coreConfig_t; diff --git a/core/MyTransport.cpp b/core/MyTransport.cpp index 811c5828b..d85f20e40 100644 --- a/core/MyTransport.cpp +++ b/core/MyTransport.cpp @@ -31,7 +31,7 @@ static transportState_t stFailure = { stFailureTransition, stFailureUpdate }; static transportSM_t _transportSM; // transport config -transportConfig_t transportConfig; +static transportConfig_t _transportConfig; // callbacks transportCallback_t transportOk_cb = NULL; @@ -41,7 +41,7 @@ extern MyMessage _msg; // incoming message extern MyMessage _msgTmp; // outgoing message #if defined(MY_RAM_ROUTING_TABLE_ENABLED) - static routingTable _transportRoutingTable; //!< routing table + static routingTable_t _transportRoutingTable; //!< routing table static uint32_t _lastRoutingTableSave; //!< last routing table dump #endif @@ -75,7 +75,7 @@ void stInitTransition(void) { #endif // Read node settings (ID, parent ID, GW distance) from EEPROM - hwReadConfigBlock((void*)&transportConfig, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(transportConfig_t)); + hwReadConfigBlock((void*)&_transportConfig, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(transportConfig_t)); } void stInitUpdate(void) { @@ -91,9 +91,9 @@ void stInitUpdate(void) { #if defined(MY_GATEWAY_FEATURE) // Set configuration for gateway TRANSPORT_DEBUG(PSTR("TSM:INIT:GW MODE\n")); - transportConfig.parentNodeId = GATEWAY_ADDRESS; - transportConfig.distanceGW = 0u; - transportConfig.nodeId = GATEWAY_ADDRESS; + _transportConfig.parentNodeId = GATEWAY_ADDRESS; + _transportConfig.distanceGW = 0u; + _transportConfig.nodeId = GATEWAY_ADDRESS; transportSetAddress(GATEWAY_ADDRESS); // GW mode: skip FPAR,ID,UPL states transportSwitchSM(stReady); @@ -101,12 +101,12 @@ void stInitUpdate(void) { if ((uint8_t)MY_NODE_ID != AUTO) { TRANSPORT_DEBUG(PSTR("TSM:INIT:STATID=%d\n"),(uint8_t)MY_NODE_ID); // Set static ID - transportConfig.nodeId = (uint8_t)MY_NODE_ID; + _transportConfig.nodeId = (uint8_t)MY_NODE_ID; // Save static ID to eeprom (for bootloader) hwWriteConfig(EEPROM_NODE_ID_ADDRESS, (uint8_t)MY_NODE_ID); } // assign ID if set - if (transportConfig.nodeId == AUTO || transportAssignNodeID(transportConfig.nodeId)) { + if (_transportConfig.nodeId == AUTO || transportAssignNodeID(_transportConfig.nodeId)) { // if node ID valid (>0 and <255), proceed to next state transportSwitchSM(stParent); } @@ -127,14 +127,14 @@ void stParentTransition(void) { #if defined(MY_PARENT_NODE_IS_STATIC) TRANSPORT_DEBUG(PSTR("TSM:FPAR:STATP=%d\n"), (uint8_t)MY_PARENT_NODE_ID); // static parent _transportSM.findingParentNode = false; - transportConfig.distanceGW = 1u; // assumption, CHKUPL:GWDC will update this variable - transportConfig.parentNodeId = (uint8_t)MY_PARENT_NODE_ID; + _transportConfig.distanceGW = 1u; // assumption, CHKUPL:GWDC will update this variable + _transportConfig.parentNodeId = (uint8_t)MY_PARENT_NODE_ID; // save parent ID to eeprom (for bootloader) hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, (uint8_t)MY_PARENT_NODE_ID); #else _transportSM.findingParentNode = true; - transportConfig.distanceGW = DISTANCE_INVALID; // Set distance to max and invalidate parent node ID - transportConfig.parentNodeId = AUTO; + _transportConfig.distanceGW = DISTANCE_INVALID; // Set distance to max and invalidate parent node ID + _transportConfig.parentNodeId = AUTO; // Broadcast find parent request (void)transportRouteMessage(build(_msgTmp, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_REQUEST).set("")); #endif @@ -149,7 +149,7 @@ void stParentUpdate(void) { #else if (transportTimeInState() > MY_TRANSPORT_STATE_TIMEOUT_MS || _transportSM.preferredParentFound) { // timeout or preferred parent found - if (transportConfig.parentNodeId != AUTO) { + if (_transportConfig.parentNodeId != AUTO) { // parent assigned TRANSPORT_DEBUG(PSTR("TSM:FPAR:OK\n")); // find parent ok _transportSM.findingParentNode = false; @@ -179,7 +179,7 @@ void stParentUpdate(void) { // stID: verify and request ID if necessary void stIDTransition(void) { TRANSPORT_DEBUG(PSTR("TSM:ID\n")); // verify/request node ID - if (transportConfig.nodeId == AUTO) { + if (_transportConfig.nodeId == AUTO) { // send ID request setIndication(INDICATION_REQ_NODEID); TRANSPORT_DEBUG(PSTR("TSM:ID:REQ\n")); // request node ID @@ -188,7 +188,7 @@ void stIDTransition(void) { } void stIDUpdate(void) { - if (transportConfig.nodeId != AUTO) { + if (_transportConfig.nodeId != AUTO) { // current node ID is valid TRANSPORT_DEBUG(PSTR("TSM:ID:OK\n")); setIndication(INDICATION_GOT_NODEID); @@ -227,9 +227,9 @@ void stUplinkUpdate(void) { // uplink ok, i.e. GW replied TRANSPORT_DEBUG(PSTR("TSM:UPL:OK\n")); // uplink ok //_transportSM.pingActive = false; ==> set false upon receiving I_PONG - if (_transportSM.pingResponse != transportConfig.distanceGW) { - TRANSPORT_DEBUG(PSTR("TSM:UPL:DGWC,O=%d,N=%d\n"), transportConfig.distanceGW, _transportSM.pingResponse); // distance to GW changed - transportConfig.distanceGW = _transportSM.pingResponse; + if (_transportSM.pingResponse != _transportConfig.distanceGW) { + TRANSPORT_DEBUG(PSTR("TSM:UPL:DGWC,O=%d,N=%d\n"), _transportConfig.distanceGW, _transportSM.pingResponse); // distance to GW changed + _transportConfig.distanceGW = _transportSM.pingResponse; } transportSwitchSM(stReady); // proceed to next state } @@ -263,7 +263,7 @@ void stReadyTransition(void) { if (transportOk_cb) { transportOk_cb(); } - TRANSPORT_DEBUG(PSTR("TSM:READY:PARAM,ID=%d,PAR=%d,DIS=%d\n"), transportConfig.nodeId, transportConfig.parentNodeId, transportConfig.distanceGW); + TRANSPORT_DEBUG(PSTR("TSM:READY:PARAM,ID=%d,PAR=%d,DIS=%d\n"), _transportConfig.nodeId, _transportConfig.parentNodeId, _transportConfig.distanceGW); } // stReadyUpdate: monitors link @@ -393,9 +393,9 @@ bool transportCheckUplink(const bool force) { _transportSM.lastUplinkCheck = hwMillis(); TRANSPORT_DEBUG(PSTR("TSF:CKU:OK\n")); // did distance to GW change upstream, eg. re-routing of uplink nodes - if (hopsCount != transportConfig.distanceGW) { - TRANSPORT_DEBUG(PSTR("TSF:CKU:DGWC,O=%d,N=%d\n"), transportConfig.distanceGW, hopsCount); // distance to GW changed - transportConfig.distanceGW = hopsCount; + if (hopsCount != _transportConfig.distanceGW) { + TRANSPORT_DEBUG(PSTR("TSF:CKU:DGWC,O=%d,N=%d\n"), _transportConfig.distanceGW, hopsCount); // distance to GW changed + _transportConfig.distanceGW = hopsCount; } return true; } @@ -408,7 +408,7 @@ bool transportCheckUplink(const bool force) { bool transportAssignNodeID(const uint8_t newNodeId) { // verify if ID valid if (newNodeId != GATEWAY_ADDRESS && newNodeId != AUTO) { - transportConfig.nodeId = newNodeId; + _transportConfig.nodeId = newNodeId; transportSetAddress(newNodeId); // Write ID to EEPROM hwWriteConfig(EEPROM_NODE_ID_ADDRESS, newNodeId); @@ -418,14 +418,14 @@ bool transportAssignNodeID(const uint8_t newNodeId) { else { TRANSPORT_DEBUG(PSTR("!TSF:SID:FAIL,ID=%d\n"),newNodeId); // ID is invalid, cannot assign ID setIndication(INDICATION_ERR_NET_FULL); - transportConfig.nodeId = AUTO; + _transportConfig.nodeId = AUTO; return false; } } bool transportRouteMessage(MyMessage &message) { const uint8_t destination = message.destination; - uint8_t route = transportConfig.parentNodeId; // by default, all traffic is routed via parent node + uint8_t route = _transportConfig.parentNodeId; // by default, all traffic is routed via parent node if (_transportSM.findingParentNode && destination != BROADCAST_ADDRESS) { TRANSPORT_DEBUG(PSTR("!TSF:RTE:FPAR ACTIVE\n")); // find parent active, message not sent @@ -434,7 +434,7 @@ bool transportRouteMessage(MyMessage &message) { } if (destination == GATEWAY_ADDRESS) { - route = transportConfig.parentNodeId; // message to GW always routes via parent + route = _transportConfig.parentNodeId; // message to GW always routes via parent } else if (destination == BROADCAST_ADDRESS) { route = BROADCAST_ADDRESS; // message to BC does not require routing @@ -446,9 +446,9 @@ bool transportRouteMessage(MyMessage &message) { if (route == AUTO) { TRANSPORT_DEBUG(PSTR("!TSF:RTE:%d UNKNOWN\n"), destination); // route unknown #if !defined(MY_GATEWAY_FEATURE) - if (message.last != transportConfig.parentNodeId) { + if (message.last != _transportConfig.parentNodeId) { // message not from parent, i.e. child node - route it to parent - route = transportConfig.parentNodeId; + route = _transportConfig.parentNodeId; } else { // route unknown and msg received from parent, send it to destination assuming in rx radius @@ -460,14 +460,14 @@ bool transportRouteMessage(MyMessage &message) { #endif } #else - route = transportConfig.parentNodeId; // not a repeater, all traffic routed via parent + route = _transportConfig.parentNodeId; // not a repeater, all traffic routed via parent #endif } // send message const bool result = transportSendWrite(route, message); #if !defined(MY_GATEWAY_FEATURE) // update counter - if (route == transportConfig.parentNodeId) { + if (route == _transportConfig.parentNodeId) { if (!result) { setIndication(INDICATION_ERR_TX); _transportSM.failedUplinkTransmissions++; @@ -496,16 +496,16 @@ bool transportSendRoute(MyMessage &message) { } // only be used inside transport -bool transportWait(const uint32_t ms, const uint8_t cmd, const uint8_t msgtype){ - const uint32_t enter = hwMillis(); +bool transportWait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t msgType){ + const uint32_t enterMS = hwMillis(); // invalidate msg type - _msg.type = !msgtype; + _msg.type = !msgType; bool expectedResponse = false; - while ((hwMillis() - enter < ms) && !expectedResponse) { + while ((hwMillis() - enterMS < waitingMS) && !expectedResponse) { // process incoming messages transportProcessFIFO(); doYield(); - expectedResponse = (mGetCommand(_msg) == cmd && _msg.type == msgtype); + expectedResponse = (mGetCommand(_msg) == cmd && _msg.type == msgType); } return expectedResponse; } @@ -513,7 +513,7 @@ bool transportWait(const uint32_t ms, const uint8_t cmd, const uint8_t msgtype){ uint8_t transportPingNode(const uint8_t targetId) { if(!_transportSM.pingActive){ TRANSPORT_DEBUG(PSTR("TSF:PNG:SEND,TO=%d\n"), targetId); - if(targetId == transportConfig.nodeId) { + if(targetId == _transportConfig.nodeId) { // pinging self _transportSM.pingResponse = 0u; } @@ -581,7 +581,7 @@ void transportProcessMessage(void) { // update routing table if msg not from parent #if defined(MY_REPEATER_FEATURE) #if !defined(MY_GATEWAY_FEATURE) - if (last != transportConfig.parentNodeId) { + if (last != _transportConfig.parentNodeId) { #else // GW doesn't have parent { @@ -595,7 +595,7 @@ void transportProcessMessage(void) { _transportSM.msgReceived = true; // Is message addressed to this node? - if (destination == transportConfig.nodeId) { + if (destination == _transportConfig.nodeId) { // prevent buffer overflow by limiting max. possible message length (5 bits=31 bytes max) to MAX_PAYLOAD (25 bytes) mSetLength(_msg, min(mGetLength(_msg),(uint8_t)MAX_PAYLOAD)); // null terminate data @@ -606,7 +606,7 @@ void transportProcessMessage(void) { _msgTmp = _msg; // Copy message mSetRequestAck(_msgTmp, false); // Reply without ack flag (otherwise we would end up in an eternal loop) mSetAck(_msgTmp, true); // set ACK flag - _msgTmp.sender = transportConfig.nodeId; + _msgTmp.sender = _transportConfig.nodeId; _msgTmp.destination = sender; // send ACK, use transportSendRoute since ACK reply is not internal, i.e. if !transportOK do not reply (void)transportSendRoute(_msgTmp); @@ -634,15 +634,15 @@ void transportProcessMessage(void) { if (isValidDistance(distance)) { distance++; // Distance to gateway is one more for us w.r.t. parent // update settings if distance shorter or preferred parent found - if (((isValidDistance(distance) && distance < transportConfig.distanceGW) || (!_autoFindParent && sender == (uint8_t)MY_PARENT_NODE_ID)) && !_transportSM.preferredParentFound) { + if (((isValidDistance(distance) && distance < _transportConfig.distanceGW) || (!_autoFindParent && sender == (uint8_t)MY_PARENT_NODE_ID)) && !_transportSM.preferredParentFound) { // Found a neighbor closer to GW than previously found if (!_autoFindParent && sender == (uint8_t)MY_PARENT_NODE_ID) { _transportSM.preferredParentFound = true; TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR PREF\n")); // find parent, preferred parent found } - transportConfig.distanceGW = distance; - transportConfig.parentNodeId = sender; - TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR OK,ID=%d,D=%d\n"), transportConfig.parentNodeId, transportConfig.distanceGW); + _transportConfig.distanceGW = distance; + _transportConfig.parentNodeId = sender; + TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR OK,ID=%d,D=%d\n"), _transportConfig.parentNodeId, _transportConfig.distanceGW); } } } @@ -704,7 +704,7 @@ void transportProcessMessage(void) { // only reply if node is fully operational if (type == I_FIND_PARENT_REQUEST) { #if defined(MY_REPEATER_FEATURE) - if (sender != transportConfig.parentNodeId) { // no circular reference + if (sender != _transportConfig.parentNodeId) { // no circular reference TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR REQ,ID=%d\n"), sender); // FPAR: find parent request // check if uplink functional - node can only be parent node if link to GW functional // this also prevents circular references in case GW ooo @@ -713,7 +713,7 @@ void transportProcessMessage(void) { TRANSPORT_DEBUG(PSTR("TSF:MSG:GWL OK\n")); // GW uplink ok // random delay minimizes collisions delay(hwMillis() & 0x3ff); - (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE).set(transportConfig.distanceGW)); + (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE).set(_transportConfig.distanceGW)); } else { TRANSPORT_DEBUG(PSTR("!TSF:MSG:GWL FAIL\n")); // GW uplink fail, do not respond to parent request @@ -728,10 +728,10 @@ void transportProcessMessage(void) { } #if !defined(MY_GATEWAY_FEATURE) if (type == I_DISCOVER_REQUEST) { - if (last == transportConfig.parentNodeId) { + if (last == _transportConfig.parentNodeId) { // random wait to minimize collisions delay(hwMillis() & 0x3ff); - (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, I_DISCOVER_RESPONSE).set(transportConfig.parentNodeId)); + (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, I_DISCOVER_RESPONSE).set(_transportConfig.parentNodeId)); // no return here (for fwd if repeater) } } @@ -740,7 +740,7 @@ void transportProcessMessage(void) { // controlled BC relay #if defined(MY_REPEATER_FEATURE) // controlled BC repeating: forward only if message received from parent and sender not self to prevent circular fwds - if(last == transportConfig.parentNodeId && sender != transportConfig.nodeId && isTransportReady()){ + if(last == _transportConfig.parentNodeId && sender != _transportConfig.nodeId && isTransportReady()){ TRANSPORT_DEBUG(PSTR("TSF:MSG:FWD BC MSG\n")); // controlled broadcast msg forwarding (void)transportRouteMessage(_msg); } @@ -750,7 +750,7 @@ void transportProcessMessage(void) { if (command != C_INTERNAL) { #if !defined(MY_GATEWAY_FEATURE) // only proceed if message received from parent - if (last != transportConfig.parentNodeId) { + if (last != _transportConfig.parentNodeId) { return; } #endif @@ -825,7 +825,7 @@ void transportProcessFIFO(void) { } bool transportSendWrite(const uint8_t to, MyMessage &message) { - message.last = transportConfig.nodeId; // Update last + message.last = _transportConfig.nodeId; // Update last // sign message if required if (!signerSignMsg(message)) { TRANSPORT_DEBUG(PSTR("!TSF:MSG:SIGN FAIL\n")); @@ -849,22 +849,22 @@ bool transportSendWrite(const uint8_t to, MyMessage &message) { return result; } -void transportRegisterTransportOkCallback(transportCallback_t cb) +void transportRegisterOkCallback(transportCallback_t cb) { transportOk_cb = cb; } uint8_t transportGetNodeId(void) { - return transportConfig.nodeId; + return _transportConfig.nodeId; } uint8_t transportGetParentNodeId(void) { - return transportConfig.parentNodeId; + return _transportConfig.parentNodeId; } uint8_t transportGetDistanceGW(void) { - return transportConfig.distanceGW; + return _transportConfig.distanceGW; } diff --git a/core/MyTransport.h b/core/MyTransport.h index edbf35df8..3553756b9 100644 --- a/core/MyTransport.h +++ b/core/MyTransport.h @@ -190,8 +190,8 @@ #endif #define _autoFindParent (bool)(MY_PARENT_NODE_ID == AUTO) //!< returns true if static parent id is undefined -#define isValidDistance(distance) (bool)(distance!=DISTANCE_INVALID) //!< returns true if distance is valid -#define isValidParent(parent) (bool)(parent != AUTO) //!< returns true if parent is valid +#define isValidDistance(_distance) (bool)(_distance!=DISTANCE_INVALID) //!< returns true if distance is valid +#define isValidParent(_parent) (bool)(_parent != AUTO) //!< returns true if parent is valid // RX queue #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) @@ -206,23 +206,22 @@ #endif /** -* @brief Callback -* -*/ + * @brief Callback type + */ typedef void(*transportCallback_t)(void); /** -* @brief Node configuration -* -* This structure stores node-related configurations -*/ + * @brief Node configuration + * + * This structure stores node-related configurations + */ typedef struct { uint8_t nodeId; //!< Current node id uint8_t parentNodeId; //!< Where this node sends its messages uint8_t distanceGW; //!< This nodes distance to sensor net gateway (number of hops) } transportConfig_t; - /** +/** * @brief SM state * * This structure stores SM state definitions @@ -233,10 +232,10 @@ typedef struct { } transportState_t; /** -* @brief Status variables and SM state -* -* This structure stores transport status and SM variables -*/ + * @brief Status variables and SM state + * + * This structure stores transport status and SM variables + */ typedef struct { // SM variables transportState_t* currentState; //!< pointer to current fsm state @@ -263,7 +262,7 @@ typedef struct { */ typedef struct { uint8_t route[SIZE_ROUTES]; //!< route for node -} routingTable; +} routingTable_t; // PRIVATE functions @@ -349,12 +348,12 @@ void transportProcessMessage(void); bool transportAssignNodeID(const uint8_t newNodeId); /** * @brief Wait and process messages for a defined amount of time until specified message received -* @param ms Time to wait and process incoming messages in ms +* @param waitingMS Time to wait and process incoming messages in ms * @param cmd Specific command -* @param msgtype Specific message type +* @param msgType Specific message type * @return true if specified command received within waiting time */ -bool transportWait(const uint32_t ms, const uint8_t cmd, const uint8_t msgtype); +bool transportWait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t msgType); /** * @brief Ping node * @param targetId Node to be pinged From 399734502dd7cab10f5cce218a1fc71b933a6a33 Mon Sep 17 00:00:00 2001 From: Olivier Date: Tue, 15 Nov 2016 00:09:29 +0100 Subject: [PATCH 122/167] Harmonize OTA code, reboot when flash is idle --- core/MyOTAFirmwareUpdate.cpp | 140 +++++++++++++++++++---------------- core/MyOTAFirmwareUpdate.h | 39 +++++----- core/MySensorsCore.cpp | 2 +- 3 files changed, 97 insertions(+), 84 deletions(-) diff --git a/core/MyOTAFirmwareUpdate.cpp b/core/MyOTAFirmwareUpdate.cpp index af0338e1e..02749c1aa 100644 --- a/core/MyOTAFirmwareUpdate.cpp +++ b/core/MyOTAFirmwareUpdate.cpp @@ -22,94 +22,98 @@ // global variables extern MyMessage _msg; extern MyMessage _msgTmp; -extern NodeConfig _nc; // local variables SPIFlash _flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID); -NodeFirmwareConfig _fc; -bool _fwUpdateOngoing; -unsigned long _fwLastRequestTime; -uint16_t _fwBlock; -uint8_t _fwRetry; +nodeFirmwareConfig_t _nodeFirmwareConfig; +bool _firmwareUpdateOngoing; +uint32_t _firmwareLastRequest; +uint16_t _firmwareBlock; +uint8_t _firmwareRetry; -void readFirmwareSettings() { - hwReadConfigBlock((void*)&_fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); +void readFirmwareSettings(void) +{ + hwReadConfigBlock((void*)&_nodeFirmwareConfig, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(nodeFirmwareConfig_t)); } -void firmwareOTAUpdateRequest() { - unsigned long enter = hwMillis(); - if (_fwUpdateOngoing && (enter - _fwLastRequestTime > MY_OTA_RETRY_DELAY)) { - if (!_fwRetry) { +void firmwareOTAUpdateRequest(void) +{ + const uint32_t enterMS = hwMillis(); + if (_firmwareUpdateOngoing && (enterMS - _firmwareLastRequest > MY_OTA_RETRY_DELAY)) { + if (!_firmwareRetry) { setIndication(INDICATION_ERR_FW_TIMEOUT); OTA_DEBUG(PSTR("!OTA:FRQ:FW UPD FAIL\n")); // fw update failed // Give up. We have requested MY_OTA_RETRY times without any packet in return. - _fwUpdateOngoing = false; + _firmwareUpdateOngoing = false; return; } - _fwRetry--; - _fwLastRequestTime = enter; + _firmwareRetry--; + _firmwareLastRequest = enterMS; // Time to (re-)request firmware block from controller - RequestFWBlock firmwareRequest; - firmwareRequest.type = _fc.type; - firmwareRequest.version = _fc.version; - firmwareRequest.block = (_fwBlock - 1); - OTA_DEBUG(PSTR("OTA:FRQ:FW REQ,T=%04X,V=%04X,B=%04X\n"),_fc.type,_fc.version,_fwBlock - 1); // request FW update block - _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_REQUEST, false).set(&firmwareRequest,sizeof(RequestFWBlock))); + requestFirmwareBlock_t firmwareRequest; + firmwareRequest.type = _nodeFirmwareConfig.type; + firmwareRequest.version = _nodeFirmwareConfig.version; + firmwareRequest.block = (_firmwareBlock - 1); + OTA_DEBUG(PSTR("OTA:FRQ:FW REQ,T=%04X,V=%04X,B=%04X\n"), _nodeFirmwareConfig.type, _nodeFirmwareConfig.version, _firmwareBlock - 1); // request FW update block + (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_REQUEST, false).set(&firmwareRequest, sizeof(requestFirmwareBlock_t))); } } -bool firmwareOTAUpdateProcess() { +bool firmwareOTAUpdateProcess(void) +{ if (_msg.type == ST_FIRMWARE_CONFIG_RESPONSE) { - NodeFirmwareConfig *firmwareConfigResponse = (NodeFirmwareConfig *)_msg.data; - // compare with current node configuration, if they differ, start fw fetch process - if (memcmp(&_fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig))) { + nodeFirmwareConfig_t *firmwareConfigResponse = (nodeFirmwareConfig_t *)_msg.data; + // compare with current node configuration, if they differ, start FW fetch process + if (memcmp(&_nodeFirmwareConfig, firmwareConfigResponse, sizeof(nodeFirmwareConfig_t))) { setIndication(INDICATION_FW_UPDATE_START); OTA_DEBUG(PSTR("OTA:FWP:UPDATE\n")); // FW update initiated // copy new FW config - memcpy(&_fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig)); + (void)memcpy(&_nodeFirmwareConfig, firmwareConfigResponse, sizeof(nodeFirmwareConfig_t)); // Init flash if (!_flash.initialize()) { setIndication(INDICATION_ERR_FW_FLASH_INIT); OTA_DEBUG(PSTR("!OTA:FWP:FLASH INIT FAIL\n")); // failed to initialise flash - _fwUpdateOngoing = false; + _firmwareUpdateOngoing = false; } else { // erase lower 32K -> max flash size for ATMEGA328 _flash.blockErase32K(0); // wait until flash erased while ( _flash.busy() ) {} - _fwBlock = _fc.blocks; - _fwUpdateOngoing = true; + _firmwareBlock = _nodeFirmwareConfig.blocks; + _firmwareUpdateOngoing = true; // reset flags - _fwRetry = MY_OTA_RETRY+1; - _fwLastRequestTime = 0; + _firmwareRetry = MY_OTA_RETRY + 1; + _firmwareLastRequest = 0; } return true; } OTA_DEBUG(PSTR("OTA:FWP:UPDATE SKIPPED\n")); // FW update skipped, no newer version available } else if (_msg.type == ST_FIRMWARE_RESPONSE) { - if (_fwUpdateOngoing) { + if (_firmwareUpdateOngoing) { // Save block to flash setIndication(INDICATION_FW_UPDATE_RX); - OTA_DEBUG(PSTR("OTA:FWP:RECV B=%04X\n"), _fwBlock); // received FW block + OTA_DEBUG(PSTR("OTA:FWP:RECV B=%04X\n"), _firmwareBlock); // received FW block // extract FW block - ReplyFWBlock *firmwareResponse = (ReplyFWBlock *)_msg.data; + replyFirmwareBlock_t *firmwareResponse = (replyFirmwareBlock_t *)_msg.data; // write to flash - _flash.writeBytes( ((_fwBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE); + _flash.writeBytes( ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE); // wait until flash written - while ( _flash.busy() ) {} - _fwBlock--; - if (!_fwBlock) { + while (_flash.busy()) {} + _firmwareBlock--; + if (!_firmwareBlock) { // We're finished! Do a checksum and reboot. OTA_DEBUG(PSTR("OTA:FWP:FW END\n")); // received FW block - _fwUpdateOngoing = false; + _firmwareUpdateOngoing = false; if (transportIsValidFirmware()) { OTA_DEBUG(PSTR("OTA:FWP:CRC OK\n")); // FW checksum ok - // All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it) - uint16_t fwsize = FIRMWARE_BLOCK_SIZE * _fc.blocks; - uint8_t OTAbuffer[10] = {'F','L','X','I','M','G',':',(uint8_t)(fwsize >> 8),(uint8_t)(fwsize & 0xff),':'}; - _flash.writeBytes(0, OTAbuffer, 10); // Write the new firmware config to eeprom - hwWriteConfigBlock((void*)&_fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); + hwWriteConfigBlock((void*)&_nodeFirmwareConfig, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(nodeFirmwareConfig_t)); + // All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it) + const uint16_t firmwareSize = FIRMWARE_BLOCK_SIZE * _nodeFirmwareConfig.blocks; + const uint8_t OTAbuffer[FIRMWARE_START_OFFSET] = {'F','L','X','I','M','G',':', (uint8_t)(firmwareSize >> 8), (uint8_t)(firmwareSize & 0xff),':'}; + _flash.writeBytes(0, OTAbuffer, FIRMWARE_START_OFFSET); + // wait until flash ready + while (_flash.busy()) {} hwReboot(); } else { setIndication(INDICATION_ERR_FW_CHECKSUM); @@ -117,8 +121,8 @@ bool firmwareOTAUpdateProcess() { } } // reset flags - _fwRetry = MY_OTA_RETRY+1; - _fwLastRequestTime = 0; + _firmwareRetry = MY_OTA_RETRY + 1; + _firmwareLastRequest = 0; } else { OTA_DEBUG(PSTR("!OTA:FWP:NO UPDATE\n")); } @@ -127,32 +131,38 @@ bool firmwareOTAUpdateProcess() { return false; } -void presentBootloaderInformation(){ - RequestFirmwareConfig *reqFWConfig = (RequestFirmwareConfig *)_msgTmp.data; - mSetLength(_msgTmp, sizeof(RequestFirmwareConfig)); +void presentBootloaderInformation(void) +{ + requestFirmwareConfig_t *requestFirmwareConfig = (requestFirmwareConfig_t *)_msgTmp.data; + mSetLength(_msgTmp, sizeof(requestFirmwareConfig_t)); mSetCommand(_msgTmp, C_STREAM); - mSetPayloadType(_msgTmp,P_CUSTOM); + mSetPayloadType(_msgTmp, P_CUSTOM); // copy node settings to reqFWConfig - memcpy(reqFWConfig,&_fc,sizeof(NodeFirmwareConfig)); + (void)memcpy(requestFirmwareConfig, &_nodeFirmwareConfig, sizeof(nodeFirmwareConfig_t)); // add bootloader information - reqFWConfig->BLVersion = MY_OTA_BOOTLOADER_VERSION; - _fwUpdateOngoing = false; - _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_CONFIG_REQUEST, false)); + requestFirmwareConfig->BLVersion = MY_OTA_BOOTLOADER_VERSION; + _firmwareUpdateOngoing = false; + (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_CONFIG_REQUEST, false)); +} +bool isFirmwareUpdateOngoing(void) +{ + return _firmwareUpdateOngoing; } // do a crc16 on the whole received firmware -bool transportIsValidFirmware() { +bool transportIsValidFirmware(void) +{ // init crc uint16_t crc = ~0; - for (uint16_t i = 0; i < _fc.blocks * FIRMWARE_BLOCK_SIZE; ++i) { + for (uint16_t i = 0; i < _nodeFirmwareConfig.blocks * FIRMWARE_BLOCK_SIZE; ++i) { crc ^= _flash.readByte(i + FIRMWARE_START_OFFSET); - for (int8_t j = 0; j < 8; ++j) { - if (crc & 1) { - crc = (crc >> 1) ^ 0xA001; - } - else { - crc = (crc >> 1); - } - } + for (int8_t j = 0; j < 8; ++j) { + if (crc & 1) { + crc = (crc >> 1) ^ 0xA001; + } + else { + crc = (crc >> 1); + } + } } - return crc == _fc.crc; + return crc == _nodeFirmwareConfig.crc; } diff --git a/core/MyOTAFirmwareUpdate.h b/core/MyOTAFirmwareUpdate.h index 1f76540fc..24846d800 100644 --- a/core/MyOTAFirmwareUpdate.h +++ b/core/MyOTAFirmwareUpdate.h @@ -56,18 +56,21 @@ #include "MySensorsCore.h" -#define FIRMWARE_BLOCK_SIZE (16) //!< Size of each firmware block -#define FIRMWARE_MAX_REQUESTS (5) //!< Number of times a firmware block should be requested before giving up -#define MY_OTA_RETRY (5) //!< Number of times to request a fw block before giving up -#define MY_OTA_RETRY_DELAY (500) //!< Number of milliseconds before re-requesting a FW block -#define FIRMWARE_START_OFFSET (10) //!< Start offset for firmware in flash (DualOptiboot wants to keeps a signature first) +#define FIRMWARE_BLOCK_SIZE (16u) //!< Size of each firmware block +#define FIRMWARE_MAX_REQUESTS (5u) //!< Number of times a firmware block should be requested before giving up +#define MY_OTA_RETRY (5u) //!< Number of times to request a fw block before giving up +#define MY_OTA_RETRY_DELAY (500u) //!< Number of milliseconds before re-requesting a FW block +#define FIRMWARE_START_OFFSET (10u) //!< Start offset for firmware in flash (DualOptiboot wants to keeps a signature first) -#define MY_OTA_BOOTLOADER_MAJOR_VERSION (3) //!< Bootloader version major -#define MY_OTA_BOOTLOADER_MINOR_VERSION (0) //!< Bootloader version minor +#define MY_OTA_BOOTLOADER_MAJOR_VERSION (3u) //!< Bootloader version major +#define MY_OTA_BOOTLOADER_MINOR_VERSION (0u) //!< Bootloader version minor #define MY_OTA_BOOTLOADER_VERSION (MY_OTA_BOOTLOADER_MINOR_VERSION * 256 + MY_OTA_BOOTLOADER_MAJOR_VERSION) //!< Bootloader version -#define OTA_DEBUG(x,...) debug(x, ##__VA_ARGS__) //!< debug - +#if defined(MY_DEBUG) + #define OTA_DEBUG(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug +#else + #define OTA_DEBUG(x,...) //!< debug NULL +#endif /** * @brief FW config structure, stored in eeprom */ @@ -76,7 +79,7 @@ typedef struct { uint16_t version; //!< Version of config uint16_t blocks; //!< Number of blocks uint16_t crc; //!< CRC of block data -} __attribute__((packed)) NodeFirmwareConfig; +} __attribute__((packed)) nodeFirmwareConfig_t; /** * @brief FW config request structure @@ -87,7 +90,7 @@ typedef struct { uint16_t blocks; //!< Number of blocks uint16_t crc; //!< CRC of block data uint16_t BLVersion; //!< Bootloader version -} __attribute__((packed)) RequestFirmwareConfig; +} __attribute__((packed)) requestFirmwareConfig_t; /** * @brief FW block request structure @@ -96,7 +99,7 @@ typedef struct { uint16_t type; //!< Type of config uint16_t version; //!< Version of config uint16_t block; //!< Block index -} __attribute__((packed)) RequestFWBlock; +} __attribute__((packed)) requestFirmwareBlock_t; /** * @brief FW block reply structure @@ -106,7 +109,7 @@ typedef struct { uint16_t version; //!< Version of config uint16_t block; //!< Block index uint8_t data[FIRMWARE_BLOCK_SIZE]; //!< Block data -} __attribute__((packed)) ReplyFWBlock; +} __attribute__((packed)) replyFirmwareBlock_t; /** @@ -114,27 +117,27 @@ typedef struct { * * Current firmware settings (type, version, crc, blocks) are read into _fc */ -void readFirmwareSettings(); +void readFirmwareSettings(void); /** * @brief Handle OTA FW update requests */ - void firmwareOTAUpdateRequest(); +void firmwareOTAUpdateRequest(void); /** * @brief Handle OTA FW update responses * * This function handles incoming OTA FW packets and stores them to external flash (Sensebender) */ -bool firmwareOTAUpdateProcess(); +bool firmwareOTAUpdateProcess(void); /** * @brief Validate uploaded FW CRC * * This function verifies if uploaded FW CRC is valid */ -bool transportIsValidFirmware(); +bool transportIsValidFirmware(void); /** * @brief Present bootloader/FW information upon startup */ -void presentBootloaderInformation(); +void presentBootloaderInformation(void); #endif diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 80c32e3a9..fe9e7a775 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -468,7 +468,7 @@ int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep, const uint8_t in debug(PSTR("MCO:SLP:MS=%lu,SMS=%d,I1=%d,M1=%d,I2=%d,M2=%d\n"), sleepingMS, smartSleep, interrupt1, mode1, interrupt2, mode2); // OTA FW feature: do not sleep if FW update ongoing #if defined(MY_OTA_FIRMWARE_FEATURE) - if (_fwUpdateOngoing) { + if (isFirmwareUpdateOngoing()) { debug(PSTR("!MCO:SLP:FWUPD\n")); // sleeping not possible, FW update ongoing wait(sleepingMS); return MY_SLEEP_NOT_POSSIBLE; From 865c4a773a359010541871357cd54238262fa0a1 Mon Sep 17 00:00:00 2001 From: Olivier Date: Wed, 16 Nov 2016 21:50:44 +0100 Subject: [PATCH 123/167] RFM95 updates for RPI --- drivers/RFM95/RFM95.cpp | 75 ++++++++++++++++++++++++++++++----------- drivers/RFM95/RFM95.h | 12 ++++--- 2 files changed, 63 insertions(+), 24 deletions(-) diff --git a/drivers/RFM95/RFM95.cpp b/drivers/RFM95/RFM95.cpp index 316040e7b..c49edd341 100644 --- a/drivers/RFM95/RFM95.cpp +++ b/drivers/RFM95/RFM95.cpp @@ -24,6 +24,11 @@ #include "RFM95.h" +#if defined(LINUX_ARCH_RASPBERRYPI) +uint8_t spi_rxbuff[32 + 1]; //SPI receive buffer (payload max 32 bytes, MYS protocol limitation) +uint8_t spi_txbuff[32 + 1]; //SPI transmit buffer (payload max 32 bytes + 1 byte for the command, MYS protocol limitation) +#endif + LOCAL void RFM95_csn(const bool level) { hwDigitalWrite(MY_RFM95_SPI_CS, level); } @@ -31,11 +36,41 @@ LOCAL void RFM95_csn(const bool level) { LOCAL uint8_t RFM95_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_t len, const bool aReadMode) { uint8_t status; uint8_t* current = buf; - noInterrupts(); #if !defined(MY_SOFTSPI) _SPI.beginTransaction(SPISettings(MY_RFM95_SPI_MAX_SPEED, MY_RFM95_SPI_DATA_ORDER, MY_RFM95_SPI_DATA_MODE)); #endif RFM95_csn(LOW); +#if defined(LINUX_ARCH_RASPBERRYPI) + uint8_t * prx = spi_rxbuff; + uint8_t * ptx = spi_txbuff; + uint8_t size = len + 1; // Add register value to transmit buffer + + *ptx++ = cmd; + while (len--) { + if (aReadMode) { + *ptx++ = RF24_NOP; + } + else { + *ptx++ = *current++; + } + } + _SPI.transfernb((char *)spi_txbuff, (char *)spi_rxbuff, size); + if (aReadMode) { + if (size == 2) { + status = *++prx; // result is 2nd byte of receive buffer + } + else { + status = *prx++; // status is 1st byte of receive buffer + // decrement before to skip status byte + while (--size) { + *buf++ = *prx++; + } + } + } + else { + status = *prx; // status is 1st byte of receive buffer + } +#else status = _SPI.transfer(cmd); while (len--) { if (aReadMode) { @@ -46,11 +81,11 @@ LOCAL uint8_t RFM95_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_ } else status = _SPI.transfer(*current++); } +#endif RFM95_csn(HIGH); #if !defined(MY_SOFTSPI) _SPI.endTransaction(); #endif - interrupts(); return status; } @@ -114,9 +149,9 @@ LOCAL bool RFM95_initialise(const float frequency) { RFM95_writeReg(RFM95_REG_23_MAX_PAYLOAD_LENGTH, RFM95_MAX_PACKET_LEN); (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); - const modemConfig_t configuration = { MY_RFM95_MODEM_CONFIGRUATION }; + const rfm95_modemConfig_t configuration = { MY_RFM95_MODEM_CONFIGRUATION }; RFM95_setModemRegisters(configuration); - RFM95_setPreambleLength(8); // default + RFM95_setPreambleLength(RFM95_PREAMBLE_LENGTH); RFM95_setFrequency(frequency); // set power level RFM95_setTxPower(MY_RFM95_TX_POWER); @@ -134,12 +169,12 @@ LOCAL bool RFM95_initialise(const float frequency) { // RxDone, TxDone, CADDone is mapped to DI0 LOCAL void RFM95_interruptHandler(void) { // Read the interrupt register - const uint8_t irq_flags = RFM95_readReg(RFM95_REG_12_IRQ_FLAGS); - if (RFM95.radioMode == RFM95_RADIO_MODE_RX && (irq_flags & (RFM95_RX_TIMEOUT | RFM95_PAYLOAD_CRC_ERROR)) ) { + const uint8_t irqFlags = RFM95_readReg(RFM95_REG_12_IRQ_FLAGS); + if (RFM95.radioMode == RFM95_RADIO_MODE_RX && (irqFlags & (RFM95_RX_TIMEOUT | RFM95_PAYLOAD_CRC_ERROR)) ) { // CRC error or timeout // RXcontinuous mode: radio stays in RX mode, clearing IRQ needed } - else if (RFM95.radioMode == RFM95_RADIO_MODE_RX && (irq_flags & RFM95_RX_DONE)) { + else if (RFM95.radioMode == RFM95_RADIO_MODE_RX && (irqFlags & RFM95_RX_DONE)) { // set radio to STDBY (we are in RXcontinuous mode) (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); // Have received a packet @@ -160,16 +195,16 @@ LOCAL void RFM95_interruptHandler(void) { } } - else if (RFM95.radioMode == RFM95_RADIO_MODE_TX && (irq_flags & RFM95_TX_DONE) ) { + else if (RFM95.radioMode == RFM95_RADIO_MODE_TX && (irqFlags & RFM95_TX_DONE) ) { (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); } - else if (RFM95.radioMode == RFM95_RADIO_MODE_CAD && (irq_flags & RFM95_CAD_DONE) ) { - RFM95.cad = irq_flags & RFM95_CAD_DETECTED; + else if (RFM95.radioMode == RFM95_RADIO_MODE_CAD && (irqFlags & RFM95_CAD_DONE) ) { + RFM95.cad = irqFlags & RFM95_CAD_DETECTED; (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); } // Clear all IRQ flags - RFM95_writeReg(RFM95_REG_12_IRQ_FLAGS, 0xff); + RFM95_writeReg(RFM95_REG_12_IRQ_FLAGS, 0xFF); } LOCAL bool RFM95_available(void) { @@ -283,7 +318,7 @@ LOCAL bool RFM95_setTxPower(uint8_t powerLevel) { } // Sets registers from a canned modem configuration structure -LOCAL void RFM95_setModemRegisters(const modemConfig_t config) { +LOCAL void RFM95_setModemRegisters(const rfm95_modemConfig_t config) { RFM95_writeReg(RFM95_REG_1D_MODEM_CONFIG1, config.reg_1d); RFM95_writeReg(RFM95_REG_1E_MODEM_CONFIG2, config.reg_1e); RFM95_writeReg(RFM95_REG_26_MODEM_CONFIG3, config.reg_26); @@ -306,13 +341,13 @@ LOCAL uint8_t RFM95_getAddress(void) { LOCAL bool RFM95_isChannelActive(void) { (void)RFM95_setRadioMode(RFM95_RADIO_MODE_CAD); while (RFM95.radioMode == RFM95_RADIO_MODE_CAD) { - yield(); + doYield(); } return RFM95.cad; } -LOCAL bool RFM95_setRadioMode(const rfm95_radio_mode_t newRadioMode) { +LOCAL bool RFM95_setRadioMode(const rfm95_radioMode_t newRadioMode) { if (RFM95.radioMode == newRadioMode) { return false; } @@ -390,7 +425,7 @@ LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, cons return true; } const uint32_t enterMS = hwMillis(); - while (hwMillis() - enterMS < 500) { + while (hwMillis() - enterMS < RFM95_RETRY_TIMEOUT_MS) { if (RFM95.rxBufferValid) { const uint8_t sender = RFM95.currentPacket.header.sender; const rfm95_sequenceNumber_t ACKsequenceNumber = RFM95.currentPacket.ACK.sequenceNumber; @@ -406,7 +441,7 @@ LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, cons return true; } // seq check } - yield(); + doYield(); } RFM95_DEBUG(PSTR("!RFM95:SWR:NACK\n")); if (RFM95.ATCenabled) { @@ -425,15 +460,16 @@ LOCAL bool RFM95_waitCAD(void) { if (hwMillis() - enterMS > RFM95_CAD_TIMEOUT_MS) { return false; } - yield(); + doYield(); } return true; } // Wait for any previous transmission to finish LOCAL bool RFM95_waitPacketSent(void) { - while (RFM95.radioMode == RFM95_RADIO_MODE_TX) - yield(); + while (RFM95.radioMode == RFM95_RADIO_MODE_TX) { + doYield(); + } return true; } @@ -454,6 +490,7 @@ LOCAL void RFM95_ATCmode(const bool OnOff, const int16_t targetRSSI) { } LOCAL bool RFM95_sanityCheck(void) { + // not implemented yet return true; } diff --git a/drivers/RFM95/RFM95.h b/drivers/RFM95/RFM95.h index c9f253fb0..b7fd629a7 100644 --- a/drivers/RFM95/RFM95.h +++ b/drivers/RFM95/RFM95.h @@ -133,6 +133,8 @@ #define RFM95_RX_FIFO_ADDR (0x00u) //!< RX FIFO addr pointer #define RFM95_TX_FIFO_ADDR (0x80u) //!< TX FIFO addr pointer #define RFM95_MAX_PACKET_LEN (0x40u) //!< This is the maximum number of bytes that can be carried by the LORA +#define RFM95_PREAMBLE_LENGTH (8u) //!< Preamble length, default=8 + #define RFM95_CAD_TIMEOUT_MS (2*1000ul) //!< channel activity detection timeout #define RFM95_FXOSC (32000000.0f) //!< The crystal oscillator frequency of the module @@ -177,7 +179,7 @@ typedef enum { RFM95_RADIO_MODE_CAD = 2, //!< CAD mode RFM95_RADIO_MODE_SLEEP = 3, //!< SLEEP mode RFM95_RADIO_MODE_STDBY = 4 //!< STDBY mode -} rfm95_radio_mode_t; +} rfm95_radioMode_t; /** * @brief RFM95 modem config registers @@ -186,7 +188,7 @@ typedef struct { uint8_t reg_1d; //!< Value for register REG_1D_MODEM_CONFIG1 uint8_t reg_1e; //!< Value for register REG_1E_MODEM_CONFIG2 uint8_t reg_26; //!< Value for register REG_26_MODEM_CONFIG3 -} modemConfig_t; +} rfm95_modemConfig_t; /** * @brief Sequence number data type @@ -258,7 +260,7 @@ typedef struct { uint8_t powerLevel; //!< TX power level dBm uint8_t ATCtargetRSSI; //!< ATC: target RSSI // 8 bit - rfm95_radio_mode_t radioMode : 3; //!< current transceiver state + rfm95_radioMode_t radioMode : 3; //!< current transceiver state bool cad : 1; //!< RFM95_cad bool rxBufferValid : 1; //!< RX buffer valid bool ATCenabled : 1; //!< ATC enabled @@ -288,7 +290,7 @@ LOCAL uint8_t RFM95_getAddress(void); * bandwidth, spreading factor etc. * @param config See modemConfig_t and references therein */ -LOCAL void RFM95_setModemRegisters(const modemConfig_t config); +LOCAL void RFM95_setModemRegisters(const rfm95_modemConfig_t config); /** * @brief Tests whether a new message is available * @return True if a new, complete, error-free uncollected message is available to be retreived by @ref RFM95_recv() @@ -374,7 +376,7 @@ LOCAL bool RFM95_waitPacketSent(void); * @param newRadioMode * @return True if mode changed */ -LOCAL bool RFM95_setRadioMode(const rfm95_radio_mode_t newRadioMode); +LOCAL bool RFM95_setRadioMode(const rfm95_radioMode_t newRadioMode); /** * @brief Low level interrupt handler */ From 330a910f3d2cfd67a21189b71efc4d291c48a2a6 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Mon, 17 Oct 2016 01:02:55 -0200 Subject: [PATCH 124/167] RPi: Improve build process Add option to set an external arduino libraries directory. All libraries from this folder will be compile and available for use in the gateway. Some Arduino libraries can be used on Linux/RPI with minor adjustments, but there are some that will have to be completely rewritten. The build process uses a separate folder for objects and binary files which can be set by the user. Initialize the bcm2835 inside a class constructor to fix cases where pin operations are used before hwInit(). Fix SPI pins default values. Fix activation interrupt functions. Fix some headers. Rename gateway binary and services to mysgw. --- .gitignore | 3 + Makefile | 120 +++++++++++++----- configure | 103 +++++++++------ core/MyHwLinuxGeneric.cpp | 4 +- core/MyHwLinuxGeneric.h | 4 +- core/MyHwRPi.cpp | 10 +- core/MyHwRPi.h | 21 ++- core/MyMainLinux.cpp | 8 +- drivers/Linux/Arduino.h | 1 + drivers/RPi/rpi_util.cpp | 13 +- drivers/RPi/rpi_util.h | 8 +- examples_linux/{mysGateway.cpp => mysgw.cpp} | 20 ++- .../{mysgateway.systemd => mysgw.systemd} | 2 +- .../{mysgateway.sysvinit => mysgw.sysvinit} | 4 +- 14 files changed, 218 insertions(+), 103 deletions(-) rename examples_linux/{mysGateway.cpp => mysgw.cpp} (83%) rename initscripts/{mysgateway.systemd => mysgw.systemd} (76%) rename initscripts/{mysgateway.sysvinit => mysgw.sysvinit} (98%) diff --git a/.gitignore b/.gitignore index 980b4fce7..02d191025 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ stino.settings MyPrivateConfig.h Documentation/html doxygen_sqlite3.db +Makefile.inc +build +bin diff --git a/Makefile b/Makefile index 3ee190c38..d307e3220 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,10 @@ # # Makefile for MySensors # +# +# The arduino library build part were inspired by +# Arduino-Makefile project, Copyright (C) 2012 Sudar +# # Description: # ------------ # use make all and make install to install the gateway @@ -11,42 +15,92 @@ CONFIG_FILE=Makefile.inc include $(CONFIG_FILE) -GATEWAY_BIN=mysGateway -GATEWAY=examples_linux/$(GATEWAY_BIN) -GATEWAY_C_SOURCES=$(wildcard drivers/Linux/*.c) -GATEWAY_CPP_SOURCES=$(wildcard drivers/Linux/*.cpp) examples_linux/mysGateway.cpp -OBJECTS=$(patsubst %.c,%.o,$(GATEWAY_C_SOURCES)) $(patsubst %.cpp,%.o,$(GATEWAY_CPP_SOURCES)) +CPPFLAGS+=-Ofast -g -Wall -Wextra +DEPFLAGS=-MT $@ -MMD -MP -DEPS+=$(patsubst %.c,%.d,$(GATEWAY_C_SOURCES)) $(patsubst %.cpp,%.d,$(GATEWAY_CPP_SOURCES)) +GATEWAY_BIN=mysgw +GATEWAY=$(BINDIR)/$(GATEWAY_BIN) +GATEWAY_C_SOURCES=$(wildcard drivers/Linux/*.c) +GATEWAY_CPP_SOURCES=$(wildcard drivers/Linux/*.cpp) examples_linux/mysgw.cpp +GATEWAY_OBJECTS=$(patsubst %.c,$(BUILDDIR)/%.o,$(GATEWAY_C_SOURCES)) $(patsubst %.cpp,$(BUILDDIR)/%.o,$(GATEWAY_CPP_SOURCES)) -CINCLUDE=-I. -I./core -I./drivers/Linux +INCLUDES=-I. -I./core -I./drivers/Linux ifeq ($(SOC),$(filter $(SOC),BCM2835 BCM2836)) RPI_C_SOURCES=$(wildcard drivers/RPi/*.c) RPI_CPP_SOURCES=$(wildcard drivers/RPi/*.cpp) -OBJECTS+=$(patsubst %.c,%.o,$(RPI_C_SOURCES)) $(patsubst %.cpp,%.o,$(RPI_CPP_SOURCES)) +GATEWAY_OBJECTS+=$(patsubst %.c,$(BUILDDIR)/%.o,$(RPI_C_SOURCES)) $(patsubst %.cpp,$(BUILDDIR)/%.o,$(RPI_CPP_SOURCES)) -DEPS+=$(patsubst %.c,%.d,$(RPI_C_SOURCES)) $(patsubst %.cpp,%.d,$(RPI_CPP_SOURCES)) +INCLUDES+=-I./drivers/RPi +endif -CINCLUDE+=-I./drivers/RPi +# Gets include flags for library +get_library_includes = $(if $(and $(wildcard $(1)/src), $(wildcard $(1)/library.properties)), \ + -I$(1)/src, \ + $(addprefix -I,$(1) $(wildcard $(1)/utility))) + +# Gets all sources with given extension (param2) for library (path = param1) +# for old (1.0.x) layout looks in . and "utility" directories +# for new (1.5.x) layout looks in src and recursively its subdirectories +get_library_files = $(if $(and $(wildcard $(1)/src), $(wildcard $(1)/library.properties)), \ + $(call rwildcard,$(1)/src/,*.$(2)), \ + $(wildcard $(1)/*.$(2) $(1)/utility/*.$(2))) + +ifdef ARDUINO_LIB_DIR +ARDUINO=arduino +ARDUINO_LIBS:=$(shell find $(ARDUINO_LIB_DIR) -mindepth 1 -maxdepth 1 -type d) +ARDUINO_INCLUDES:=$(foreach lib, $(ARDUINO_LIBS), $(call get_library_includes,$(lib))) +ARDUINO_LIB_CPP_SRCS:=$(foreach lib, $(ARDUINO_LIBS), $(call get_library_files,$(lib),cpp)) +ARDUINO_LIB_C_SRCS:=$(foreach lib, $(ARDUINO_LIBS), $(call get_library_files,$(lib),c)) +ARDUINO_LIB_AS_SRCS:=$(foreach lib, $(ARDUINO_LIBS), $(call get_library_files,$(lib),S)) +ARDUINO_LIB_OBJS=$(patsubst $(ARDUINO_LIB_DIR)/%.cpp,$(BUILDDIR)/arduinolibs/%.cpp.o,$(ARDUINO_LIB_CPP_SRCS)) \ + $(patsubst $(ARDUINO_LIB_DIR)/%.c,$(BUILDDIR)/arduinolibs/%.c.o,$(ARDUINO_LIB_C_SRCS)) \ + $(patsubst $(ARDUINO_LIB_DIR)/%.S,$(BUILDDIR)/arduinolibs/%.S.o,$(ARDUINO_LIB_AS_SRCS)) + +INCLUDES+=$(ARDUINO_INCLUDES) +DEPS+=$(ARDUINO_LIB_OBJS:.o=.d) endif -.PHONY: all gateway cleanconfig clean install uninstall force +DEPS+=$(GATEWAY_OBJECTS:.o=.d) + +.PHONY: all createdir cleanconfig clean install uninstall -all: $(GATEWAY) +all: createdir $(ARDUINO) $(GATEWAY) + +createdir: + @mkdir -p $(BUILDDIR) $(BINDIR) + +# Arduino libraries Build +$(ARDUINO): CPPFLAGS+=-DARDUINO=100 +$(ARDUINO): $(ARDUINO_LIB_OBJS) + @printf "[Done building Arduino Libraries]\n" # Gateway Build -$(GATEWAY): $(OBJECTS) - $(CXX) $(LDFLAGS) -o $@ $(OBJECTS) +$(GATEWAY): $(GATEWAY_OBJECTS) $(ARDUINO_LIB_OBJS) + $(CXX) $(LDFLAGS) -o $@ $(GATEWAY_OBJECTS) $(ARDUINO_LIB_OBJS) # Include all .d files -include $(DEPS) -%.o: %.cpp - $(CXX) $(CXXFLAGS) $(CINCLUDE) -MMD -c -o $@ $< +$(BUILDDIR)/arduinolibs/%.cpp.o: $(ARDUINO_LIB_DIR)/%.cpp + @mkdir -p $(dir $@) + $(CXX) $(DEPFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $< -o $@ + +$(BUILDDIR)/arduinolibs/%.c.o: $(ARDUINO_LIB_DIR)/%.c + @mkdir -p $(dir $@) + $(CC) $(DEPFLAGS) $(CPPFLAGS) $(CFLAGS) $(INCLUDES) -c $< -o $@ + +$(BUILDDIR)/arduinolibs/%.S.o: $(ARDUINO_LIB_DIR)/%.S + @mkdir -p $(dir $@) + $(CC) $(DEPFLAGS) $(CPPFLAGS) $(ASFLAGS) $(INCLUDES) -c $< -o $@ + +$(BUILDDIR)/%.o: %.cpp + @mkdir -p $(dir $@) + $(CXX) $(DEPFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(INCLUDES) -c $< -o $@ -%.o: %.c - $(CC) $(CFLAGS) $(CINCLUDE) -MMD -c -o $@ $< +$(BUILDDIR)/%.o: %.c + @mkdir -p $(dir $@) + $(CC) $(DEPFLAGS) $(CPPFLAGS) $(CFLAGS) $(INCLUDES) -c $< -o $@ # clear configuration files cleanconfig: @@ -56,7 +110,7 @@ cleanconfig: # clear build files clean: @echo "[Cleaning]" - rm -rf build $(OBJECTS) $(GATEWAY) $(DEPS) + rm -rf $(BUILDDIR) $(BINDIR) $(CONFIG_FILE): @echo "[Running configure]" @@ -70,31 +124,31 @@ install-gateway: install-initscripts: ifeq ($(INIT_SYSTEM), systemd) - install -m0644 initscripts/mysgateway.systemd /etc/systemd/system/mysgateway.service - @sed -i -e "s|%gateway_dir%|${GATEWAY_DIR}|g" /etc/systemd/system/mysgateway.service + install -m0644 initscripts/mysgw.systemd /etc/systemd/system/mysgw.service + @sed -i -e "s|%gateway_dir%|${GATEWAY_DIR}|g" /etc/systemd/system/mysgw.service systemctl daemon-reload @echo "MySensors gateway has been installed, to add to the boot run:" - @echo " sudo systemctl enable mysgateway.service" + @echo " sudo systemctl enable mysgw.service" @echo "To start the gateway run:" - @echo " sudo systemctl start mysgateway.service" + @echo " sudo systemctl start mysgw.service" else ifeq ($(INIT_SYSTEM), sysvinit) - install -m0755 initscripts/mysgateway.sysvinit /etc/init.d/mysgateway - @sed -i -e "s|%gateway_dir%|${GATEWAY_DIR}|g" /etc/init.d/mysgateway + install -m0755 initscripts/mysgw.sysvinit /etc/init.d/mysgw + @sed -i -e "s|%gateway_dir%|${GATEWAY_DIR}|g" /etc/init.d/mysgw @echo "MySensors gateway has been installed, to add to the boot run:" - @echo " sudo update-rc.d mysgateway defaults" + @echo " sudo update-rc.d mysgw defaults" @echo "To start the gateway run:" - @echo " sudo service mysgateway start" + @echo " sudo service mysgw start" endif uninstall: ifeq ($(INIT_SYSTEM), systemd) - @echo "Stopping daemon mysgateway (ignore errors)" - -@systemctl stop mysgateway.service + @echo "Stopping daemon mysgw (ignore errors)" + -@systemctl stop mysgw.service @echo "removing files" - rm /etc/systemd/system/mysgateway.service $(GATEWAY_DIR)/$(GATEWAY_BIN) + rm /etc/systemd/system/mysgw.service $(GATEWAY_DIR)/$(GATEWAY_BIN) else ifeq ($(INIT_SYSTEM), sysvinit) - @echo "Stopping daemon mysgateway (ignore errors)" - -@service mysgateway stop + @echo "Stopping daemon mysgw (ignore errors)" + -@service mysgw stop @echo "removing files" - rm /etc/init.d/mysgateway $(GATEWAY_DIR)/$(GATEWAY_BIN) + rm /etc/init.d/mysgw $(GATEWAY_DIR)/$(GATEWAY_BIN) endif diff --git a/configure b/configure index 4d54aa157..e7fabc782 100755 --- a/configure +++ b/configure @@ -14,10 +14,15 @@ Help: Building options: --soc=[BCM2835|BCM2836|AM33XX|A10|A13|A20|H3] SoC type to be used. [configure autodetected] - --cpu-flags= CPU defining/optimizing flags to be used. [configure autodetected] - --extra-cxxflags= Extra C flags passed to C/C++ compilation. [] + --cpu-flags= CPU defining/optimizing flags to be used. [configure autodetected] + --extra-cflags= Extra C flags passed to C compilation. [] + --extra-cxxflags= Extra C++ flags passed to C++ compilation. [] --extra-ldflags= Extra C flags passed to linking. [] + --c_compiler= C compiler. [arm-linux-gnueabihf-gcc][gcc] --cxx_compiler= C++ compiler [arm-linux-gnueabihf-g++][g++] + --build-dir= Compiler directory to store object files. [build] + --bin-dir= Compiler directory to store binary files. [bin] + --arduino-lib-dir= Arduino library directory. --no-clean Don't clean previous build artifacts. Installation options: @@ -175,10 +180,10 @@ function gcc_cpu_flags { local soc=$1 case $soc in BCM2835) - flags="-march=armv6zk -mtune=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard -DLINUX_ARCH_RASPBERRYPI" + flags="-march=armv6zk -mtune=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard" ;; BCM2836) - flags="-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard -DLINUX_ARCH_RASPBERRYPI" + flags="-march=armv7-a -mtune=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard" ;; AM33XX) flags="-march=armv7-a -mtune=cortex-a8 -mfpu=neon -mfloat-abi=hard" @@ -206,7 +211,7 @@ debug=enable gateway_type=ethernet transport_type=nrf24 -params="SOC CXXFLAGS LDFLAGS PREFIX CXX GATEWAY_DIR INIT_SYSTEM" +params="SOC CFLAGS CXXFLAGS CPPFLAGS LDFLAGS PREFIX CC CXX ARDUINO_LIB_DIR BUILDDIR BINDIR GATEWAY_DIR INIT_SYSTEM" for opt do if [ "$opt" = "-h" ] || [ "$opt" = "--help" ]; then @@ -221,15 +226,30 @@ for opt do --cpu-flags=*) CPUFLAGS="$optarg" ;; + --extra-cflags=*) + CFLAGS="$optarg" + ;; --extra-cxxflags=*) CXXFLAGS="$optarg" ;; --extra-ldflags=*) LDFLAGS="$optarg" ;; + --c_compiler=*) + CC="$optarg" + ;; --cxx_compiler=*) CXX="$optarg" ;; + --arduino-lib-dir=*) + ARDUINO_LIB_DIR=$optarg + ;; + --build-dir=*) + BUILDDIR="$optarg" + ;; + --bin-dir=*) + BINDIR="$optarg" + ;; --no-clean*) NO_CLEAN="1" ;; @@ -247,10 +267,10 @@ for opt do ;; --my-node-id=*) gateway_type="none"; - CXXFLAGS="-DMY_NODE_ID=${optarg} $CXXFLAGS" + CPPFLAGS="-DMY_NODE_ID=${optarg} $CPPFLAGS" ;; --my-config-file=*) - CXXFLAGS="-DMY_LINUX_CONFIG_FILE=\\\"${optarg}\\\" $CXXFLAGS" + CPPFLAGS="-DMY_LINUX_CONFIG_FILE=\\\"${optarg}\\\" $CPPFLAGS" ;; --my-transport=*) transport_type=${optarg} @@ -260,74 +280,74 @@ for opt do transport_type=${optarg} ;; --my-serial-port=*) - CXXFLAGS="-DMY_LINUX_SERIAL_PORT=\\\"${optarg}\\\" $CXXFLAGS" + CPPFLAGS="-DMY_LINUX_SERIAL_PORT=\\\"${optarg}\\\" $CPPFLAGS" ;; --my-serial-baudrate=*) - CXXFLAGS="-DMY_BAUD_RATE=${optarg} $CXXFLAGS" + CPPFLAGS="-DMY_BAUD_RATE=${optarg} $CPPFLAGS" ;; --my-serial-is-pty*) - CXXFLAGS="-DMY_IS_SERIAL_PTY $CXXFLAGS" + CPPFLAGS="-DMY_IS_SERIAL_PTY $CPPFLAGS" ;; --my-serial-pty=*) - CXXFLAGS="-DMY_LINUX_SERIAL_PTY=\\\"${optarg}\\\" $CXXFLAGS" + CPPFLAGS="-DMY_LINUX_SERIAL_PTY=\\\"${optarg}\\\" $CPPFLAGS" ;; --my-serial-groupname=*) - CXXFLAGS="-DMY_LINUX_SERIAL_GROUPNAME=\\\"${optarg}\\\" $CXXFLAGS" + CPPFLAGS="-DMY_LINUX_SERIAL_GROUPNAME=\\\"${optarg}\\\" $CPPFLAGS" ;; --my-rf24-channel=*) - CXXFLAGS="-DMY_RF24_CHANNEL=${optarg} $CXXFLAGS" + CPPFLAGS="-DMY_RF24_CHANNEL=${optarg} $CPPFLAGS" ;; --my-rf24-pa-level=*) - CXXFLAGS="-DMY_RF24_PA_LEVEL=${optarg} $CXXFLAGS" + CPPFLAGS="-DMY_RF24_PA_LEVEL=${optarg} $CPPFLAGS" ;; --my-controller-url-address=*) - CXXFLAGS="-DMY_CONTROLLER_URL_ADDRESS=\\\"${optarg}\\\" $CXXFLAGS" + CPPFLAGS="-DMY_CONTROLLER_URL_ADDRESS=\\\"${optarg}\\\" $CPPFLAGS" ;; --my-controller-ip-address=*) controller_ip=`echo ${optarg//./,}` - CXXFLAGS="-DMY_CONTROLLER_IP_ADDRESS=${controller_ip} $CXXFLAGS" + CPPFLAGS="-DMY_CONTROLLER_IP_ADDRESS=${controller_ip} $CPPFLAGS" ;; --my-port=*) - CXXFLAGS="-DMY_PORT=${optarg} $CXXFLAGS" + CPPFLAGS="-DMY_PORT=${optarg} $CPPFLAGS" ;; --my-mqtt-client-id=*) - CXXFLAGS="-DMY_MQTT_CLIENT_ID=\\\"${optarg}\\\" $CXXFLAGS" + CPPFLAGS="-DMY_MQTT_CLIENT_ID=\\\"${optarg}\\\" $CPPFLAGS" ;; --my-mqtt-publish-topic-prefix=*) - CXXFLAGS="-DMY_MQTT_PUBLISH_TOPIC_PREFIX=\\\"${optarg}\\\" $CXXFLAGS" + CPPFLAGS="-DMY_MQTT_PUBLISH_TOPIC_PREFIX=\\\"${optarg}\\\" $CPPFLAGS" ;; --my-mqtt-subscribe-topic-prefix=*) - CXXFLAGS="-DMY_MQTT_SUBSCRIBE_TOPIC_PREFIX=\\\"${optarg}\\\" $CXXFLAGS" + CPPFLAGS="-DMY_MQTT_SUBSCRIBE_TOPIC_PREFIX=\\\"${optarg}\\\" $CPPFLAGS" ;; --my-rf24-irq-pin=*) - CXXFLAGS="-DMY_RX_MESSAGE_BUFFER_FEATURE -DMY_RF24_IRQ_PIN=${optarg} $CXXFLAGS" + CPPFLAGS="-DMY_RX_MESSAGE_BUFFER_FEATURE -DMY_RF24_IRQ_PIN=${optarg} $CPPFLAGS" ;; --my-rx-message-buffer-size=*) - CXXFLAGS="-DMY_RX_MESSAGE_BUFFER_SIZE=${optarg} $CXXFLAGS" + CPPFLAGS="-DMY_RX_MESSAGE_BUFFER_SIZE=${optarg} $CPPFLAGS" ;; --my-rs485-serial-port=*) - CXXFLAGS="-DMY_RS485_HWSERIAL=\\\"${optarg}\\\" $CXXFLAGS" + CPPFLAGS="-DMY_RS485_HWSERIAL=\\\"${optarg}\\\" $CPPFLAGS" ;; --my-rs485-baudrate=*) - CXXFLAGS="-DMY_RS485_BAUD_RATE=${optarg} $CXXFLAGS" + CPPFLAGS="-DMY_RS485_BAUD_RATE=${optarg} $CPPFLAGS" ;; --my-rs485-de-pin=*) - CXXFLAGS="-DMY_RS485_DE_PIN=${optarg} $CXXFLAGS" + CPPFLAGS="-DMY_RS485_DE_PIN=${optarg} $CPPFLAGS" ;; --my-rs485-max-msg-length=*) - CXXFLAGS="-DMY_RS485_MAX_MESSAGE_LENGTH=${optarg} $CXXFLAGS" + CPPFLAGS="-DMY_RS485_MAX_MESSAGE_LENGTH=${optarg} $CPPFLAGS" ;; --my-leds-err-pin=*) - CXXFLAGS="-DMY_DEFAULT_ERR_LED_PIN=${optarg} $CXXFLAGS" + CPPFLAGS="-DMY_DEFAULT_ERR_LED_PIN=${optarg} $CPPFLAGS" ;; --my-leds-rx-pin=*) - CXXFLAGS="-DMY_DEFAULT_RX_LED_PIN=${optarg} $CXXFLAGS" + CPPFLAGS="-DMY_DEFAULT_RX_LED_PIN=${optarg} $CPPFLAGS" ;; --my-leds-tx-pin=*) - CXXFLAGS="-DMY_DEFAULT_TX_LED_PIN=${optarg} $CXXFLAGS" + CPPFLAGS="-DMY_DEFAULT_TX_LED_PIN=${optarg} $CPPFLAGS" ;; --my-leds-blinking-inverse*) - CXXFLAGS="-DMY_WITH_LEDS_BLINKING_INVERSE $CXXFLAGS" + CPPFLAGS="-DMY_WITH_LEDS_BLINKING_INVERSE $CPPFLAGS" ;; *) echo "[WARNING] Unknown option detected:$opt, ignored" @@ -336,7 +356,10 @@ for opt do done PREFIX=${PREFIX:-/usr/local} +BUILDDIR=${BUILDDIR:-build} +BINDIR=${BINDIR:-bin} GATEWAY_DIR=${GATEWAY_DIR:-${PREFIX}/bin} +CC=${CC:-gcc} CXX=${CXX:-g++} if [ -z "${SOC}" ]; then @@ -353,32 +376,34 @@ if [ -z "${CPUFLAGS}" ]; then CPUFLAGS=$(gcc_cpu_flags $SOC) fi -CXXFLAGS="$CPUFLAGS -Ofast -g -Wall -Wextra $CXXFLAGS" -CFLAGS="-Ofast -g -Wall -Wextra $CFLAGS" +if [[ $SOC == "BCM2835" || $SOC == "BCM2836" ]]; then + CPPFLAGS="-DLINUX_ARCH_RASPBERRYPI $CPPFLAGS" +fi if [[ $TYPE == "RPi2" || $TYPE == "RPi3" || $REV == "0010" ]]; then - CXXFLAGS+="-D__RPI_BPLUS" + CPPFLAGS="-D__RPI_BPLUS $CPPFLAGS" fi if [[ ${debug} == "enable" ]]; then - CXXFLAGS="-DMY_DEBUG $CXXFLAGS" + CPPFLAGS="-DMY_DEBUG $CPPFLAGS" fi if [[ ${gateway_type} == "ethernet" ]]; then - CXXFLAGS="-DMY_GATEWAY_LINUX $CXXFLAGS" + CPPFLAGS="-DMY_GATEWAY_LINUX $CPPFLAGS" elif [[ ${gateway_type} == "serial" ]]; then - CXXFLAGS="-DMY_GATEWAY_SERIAL $CXXFLAGS" + CPPFLAGS="-DMY_GATEWAY_SERIAL $CPPFLAGS" elif [[ ${gateway_type} == "mqtt" ]]; then - CXXFLAGS="-DMY_GATEWAY_LINUX -DMY_GATEWAY_MQTT_CLIENT $CXXFLAGS" + CPPFLAGS="-DMY_GATEWAY_LINUX -DMY_GATEWAY_MQTT_CLIENT $CPPFLAGS" fi if [[ ${transport_type} == "nrf24" ]]; then - CXXFLAGS="-DMY_RADIO_NRF24 $CXXFLAGS" + CPPFLAGS="-DMY_RADIO_NRF24 $CPPFLAGS" elif [[ ${transport_type} == "rs485" ]]; then - CXXFLAGS="-DMY_RS485 $CXXFLAGS" + CPPFLAGS="-DMY_RS485 $CPPFLAGS" fi LDFLAGS="-pthread $LDFLAGS" +CPPFLAGS="$CPUFLAGS $CPPFLAGS" if [ -x /usr/bin/systemctl ] || [ -x /bin/systemctl ]; then INIT_SYSTEM=systemd diff --git a/core/MyHwLinuxGeneric.cpp b/core/MyHwLinuxGeneric.cpp index a71c32309..ea7a47cde 100644 --- a/core/MyHwLinuxGeneric.cpp +++ b/core/MyHwLinuxGeneric.cpp @@ -5,8 +5,8 @@ * 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 + * 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 diff --git a/core/MyHwLinuxGeneric.h b/core/MyHwLinuxGeneric.h index ff8b0083e..460317687 100644 --- a/core/MyHwLinuxGeneric.h +++ b/core/MyHwLinuxGeneric.h @@ -5,8 +5,8 @@ * 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 + * 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 diff --git a/core/MyHwRPi.cpp b/core/MyHwRPi.cpp index 34c530fc5..79c04cec7 100644 --- a/core/MyHwRPi.cpp +++ b/core/MyHwRPi.cpp @@ -5,8 +5,8 @@ * 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 + * 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 @@ -22,17 +22,11 @@ #include #include #include "SoftEeprom.h" -#include "log.h" static SoftEeprom eeprom = SoftEeprom(MY_LINUX_CONFIG_FILE, 1024); // ATMega328 has 1024 bytes void hwInit() { - if (!bcm2835_init()) { - logError("Failed to initialized bcm2835.\n"); - exit(1); - } - #ifdef MY_GATEWAY_SERIAL MY_SERIALDEVICE.begin(MY_BAUD_RATE); #ifdef MY_LINUX_SERIAL_GROUPNAME diff --git a/core/MyHwRPi.h b/core/MyHwRPi.h index f6bbb8ece..2252a22ab 100644 --- a/core/MyHwRPi.h +++ b/core/MyHwRPi.h @@ -5,8 +5,8 @@ * 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 + * 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 @@ -20,7 +20,24 @@ #ifndef MyHwRPi_h #define MyHwRPi_h +#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; #undef hwDigitalWrite inline void hwDigitalWrite(uint8_t, uint8_t); diff --git a/core/MyMainLinux.cpp b/core/MyMainLinux.cpp index e6155baf9..7c4ec6be4 100644 --- a/core/MyMainLinux.cpp +++ b/core/MyMainLinux.cpp @@ -102,7 +102,7 @@ static int daemonize(void) void print_usage() { - printf("Usage: mysGateway [options]\n\n" \ + printf("Usage: mysgw [options]\n\n" \ "Options:\n" \ " -h, --help Display a short summary of all program options.\n" \ " -d, --debug Enable debug.\n" \ @@ -154,7 +154,7 @@ void generate_soft_sign_hmac_key() print_soft_sign_hmac_key(key); - printf("To use this key, run mysGateway with:\n" + printf("To use this key, run mysgw with:\n" " --set-soft-hmac-key="); for (int i = 0; i < 32; i++) { printf("%02X", key[i]); @@ -226,7 +226,7 @@ void generate_soft_sign_serial_key() print_soft_sign_serial_key(key); - printf("To use this key, run mysGateway with:\n" + printf("To use this key, run mysgw with:\n" " --set-soft-serial-key="); for (int i = 0; i < 9; i++) { printf("%02X", key[i]); @@ -298,7 +298,7 @@ void generate_aes_key() print_aes_key(key); - printf("To use this key, run mysGateway with:\n" + printf("To use this key, run mysgw with:\n" " --set-aes-key="); for (int i = 0; i < 16; i++) { printf("%02X", key[i]); diff --git a/drivers/Linux/Arduino.h b/drivers/Linux/Arduino.h index eaa4ed9a6..71bca2330 100644 --- a/drivers/Linux/Arduino.h +++ b/drivers/Linux/Arduino.h @@ -68,6 +68,7 @@ using std::abs; typedef bool boolean; typedef uint8_t byte; typedef string String; +typedef char __FlashStringHelper; void yield(void); unsigned long millis(void); diff --git a/drivers/RPi/rpi_util.cpp b/drivers/RPi/rpi_util.cpp index 7ee1a9288..08885543d 100644 --- a/drivers/RPi/rpi_util.cpp +++ b/drivers/RPi/rpi_util.cpp @@ -44,6 +44,7 @@ struct ThreadArgs { int gpioPin; }; +volatile bool interruptsEnabled = true; static pthread_mutex_t intMutex = PTHREAD_MUTEX_INITIALIZER; static pthread_t *threadIds[64] = {NULL}; @@ -152,7 +153,13 @@ void *interruptHandler(void *args) { (void)read (fd, &c, 1) ; lseek (fd, 0, SEEK_SET) ; // Call user function. - func(); + pthread_mutex_lock(&intMutex); + if (interruptsEnabled) { + pthread_mutex_unlock(&intMutex); + func(); + } else { + pthread_mutex_unlock(&intMutex); + } } close(fd); @@ -322,9 +329,13 @@ uint8_t rpi_util::digitalPinToInterrupt(uint8_t physPin) { } void rpi_util::interrupts() { + pthread_mutex_lock(&intMutex); + interruptsEnabled = true; pthread_mutex_unlock(&intMutex); } void rpi_util::noInterrupts() { pthread_mutex_lock(&intMutex); + interruptsEnabled = false; + pthread_mutex_unlock(&intMutex); } diff --git a/drivers/RPi/rpi_util.h b/drivers/RPi/rpi_util.h index 3d31eb9c3..f7447baa5 100644 --- a/drivers/RPi/rpi_util.h +++ b/drivers/RPi/rpi_util.h @@ -45,10 +45,10 @@ typedef enum { } rpi_pinedge; typedef enum { - PIN_SPI_SS = RPI_GPIO_P1_24, - PIN_SPI_MOSI = RPI_GPIO_P1_19, - PIN_SPI_MISO = RPI_GPIO_P1_21, - PIN_SPI_SCK = RPI_GPIO_P1_23 + 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; diff --git a/examples_linux/mysGateway.cpp b/examples_linux/mysgw.cpp similarity index 83% rename from examples_linux/mysGateway.cpp rename to examples_linux/mysgw.cpp index c94d482a5..7ada2f0b9 100644 --- a/examples_linux/mysGateway.cpp +++ b/examples_linux/mysgw.cpp @@ -5,8 +5,8 @@ * 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 - * Copyleft (c) 2016, Marcelo Aquino + * Created by Henrik Ekblad + * Copyright (C) 2013-2016 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -67,15 +67,25 @@ // Note: MY_SIGNING_REQUEST_SIGNATURES must also be set //#define MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL +// Enables RF24 encryption (all nodes and gateway must have this enabled, and all must be +// personalized with the same AES key) +//#define MY_RF24_ENABLE_ENCRYPTION + #include -void setup() { +#define ARDUINO 100 +// This space is intended to be used to include arduino libraries + +#undef ARDUINO + +void setup() { + // Setup locally attached sensors } void presentation() { - // Present locally attached sensors here + // Present locally attached sensors here } void loop() { - // Send locally attached sensors data here + // Send locally attached sensors data here } diff --git a/initscripts/mysgateway.systemd b/initscripts/mysgw.systemd similarity index 76% rename from initscripts/mysgateway.systemd rename to initscripts/mysgw.systemd index 5b707c6dd..41e7279e5 100644 --- a/initscripts/mysgateway.systemd +++ b/initscripts/mysgw.systemd @@ -3,7 +3,7 @@ Description=MySensors Gateway daemon Requires=network.target [Service] -ExecStart=%gateway_dir%/mysGateway +ExecStart=%gateway_dir%/mysgw [Install] WantedBy=multi-user.target diff --git a/initscripts/mysgateway.sysvinit b/initscripts/mysgw.sysvinit similarity index 98% rename from initscripts/mysgateway.sysvinit rename to initscripts/mysgw.sysvinit index 5ca7e12f3..a511f0567 100644 --- a/initscripts/mysgateway.sysvinit +++ b/initscripts/mysgw.sysvinit @@ -1,6 +1,6 @@ #! /bin/sh ### BEGIN INIT INFO -# Provides: mysGateway +# Provides: mysgw # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 @@ -15,7 +15,7 @@ # PATH should only include /usr/* if it runs after the mountnfs.sh script PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin DESC="MySensors Gateway" -NAME=mysGateway +NAME=mysgw DAEMON=%gateway_dir%/$NAME DAEMON_ARGS="-b" PIDFILE=/var/run/$NAME.pid From d8f8ea3418e9108550b8bba8a029be99ab69e636 Mon Sep 17 00:00:00 2001 From: tekka007 Date: Sun, 20 Nov 2016 13:17:13 +0100 Subject: [PATCH 125/167] Bump version to 2.1.0 --- README.md | 2 +- core/Version.h | 2 +- library.json | 4 ++-- library.properties | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index db75a27f4..73eec036d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Arduino ======= -MySensors Arduino Library v2.0.0-beta +MySensors Arduino Library v2.1.0-beta Please visit www.mysensors.org for more information diff --git a/core/Version.h b/core/Version.h index b279f564d..0f781abf8 100644 --- a/core/Version.h +++ b/core/Version.h @@ -24,6 +24,6 @@ #ifndef Version_h #define Version_h -#define MYSENSORS_LIBRARY_VERSION "2.0.1-beta" +#define MYSENSORS_LIBRARY_VERSION "2.1.0-beta" #endif diff --git a/library.json b/library.json index d55c3e4a4..3d5353357 100644 --- a/library.json +++ b/library.json @@ -1,13 +1,13 @@ { "name": "MySensors", "keywords": "framework, sensor, rf", - "description": "Home Automation Framework. Create your own wireless sensor mesh using NRF24L01+ and RFM69 radios running on Arduino or ESP8266. Over-the-air updates and MySensors support in 16+ home automation controllers.", + "description": "Home Automation Framework. Create your own wireless sensor mesh using NRF24L01+, RFM69 and RFM95 radios running on Arduino or ESP8266. Over-the-air updates and MySensors support in 16+ home automation controllers.", "repository": { "type": "git", "url": "https://github.com/mysensors/MySensors.git" }, - "version": "2.0.1-beta", + "version": "2.1.0-beta", "frameworks": "arduino", "platforms": [ "atmelavr", diff --git a/library.properties b/library.properties index 9d945cd2c..f0d927c67 100644 --- a/library.properties +++ b/library.properties @@ -1,9 +1,9 @@ name=MySensors -version=2.0.1-beta +version=2.1.0-beta author=The MySensors Team maintainer=The MySensors Team sentence=Home Automation Framework -paragraph=Create your own wireless sensor mesh using NRF24L01+ and RFM69 radios running on Arduino, SAMD and ESP8266. Allows over-the-air updates of nodes. Supported by 20+ home automation controllers. +paragraph=Create your own wireless sensor mesh using NRF24L01+, RFM69 and RFM95 radios running on Arduino, SAMD and ESP8266. Allows over-the-air updates of nodes. Supported by 20+ home automation controllers. category=Communication url=https://www.mysensors.org architectures=avr,esp8266,samd From ec09161c422da45e95b5110122776fb60cba2bc4 Mon Sep 17 00:00:00 2001 From: tekka007 Date: Sun, 20 Nov 2016 16:27:30 +0100 Subject: [PATCH 126/167] AVR: Use avr-libc eeprom update functions --- core/MyHwATMega328.h | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/core/MyHwATMega328.h b/core/MyHwATMega328.h index bf38a24e5..bb5962f75 100644 --- a/core/MyHwATMega328.h +++ b/core/MyHwATMega328.h @@ -73,15 +73,9 @@ do { \ #define hwMillis() millis() #define hwRandomNumberInit() randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)) #define hwReadConfig(__pos) eeprom_read_byte((uint8_t*)(__pos)) - -#ifndef eeprom_update_byte - #define hwWriteConfig(__loc, __val) if((uint8_t)(__val) != eeprom_read_byte((uint8_t*)(__loc))) { eeprom_write_byte((uint8_t*)(__loc), (__val)); } -#else - #define hwWriteConfig(__pos, __val) eeprom_update_byte((uint8_t*)(__pos), (__val)) -#endif - +#define hwWriteConfig(__pos, __val) eeprom_update_byte((uint8_t*)(__pos), (__val)) #define hwReadConfigBlock(__buf, __pos, __length) eeprom_read_block((void*)(__buf), (void*)(__pos), (__length)) -#define hwWriteConfigBlock(__buf, __pos, __length) eeprom_write_block((void*)(__buf), (void*)(__pos), (__length)) +#define hwWriteConfigBlock(__buf, __pos, __length) eeprom_update_block((void*)(__buf), (void*)(__pos), (__length)) From 26375757cda177664baabae1e0dfd6a8ff1c866b Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Mon, 21 Nov 2016 17:02:25 +0100 Subject: [PATCH 127/167] README.md updated with new Jenkins URL:s --- README.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index db75a27f4..59b2c013d 100644 --- a/README.md +++ b/README.md @@ -7,17 +7,13 @@ Please visit www.mysensors.org for more information Doxygen ------- -[master](https://ci.mysensors.org/job/Verifiers/job/MySensorsArduino/branch/master/Doxygen_HTML/index.html) [development](https://ci.mysensors.org/job/Verifiers/job/MySensorsArduino/branch/development/Doxygen_HTML/index.html) +[master](https://ci.mysensors.org/job/Verifiers/job/MySensors/branch/master/Doxygen_HTML/index.html) [development](https://ci.mysensors.org/job/Verifiers/job/MySensors/branch/development/Doxygen_HTML/index.html) CI statuses ----------- -Current build status of master branch: [![Build Status](https://ci.mysensors.org/job/Verifiers/job/MySensorsArduino/job/master/badge/icon)](https://ci.mysensors.org/job/Verifiers/job/MySensorsArduino/job/master/) +Current build status of master branch: [![Build Status](https://ci.mysensors.org/job/Verifiers/job/MySensors/job/master/badge/icon)](https://ci.mysensors.org/job/Verifiers/job/MySensors/job/master/) -Current build status of development branch: [![Build Status](https://ci.mysensors.org/job/Verifiers/job/MySensorsArduino/job/development/badge/icon)](https://ci.mysensors.org/job/Verifiers/job/MySensorsArduino/job/development/) - -Current build status of master branch (nightly build): [![Build Status](https://ci.mysensors.org/job/Nightlies/job/MySensorsArduinoNightly/job/master/badge/icon)](https://ci.mysensors.org/job/Nightlies/job/MySensorsArduinoNightly/job/master/) - -Current build status of development branch (nightly build): [![Build Status](https://ci.mysensors.org/job/Nightlies/job/MySensorsArduinoNightly/job/development/badge/icon)](https://ci.mysensors.org/job/Nightlies/job/MySensorsArduinoNightly/job/development/) +Current build status of development branch: [![Build Status](https://ci.mysensors.org/job/Verifiers/job/MySensors/job/development/badge/icon)](https://ci.mysensors.org/job/Verifiers/job/MySensors/job/development/) Current build status of master branch (nightly build of Arduino IDE): [![Build Status](https://ci.mysensors.org/job/Nightlies/job/MySensorsArduinoNightlyIDE/job/master/badge/icon)](https://ci.mysensors.org/job/Nightlies/job/MySensorsArduinoNightlyIDE/job/master/) From 66599c0b2323cb6a6f61845753e9e096cb2eb4f4 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Thu, 24 Nov 2016 15:31:36 +0100 Subject: [PATCH 128/167] Fix typo for MY_DEFAULT_ERR_LED_PIN (#657) --- MySensors.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MySensors.h b/MySensors.h index bc1a94132..2276d097e 100644 --- a/MySensors.h +++ b/MySensors.h @@ -79,7 +79,7 @@ #endif // LEDS -#if !defined(MY_DEFAULT_ERR_LED_PIN) & defined(MY_HW_ERR_LED_PIN) +#if !defined(MY_DEFAULT_ERR_LED_PIN) && defined(MY_HW_ERR_LED_PIN) #define MY_DEFAULT_ERR_LED_PIN MY_HW_ERR_LED_PIN #endif From 9ef1df540759b07366f57bdab67ab6c544bfd651 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Thu, 24 Nov 2016 12:59:01 -0200 Subject: [PATCH 129/167] RPi: Fix RFM95 build (#654) --- configure | 13 +++++++++++-- drivers/RFM95/RFM95.cpp | 10 ++++++---- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/configure b/configure index e7fabc782..f172cf5a7 100755 --- a/configure +++ b/configure @@ -53,7 +53,7 @@ MySensors options: MQTT publish topic prefix. --my-mqtt-subscribe-topic-prefix= MQTT subscribe topic prefix. - --my-transport=[none|nrf24|rs485] + --my-transport=[none|nrf24|rs485|rfm95] Transport type, set to none to disable transport feature. [nrf24] --my-rf24-channel=<0-125> RF channel for the sensor net, 0-125. [76] --my-rf24-pa-level=[RF24_PA_MAX|RF24_PA_LOW] @@ -396,10 +396,19 @@ elif [[ ${gateway_type} == "mqtt" ]]; then CPPFLAGS="-DMY_GATEWAY_LINUX -DMY_GATEWAY_MQTT_CLIENT $CPPFLAGS" fi -if [[ ${transport_type} == "nrf24" ]]; then +if [[ ${transport_type} == "none" ]]; then + # Transport disabled + : +elif [[ ${transport_type} == "nrf24" ]]; then CPPFLAGS="-DMY_RADIO_NRF24 $CPPFLAGS" elif [[ ${transport_type} == "rs485" ]]; then CPPFLAGS="-DMY_RS485 $CPPFLAGS" +elif [[ ${transport_type} == "rfm95" ]]; then + CPPFLAGS="-DMY_RADIO_RFM95 $CPPFLAGS" +else + echo "Invalid transport type." + echo "Aborting." + exit 1 fi LDFLAGS="-pthread $LDFLAGS" diff --git a/drivers/RFM95/RFM95.cpp b/drivers/RFM95/RFM95.cpp index c49edd341..4ea1dfa4c 100644 --- a/drivers/RFM95/RFM95.cpp +++ b/drivers/RFM95/RFM95.cpp @@ -179,7 +179,7 @@ LOCAL void RFM95_interruptHandler(void) { (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); // Have received a packet //In order to retrieve received data from FIFO the user must ensure that ValidHeader, PayloadCrcError, RxDone and RxTimeout interrupts in the status register RegIrqFlags are not asserted to ensure that packet reception has terminated successfully(i.e.no flags should be set). - const uint8_t bufLen = min(RFM95_readReg(RFM95_REG_13_RX_NB_BYTES), RFM95_MAX_PACKET_LEN); + const uint8_t bufLen = min(RFM95_readReg(RFM95_REG_13_RX_NB_BYTES), (uint8_t)RFM95_MAX_PACKET_LEN); if (bufLen >= RFM95_HEADER_LEN) { // Reset the fifo read ptr to the beginning of the packet RFM95_writeReg(RFM95_REG_0D_FIFO_ADDR_PTR, RFM95_readReg(RFM95_REG_10_FIFO_RX_CURRENT_ADDR)); @@ -277,7 +277,7 @@ LOCAL bool RFM95_sendFrame(const uint8_t recipient, uint8_t* data, const uint8_t packet.header.sender = RFM95.address; packet.header.recipient = recipient; packet.header.controlFlags = 0x00; - packet.payloadLen = min(len, RFM95_MAX_PAYLOAD_LEN); + packet.payloadLen = min(len, (const uint8_t)RFM95_MAX_PAYLOAD_LEN); packet.header.controlFlags = flags; memcpy(&packet.payload, data, packet.payloadLen); return RFM95_send(packet); @@ -292,8 +292,8 @@ LOCAL void RFM95_setFrequency(const float centre) { LOCAL bool RFM95_setTxPower(uint8_t powerLevel) { // RFM95/96/97/98 does not have RFO pins connected to anything. Only PA_BOOST - powerLevel = max(RFM95_MIN_POWER_LEVEL_DBM, powerLevel); - powerLevel = min(RFM95_MAX_POWER_LEVEL_DBM, powerLevel); + powerLevel = max((uint8_t)RFM95_MIN_POWER_LEVEL_DBM, powerLevel); + powerLevel = min((uint8_t)RFM95_MAX_POWER_LEVEL_DBM, powerLevel); if (powerLevel != RFM95.powerLevel) { RFM95.powerLevel = powerLevel; uint8_t val; @@ -414,6 +414,8 @@ LOCAL bool RFM95_executeATC(const rfm95_RSSI_t currentRSSI, const rfm95_RSSI_t t } LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, const uint8_t bufferSize, const uint8_t retries, const uint32_t retryWaitTime) { + (void)retryWaitTime; + for (uint8_t retry = 0; retry < retries; retry++) { RFM95_DEBUG(PSTR("RFM95:SWR:SEND TO=%d,RETRY=%d\n"), recipient, retry); rfm95_flag_t flags = 0x00; From 45b671457dd85530c85f70e8d7c1002495753ccd Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Thu, 24 Nov 2016 16:43:04 +0100 Subject: [PATCH 130/167] Coding style related changes (#653) * Add .astylerc with the core coding standard * Added pre-commit git hook The hook currently only checks code format using astyle and will not permit commits which cause astyle to change the contents of any source file in the commit. This is useful to have automatic coding standard verification done without having to wait for Jenkins to react to a pull request. Installation: Linux: ln -s ../../tools/hooks/pre-commit.sh .git/hooks/pre-commit Windows: copy tools\hooks\pre-commit.sh .git\hooks\pre-commit * Added editorconfig and updated gitattributes Unix style line endings are now default. * Resolved doxygen warning --- .astylerc | 23 +++++++++++++++++++++++ .editorconfig | 19 +++++++++++++++++++ .gitattributes | 2 +- MyConfig.h | 1 + hooks/pre-commit.sh | 27 +++++++++++++++++++++++++++ 5 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 .astylerc create mode 100644 .editorconfig create mode 100644 hooks/pre-commit.sh diff --git a/.astylerc b/.astylerc new file mode 100644 index 000000000..ebd67ec6d --- /dev/null +++ b/.astylerc @@ -0,0 +1,23 @@ +# Coding standard for MySensors core library (see https://www.mysensors.org/download/contributing) + +# Curly braces should follow "One True Brace Style" format +style=1tbs + +# All control statements ('if', 'for', 'while' etc.) should include curly braces {}. Even one-liners. +add-brackets + +# Tab-character for white space/indentation +indent=tab + +# All lines should be kept at 100 character width or less +max-code-length=100 +break-after-logical + +# Preprocessor blocks should be indented +indent-preproc-block + +# Preprocessor definitions should be indented if linebroken +indent-preproc-define + +# C++ comments should be indented to source level, and not be kept in first column +indent-col1-comments diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..c2b4a9aa7 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,19 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with UTF-8 encoding for every file +[*] +end_of_line = lf +charset = utf-8 + +# For all source code +[*.{c,cpp,h,ino}] +insert_final_newline = true +indent_style = tab +indent_size = 2 + +# Tab indentation also for makefiles +[Makefile] +indent_style = tab diff --git a/.gitattributes b/.gitattributes index 463573798..415abee25 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,5 @@ # Set default behaviour, in case users don't have core.autocrlf set. -* text=auto +* text eol=lf # Explicitly declare text files we want to always be normalized and converted # to native line endings on checkout. diff --git a/MyConfig.h b/MyConfig.h index eec92de0c..1a1de4b68 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -953,6 +953,7 @@ #define MY_RX_MESSAGE_BUFFER_SIZE #define MY_NODE_LOCK_FEATURE #define MY_REPEATER_FEATURE +#define MY_TRANSPORT_UPLINK_CHECK_DISABLED #define MY_TRANSPORT_DONT_CARE_MODE #define MY_LINUX_SERIAL_GROUPNAME #define MY_IS_SERIAL_PTY diff --git a/hooks/pre-commit.sh b/hooks/pre-commit.sh new file mode 100644 index 000000000..bb725f029 --- /dev/null +++ b/hooks/pre-commit.sh @@ -0,0 +1,27 @@ +#!/bin/sh + +OPTIONS="--options=.astylerc" + +RETURN=0 +ASTYLE=astyle +if [ $? -ne 0 ]; then + echo "[!] astyle not installed or not in current path. Unable to check source file format policy." >&2 + exit 1 +fi + +FILES=`git diff --name-only --diff-filter=ACMR | grep -E "\.(c|cpp|h|ino)$"` +for FILE in $FILES; do + $ASTYLE $OPTIONS < $FILE | cmp -s $FILE - + if [ $? -ne 0 ]; then + echo "[!] $FILE does not respect the agreed coding style." >&2 + RETURN=1 + fi +done + +if [ $RETURN -eq 1 ]; then + echo "" >&2 + echo "Make sure you have run astyle with the following options:" >&2 + echo $OPTIONS >&2 +fi + +exit $RETURN \ No newline at end of file From 5bc5eff1f911b545f8f08c797faaaf66ef805bed Mon Sep 17 00:00:00 2001 From: Olivier Date: Thu, 24 Nov 2016 16:55:42 +0100 Subject: [PATCH 131/167] Fix timeout and add RFM95 test --- drivers/RFM95/RFM95.cpp | 14 ++----- drivers/RFM95/RFM95.h | 10 ----- ...ning_whitelisting_full_debug_rfm95_rsa.ino | 38 +++++++++++++++++++ 3 files changed, 41 insertions(+), 21 deletions(-) create mode 100644 tests/Arduino/sketches/hard_signing_whitelisting_full_debug_rfm95_rsa/hard_signing_whitelisting_full_debug_rfm95_rsa.ino diff --git a/drivers/RFM95/RFM95.cpp b/drivers/RFM95/RFM95.cpp index 4ea1dfa4c..37bcf5121 100644 --- a/drivers/RFM95/RFM95.cpp +++ b/drivers/RFM95/RFM95.cpp @@ -413,9 +413,8 @@ LOCAL bool RFM95_executeATC(const rfm95_RSSI_t currentRSSI, const rfm95_RSSI_t t return RFM95_setTxPower(RFM95.powerLevel);; } -LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, const uint8_t bufferSize, const uint8_t retries, const uint32_t retryWaitTime) { - (void)retryWaitTime; - +LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, const uint8_t bufferSize, const uint8_t retries, const uint32_t retryWaitTime) +{ for (uint8_t retry = 0; retry < retries; retry++) { RFM95_DEBUG(PSTR("RFM95:SWR:SEND TO=%d,RETRY=%d\n"), recipient, retry); rfm95_flag_t flags = 0x00; @@ -427,7 +426,7 @@ LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, cons return true; } const uint32_t enterMS = hwMillis(); - while (hwMillis() - enterMS < RFM95_RETRY_TIMEOUT_MS) { + while (hwMillis() - enterMS < retryWaitTime) { if (RFM95.rxBufferValid) { const uint8_t sender = RFM95.currentPacket.header.sender; const rfm95_sequenceNumber_t ACKsequenceNumber = RFM95.currentPacket.ACK.sequenceNumber; @@ -478,13 +477,6 @@ LOCAL bool RFM95_waitPacketSent(void) { LOCAL int16_t RFM95_getRSSI(void) { return (int16_t)(RFM95.currentPacket.RSSI - RFM95_RSSI_OFFSET); } -LOCAL int16_t RFM95_getSNR(void) { - return (int16_t)(RFM95.currentPacket.SNR / 4); -} - -LOCAL int8_t RFM95_getTxPower(void) { - return RFM95.powerLevel; -} LOCAL void RFM95_ATCmode(const bool OnOff, const int16_t targetRSSI) { RFM95.ATCenabled = OnOff; diff --git a/drivers/RFM95/RFM95.h b/drivers/RFM95/RFM95.h index b7fd629a7..963fcf76a 100644 --- a/drivers/RFM95/RFM95.h +++ b/drivers/RFM95/RFM95.h @@ -386,11 +386,6 @@ LOCAL void RFM95_interruptHandler(void); */ LOCAL void RFM95_clearRxBuffer(void); /** -* @brief RFM95_getSNR -* @return SNR Signal strength of last packet -*/ -LOCAL int16_t RFM95_getSNR(void); -/** * @brief RFM95_getRSSI * @return RSSI Signal strength of last packet */ @@ -403,11 +398,6 @@ LOCAL int16_t RFM95_getRSSI(void); */ LOCAL bool RFM95_executeATC(const rfm95_RSSI_t currentRSSI, const rfm95_RSSI_t targetRSSI); /** -* @brief RFM95_getTxPower -* @return Current power level -*/ -LOCAL int8_t RFM95_getTxPower(void); -/** * @brief RFM95_ATCmode * @param targetRSSI Target RSSI for transmitter (default -60) * @param OnOff True to enable ATC diff --git a/tests/Arduino/sketches/hard_signing_whitelisting_full_debug_rfm95_rsa/hard_signing_whitelisting_full_debug_rfm95_rsa.ino b/tests/Arduino/sketches/hard_signing_whitelisting_full_debug_rfm95_rsa/hard_signing_whitelisting_full_debug_rfm95_rsa.ino new file mode 100644 index 000000000..510c72c8e --- /dev/null +++ b/tests/Arduino/sketches/hard_signing_whitelisting_full_debug_rfm95_rsa/hard_signing_whitelisting_full_debug_rfm95_rsa.ino @@ -0,0 +1,38 @@ +/* + * 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/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_DEBUG_VERBOSE_SIGNING +#define MY_RADIO_RFM95 +//#define MY_SIGNING_SOFT +#define MY_SIGNING_ATSHA204 +#define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01}}} +#define MY_SIGNING_REQUEST_SIGNATURES +#ifndef MY_SIGNING_SOFT_RANDOMSEED_PIN +#define MY_SIGNING_SOFT_RANDOMSEED_PIN 7 +#endif +#ifndef MY_SIGNING_ATSHA204_PIN +#define MY_SIGNING_ATSHA204_PIN 17 +#endif +#define MY_RFM69_ENABLE_ENCRYPTION + +#include From c23b7d563ed0841bf4a0482cb44d1482d0d17b10 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Thu, 24 Nov 2016 18:25:14 -0200 Subject: [PATCH 132/167] RPi: Add signing and encryption to configure (#655) --- configure | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/configure b/configure index f172cf5a7..9ec9fc003 100755 --- a/configure +++ b/configure @@ -59,6 +59,10 @@ MySensors options: --my-rf24-pa-level=[RF24_PA_MAX|RF24_PA_LOW] RF24 PA level. [RF24_PA_MAX] --my-rf24-irq-pin= Pin number connected to nRF24L01 IRQ pin. + --my-rf24-encryption-enabled + Enables RF24 encryption. + All nodes and gateway must have this enabled, and all must be + personalized with the same AES key --my-rx-message-buffer-size= Buffer size for incoming messages when using rf24 interrupts. [20] --my-rs485-serial-port= @@ -71,6 +75,15 @@ MySensors options: --my-leds-rx-pin= Receive LED pin. --my-leds-tx-pin= Transmit LED pin. --my-leds-blinking-inverse Inverse the blinking feature. + --my-signing=[none|software] + Message signing. [none] + --my-signing-debug Enable signing related debug. + --my-signing-request-signatures + Enable signature request from nodes that in turn requested + gateway signature. + --my-signing-request-gw-signatures-from-all + Require all nodes in the network to sign messages sent to the + gateway. EOF } @@ -210,6 +223,8 @@ function gcc_cpu_flags { debug=enable gateway_type=ethernet 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" @@ -322,6 +337,9 @@ for opt do --my-rf24-irq-pin=*) CPPFLAGS="-DMY_RX_MESSAGE_BUFFER_FEATURE -DMY_RF24_IRQ_PIN=${optarg} $CPPFLAGS" ;; + --my-rf24-encryption-enabled*) + CPPFLAGS="-DMY_RF24_ENABLE_ENCRYPTION $CPPFLAGS" + ;; --my-rx-message-buffer-size=*) CPPFLAGS="-DMY_RX_MESSAGE_BUFFER_SIZE=${optarg} $CPPFLAGS" ;; @@ -349,6 +367,19 @@ for opt do --my-leds-blinking-inverse*) CPPFLAGS="-DMY_WITH_LEDS_BLINKING_INVERSE $CPPFLAGS" ;; + --my-signing=*) + signing=${optarg} + ;; + --my-signing-debug*) + CPPFLAGS="-DMY_DEBUG_VERBOSE_SIGNING $CPPFLAGS" + ;; + --my-signing-request-signatures*) + signing_request_signatures=true + ;; + --my-signing-request-gw-signatures-from-all*) + signing_request_signatures=true + CPPFLAGS="-DMY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL $CPPFLAGS" + ;; *) echo "[WARNING] Unknown option detected:$opt, ignored" ;; @@ -388,12 +419,19 @@ if [[ ${debug} == "enable" ]]; then CPPFLAGS="-DMY_DEBUG $CPPFLAGS" fi -if [[ ${gateway_type} == "ethernet" ]]; then +if [[ ${gateway_type} == "none" ]]; then + # Node mode selected + : +elif [[ ${gateway_type} == "ethernet" ]]; then CPPFLAGS="-DMY_GATEWAY_LINUX $CPPFLAGS" elif [[ ${gateway_type} == "serial" ]]; then CPPFLAGS="-DMY_GATEWAY_SERIAL $CPPFLAGS" elif [[ ${gateway_type} == "mqtt" ]]; then CPPFLAGS="-DMY_GATEWAY_LINUX -DMY_GATEWAY_MQTT_CLIENT $CPPFLAGS" +else + echo "Invalid gateway type." + echo "Aborting." + exit 1 fi if [[ ${transport_type} == "none" ]]; then @@ -411,6 +449,20 @@ else exit 1 fi +if [[ ${signing} == "none" ]]; then + # Signing disabled + : +elif [[ ${signing} == "software" ]]; then + CPPFLAGS="-DMY_SIGNING_SOFT $CPPFLAGS" + if [[ ${signing_request_signatures} == true ]]; then + CPPFLAGS="-DMY_SIGNING_REQUEST_SIGNATURES $CPPFLAGS" + fi +else + echo "Invalid message signing option." + echo "Aborting." + exit 1 +fi + LDFLAGS="-pthread $LDFLAGS" CPPFLAGS="$CPUFLAGS $CPPFLAGS" From c1d88b236db35f5276941a53634286df381cba51 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Thu, 24 Nov 2016 23:39:17 +0100 Subject: [PATCH 133/167] Add MySensors specific cppcheck config files (#660) --- tools/cppcheck/avr.xml | 17 +++++++++++++++++ tools/cppcheck/includes.cfg | 4 ++++ tools/cppcheck/suppressions.cfg | 5 +++++ 3 files changed, 26 insertions(+) create mode 100644 tools/cppcheck/avr.xml create mode 100644 tools/cppcheck/includes.cfg create mode 100644 tools/cppcheck/suppressions.cfg diff --git a/tools/cppcheck/avr.xml b/tools/cppcheck/avr.xml new file mode 100644 index 000000000..f2ba74526 --- /dev/null +++ b/tools/cppcheck/avr.xml @@ -0,0 +1,17 @@ + + + 8 + signed + + 2 + 2 + 4 + 8 + 4 + 4 + 8 + 2 + 2 + 2 + + \ No newline at end of file diff --git a/tools/cppcheck/includes.cfg b/tools/cppcheck/includes.cfg new file mode 100644 index 000000000..a57a7f30a --- /dev/null +++ b/tools/cppcheck/includes.cfg @@ -0,0 +1,4 @@ +. +drivers/Linux +drivers/AES +drivers/RPi diff --git a/tools/cppcheck/suppressions.cfg b/tools/cppcheck/suppressions.cfg new file mode 100644 index 000000000..0fac41281 --- /dev/null +++ b/tools/cppcheck/suppressions.cfg @@ -0,0 +1,5 @@ +ConfigurationNotChecked +missingInclude:core\MyMainESP8266.cpp +missingInclude:drivers\AltSoftSerial\AltSoftSerial.h +missingInclude:drivers\SPIFlash\SPIFlash.h +missingIncludeSystem From 03aa0f44d4d023a039716cf2ccf2cadcdb98ed94 Mon Sep 17 00:00:00 2001 From: tekka007 Date: Fri, 25 Nov 2016 12:01:51 +0100 Subject: [PATCH 134/167] Update forward link driver limit --- MySensors.h | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/MySensors.h b/MySensors.h index b012d197c..a3388233e 100644 --- a/MySensors.h +++ b/MySensors.h @@ -259,9 +259,34 @@ #endif #include "core/MyTransport.cpp" - #if (defined(MY_RADIO_NRF24) && defined(MY_RADIO_RFM69)) || (defined(MY_RADIO_NRF24) && defined(MY_RS485)) || (defined(MY_RADIO_RFM69) && defined(MY_RS485)) + + // count enabled transports + #if defined(MY_RADIO_NRF24) + #define __RF24CNT 1 + #else + #define __RF24CNT 0 + #endif + #if defined(MY_RADIO_RFM69) + #define __RFM69CNT 1 + #else + #define __RFM69CNT 0 + #endif + #if defined(MY_RADIO_RFM95) + #define __RFM95CNT 1 + #else + #define __RFM95CNT 0 + #endif + #if defined(MY_RS485) + #define __RS485CNT 1 + #else + #define __RS485CNT 0 + #endif + + + #if (__RF24CNT + __RFM69CNT + __RFM95CNT + __RS485CNT > 1) #error Only one forward link driver can be activated #endif + #if defined(MY_RADIO_NRF24) #if defined(MY_RF24_ENABLE_ENCRYPTION) #include "drivers/AES/AES.cpp" From fb872fae6707ce11ec067c6d9464efcc2746ae50 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Fri, 25 Nov 2016 14:27:43 +0100 Subject: [PATCH 135/167] Clean up cppcheck suppressions --- tools/cppcheck/suppressions.cfg | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/cppcheck/suppressions.cfg b/tools/cppcheck/suppressions.cfg index 0fac41281..797e9d76b 100644 --- a/tools/cppcheck/suppressions.cfg +++ b/tools/cppcheck/suppressions.cfg @@ -1,5 +1,3 @@ +toomanyconfigs +missingInclude ConfigurationNotChecked -missingInclude:core\MyMainESP8266.cpp -missingInclude:drivers\AltSoftSerial\AltSoftSerial.h -missingInclude:drivers\SPIFlash\SPIFlash.h -missingIncludeSystem From b16839cc5d6a6ef04d57d2bd82901b044aba80a8 Mon Sep 17 00:00:00 2001 From: Olivier Date: Sat, 26 Nov 2016 09:12:55 +0100 Subject: [PATCH 136/167] ESP8266: Reorganize EEPROM handling --- core/MyHwESP8266.cpp | 73 +++++++++++++++----------------------------- core/MyHwESP8266.h | 14 +++------ 2 files changed, 30 insertions(+), 57 deletions(-) diff --git a/core/MyHwESP8266.cpp b/core/MyHwESP8266.cpp index 7901e4dd5..e43fafd8b 100644 --- a/core/MyHwESP8266.cpp +++ b/core/MyHwESP8266.cpp @@ -20,73 +20,50 @@ #include "MyHwESP8266.h" #include -/* -int8_t pinIntTrigger = 0; -void wakeUp() //place to send the interrupts +void hwInit(void) { - pinIntTrigger = 1; -} -void wakeUp2() //place to send the second interrupts -{ - pinIntTrigger = 2; -} - -// Watchdog Timer interrupt service routine. This routine is required -// to allow automatic WDIF and WDIE bit clearance in hardware. -ISR (WDT_vect) -{ - // WDIE & WDIF is cleared in hardware upon entering this ISR - wdt_disable(); -} -*/ - -static void hwInitConfigBlock( size_t length = 1024 /*ATMega328 has 1024 bytes*/ ) -{ - static bool initDone = false; - if (!initDone) - { - EEPROM.begin(length); - initDone = true; - } +#if !defined(MY_DISABLED_SERIAL) + MY_SERIALDEVICE.begin(MY_BAUD_RATE, SERIAL_8N1, MY_ESP8266_SERIAL_MODE, 1); + MY_SERIALDEVICE.setDebugOutput(true); +#endif + EEPROM.begin(EEPROM_size); } -void hwReadConfigBlock(void* buf, void* adr, size_t length) +void hwReadConfigBlock(void* buf, void* addr, size_t length) { - hwInitConfigBlock(); uint8_t* dst = static_cast(buf); - int offs = reinterpret_cast(adr); + int pos = reinterpret_cast(addr); while (length-- > 0) { - *dst++ = EEPROM.read(offs++); + *dst++ = EEPROM.read(pos++); } } -void hwWriteConfigBlock(void* buf, void* adr, size_t length) +void hwWriteConfigBlock(void* buf, void* addr, size_t length) { - hwInitConfigBlock(); - uint8_t* src = static_cast(buf); - int offs = reinterpret_cast(adr); - while (length-- > 0) - { - EEPROM.write(offs++, *src++); - } - EEPROM.commit(); + uint8_t* src = static_cast(buf); + int pos = reinterpret_cast(addr); + bool doCommit = false; + while (length-- > 0) { + doCommit |= EEPROM.read(pos) != *src; + EEPROM.write(pos++, *src++); + } + // only commit if there are changes + if (doCommit) { + EEPROM.commit(); + } } -uint8_t hwReadConfig(int adr) +uint8_t hwReadConfig(const int addr) { uint8_t value; - hwReadConfigBlock(&value, reinterpret_cast(adr), 1); + hwReadConfigBlock(&value, reinterpret_cast(addr), 1); return value; } -void hwWriteConfig(int adr, uint8_t value) +void hwWriteConfig(const int addr, uint8_t value) { - uint8_t curr = hwReadConfig(adr); - if (curr != value) - { - hwWriteConfigBlock(&value, reinterpret_cast(adr), 1); - } + hwWriteConfigBlock(&value, reinterpret_cast(addr), 1); } diff --git a/core/MyHwESP8266.h b/core/MyHwESP8266.h index 3b92169ee..f95ace0bd 100644 --- a/core/MyHwESP8266.h +++ b/core/MyHwESP8266.h @@ -30,27 +30,23 @@ #define min(a,b) ((a)<(b)?(a):(b)) #define max(a,b) ((a)>(b)?(a):(b)) +#define EEPROM_size (1024) + // Define these as macros to save valuable space #define hwDigitalWrite(__pin, __value) digitalWrite(__pin, __value) #define hwDigitalRead(__pin) digitalRead(__pin) #define hwPinMode(__pin, __value) pinMode(__pin, __value) - -#if defined(MY_DISABLED_SERIAL) - #define hwInit() -#else - #define hwInit() MY_SERIALDEVICE.begin(MY_BAUD_RATE, SERIAL_8N1, MY_ESP8266_SERIAL_MODE, 1); MY_SERIALDEVICE.setDebugOutput(true) -#endif - #define hwWatchdogReset() wdt_reset() #define hwReboot() ESP.restart() #define hwMillis() millis() #define hwRandomNumberInit() randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)) +void hwInit(void); void hwReadConfigBlock(void* buf, void* adr, size_t length); void hwWriteConfigBlock(void* buf, void* adr, size_t length); -void hwWriteConfig(int adr, uint8_t value); -uint8_t hwReadConfig(int adr); +void hwWriteConfig(const int addr, uint8_t value); +uint8_t hwReadConfig(const int addr); /** * Restore interrupt state. From cca055fdae5725385c614f230941f8ca8821da12 Mon Sep 17 00:00:00 2001 From: Olivier Date: Sat, 26 Nov 2016 10:05:21 +0100 Subject: [PATCH 137/167] Refine routing table upgrade --- core/MyTransport.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/core/MyTransport.cpp b/core/MyTransport.cpp index 180e93931..d2e0d4b3b 100644 --- a/core/MyTransport.cpp +++ b/core/MyTransport.cpp @@ -592,15 +592,18 @@ void transportProcessMessage(void) { // update routing table if msg not from parent #if defined(MY_REPEATER_FEATURE) #if !defined(MY_GATEWAY_FEATURE) - if (last != _transportConfig.parentNodeId) { + if (last != getParentNodeId()) + { #else - // GW doesn't have parent - { + // GW doesn't have parent + { #endif - // Message is from one of the child nodes. Add it to routing table. - transportSetRoute(sender, last); + // Message is from one of the child nodes and not sent from this node. Add it to routing table. + if (sender != getNodeId()) { + transportSetRoute(sender, last); + } } - #endif + #endif // MY_REPEATER_FEATURE // set message received flag _transportSM.msgReceived = true; From de82269d68b10df1ebba752846ff88986590e4a3 Mon Sep 17 00:00:00 2001 From: tekka007 Date: Sun, 27 Nov 2016 22:57:28 +0100 Subject: [PATCH 138/167] Add DigitalWriteFast support for Atmega1284 --- drivers/AVR/DigitalWriteFast/digitalWriteFast.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/AVR/DigitalWriteFast/digitalWriteFast.h b/drivers/AVR/DigitalWriteFast/digitalWriteFast.h index 555d90305..f90b4f683 100644 --- a/drivers/AVR/DigitalWriteFast/digitalWriteFast.h +++ b/drivers/AVR/DigitalWriteFast/digitalWriteFast.h @@ -56,7 +56,7 @@ (((__pin) == 5 || (__pin) == 6 || (__pin) == 18) ? 3 : \ (((__pin) == 2) ? 4 : \ (((__pin) == 3 || (__pin) == 4) ? 5 : 7))))))))))))))) -#elif defined(__AVR_ATmega644__) || defined(__AVR_ATmega644P__) +#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))) From 6564daec3e66389264783776745e45ccf4ca5a3c Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Mon, 28 Nov 2016 23:57:26 +0100 Subject: [PATCH 139/167] Update the pre-commit git hook (#667) It now supports both Linux and Windows and checks both coding style (astyle) and does static code analysis (cppcheck). Tested using "Bash on Ubuntu on Windows" and the git shell (via GitHub for Windows). Installation is done by executing hooks/install-hooks.sh Windows users has to execute it in a cygwin based git shell. Tools: astyle (2.05.1 or newer) cppcheck (1.76.1 or newer) --- hooks/install-hooks.sh | 21 +++++++++++ hooks/pre-commit.sh | 66 ++++++++++++++++++++++++--------- tools/cppcheck/suppressions.cfg | 2 + 3 files changed, 71 insertions(+), 18 deletions(-) create mode 100755 hooks/install-hooks.sh mode change 100644 => 100755 hooks/pre-commit.sh diff --git a/hooks/install-hooks.sh b/hooks/install-hooks.sh new file mode 100755 index 000000000..3245cba7b --- /dev/null +++ b/hooks/install-hooks.sh @@ -0,0 +1,21 @@ +#!/bin/bash +PRECOMMIT=hooks/pre-commit +GITROOT=$(git rev-parse --git-dir) +if [[ "$OSTYPE" == "linux-gnu" ]]; then + rm -f $GITROOT/$PRECOMMIT + ln -s ../../$PRECOMMIT.sh $GITROOT/$PRECOMMIT +elif [[ "$OSTYPE" == "darwin"* ]]; then + rm -f $GITROOT/$PRECOMMIT + ln -s ../../$PRECOMMIT.sh $GITROOT/$PRECOMMIT +elif [[ "$OSTYPE" == "cygwin" ]]; then + rm -f $GITROOT/$PRECOMMIT + cp $GITROOT/../$PRECOMMIT.sh $GITROOT/$PRECOMMIT +elif [[ "$OSTYPE" == "msys" ]]; then + rm -f $GITROOT/$PRECOMMIT + cp $GITROOT/../$PRECOMMIT.sh $GITROOT/$PRECOMMIT +elif [[ "$OSTYPE" == "freebsd"* ]]; then + rm -f $GITROOT/$PRECOMMIT + ln -s ../../$PRECOMMIT.sh $GITROOT/$PRECOMMIT +else + echo "Unknown/unsupported OS, won't install anything" +fi diff --git a/hooks/pre-commit.sh b/hooks/pre-commit.sh old mode 100644 new mode 100755 index bb725f029..e31904649 --- a/hooks/pre-commit.sh +++ b/hooks/pre-commit.sh @@ -1,27 +1,57 @@ #!/bin/sh +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi -OPTIONS="--options=.astylerc" +OPTIONS="--options=.astylerc -n" +CPPCHECK_OPTIONS="--quiet --error-exitcode=1 --force --enable=style,information --library=avr --platform=tools/cppcheck/avr.xml --includes-file=tools/cppcheck/includes.cfg --suppressions-list=tools/cppcheck/suppressions.cfg" +FILES=$(git diff-index --cached $against | grep -E '[MA] .*\.(c|cpp|h|hpp|ino)$' | cut -d' ' -f 2) RETURN=0 -ASTYLE=astyle +ASTYLE=$(which astyle >/dev/null) if [ $? -ne 0 ]; then - echo "[!] astyle not installed or not in current path. Unable to check source file format policy." >&2 - exit 1 -fi + echo "astyle not installed or not in current path. Unable to check source file format policy. Make sure you have a clean commit, or the CI system will reject your pull request." >&2 +else + ASTYLE=astyle + for FILE in $FILES; do + $ASTYLE $OPTIONS $FILE >/dev/null + $(git diff-files --quiet $FILE) >&2 + if [ $? -ne 0 ]; then + echo "[!] $FILE has been updated to match the MySensors core coding style." >&2 + RETURN=1 + fi + done -FILES=`git diff --name-only --diff-filter=ACMR | grep -E "\.(c|cpp|h|ino)$"` -for FILE in $FILES; do - $ASTYLE $OPTIONS < $FILE | cmp -s $FILE - - if [ $? -ne 0 ]; then - echo "[!] $FILE does not respect the agreed coding style." >&2 - RETURN=1 + if [ $RETURN -ne 0 ]; then + echo "" >&2 + echo "Styling updates applied. Review the changes and use 'git add' to update your staged data." >&2 + exit $RETURN fi -done - -if [ $RETURN -eq 1 ]; then - echo "" >&2 - echo "Make sure you have run astyle with the following options:" >&2 - echo $OPTIONS >&2 fi -exit $RETURN \ No newline at end of file +RETURN=0 +CPPCHECK=$(which cppcheck >/dev/null) +if [ $? -ne 0 ]; then + echo "cppcheck not installed or not in current path. Unable to do static code analysis. Make sure you have a clean commit, or the CI system will reject your pull request." >&2 +else + CPPCHECK=cppcheck + for FILE in $FILES; do + $CPPCHECK $CPPCHECK_OPTIONS $FILE 2>&1 + if [ $? -eq 1 ]; then + echo "[!] $FILE has coding issues." >&2 + RETURN=1 + fi + done + + if [ $RETURN -ne 0 ]; then + echo "" >&2 + echo "Make sure you have run cppcheck 1.76.1 or newer cleanly with the following options:" >&2 + echo $CPPCHECK $CPPCHECK_OPTIONS $FILES >&2 + exit 1 + fi +fi +exit $RETURN diff --git a/tools/cppcheck/suppressions.cfg b/tools/cppcheck/suppressions.cfg index 797e9d76b..57465da1e 100644 --- a/tools/cppcheck/suppressions.cfg +++ b/tools/cppcheck/suppressions.cfg @@ -1,3 +1,5 @@ toomanyconfigs missingInclude +missingIncludeSystem ConfigurationNotChecked +unmatchedSuppression From ea65c5b1503eaeb3ff161e1aeeade862a0a9a5d7 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Tue, 29 Nov 2016 11:18:49 +0100 Subject: [PATCH 140/167] Move Doxyfile to repository root (#674) This makes most tools/plugins for Doxygen work without much adjustment. Also resolved some Doxygen warnings. --- Documentation/Doxyfile => Doxyfile | 0 MyConfig.h | 1 - core/MySensorsCore.h | 1 - .../SecurityPersonalizer/sha204_library.h | 173 +++++++++++++++--- 4 files changed, 150 insertions(+), 25 deletions(-) rename Documentation/Doxyfile => Doxyfile (100%) diff --git a/Documentation/Doxyfile b/Doxyfile similarity index 100% rename from Documentation/Doxyfile rename to Doxyfile diff --git a/MyConfig.h b/MyConfig.h index 2addec27d..9a9f31706 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -951,7 +951,6 @@ #define MY_TRANSPORT_UPLINK_CHECK_DISABLED #define MY_DEBUG_VERBOSE_RF24 #define MY_TRANSPORT_SANITY_CHECK -#define MY_RF24_IRQ_PIN #define MY_RX_MESSAGE_BUFFER_FEATURE #define MY_RX_MESSAGE_BUFFER_SIZE #define MY_NODE_LOCK_FEATURE diff --git a/core/MySensorsCore.h b/core/MySensorsCore.h index cf5c9f4d6..7eda5d15f 100644 --- a/core/MySensorsCore.h +++ b/core/MySensorsCore.h @@ -335,7 +335,6 @@ int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep = false, const ui /** * @ingroup MyLockgrp - * @ingroup internals * @brief Lock a node and transmit provided message with 30m intervals * * This function is called if suspicious activity has exceeded the threshold (see diff --git a/examples/SecurityPersonalizer/sha204_library.h b/examples/SecurityPersonalizer/sha204_library.h index c22f9edd1..e9682bb46 100644 --- a/examples/SecurityPersonalizer/sha204_library.h +++ b/examples/SecurityPersonalizer/sha204_library.h @@ -260,7 +260,7 @@ #define SHA204_COMMAND_EXEC_MAX ((uint8_t) (69.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) //! maximum command delay #define SHA204_CMD_SIZE_MIN ((uint8_t) 7) //! minimum number of bytes in command (from count byte to second CRC byte) #ifndef SHA204_CMD_SIZE_MAX -#define SHA204_CMD_SIZE_MAX ((uint8_t) 84) //! maximum size of command packet (CheckMac) + #define SHA204_CMD_SIZE_MAX ((uint8_t) 84) //! maximum size of command packet (CheckMac) #endif #define SHA204_CRC_SIZE ((uint8_t) 2) //! number of CRC bytes #define SHA204_BUFFER_POS_STATUS (1) //! buffer index of status byte in status response @@ -284,26 +284,29 @@ /* Low level HW access macros */ /* function calls is not working, as it will have too much overhead */ #if !defined(ARDUINO_ARCH_AVR) // For everything else than AVR use pinMode / digitalWrite -#define SHA204_SET_OUTPUT() pinMode(device_pin, OUTPUT) -#define SHA204_SET_INPUT() pinMode(device_pin, INPUT) -#define SHA204_POUT_HIGH() digitalWrite(device_pin, HIGH) -#define SHA204_POUT_LOW() digitalWrite(device_pin, LOW) -#define SHA204_PIN_READ() digitalRead(device_pin) + #define SHA204_SET_OUTPUT() pinMode(device_pin, OUTPUT) + #define SHA204_SET_INPUT() pinMode(device_pin, INPUT) + #define SHA204_POUT_HIGH() digitalWrite(device_pin, HIGH) + #define SHA204_POUT_LOW() digitalWrite(device_pin, LOW) + #define SHA204_PIN_READ() digitalRead(device_pin) #else -#define SHA204_SET_INPUT() *device_port_DDR &= ~device_pin -#define SHA204_SET_OUTPUT() *device_port_DDR |= device_pin -#define SHA204_POUT_HIGH() *device_port_OUT |= device_pin -#define SHA204_POUT_LOW() *device_port_OUT &= ~device_pin -#define SHA204_PIN_READ() (*device_port_IN & device_pin) + #define SHA204_SET_INPUT() *device_port_DDR &= ~device_pin + #define SHA204_SET_OUTPUT() *device_port_DDR |= device_pin + #define SHA204_POUT_HIGH() *device_port_OUT |= device_pin + #define SHA204_POUT_LOW() *device_port_OUT &= ~device_pin + #define SHA204_PIN_READ() (*device_port_IN & device_pin) #endif +/** + * atsha204Class class + */ class atsha204Class { private: uint8_t device_pin; - #ifdef ARDUINO_ARCH_AVR +#ifdef ARDUINO_ARCH_AVR volatile uint8_t *device_port_DDR, *device_port_OUT, *device_port_IN; - #endif +#endif void sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc); uint8_t sha204c_check_crc(uint8_t *response); void swi_set_signal_pin(uint8_t is_high); @@ -315,26 +318,150 @@ class atsha204Class uint8_t sha204p_send_command(uint8_t count, uint8_t * command); uint8_t sha204p_sleep(); uint8_t sha204p_resync(uint8_t size, uint8_t *response); - + public: - atsha204Class(uint8_t pin); // Constructor + /** + * @brief Constructor + * + * @param[in] pin The pin to use for communication + */ + atsha204Class(uint8_t pin); + + /** + * @brief Wake up device + * + * @param response The response from the device + * + * @return Error code (SHA204_SUCCESS if OK) + */ uint8_t sha204c_wakeup(uint8_t *response); - uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout); - uint8_t sha204c_resync(uint8_t size, uint8_t *response); + + /** + * @brief Send and receive data + * + * @param tx_buffer The transmit buffer + * @param[in] rx_size The receive size + * @param rx_buffer The receive buffer + * @param[in] execution_delay The execution delay + * @param[in] execution_timeout The execution timeout + * + * @return Error code (SHA204_SUCCESS if OK) + */ + uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, + uint8_t execution_delay, uint8_t execution_timeout); + + /** + * @brief Resyncronize the device + * + * @param[in] size The size of the response buffer + * @param response The response + * + * @return Error code (SHA204_SUCCESS if OK) + */ + uint8_t sha204c_resync(uint8_t size, uint8_t *response); + + /** + * @brief Generate random data + * + * @param tx_buffer The transmit buffer + * @param rx_buffer The receive buffer + * @param[in] mode The mode + * + * @return Error code (SHA204_SUCCESS if OK) + */ uint8_t sha204m_random(uint8_t * tx_buffer, uint8_t * rx_buffer, uint8_t mode); + + /** + * @brief Read device revision + * + * @param tx_buffer The transmit buffer + * @param rx_buffer The receive buffer + * + * @return Error code (SHA204_SUCCESS if OK) + */ uint8_t sha204m_dev_rev(uint8_t *tx_buffer, uint8_t *rx_buffer); + + /** + * @brief Read from device + * + * @param tx_buffer The transmit buffer + * @param rx_buffer The receive buffer + * @param[in] zone The zone + * @param[in] address The address + * + * @return Error code (SHA204_SUCCESS if OK) + */ uint8_t sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address); + + /** + * @brief Execute command + * + * @param[in] op_code The operation code + * @param[in] param1 The parameter 1 + * @param[in] param2 The parameter 2 + * @param[in] datalen1 The datalen 1 + * @param data1 The data 1 + * @param[in] datalen2 The datalen 2 + * @param data2 The data 2 + * @param[in] datalen3 The datalen 3 + * @param data3 The data 3 + * @param[in] tx_size The transmit size + * @param tx_buffer The transmit buffer + * @param[in] rx_size The receive size + * @param rx_buffer The receive buffer + * + * @return Error code (SHA204_SUCCESS if OK) + */ uint8_t sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t param2, - uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3, - uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer); + uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, + uint8_t *data3, + uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer); + + /** + * @brief Validate parameters + * + * @param[in] op_code The operation code + * @param[in] param1 The parameter 1 + * @param[in] param2 The parameter 2 + * @param[in] datalen1 The datalen 1 + * @param data1 The data 1 + * @param[in] datalen2 The datalen 2 + * @param data2 The data 2 + * @param[in] datalen3 The datalen 3 + * @param data3 The data 3 + * @param[in] tx_size The transmit size + * @param tx_buffer The transmit buffer + * @param[in] rx_size The receive size + * @param rx_buffer The receive buffer + * + * @return Error code (SHA204_SUCCESS if OK) + */ uint8_t sha204m_check_parameters(uint8_t op_code, uint8_t param1, uint16_t param2, - uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3, - uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer); - + uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, + uint8_t *data3, + uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer); + + /** + * @brief Gets the serial number. + * + * @param response The response + * + * @return The serial number + */ uint8_t getSerialNumber(uint8_t *response); + + /** + * @brief Calculates and update crc. + * + * @param[in] length The length + * @param data The data + * @param[in] current_crc The current crc + * + * @return The updated crc + */ uint16_t calculateAndUpdateCrc(uint8_t length, uint8_t *data, uint16_t current_crc); - + }; #endif From 65bece33fde6e0cf1b8fb4271c1e4b24aa0d30a6 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Fri, 2 Dec 2016 21:26:50 +0100 Subject: [PATCH 141/167] Add a SublimeText 3 MySensors project (#676) Various plugins exist to enhance the experience. The project file contain references for all plugins it holds configurations for. --- .gitignore | 1 + .../SublimeText/MySensors.sublime-project | 154 ++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 projects/SublimeText/MySensors.sublime-project diff --git a/.gitignore b/.gitignore index 02d191025..c99392e32 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ doxygen_sqlite3.db Makefile.inc build bin +*.sublime-workspace diff --git a/projects/SublimeText/MySensors.sublime-project b/projects/SublimeText/MySensors.sublime-project new file mode 100644 index 000000000..8b2d26847 --- /dev/null +++ b/projects/SublimeText/MySensors.sublime-project @@ -0,0 +1,154 @@ +{ + "folders": + [ + { + "path": "..\\..\\" + } + ], + "settings": + { + // Plugins that are nice to have but does not require any project specific settings: + // PackageControl (https://packagecontrol.io/installation) Practically mandatory if you indend to install plugins + // EditorConfig (https://github.com/sindresorhus/editorconfig-sublime) Automatically apply the default MySensors file encoding and settings + // DoxyDoxygen (https://github.com/20Tauri/DoxyDoxygen) Helps writig Doxygen tags and allows to generate documentation + // BracketHighlighter (https://github.com/facelessuser/BracketHighlighter) Highlights any type of brackets and provides easy navigation between them + // GitGutter (https://github.com/jisaacks/GitGutter) Provides access to file diffs through the gutter area + // OpenInclude (https://github.com/titoBouzout/Open-Include) Allows opening header files found in project without having to look them up + // SideBarEnhancements (https://github.com/SideBarEnhancements-org/SideBarEnhancements) Enhances the sidebar + // SyncedSideBar (https://github.com/TheSpyder/SyncedSideBar) Syncs the sidebar to the currently opened file + + // EasyClangComplete is a clang based plugin that provides autocompletion features. + // Installation instructions is available here: https://github.com/niosus/EasyClangComplete + "ecc_errors_on_save": false, // disable clang error checking since it is hard to figure out the standard library locations and this gives many false positives + + // MySensors core library uses some coding style rules. Artistic Style can be used to format the code according to these rules + // The below settings enable automatic formatting of the code upon saving in Sublime Text + // Artistic Style is avaliable here: http://astyle.sourceforge.net + // The plugin is available here: https://github.com/timonwong/SublimeAStyleFormatter + // The coding style is documented here: https://www.mysensors.org/download/contributing + "AStyleFormatter": + { + "debug": true, + "autoformat_on_save": false, + "options_c": + { + "additional_options_file": "$project_path/../../.astylerc", + "use_only_additional_options": true + }, + "options_c++": + { + "additional_options_file": "$project_path/../../.astylerc", + "use_only_additional_options": true + }, + }, + }, + // MySensors core library uses cppcheck to do static code analysis. + // The below settings enable cppcheck as a linter for automatic code analysis during development. + // cppcheck is avaliable here: http://cppcheck.sourceforge.net + // The plugin is available here: https://github.com/SublimeLinter/SublimeLinter-cppcheck + // The framework for the plugin is available here: https://sublimelinter.readthedocs.io/en/latest/installation.html + "SublimeLinter": + { + "linters": + { + "cppcheck": + { + "@disable": false, + "args": ["--force", "--library=avr"], + "enable": "style,information", + "excludes": [], + "std": [] + }, + } + }, + + // The project defines build targets for all Arduino based boards supported by MySensors. + // The plugin needed to do the build (which require the Arduino IDE to be installed) is + // available here: https://github.com/jacobrosenthal/arduino-cli + "build_systems": + [ + { + "name": "MySensors", + "file_regex": "^(?'filename'.*.ino).*$", + "line_regex": "^.*:(?'line number'[0-9]+)(: )(?'error message'.*)$", + "selector": "source.arduino", + "shell": true, + "target": "arduinocli", + "variants": + [ + { + "cmd": ["--board","MySensors:samd:mysensors_gw_native","--verify","$file"], + "name": "just build (SenseBenderGW)" + }, + { + "cmd": ["--board","MySensors:samd:mysensors_gw_native","--upload","$file"], + "name": "build and upload (SenseBenderGW)" + }, + { + "cmd": ["--board","MySensors:avr:MysensorsMicro:cpu=8Mhz","--verify","$file"], + "name": "just build (SenseBenderMicro 8Mhz)" + }, + { + "cmd": ["--board","MySensors:avr:MysensorsMicro:cpu=8Mhz","--upload","$file"], + "name": "build and upload (SenseBenderMicro 8Mhz)" + }, + { + "cmd": ["--board","MySensors:avr:MysensorsMicro:cpu=1Mhz","--verify","$file"], + "name": "just build (SenseBenderMicro 1Mhz)" + }, + { + "cmd": ["--board","MySensors:avr:MysensorsMicro:cpu=1Mhz","--upload","$file"], + "name": "build and upload (SenseBenderMicro 1Mhz)" + }, + { + "cmd": ["--board","arduino:avr:pro:cpu=8MHzatmega328","--verify","$file"], + "name": "just build (ArduinoProMini 3.3V)" + }, + { + "cmd": ["--board","arduino:avr:pro:cpu=8MHzatmega328","--upload","$file"], + "name": "build and upload (ArduinoProMini 3.3V)" + }, + { + "cmd": ["--board","arduino:avr:pro:cpu=16MHzatmega328","--verify","$file"], + "name": "just build (ArduinoProMini 5V)" + }, + { + "cmd": ["--board","arduino:avr:pro:cpu=16MHzatmega328","--upload","$file"], + "name": "build and upload (ArduinoProMini 5V)" + }, + { + "cmd": ["--board","arduino:avr:nano:cpu=atmega328","--verify","$file"], + "name": "just build (ArduinoNano)" + }, + { + "cmd": ["--board","arduino:avr:nano:cpu=atmega328","--upload","$file"], + "name": "build and upload (ArduinoNano)" + }, + { + "cmd": ["--board","arduino:avr:uno","--verify","$file"], + "name": "just build (ArduinoUno)" + }, + { + "cmd": ["--board","arduino:avr:uno","--upload","$file"], + "name": "build and upload (ArduinoUno)" + }, + { + "cmd": ["--board","arduino:avr:mega:cpu=atmega2560","--verify","$file"], + "name": "just build (ArduinoMega)" + }, + { + "cmd": ["--board","arduino:avr:mega:cpu=atmega2560","--upload","$file"], + "name": "build and upload (ArduinoMega)" + }, + { + "cmd": ["--board","esp8266:esp8266:generic:CpuFrequency=80,FlashFreq=40,FlashMode=dio,UploadSpeed=115200,FlashSize=512K64,ResetMethod=ck,Debug=Disabled,DebugLevel=None____","--verify","$file"], + "name": "just build (ESP8266)" + }, + { + "cmd": ["--board","esp8266:esp8266:generic:CpuFrequency=80,FlashFreq=40,FlashMode=dio,UploadSpeed=115200,FlashSize=512K64,ResetMethod=ck,Debug=Disabled,DebugLevel=None____","--upload","$file"], + "name": "build and upload (ESP8266)" + }, + ] + } + ], +} From 3570a507a65ed83f4890ae831a24d354449fd5cc Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Sat, 3 Dec 2016 15:57:23 +0100 Subject: [PATCH 142/167] Fix regression MY_NODE_ID (#669) --- core/MyTransport.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/MyTransport.cpp b/core/MyTransport.cpp index d2e0d4b3b..9c508b4b4 100644 --- a/core/MyTransport.cpp +++ b/core/MyTransport.cpp @@ -98,13 +98,13 @@ void stInitUpdate(void) { // GW mode: skip FPAR,ID,UPL states transportSwitchSM(stReady); #else - #if MY_NODE_ID != AUTO + if (MY_NODE_ID != AUTO) { TRANSPORT_DEBUG(PSTR("TSM:INIT:STATID=%d\n"),(uint8_t)MY_NODE_ID); // Set static ID _transportConfig.nodeId = (uint8_t)MY_NODE_ID; // Save static ID to eeprom (for bootloader) hwWriteConfig(EEPROM_NODE_ID_ADDRESS, (uint8_t)MY_NODE_ID); - #endif + } // assign ID if set if (_transportConfig.nodeId == AUTO || transportAssignNodeID(_transportConfig.nodeId)) { // if node ID valid (>0 and <255), proceed to next state From 0fe9df1a77cb50dbfff64ef1657dda2d2b767d9e Mon Sep 17 00:00:00 2001 From: Bram Oosterhuis Date: Sat, 3 Dec 2016 16:25:25 +0100 Subject: [PATCH 143/167] Buildroot integration possible using autotools * Add option to not install a init script * Added autotools default install prefix * Add autotools ${DESTDIR} to the install paths * Add option to specify platform type --- Makefile | 12 ++++++------ configure | 18 +++++++++++++++++- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index d307e3220..742dd82d0 100644 --- a/Makefile +++ b/Makefile @@ -119,21 +119,21 @@ $(CONFIG_FILE): install: all install-gateway install-initscripts install-gateway: - @echo "Installing $(GATEWAY) to $(GATEWAY_DIR)" - @install -m 0755 $(GATEWAY) $(GATEWAY_DIR) + @echo "Installing $(GATEWAY) to ${DESTDIR}$(GATEWAY_DIR)" + @install -m 0755 $(GATEWAY) ${DESTDIR}$(GATEWAY_DIR) install-initscripts: ifeq ($(INIT_SYSTEM), systemd) - install -m0644 initscripts/mysgw.systemd /etc/systemd/system/mysgw.service - @sed -i -e "s|%gateway_dir%|${GATEWAY_DIR}|g" /etc/systemd/system/mysgw.service + install -m0644 initscripts/mysgw.systemd ${DESTDIR}/etc/systemd/system/mysgw.service + @sed -i -e "s|%gateway_dir%|${GATEWAY_DIR}|g" ${DESTDIR}/etc/systemd/system/mysgw.service systemctl daemon-reload @echo "MySensors gateway has been installed, to add to the boot run:" @echo " sudo systemctl enable mysgw.service" @echo "To start the gateway run:" @echo " sudo systemctl start mysgw.service" else ifeq ($(INIT_SYSTEM), sysvinit) - install -m0755 initscripts/mysgw.sysvinit /etc/init.d/mysgw - @sed -i -e "s|%gateway_dir%|${GATEWAY_DIR}|g" /etc/init.d/mysgw + install -m0755 initscripts/mysgw.sysvinit ${DESTDIR}/etc/init.d/mysgw + @sed -i -e "s|%gateway_dir%|${GATEWAY_DIR}|g" ${DESTDIR}/etc/init.d/mysgw @echo "MySensors gateway has been installed, to add to the boot run:" @echo " sudo update-rc.d mysgw defaults" @echo "To start the gateway run:" diff --git a/configure b/configure index 9ec9fc003..c47b1865d 100755 --- a/configure +++ b/configure @@ -14,6 +14,7 @@ Help: Building options: --soc=[BCM2835|BCM2836|AM33XX|A10|A13|A20|H3] SoC type to be used. [configure autodetected] + --platform-type= Type of platform --cpu-flags= CPU defining/optimizing flags to be used. [configure autodetected] --extra-cflags= Extra C flags passed to C compilation. [] --extra-cxxflags= Extra C++ flags passed to C++ compilation. [] @@ -238,6 +239,9 @@ for opt do --soc=*) SOC="$optarg" ;; + --platform-type=*) + PT="$optarg" + ;; --cpu-flags=*) CPUFLAGS="$optarg" ;; @@ -271,6 +275,12 @@ for opt do --prefix=*) PREFIX="$optarg" ;; + --exec-prefix=*) + PREFIX="$optarg" + ;; + --no_init_system*) + NO_INIT="1" + ;; --gateway-dir=*) GATEWAY_DIR="$optarg" ;; @@ -403,6 +413,10 @@ if [ -z "${SOC}" ]; then echo "[OK] machine detected: SoC=${SOC}, Type=${TYPE}, CPU=${CPU}, REV=${REV}." fi +if [ "${PT}" ]; then + TYPE=${PT} +fi + if [ -z "${CPUFLAGS}" ]; then CPUFLAGS=$(gcc_cpu_flags $SOC) fi @@ -466,7 +480,9 @@ fi LDFLAGS="-pthread $LDFLAGS" CPPFLAGS="$CPUFLAGS $CPPFLAGS" -if [ -x /usr/bin/systemctl ] || [ -x /bin/systemctl ]; then +if [ "${NO_INIT}" ]; then + echo "[OK] no init system chosen." +elif [ -x /usr/bin/systemctl ] || [ -x /bin/systemctl ]; then INIT_SYSTEM=systemd echo "[OK] init system detected: systemd" elif [ -f /etc/init.d/cron ] && [ ! -h /etc/init.d/cron ]; then From f59be0aa2a350e6be8e4dd4947c0ce8734df88fe Mon Sep 17 00:00:00 2001 From: Olivier Date: Sat, 3 Dec 2016 16:53:36 +0100 Subject: [PATCH 144/167] ESP8266: remove redundant EEPROM check (#668) --- core/MyHwESP8266.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/core/MyHwESP8266.cpp b/core/MyHwESP8266.cpp index e43fafd8b..c4d39d141 100644 --- a/core/MyHwESP8266.cpp +++ b/core/MyHwESP8266.cpp @@ -43,15 +43,11 @@ void hwWriteConfigBlock(void* buf, void* addr, size_t length) { uint8_t* src = static_cast(buf); int pos = reinterpret_cast(addr); - bool doCommit = false; while (length-- > 0) { - doCommit |= EEPROM.read(pos) != *src; EEPROM.write(pos++, *src++); } - // only commit if there are changes - if (doCommit) { - EEPROM.commit(); - } + // see implementation, commit only executed if diff + EEPROM.commit(); } uint8_t hwReadConfig(const int addr) From fdbb285deeb640c1ad35f29a04b075df517316ba Mon Sep 17 00:00:00 2001 From: Olivier Date: Tue, 6 Dec 2016 15:45:27 +0100 Subject: [PATCH 145/167] Fix payload length verification (#680) --- core/MyTransport.cpp | 7 ++++++- core/MyTransportNRF24.cpp | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/core/MyTransport.cpp b/core/MyTransport.cpp index 9c508b4b4..5d3a1ca86 100644 --- a/core/MyTransport.cpp +++ b/core/MyTransport.cpp @@ -554,11 +554,16 @@ void transportProcessMessage(void) { (void)signerCheckTimer(); // receive message setIndication(INDICATION_RX); - const uint8_t payloadLength = transportReceive((uint8_t *)&_msg); + uint8_t payloadLength = transportReceive((uint8_t *)&_msg); // get message length and limit size + const uint8_t msgLength = min(mGetLength(_msg), (uint8_t)MAX_PAYLOAD); // calculate expected length const uint8_t expectedMessageLength = HEADER_SIZE + (mGetSigned(_msg) ? MAX_PAYLOAD : msgLength); +#if defined(MY_RF24_ENABLE_ENCRYPTION) + // payload length = a multiple of blocksize length for decrypted messages, i.e. cannot be used for payload length check + payloadLength = expectedMessageLength; +#endif const uint8_t command = mGetCommand(_msg); const uint8_t type = _msg.type; const uint8_t sender = _msg.sender; diff --git a/core/MyTransportNRF24.cpp b/core/MyTransportNRF24.cpp index 9a21a25a1..e1d6ba4bc 100644 --- a/core/MyTransportNRF24.cpp +++ b/core/MyTransportNRF24.cpp @@ -141,7 +141,9 @@ uint8_t transportReceive(void* data) // has to be adjusted, WIP! _aes.set_IV(0); // decrypt data - _aes.cbc_decrypt((byte*)(data), (byte*)(data), len>16?2:1); + if (_aes.cbc_decrypt((uint8_t*)(data), (uint8_t*)(data), len > 16 ? 2 : 1) != AES_SUCCESS) { + len = 0; + } #endif return len; } From 62b74bb88a567d46d119d2fde244d2ed57fa241d Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Wed, 7 Dec 2016 18:17:59 -0200 Subject: [PATCH 146/167] RPi: Improve board revision detection (#681) Revision detection is done at runtime, the configure script has been simplified to reflect this. --- configure | 18 +--- core/MyHwRPi.h | 1 + drivers/RPi/cpuinfo.c | 216 +++++++++++++++++++++++++++++++++++++++ drivers/RPi/cpuinfo.h | 48 +++++++++ drivers/RPi/rpi_util.cpp | 122 ++++++++++------------ drivers/RPi/rpi_util.h | 8 +- 6 files changed, 326 insertions(+), 87 deletions(-) create mode 100644 drivers/RPi/cpuinfo.c create mode 100644 drivers/RPi/cpuinfo.h diff --git a/configure b/configure index c47b1865d..7fee365a8 100755 --- a/configure +++ b/configure @@ -14,7 +14,6 @@ Help: Building options: --soc=[BCM2835|BCM2836|AM33XX|A10|A13|A20|H3] SoC type to be used. [configure autodetected] - --platform-type= Type of platform --cpu-flags= CPU defining/optimizing flags to be used. [configure autodetected] --extra-cflags= Extra C flags passed to C compilation. [] --extra-cxxflags= Extra C++ flags passed to C++ compilation. [] @@ -109,7 +108,6 @@ function detect_machine { fi local soc="unknown" local tp="unknown" - local rev="unknown" if [ -z "$cpu" ]; then cpu="unknown" @@ -120,13 +118,12 @@ function detect_machine { soc="BCM2835" if [[ $machine == "Raspberry"* ]]; then tp="RPi" - rev=($(detect_rpi_revision)) fi ;; BCM2709) soc="BCM2836" if [[ $machine == "Raspberry"* ]]; then - rev=($(detect_rpi_revision)) + local rev=($(detect_rpi_revision)) if [[ $rev == "a02082" || $rev == "a22082" ]]; then tp="RPi3" else @@ -187,7 +184,7 @@ function detect_machine { *) soc="unknown" esac - echo "${soc} ${tp} ${cpu} ${rev}" + echo "${soc} ${tp} ${cpu}" } function gcc_cpu_flags { @@ -409,12 +406,7 @@ if [ -z "${SOC}" ]; then SOC=${info[0]} TYPE=${info[1]} CPU=${info[2]} - REV=${info[3]} - echo "[OK] machine detected: SoC=${SOC}, Type=${TYPE}, CPU=${CPU}, REV=${REV}." -fi - -if [ "${PT}" ]; then - TYPE=${PT} + echo "[OK] machine detected: SoC=${SOC}, Type=${TYPE}, CPU=${CPU}." fi if [ -z "${CPUFLAGS}" ]; then @@ -425,10 +417,6 @@ if [[ $SOC == "BCM2835" || $SOC == "BCM2836" ]]; then CPPFLAGS="-DLINUX_ARCH_RASPBERRYPI $CPPFLAGS" fi -if [[ $TYPE == "RPi2" || $TYPE == "RPi3" || $REV == "0010" ]]; then - CPPFLAGS="-D__RPI_BPLUS $CPPFLAGS" -fi - if [[ ${debug} == "enable" ]]; then CPPFLAGS="-DMY_DEBUG $CPPFLAGS" fi diff --git a/core/MyHwRPi.h b/core/MyHwRPi.h index 2252a22ab..a4f3c6426 100644 --- a/core/MyHwRPi.h +++ b/core/MyHwRPi.h @@ -20,6 +20,7 @@ #ifndef MyHwRPi_h #define MyHwRPi_h +#include #include #include "MyHwLinuxGeneric.h" #include "log.h" diff --git a/drivers/RPi/cpuinfo.c b/drivers/RPi/cpuinfo.c new file mode 100644 index 000000000..5fa48dcd3 --- /dev/null +++ b/drivers/RPi/cpuinfo.c @@ -0,0 +1,216 @@ +/* +Copyright (c) 2012-2016 Ben Croston + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "cpuinfo.h" +#include +#include +#include + +int get_rpi_info(rpi_info *info) +{ + FILE *fp; + char buffer[1024]; + char hardware[1024]; + char revision[1024]; + char *rev; + int found = 0; + int len; + + if ((fp = fopen("/proc/cpuinfo", "r")) == NULL) + return -1; + while(!feof(fp)) { + fgets(buffer, sizeof(buffer), fp); + sscanf(buffer, "Hardware : %s", hardware); + if (strcmp(hardware, "BCM2708") == 0 || + strcmp(hardware, "BCM2709") == 0 || + strcmp(hardware, "BCM2835") == 0 || + strcmp(hardware, "BCM2836") == 0 || + strcmp(hardware, "BCM2837") == 0 ) { + found = 1; + } + sscanf(buffer, "Revision : %s", revision); + } + fclose(fp); + + if (!found) + return -1; + + if ((len = strlen(revision)) == 0) + return -1; + + if (len >= 6 && strtol((char[]){revision[len-6],0}, NULL, 16) & 8) { + // new scheme + //info->rev = revision[len-1]-'0'; + strcpy(info->revision, revision); + switch (revision[len-2]) { + case '0': info->type = "Model A"; info->p1_revision = 2; break; + case '1': info->type = "Model B"; info->p1_revision = 2; break; + case '2': info->type = "Model A+"; info->p1_revision = 3; break; + case '3': info->type = "Model B+"; info->p1_revision = 3; break; + case '4': info->type = "Pi 2 Model B"; info->p1_revision = 3; break; + case '5': info->type = "Alpha"; info->p1_revision = 3; break; + case '6': info->type = "Compute"; info->p1_revision = 0; break; + case '8': info->type = "Pi 3 Model B"; info->p1_revision = 3; break; + case '9': info->type = "Zero"; info->p1_revision = 3; break; + default : info->type = "Unknown"; info->p1_revision = 3; break; + } + switch (revision[len-4]) { + case '0': info->processor = "BCM2835"; break; + case '1': info->processor = "BCM2836"; break; + case '2': info->processor = "BCM2837"; break; + default : info->processor = "Unknown"; break; + } + switch (revision[len-5]) { + case '0': info->manufacturer = "Sony"; break; + case '1': info->manufacturer = "Egoman"; break; + case '2': info->manufacturer = "Embest"; break; + case '4': info->manufacturer = "Embest"; break; + default : info->manufacturer = "Unknown"; break; + } + switch (strtol((char[]){revision[len-6],0}, NULL, 16) & 7) { + case 0: info->ram = "256M"; break; + case 1: info->ram = "512M"; break; + case 2: info->ram = "1024M"; break; + default: info->ram = "Unknown"; break; + } + } else { + // old scheme + info->ram = "Unknown"; + info->manufacturer = "Unknown"; + info->processor = "Unknown"; + info->type = "Unknown"; + strcpy(info->revision, revision); + + // get last four characters (ignore preceeding 1000 for overvolt) + if (len > 4) + rev = (char *)&revision+len-4; + else + rev = revision; + + if ((strcmp(rev, "0002") == 0) || + (strcmp(rev, "0003") == 0)) { + info->type = "Model B"; + info->p1_revision = 1; + info->ram = "256M"; + info->processor = "BCM2835"; + } else if (strcmp(rev, "0004") == 0) { + info->type = "Model B"; + info->p1_revision = 2; + info->ram = "256M"; + info->manufacturer = "Sony"; + info->processor = "BCM2835"; + } else if (strcmp(rev, "0005") == 0) { + info->type = "Model B"; + info->p1_revision = 2; + info->ram = "256M"; + info->manufacturer = "Qisda"; + info->processor = "BCM2835"; + } else if (strcmp(rev, "0006") == 0) { + info->type = "Model B"; + info->p1_revision = 2; + info->ram = "256M"; + info->manufacturer = "Egoman"; + info->processor = "BCM2835"; + } else if (strcmp(rev, "0007") == 0) { + info->type = "Model A"; + info->p1_revision = 2; + info->ram = "256M"; + info->manufacturer = "Egoman"; + info->processor = "BCM2835"; + } else if (strcmp(rev, "0008") == 0) { + info->type = "Model A"; + info->p1_revision = 2; + info->ram = "256M"; + info->manufacturer = "Sony"; + info->processor = "BCM2835"; + } else if (strcmp(rev, "0009") == 0) { + info->type = "Model A"; + info->p1_revision = 2; + info->ram = "256M"; + info->manufacturer = "Qisda"; + info->processor = "BCM2835"; + } else if (strcmp(rev, "000d") == 0) { + info->type = "Model B"; + info->p1_revision = 2; + info->ram = "512M"; + info->manufacturer = "Egoman"; + info->processor = "BCM2835"; + } else if (strcmp(rev, "000e") == 0) { + info->type = "Model B"; + info->p1_revision = 2; + info->ram = "512M"; + info->manufacturer = "Sony"; + info->processor = "BCM2835"; + } else if (strcmp(rev, "000f") == 0) { + info->type = "Model B"; + info->p1_revision = 2; + info->ram = "512M"; + info->manufacturer = "Qisda"; + info->processor = "BCM2835"; + } else if ((strcmp(rev, "0011") == 0) || + (strcmp(rev, "0014") == 0)) { + info->type = "Compute Module"; + info->p1_revision = 0; + info->ram = "512M"; + info->processor = "BCM2835"; + } else if (strcmp(rev, "0012") == 0) { + info->type = "Model A+"; + info->p1_revision = 3; + info->ram = "256M"; + info->processor = "BCM2835"; + } else if ((strcmp(rev, "0010") == 0) || + (strcmp(rev, "0013") == 0)) { + info->type = "Model B+"; + info->p1_revision = 3; + info->ram = "512M"; + info->processor = "BCM2835"; + } else { // don't know - assume revision 3 p1 connector + info->p1_revision = 3; + } + } + return 0; +} + +/* + +32 bits +NEW 23: will be 1 for the new scheme, 0 for the old scheme +MEMSIZE 20: 0=256M 1=512M 2=1G +MANUFACTURER 16: 0=SONY 1=EGOMAN +PROCESSOR 12: 0=2835 1=2836 +TYPE 04: 0=MODELA 1=MODELB 2=MODELA+ 3=MODELB+ 4=Pi2 MODEL B 5=ALPHA 6=CM +REV 00: 0=REV0 1=REV1 2=REV2 + +pi2 = 1<<23 | 2<<20 | 1<<12 | 4<<4 = 0xa01040 + +-------------------- + +SRRR MMMM PPPP TTTT TTTT VVVV + +S scheme (0=old, 1=new) +R RAM (0=256, 1=512, 2=1024) +M manufacturer (0='SONY',1='EGOMAN',2='EMBEST',3='UNKNOWN',4='EMBEST') +P processor (0=2835, 1=2836 2=2837) +T type (0='A', 1='B', 2='A+', 3='B+', 4='Pi 2 B', 5='Alpha', 6='Compute Module') +V revision (0-15) + +*/ diff --git a/drivers/RPi/cpuinfo.h b/drivers/RPi/cpuinfo.h new file mode 100644 index 000000000..b3c43fe33 --- /dev/null +++ b/drivers/RPi/cpuinfo.h @@ -0,0 +1,48 @@ +/* +Copyright (c) 2012-2015 Ben Croston + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef CPUINFO_H +#define CPUINFO_H +#if !DOXYGEN + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + int p1_revision; + char *ram; + char *manufacturer; + char *processor; + char *type; + char revision[1024]; +} rpi_info; + +int get_rpi_info(rpi_info *info); + +#ifdef __cplusplus +} +#endif + +#endif +#endif /* CPUINFO_H */ diff --git a/drivers/RPi/rpi_util.cpp b/drivers/RPi/rpi_util.cpp index 08885543d..f3ea8fe3d 100644 --- a/drivers/RPi/rpi_util.cpp +++ b/drivers/RPi/rpi_util.cpp @@ -19,6 +19,7 @@ * Based on wiringPi Copyright (c) 2012 Gordon Henderson. */ +#include "rpi_util.h" #include #include #include @@ -31,9 +32,9 @@ #include #include #include -#include "rpi_util.h" #include "SPI.h" #include "log.h" +#include "cpuinfo.h" extern "C" { int piHiPri(const int pri); @@ -44,6 +45,9 @@ struct ThreadArgs { 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; @@ -59,66 +63,37 @@ static int sysFds[64] = -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; -#ifdef __RPI_BPLUS -static uint8_t physToGpio[64] = +int get_gpio_number(uint8_t physPin, uint8_t *gpio) { - 255, // 0 - 255, 255, // 1, 2 - 2, 255, - 3, 255, - 4, 14, - 255, 15, - 17, 18, - 27, 255, - 22, 23, - 255, 24, - 10, 255, - 9, 25, - 11, 8, - 255, 7, // 25, 26 -// B+ - 0, 1, - 5, 255, - 6, 12, - 13, 255, - 19, 16, - 26, 20, - 255, 21, -// the P5 connector on the Rev 2 boards: - 255, 255, - 255, 255, - 255, 255, - 255, 255, - 255, 255, - 28, 29, - 30, 31, - 255, 255, - 255, 255, - 255, 255, - 255, 255, -}; -#else -static uint8_t physToGpio[64] = -{ - 255, // 0 - 255, 255, // 1, 2 - 0, 255, - 1, 255, - 4, 14, - 255, 15, - 17, 18, - 21, 255, - 22, 23, - 255, 24, - 10, 255, - 9, 25, - 11, 8, - 255, 7, // 25, 26 - 255, 255, 255, 255, 255, // ... 31 - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // ... 47 - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // ... 63 -}; -#endif + 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); + } + + 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; +} void *interruptHandler(void *args) { int fd, ret; @@ -168,11 +143,13 @@ void *interruptHandler(void *args) { } void rpi_util::pinMode(uint8_t physPin, uint8_t mode) { - uint8_t gpioPin = (physPin > 63)? 255 : physToGpio[physPin]; - if (gpioPin == 255) { + 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; @@ -182,11 +159,13 @@ void rpi_util::pinMode(uint8_t physPin, uint8_t mode) { } void rpi_util::digitalWrite(uint8_t physPin, uint8_t value) { - uint8_t gpioPin = (physPin > 63)? 255 : physToGpio[physPin]; - if (gpioPin == 255) { + 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)) { @@ -200,11 +179,13 @@ void rpi_util::digitalWrite(uint8_t physPin, uint8_t value) { } uint8_t rpi_util::digitalRead(uint8_t physPin) { - uint8_t gpioPin = (physPin > 63)? 255 : physToGpio[physPin]; - if (gpioPin == 255) { + 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; @@ -218,9 +199,9 @@ void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode) { char fName[40]; char c; int count, i; + uint8_t gpioPin; - uint8_t gpioPin = (physPin > 63)? 255 : physToGpio[physPin]; - if (gpioPin == 255) { + if (get_gpio_number(physPin, &gpioPin)) { logError("attachInterrupt: invalid pin: %d\n", physPin); return; } @@ -295,8 +276,9 @@ void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode) { } void rpi_util::detachInterrupt(uint8_t physPin) { - uint8_t gpioPin = (physPin > 63)? 255 : physToGpio[physPin]; - if (gpioPin == 255) { + uint8_t gpioPin; + + if (get_gpio_number(physPin, &gpioPin)) { logError("detachInterrupt: invalid pin: %d\n", physPin); return; } diff --git a/drivers/RPi/rpi_util.h b/drivers/RPi/rpi_util.h index f7447baa5..0a10981b0 100644 --- a/drivers/RPi/rpi_util.h +++ b/drivers/RPi/rpi_util.h @@ -19,12 +19,16 @@ * Based on wiringPi Copyright (c) 2012 Gordon Henderson. */ -#ifndef pins_io_h -#define pins_io_h +#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 { From d4c4ab82ea4820768fb87744d15d2de450e77abf Mon Sep 17 00:00:00 2001 From: Olivier Date: Wed, 7 Dec 2016 21:48:37 +0100 Subject: [PATCH 147/167] Fix debug message, add test sketch (#682) --- core/MySensorsCore.cpp | 6 +++-- core/MySensorsCore.h | 2 +- ...serial_gateway_no_transport_full_debug.ino | 24 +++++++++++++++++++ 3 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 tests/Arduino/sketches/serial_gateway_no_transport_full_debug/serial_gateway_no_transport_full_debug.ino diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 606fb3123..be567a5e1 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -145,9 +145,11 @@ void _begin(void) { CORE_DEBUG(PSTR("MCO:BGN:STP\n")); // setup callback setup(); } - +#if defined(MY_SENSOR_NETWORK) CORE_DEBUG(PSTR("MCO:BGN:INIT OK,TSP=%d\n"), isTransportReady()); - +#else + CORE_DEBUG(PSTR("MCO:BGN:INIT OK,TSP=NA\n")); +#endif // reset wdt before handing over to loop hwWatchdogReset(); } diff --git a/core/MySensorsCore.h b/core/MySensorsCore.h index 7eda5d15f..1c82e0bc4 100644 --- a/core/MySensorsCore.h +++ b/core/MySensorsCore.h @@ -43,7 +43,7 @@ * | | MCO | BGN | BFR | Callback before() * | | MCO | BGN | MTR | MY_TRANSPORT_RELAXED enabled * | | MCO | BGN | STP | Callback setup() - * | | MCO | BGN | INIT OK,TSP=%%d | Core initialised, transport status (TSP), 1=initialised, 0=not initialised + * | | MCO | BGN | INIT OK,TSP=%%d | Core initialised, transport status (TSP), 1=initialised, 0=not initialised, NA=not available * | | MCO | BGN | NODE UNLOCKED | Node successfully unlocked (see signing chapter) * |!| MCO | BGN | TSP FAIL | Transport initialization failed * | | MCO | REG | REQ | Registration request diff --git a/tests/Arduino/sketches/serial_gateway_no_transport_full_debug/serial_gateway_no_transport_full_debug.ino b/tests/Arduino/sketches/serial_gateway_no_transport_full_debug/serial_gateway_no_transport_full_debug.ino new file mode 100644 index 000000000..4db3a7023 --- /dev/null +++ b/tests/Arduino/sketches/serial_gateway_no_transport_full_debug/serial_gateway_no_transport_full_debug.ino @@ -0,0 +1,24 @@ +/* + * 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/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. + * + ******************************* + */ + +#define MY_DEBUG +#define MY_GATEWAY_SERIAL +#include \ No newline at end of file From 8e1ef13804f2737079298c63bd0d8aa7b82e7f73 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Wed, 7 Dec 2016 23:44:29 +0100 Subject: [PATCH 148/167] Repo restyled using astyle (#683) The rules are in .tools/astyle/config/style.cfg and can also be reviewed at https://www.mysensors.org/view/260#coding-guidelines-core-library --- .astylerc => .tools/astyle/config/style.cfg | 2 +- MyConfig.h | 188 +- MySensors.h | 402 ++-- core/MyCapabilities.h | 42 +- core/MyEepromAddresses.h | 26 +- core/MyGatewayTransport.cpp | 16 +- core/MyGatewayTransport.h | 2 +- core/MyGatewayTransportEthernet.cpp | 601 +++-- core/MyGatewayTransportMQTTClient.cpp | 137 +- core/MyGatewayTransportSerial.cpp | 25 +- core/MyHw.h | 23 +- core/MyHwATMega328.cpp | 212 +- core/MyHwATMega328.h | 30 +- core/MyHwESP8266.cpp | 67 +- core/MyHwESP8266.h | 6 +- core/MyHwLinuxGeneric.cpp | 21 +- core/MyHwLinuxGeneric.h | 42 +- core/MyHwRPi.cpp | 65 +- core/MyHwRPi.h | 11 +- core/MyHwSAMD.cpp | 184 +- core/MyHwSAMD.h | 12 +- core/MyInclusionMode.cpp | 41 +- core/MyIndication.cpp | 29 +- core/MyIndication.h | 66 +- core/MyLeds.cpp | 80 +- core/MyLeds.h | 42 +- core/MyMainDefault.cpp | 19 +- core/MyMainESP8266.cpp | 55 +- core/MyMainLinux.cpp | 163 +- core/MyMessage.cpp | 107 +- core/MyMessage.h | 71 +- core/MyOTAFirmwareUpdate.cpp | 31 +- core/MyOTAFirmwareUpdate.h | 68 +- core/MyProtocolMySensors.cpp | 170 +- core/MySensorsCore.cpp | 675 +++--- core/MySensorsCore.h | 124 +- core/MySigning.cpp | 220 +- core/MySigning.h | 8 +- core/MySigningAtsha204.cpp | 99 +- core/MySigningAtsha204Soft.cpp | 64 +- core/MyTransport.cpp | 822 +++---- core/MyTransport.h | 296 +-- core/MyTransportNRF24.cpp | 107 +- core/MyTransportRFM69.cpp | 38 +- core/MyTransportRFM95.cpp | 37 +- core/MyTransportRS485.cpp | 373 +-- drivers/AES/AES.cpp | 622 ++--- drivers/AES/AES.h | 239 +- drivers/AES/AES_config.h | 36 +- drivers/AES/examples_Rpi/aes.cpp | 40 +- drivers/AES/examples_Rpi/test_vectors.cpp | 259 ++- drivers/AES/printf.h | 26 +- drivers/ATSHA204/ATSHA204.cpp | 977 ++++---- drivers/ATSHA204/ATSHA204.h | 4 +- drivers/ATSHA204/sha256.cpp | 274 +-- drivers/ATSHA204/sha256.h | 42 +- drivers/AVR/DigitalIO/DigitalPin.h | 865 +++---- drivers/AVR/DigitalIO/PinIO.cpp | 35 +- drivers/AVR/DigitalIO/PinIO.h | 259 ++- drivers/AVR/DigitalIO/SoftI2cMaster.cpp | 248 +- drivers/AVR/DigitalIO/SoftI2cMaster.h | 512 +++-- drivers/AVR/DigitalIO/SoftSPI.h | 222 +- drivers/AVR/DigitalIO/attic/ADS7818.h | 198 +- drivers/AVR/DigitalIO/attic/MCP320X.h | 521 +++-- drivers/AVR/DigitalIO/attic/MCP355X.h | 252 +- .../DigitalPinBlink/DigitalPinBlink.ino | 11 +- .../DigitalPinConfigToggle.ino | 22 +- .../DigitalPinReadWrite.ino | 5 +- .../DigitalPinShiftOut/DigitalPinShiftOut.ino | 42 +- .../examples/PinIOBegin/PinIOBegin.ino | 26 +- .../PinIOConfigToggle/PinIOConfigToggle.ino | 18 +- .../PinIOReadWrite/PinIOReadWrite.ino | 16 +- .../examples/ScanI2cBus/ScanI2cBus.ino | 87 +- .../SoftDS1307Utility/SoftDS1307Utility.ino | 494 ++-- .../examples/testArduino/testArduino.ino | 20 +- .../testDigitalPin/testDigitalPin.ino | 24 +- .../testFastDigital/testFastDigital.ino | 18 +- .../examples/testPinIO/testPinIO.ino | 24 +- .../examples/testSoftSPI/testSoftSPI.ino | 54 +- .../AVR/DigitalWriteFast/digitalWriteFast.h | 160 +- drivers/AltSoftSerial/AltSoftSerial.h | 59 +- .../config/AltSoftSerial_Boards.h | 120 +- .../config/AltSoftSerial_Timers.h | 276 +-- drivers/AltSoftSerial/config/known_boards.h | 96 +- drivers/AltSoftSerial/config/known_timers.h | 184 +- drivers/CircularBuffer/CircularBuffer.h | 327 ++- drivers/Linux/Arduino.h | 6 +- drivers/Linux/Client.h | 8 +- drivers/Linux/EthernetClient.cpp | 112 +- drivers/Linux/EthernetClient.h | 18 +- drivers/Linux/EthernetServer.cpp | 3 +- drivers/Linux/EthernetServer.h | 9 +- drivers/Linux/IPAddress.cpp | 42 +- drivers/Linux/IPAddress.h | 246 +- drivers/Linux/Print.cpp | 72 +- drivers/Linux/Print.h | 95 +- drivers/Linux/SerialPort.cpp | 71 +- drivers/Linux/SerialPort.h | 3 +- drivers/Linux/Server.h | 7 +- drivers/Linux/SoftEeprom.cpp | 7 +- drivers/Linux/SoftEeprom.h | 3 +- drivers/Linux/Stream.cpp | 388 ++-- drivers/Linux/Stream.h | 169 +- drivers/Linux/compatibility.cpp | 48 +- drivers/Linux/noniso.cpp | 223 +- drivers/Linux/stdlib_noniso.h | 8 +- drivers/PubSubClient/PubSubClient.cpp | 1189 +++++----- drivers/PubSubClient/PubSubClient.h | 120 +- drivers/RF24/RF24.cpp | 477 ++-- drivers/RF24/RF24.h | 122 +- drivers/RFM69/RFM69.cpp | 1293 ++++++----- drivers/RFM69/RFM69.h | 199 +- drivers/RFM69/RFM69registers.h | 36 +- drivers/RFM95/RFM95.cpp | 223 +- drivers/RFM95/RFM95.h | 159 +- drivers/RPi/SPI.cpp | 39 +- drivers/RPi/SPI.h | 68 +- drivers/RPi/Wire.cpp | 2 +- drivers/RPi/Wire.h | 23 +- drivers/RPi/bcm2835.c | 1865 ++++++++------- drivers/RPi/bcm2835.h | 1813 ++++++++------- drivers/RPi/cpuinfo.c | 387 ++-- drivers/RPi/cpuinfo.h | 15 +- drivers/RPi/piHiPri.c | 15 +- drivers/RPi/rpi_util.cpp | 68 +- drivers/RPi/rpi_util.h | 3 +- drivers/SPIFlash/SPIFlash.cpp | 403 ++-- drivers/SPIFlash/SPIFlash.h | 109 +- .../AirQualitySensor/AirQualitySensor.ino | 142 +- .../BatteryPoweredSensor.ino | 73 +- .../BinarySwitchSleepSensor.ino | 69 +- examples/CO2Sensor/CO2Sensor.ino | 70 +- .../ClearEepromConfig/ClearEepromConfig.ino | 28 +- .../DimmableLEDActuator.ino | 67 +- examples/DimmableLight/DimmableLight.ino | 158 +- examples/DustSensor/DustSensor.ino | 76 +- examples/DustSensorDSM/DustSensorDSM.ino | 153 +- .../EnergyMeterPulseSensor.ino | 161 +- examples/GatewayESP8266/GatewayESP8266.ino | 15 +- .../GatewayESP8266MQTTClient.ino | 15 +- .../GatewayESP8266OTA/GatewayESP8266OTA.ino | 69 +- examples/GatewaySerial/GatewaySerial.ino | 89 +- .../GatewaySerialRS485/GatewaySerialRS485.ino | 117 +- examples/GatewayW5100/GatewayW5100.ino | 17 +- .../GatewayW5100MQTTClient.ino | 27 +- examples/LightSensor/LightSensor.ino | 37 +- examples/MockMySensors/MockMySensors.ino | 2039 +++++++++-------- examples/MotionSensor/MotionSensor.ino | 39 +- .../MotionSensorRS485/MotionSensorRS485.ino | 51 +- examples/PHSensor/PHSensor.ino | 36 +- examples/PingPongSensor/MYSLog.h | 38 +- examples/PingPongSensor/PingPongSensor.ino | 114 +- examples/RelayActuator/RelayActuator.ino | 75 +- examples/RepeaterNode/RepeaterNode.ino | 25 +- .../SecretKnockSensor/SecretKnockSensor.ino | 599 ++--- examples/SecureActuator/SecureActuator.ino | 66 +- .../SecurityPersonalizer.ino | 1805 +++++++-------- .../SecurityPersonalizer/sha204_library.cpp | 1284 ++++++----- .../SecurityPersonalizer/sha204_library.h | 22 +- .../SensebenderGatewaySerial.ino | 390 ++-- examples/SoilMoistSensor/SoilMoistSensor.ino | 145 +- examples/UVSensor/UVSensor.ino | 100 +- examples/VibrationSensor/VibrationSensor.ino | 44 +- .../WaterMeterPulseSensor.ino | 216 +- examples_linux/mysgw.cpp | 13 +- .../SublimeText/MySensors.sublime-project | 6 +- ...serial_gateway_no_transport_full_debug.ino | 2 +- 167 files changed, 16613 insertions(+), 15678 deletions(-) rename .astylerc => .tools/astyle/config/style.cfg (96%) diff --git a/.astylerc b/.tools/astyle/config/style.cfg similarity index 96% rename from .astylerc rename to .tools/astyle/config/style.cfg index ebd67ec6d..363270ef4 100644 --- a/.astylerc +++ b/.tools/astyle/config/style.cfg @@ -14,7 +14,7 @@ max-code-length=100 break-after-logical # Preprocessor blocks should be indented -indent-preproc-block +#indent-preproc-block # Preprocessor definitions should be indented if linebroken indent-preproc-define diff --git a/MyConfig.h b/MyConfig.h index 9a9f31706..1efd3970e 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -67,10 +67,10 @@ #ifndef MY_BAUD_RATE #define MY_BAUD_RATE 115200 #endif - /** - * @def MY_SERIAL_OUTPUT_SIZE - * @brief Max. characters for serial output. - */ +/** +* @def MY_SERIAL_OUTPUT_SIZE +* @brief Max. characters for serial output. +*/ #ifndef MY_SERIAL_OUTPUT_SIZE #define MY_SERIAL_OUTPUT_SIZE (120u) #endif @@ -107,7 +107,7 @@ #endif /** * @def MY_TRANSPORT_SANITY_CHECK -* @brief If enabled, node will check transport in regular intervals to detect HW issues and re-initialize in case of failure. +* @brief If enabled, node will check transport in regular intervals to detect HW issues and re-initialize in case of failure. * This feature is enabled for all repeater nodes (incl. GW) */ //#define MY_TRANSPORT_SANITY_CHECK @@ -121,7 +121,7 @@ #endif /** * @def MY_TRANSPORT_DISCOVERY_INTERVAL_MS -* @brief This is a gateway-only feature: Interval (in ms) to issue network discovery checks +* @brief This is a gateway-only feature: Interval (in ms) to issue network discovery checks */ #ifndef MY_TRANSPORT_DISCOVERY_INTERVAL_MS #define MY_TRANSPORT_DISCOVERY_INTERVAL_MS (10*60*1000ul) @@ -145,34 +145,34 @@ */ #define MY_REGISTRATION_FEATURE - /** - * @def MY_REGISTRATION_RETRIES - * @brief Number of registration retries if no reply received from GW/controller - */ +/** +* @def MY_REGISTRATION_RETRIES +* @brief Number of registration retries if no reply received from GW/controller +*/ #ifndef MY_REGISTRATION_RETRIES #define MY_REGISTRATION_RETRIES (3u) #endif - /** - * @def MY_REGISTRATION_DEFAULT - * @brief Node registration default - this applies if no registration response is received from controller - */ +/** +* @def MY_REGISTRATION_DEFAULT +* @brief Node registration default - this applies if no registration response is received from controller +*/ #define MY_REGISTRATION_DEFAULT true - /** - * @def MY_REGISTRATION_CONTROLLER - * @brief If enabled, node registration request has to be handled by controller - */ - // #define MY_REGISTRATION_CONTROLLER +/** +* @def MY_REGISTRATION_CONTROLLER +* @brief If enabled, node registration request has to be handled by controller +*/ +// #define MY_REGISTRATION_CONTROLLER - /** - * @def MY_CORE_COMPATIBILITY_CHECK - * @brief If enabled, library compatibility is checked during node registration. Incompatible libraries are unable to send sensor data. - */ +/** +* @def MY_CORE_COMPATIBILITY_CHECK +* @brief If enabled, library compatibility is checked during node registration. Incompatible libraries are unable to send sensor data. +*/ #define MY_CORE_COMPATIBILITY_CHECK - /** +/** * @def MY_TRANSPORT_WAIT_READY_MS * @brief Timeout in MS until transport is ready during startup, set to 0 for no timeout */ @@ -323,11 +323,11 @@ * @brief The default input pin used for the inclusion mode button. */ #ifndef MY_INCLUSION_MODE_BUTTON_PIN - #if defined(ARDUINO_ARCH_ESP8266) - #define MY_INCLUSION_MODE_BUTTON_PIN 5 - #else - #define MY_INCLUSION_MODE_BUTTON_PIN 3 - #endif +#if defined(ARDUINO_ARCH_ESP8266) +#define MY_INCLUSION_MODE_BUTTON_PIN 5 +#else +#define MY_INCLUSION_MODE_BUTTON_PIN 3 +#endif #endif /** @@ -488,15 +488,15 @@ * @brief Default RF24 chip enable pin setting. Override in sketch if needed. */ #ifndef MY_RF24_CE_PIN - #if defined(ARDUINO_ARCH_ESP8266) - #define MY_RF24_CE_PIN 4 - #elif defined(ARDUINO_ARCH_SAMD) - #define MY_RF24_CE_PIN 27 - #elif defined(LINUX_ARCH_RASPBERRYPI) - #define MY_RF24_CE_PIN 22 - #else - #define MY_RF24_CE_PIN 9 - #endif +#if defined(ARDUINO_ARCH_ESP8266) +#define MY_RF24_CE_PIN 4 +#elif defined(ARDUINO_ARCH_SAMD) +#define MY_RF24_CE_PIN 27 +#elif defined(LINUX_ARCH_RASPBERRYPI) +#define MY_RF24_CE_PIN 22 +#else +#define MY_RF24_CE_PIN 9 +#endif #endif /** @@ -504,15 +504,15 @@ * @brief Default RF24 chip select pin setting. Override in sketch if needed. */ #ifndef MY_RF24_CS_PIN - #if defined(ARDUINO_ARCH_ESP8266) - #define MY_RF24_CS_PIN 15 - #elif defined(ARDUINO_ARCH_SAMD) - #define MY_RF24_CS_PIN 3 - #elif defined(LINUX_ARCH_RASPBERRYPI) - #define MY_RF24_CS_PIN 24 - #else - #define MY_RF24_CS_PIN 10 - #endif +#if defined(ARDUINO_ARCH_ESP8266) +#define MY_RF24_CS_PIN 15 +#elif defined(ARDUINO_ARCH_SAMD) +#define MY_RF24_CS_PIN 3 +#elif defined(LINUX_ARCH_RASPBERRYPI) +#define MY_RF24_CS_PIN 24 +#else +#define MY_RF24_CS_PIN 10 +#endif #endif /** @@ -528,9 +528,9 @@ * @brief Declare the amount of incoming messages that can be buffered. */ #ifdef MY_RX_MESSAGE_BUFFER_FEATURE - #ifndef MY_RX_MESSAGE_BUFFER_SIZE - #define MY_RX_MESSAGE_BUFFER_SIZE (20) - #endif +#ifndef MY_RX_MESSAGE_BUFFER_SIZE +#define MY_RX_MESSAGE_BUFFER_SIZE (20) +#endif #endif /** @@ -639,9 +639,9 @@ * @brief Set to true if @ref MY_IS_RFM69HW is set. */ #ifdef MY_IS_RFM69HW - #define MY_RFM69HW true +#define MY_RFM69HW true #else - #define MY_RFM69HW false +#define MY_RFM69HW false #endif /** @@ -673,11 +673,11 @@ * @brief RF69 IRQ pin number. */ #ifndef MY_RF69_IRQ_NUM - #if defined(ARDUINO_ARCH_ESP8266) - #define MY_RF69_IRQ_NUM RF69_IRQ_PIN - #else - #define MY_RF69_IRQ_NUM RF69_IRQ_NUM - #endif +#if defined(ARDUINO_ARCH_ESP8266) +#define MY_RF69_IRQ_NUM RF69_IRQ_PIN +#else +#define MY_RF69_IRQ_NUM RF69_IRQ_NUM +#endif #endif // Enables RFM69 encryption (all nodes and gateway must have this enabled, and all must be personalized with the same AES key) @@ -694,28 +694,28 @@ * This must match the hardware version of the RFM95 radio. */ #ifndef MY_RFM95_FREQUENCY - #define MY_RFM95_FREQUENCY (868.1f) -#endif - /** - * @def MY_RFM95_MODEM_CONFIGRUATION - * @brief RFM95 modem configuration, see table - * - * BW = Bandwidth in kHz - * CR = Error correction code - * SF = Spreading factor, chips / symbol - * - * | CONFIG | BW | CR | SF | Comment - * |------------------------|-------|-----|------|----------------------------- - * | RFM95_BW125CR45SF128 | 125 | 4/5 | 128 | Default, medium range - * | RFM95_BW500CR45SF128 | 500 | 4/5 | 128 | Fast, short range - * | RFM95_BW31_25CR48SF512 | 31.25 | 4/8 | 512 | Slow, long range - * | RFM95_BW125CR48SF4096 | 125 | 4/8 | 4096 | Slow, long range - * - */ +#define MY_RFM95_FREQUENCY (868.1f) +#endif +/** +* @def MY_RFM95_MODEM_CONFIGRUATION +* @brief RFM95 modem configuration, see table +* +* BW = Bandwidth in kHz +* CR = Error correction code +* SF = Spreading factor, chips / symbol +* +* | CONFIG | BW | CR | SF | Comment +* |------------------------|-------|-----|------|----------------------------- +* | RFM95_BW125CR45SF128 | 125 | 4/5 | 128 | Default, medium range +* | RFM95_BW500CR45SF128 | 500 | 4/5 | 128 | Fast, short range +* | RFM95_BW31_25CR48SF512 | 31.25 | 4/8 | 512 | Slow, long range +* | RFM95_BW125CR48SF4096 | 125 | 4/8 | 4096 | Slow, long range +* +*/ #ifndef MY_RFM95_MODEM_CONFIGRUATION - // default - #define MY_RFM95_MODEM_CONFIGRUATION RFM95_BW125CR45SF128 +// default +#define MY_RFM95_MODEM_CONFIGRUATION RFM95_BW125CR45SF128 #endif /** @@ -729,7 +729,7 @@ * @brief RFM95 IRQ pin */ #ifndef MY_RFM95_IRQ_PIN - #define MY_RFM95_IRQ_PIN RFM95_IRQ_PIN +#define MY_RFM95_IRQ_PIN RFM95_IRQ_PIN #endif /** @@ -737,7 +737,7 @@ * @brief RFM95 SPI chip select pin */ #ifndef MY_RFM95_SPI_CS - #define MY_RFM95_SPI_CS RFM95_SPI_CS +#define MY_RFM95_SPI_CS RFM95_SPI_CS #endif /** @@ -745,21 +745,21 @@ * @brief RFM95 TX power level. */ #ifndef MY_RFM95_TX_POWER - #define MY_RFM95_TX_POWER 13 +#define MY_RFM95_TX_POWER 13 #endif - /** - * @def MY_RFM95_ATC_MODE_DISABLED - * @brief Enable to disable ATC mode - */ +/** +* @def MY_RFM95_ATC_MODE_DISABLED +* @brief Enable to disable ATC mode +*/ //#define MY_RFM95_ATC_MODE_DISABLED - /** - * @def MY_RFM95_ATC_TARGET_RSSI - * @brief Traget RSSI level for ATC mode - */ +/** +* @def MY_RFM95_ATC_TARGET_RSSI +* @brief Traget RSSI level for ATC mode +*/ #ifndef MY_RFM95_ATC_TARGET_RSSI - #define MY_RFM95_ATC_TARGET_RSSI (-60) +#define MY_RFM95_ATC_TARGET_RSSI (-60) #endif @@ -779,11 +779,11 @@ * @brief The Ethernet TCP/UDP port to open on controller or gateway. */ #ifndef MY_PORT - #ifdef MY_GATEWAY_MQTT_CLIENT - #define MY_PORT 1883 - #else - #define MY_PORT 5003 - #endif +#ifdef MY_GATEWAY_MQTT_CLIENT +#define MY_PORT 1883 +#else +#define MY_PORT 5003 +#endif #endif // Static ip address of gateway (if this is disabled, DHCP will be used) diff --git a/MySensors.h b/MySensors.h index a3388233e..6471f8a6e 100644 --- a/MySensors.h +++ b/MySensors.h @@ -41,60 +41,60 @@ * @brief Contain a string describing the class of sketch/node (gateway/repeater/sensor). */ #if defined(MY_GATEWAY_SERIAL) || defined(MY_GATEWAY_W5100) || defined(MY_GATEWAY_ENC28J60) || defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX) || defined(MY_GATEWAY_MQTT_CLIENT) - #define MY_GATEWAY_FEATURE - #define MY_IS_GATEWAY (true) - #define MY_NODE_TYPE "GW" +#define MY_GATEWAY_FEATURE +#define MY_IS_GATEWAY (true) +#define MY_NODE_TYPE "GW" #elif defined(MY_REPEATER_FEATURE) - #define MY_IS_GATEWAY (false) - #define MY_NODE_TYPE "REPEATER" +#define MY_IS_GATEWAY (false) +#define MY_NODE_TYPE "REPEATER" #else - #define MY_IS_GATEWAY (false) - #define MY_NODE_TYPE "NODE" +#define MY_IS_GATEWAY (false) +#define MY_NODE_TYPE "NODE" #endif // Enable radio "feature" if one of the radio types was enabled #if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) || defined(MY_RADIO_RFM95) || defined(MY_RS485) - #define MY_SENSOR_NETWORK +#define MY_SENSOR_NETWORK #endif // HARDWARE #if defined(ARDUINO_ARCH_ESP8266) - // Remove PSTR macros from debug prints - #undef PSTR - #define PSTR(x) (x) - //#undef F - //#define F(x) (x) - #include "core/MyHwESP8266.cpp" +// Remove PSTR macros from debug prints +#undef PSTR +#define PSTR(x) (x) +//#undef F +//#define F(x) (x) +#include "core/MyHwESP8266.cpp" #elif defined(ARDUINO_ARCH_AVR) - #include "drivers/AVR/DigitalWriteFast/digitalWriteFast.h" - #include "core/MyHwATMega328.cpp" +#include "drivers/AVR/DigitalWriteFast/digitalWriteFast.h" +#include "core/MyHwATMega328.cpp" #elif defined(ARDUINO_ARCH_SAMD) - #include "core/MyHwSAMD.cpp" +#include "core/MyHwSAMD.cpp" #elif defined(__linux__) - #ifdef LINUX_ARCH_RASPBERRYPI - #include "core/MyHwRPi.cpp" - #else - #include "core/MyHwLinuxGeneric.cpp" - #endif +#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) - #define MY_DEFAULT_ERR_LED_PIN MY_HW_ERR_LED_PIN +#define MY_DEFAULT_ERR_LED_PIN MY_HW_ERR_LED_PIN #endif #if !defined(MY_DEFAULT_TX_LED_PIN) && defined(MY_HW_TX_LED_PIN) - #define MY_DEFAULT_TX_LED_PIN MY_HW_TX_LED_PIN +#define MY_DEFAULT_TX_LED_PIN MY_HW_TX_LED_PIN #endif #if !defined(MY_DEFAULT_RX_LED_PIN) && defined(MY_HW_TX_LED_PIN) - #define MY_DEFAULT_RX_LED_PIN MY_HW_TX_LED_PIN +#define MY_DEFAULT_RX_LED_PIN MY_HW_TX_LED_PIN #endif #if defined(MY_LEDS_BLINKING_FEATURE) #error MY_LEDS_BLINKING_FEATURE is now removed from MySensors core,\ - define MY_DEFAULT_ERR_LED_PIN, MY_DEFAULT_TX_LED_PIN or\ - MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs +define MY_DEFAULT_ERR_LED_PIN, MY_DEFAULT_TX_LED_PIN or\ +MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs #endif /** @@ -106,9 +106,9 @@ #endif #if defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) - #include "core/MyLeds.cpp" +#include "core/MyLeds.cpp" #else - #include "core/MyLeds.h" +#include "core/MyLeds.h" #endif #include "core/MyIndication.cpp" @@ -116,221 +116,221 @@ // INCLUSION MODE #if defined(MY_INCLUSION_MODE_FEATURE) - #include "core/MyInclusionMode.cpp" +#include "core/MyInclusionMode.cpp" #endif // SIGNING #if defined(MY_SIGNING_ATSHA204) || defined(MY_SIGNING_SOFT) - #define MY_SIGNING_FEATURE +#define MY_SIGNING_FEATURE #endif #include "core/MySigning.cpp" #include "drivers/ATSHA204/sha256.cpp" #if defined(MY_SIGNING_FEATURE) - // SIGNING COMMON FUNCTIONS - #if defined(MY_SIGNING_ATSHA204) && defined(MY_SIGNING_SOFT) - #error Only one signing engine can be activated - #endif - #if defined(MY_SIGNING_ATSHA204) && defined(__linux__) - #error No support for ATSHA204 on this platform - #endif +// SIGNING COMMON FUNCTIONS +#if defined(MY_SIGNING_ATSHA204) && defined(MY_SIGNING_SOFT) +#error Only one signing engine can be activated +#endif +#if defined(MY_SIGNING_ATSHA204) && defined(__linux__) +#error No support for ATSHA204 on this platform +#endif - #if defined(MY_SIGNING_ATSHA204) - #include "core/MySigningAtsha204.cpp" - #include "drivers/ATSHA204/ATSHA204.cpp" - #elif defined(MY_SIGNING_SOFT) - #include "core/MySigningAtsha204Soft.cpp" - #endif +#if defined(MY_SIGNING_ATSHA204) +#include "core/MySigningAtsha204.cpp" +#include "drivers/ATSHA204/ATSHA204.cpp" +#elif defined(MY_SIGNING_SOFT) +#include "core/MySigningAtsha204Soft.cpp" +#endif #endif // FLASH #if defined(MY_OTA_FIRMWARE_FEATURE) - #include "drivers/SPIFlash/SPIFlash.cpp" - #include "core/MyOTAFirmwareUpdate.cpp" +#include "drivers/SPIFlash/SPIFlash.cpp" +#include "core/MyOTAFirmwareUpdate.cpp" #endif // GATEWAY - TRANSPORT #if defined(MY_CONTROLLER_IP_ADDRESS) || defined(MY_CONTROLLER_URL_ADDRESS) - #define MY_GATEWAY_CLIENT_MODE +#define MY_GATEWAY_CLIENT_MODE #endif #if defined(MY_USE_UDP) && !defined(MY_GATEWAY_CLIENT_MODE) - #error You must specify MY_CONTROLLER_IP_ADDRESS or MY_CONTROLLER_URL_ADDRESS for UDP +#error You must specify MY_CONTROLLER_IP_ADDRESS or MY_CONTROLLER_URL_ADDRESS for UDP #endif #if defined(MY_GATEWAY_MQTT_CLIENT) - #if defined(MY_SENSOR_NETWORK) - // We assume that a gateway having a radio also should act as repeater - #define MY_REPEATER_FEATURE - #endif - // GATEWAY - COMMON FUNCTIONS - // We support MQTT Client using W5100, ESP8266 and Linux - #if !defined(MY_GATEWAY_CLIENT_MODE) - #error You must specify MY_CONTROLLER_IP_ADDRESS or MY_CONTROLLER_URL_ADDRESS - #endif - - #if !defined(MY_MQTT_PUBLISH_TOPIC_PREFIX) - #error You must specify a topic publish prefix MY_MQTT_PUBLISH_TOPIC_PREFIX for this MQTT client - #endif - #if !defined(MY_MQTT_SUBSCRIBE_TOPIC_PREFIX) - #error You must specify a topic subscribe prefix MY_MQTT_SUBSCRIBE_TOPIC_PREFIX for this MQTT client - #endif - - #if !defined(MY_MQTT_CLIENT_ID) - #error You must define a unique MY_MQTT_CLIENT_ID for this MQTT client - #endif - - #include "core/MyGatewayTransport.cpp" - #include "core/MyProtocolMySensors.cpp" - - #if defined(MY_GATEWAY_LINUX) - #include "drivers/Linux/EthernetClient.h" - #include "drivers/Linux/EthernetServer.h" - #include "drivers/Linux/IPAddress.h" - #endif - #include "drivers/PubSubClient/PubSubClient.cpp" - #include "core/MyGatewayTransportMQTTClient.cpp" +#if defined(MY_SENSOR_NETWORK) +// We assume that a gateway having a radio also should act as repeater +#define MY_REPEATER_FEATURE +#endif +// GATEWAY - COMMON FUNCTIONS +// We support MQTT Client using W5100, ESP8266 and Linux +#if !defined(MY_GATEWAY_CLIENT_MODE) +#error You must specify MY_CONTROLLER_IP_ADDRESS or MY_CONTROLLER_URL_ADDRESS +#endif + +#if !defined(MY_MQTT_PUBLISH_TOPIC_PREFIX) +#error You must specify a topic publish prefix MY_MQTT_PUBLISH_TOPIC_PREFIX for this MQTT client +#endif +#if !defined(MY_MQTT_SUBSCRIBE_TOPIC_PREFIX) +#error You must specify a topic subscribe prefix MY_MQTT_SUBSCRIBE_TOPIC_PREFIX for this MQTT client +#endif + +#if !defined(MY_MQTT_CLIENT_ID) +#error You must define a unique MY_MQTT_CLIENT_ID for this MQTT client +#endif + +#include "core/MyGatewayTransport.cpp" +#include "core/MyProtocolMySensors.cpp" + +#if defined(MY_GATEWAY_LINUX) +#include "drivers/Linux/EthernetClient.h" +#include "drivers/Linux/EthernetServer.h" +#include "drivers/Linux/IPAddress.h" +#endif +#include "drivers/PubSubClient/PubSubClient.cpp" +#include "core/MyGatewayTransportMQTTClient.cpp" #elif defined(MY_GATEWAY_FEATURE) - // GATEWAY - COMMON FUNCTIONS - #include "core/MyGatewayTransport.cpp" - - #include "core/MyProtocolMySensors.cpp" - - // GATEWAY - CONFIGURATION - #if defined(MY_SENSOR_NETWORK) - // We assume that a gateway having a radio also should act as repeater - #define MY_REPEATER_FEATURE - #endif - #if !defined(MY_PORT) - #error You must define MY_PORT (controller or gatway port to open) - #endif - #if defined(MY_GATEWAY_ESP8266) - // GATEWAY - ESP8266 - #include "core/MyGatewayTransportEthernet.cpp" - #elif defined(MY_GATEWAY_LINUX) - // GATEWAY - Generic Linux - #include "drivers/Linux/EthernetClient.h" - #include "drivers/Linux/EthernetServer.h" - #include "drivers/Linux/IPAddress.h" - #include "core/MyGatewayTransportEthernet.cpp" - #elif defined(MY_GATEWAY_W5100) - // GATEWAY - W5100 - #include "core/MyGatewayTransportEthernet.cpp" - #elif defined(MY_GATEWAY_ENC28J60) - // GATEWAY - ENC28J60 - #if defined(MY_USE_UDP) - #error UDP mode is not available for ENC28J60 - #endif - #include "core/MyGatewayTransportEthernet.cpp" - #elif defined(MY_GATEWAY_SERIAL) - // GATEWAY - SERIAL - #include "core/MyGatewayTransportSerial.cpp" - #endif +// GATEWAY - COMMON FUNCTIONS +#include "core/MyGatewayTransport.cpp" + +#include "core/MyProtocolMySensors.cpp" + +// GATEWAY - CONFIGURATION +#if defined(MY_SENSOR_NETWORK) +// We assume that a gateway having a radio also should act as repeater +#define MY_REPEATER_FEATURE +#endif +#if !defined(MY_PORT) +#error You must define MY_PORT (controller or gatway port to open) +#endif +#if defined(MY_GATEWAY_ESP8266) +// GATEWAY - ESP8266 +#include "core/MyGatewayTransportEthernet.cpp" +#elif defined(MY_GATEWAY_LINUX) +// GATEWAY - Generic Linux +#include "drivers/Linux/EthernetClient.h" +#include "drivers/Linux/EthernetServer.h" +#include "drivers/Linux/IPAddress.h" +#include "core/MyGatewayTransportEthernet.cpp" +#elif defined(MY_GATEWAY_W5100) +// GATEWAY - W5100 +#include "core/MyGatewayTransportEthernet.cpp" +#elif defined(MY_GATEWAY_ENC28J60) +// GATEWAY - ENC28J60 +#if defined(MY_USE_UDP) +#error UDP mode is not available for ENC28J60 +#endif +#include "core/MyGatewayTransportEthernet.cpp" +#elif defined(MY_GATEWAY_SERIAL) +// GATEWAY - SERIAL +#include "core/MyGatewayTransportSerial.cpp" +#endif #endif // RAM ROUTING TABLE #if defined(MY_RAM_ROUTING_TABLE_FEATURE) && defined(MY_REPEATER_FEATURE) - // activate feature based on architecture - #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_SAMD) || defined(LINUX_ARCH_RASPBERRYPI) - #define MY_RAM_ROUTING_TABLE_ENABLED - #elif defined(ARDUINO_ARCH_AVR) - // memory limited, enable with care - // #define MY_RAM_ROUTING_TABLE_ENABLED - #endif +// activate feature based on architecture +#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_SAMD) || defined(LINUX_ARCH_RASPBERRYPI) +#define MY_RAM_ROUTING_TABLE_ENABLED +#elif defined(ARDUINO_ARCH_AVR) +// memory limited, enable with care +// #define MY_RAM_ROUTING_TABLE_ENABLED +#endif #endif #if defined(MY_TRANSPORT_DONT_CARE_MODE) - #error This directive is deprecated, set MY_TRANSPORT_WAIT_READY_MS instead! +#error This directive is deprecated, set MY_TRANSPORT_WAIT_READY_MS instead! #endif // RADIO #if defined(MY_RADIO_NRF24) || defined(MY_RADIO_RFM69) || defined(MY_RADIO_RFM95) ||defined(MY_RS485) - // SOFTSPI - #ifdef MY_SOFTSPI - #if defined(ARDUINO_ARCH_ESP8266) - #error Soft SPI is not available on ESP8266 - #endif - #include "drivers/AVR/DigitalIO/DigitalIO.h" - #endif - - #if defined(MY_RADIO_NRF24) && defined(__linux__) && !defined(LINUX_ARCH_RASPBERRYPI) - #error No support for nRF24 radio on this platform - #endif - - #include "core/MyTransport.cpp" - - // count enabled transports - #if defined(MY_RADIO_NRF24) - #define __RF24CNT 1 - #else - #define __RF24CNT 0 - #endif - #if defined(MY_RADIO_RFM69) - #define __RFM69CNT 1 - #else - #define __RFM69CNT 0 - #endif - #if defined(MY_RADIO_RFM95) - #define __RFM95CNT 1 - #else - #define __RFM95CNT 0 - #endif - #if defined(MY_RS485) - #define __RS485CNT 1 - #else - #define __RS485CNT 0 - #endif - - - #if (__RF24CNT + __RFM69CNT + __RFM95CNT + __RS485CNT > 1) - #error Only one forward link driver can be activated - #endif - - #if defined(MY_RADIO_NRF24) - #if defined(MY_RF24_ENABLE_ENCRYPTION) - #include "drivers/AES/AES.cpp" - #endif - #include "drivers/RF24/RF24.cpp" - #include "core/MyTransportNRF24.cpp" - #elif defined(MY_RS485) - #if !defined(MY_RS485_HWSERIAL) - #if defined(__linux__) - #error You must specify MY_RS485_HWSERIAL for RS485 transport - #endif - #include "drivers/AltSoftSerial/AltSoftSerial.cpp" - #endif - #include "core/MyTransportRS485.cpp" - #elif defined(MY_RADIO_RFM69) - #include "drivers/RFM69/RFM69.cpp" - #include "core/MyTransportRFM69.cpp" - #elif defined(MY_RADIO_RFM95) - #include "drivers/RFM95/RFM95.cpp" - #include "core/MyTransportRFM95.cpp" - #endif +// SOFTSPI +#ifdef MY_SOFTSPI +#if defined(ARDUINO_ARCH_ESP8266) +#error Soft SPI is not available on ESP8266 +#endif +#include "drivers/AVR/DigitalIO/DigitalIO.h" +#endif + +#if defined(MY_RADIO_NRF24) && defined(__linux__) && !defined(LINUX_ARCH_RASPBERRYPI) +#error No support for nRF24 radio on this platform +#endif + +#include "core/MyTransport.cpp" + +// count enabled transports +#if defined(MY_RADIO_NRF24) +#define __RF24CNT 1 +#else +#define __RF24CNT 0 +#endif +#if defined(MY_RADIO_RFM69) +#define __RFM69CNT 1 +#else +#define __RFM69CNT 0 +#endif +#if defined(MY_RADIO_RFM95) +#define __RFM95CNT 1 +#else +#define __RFM95CNT 0 +#endif +#if defined(MY_RS485) +#define __RS485CNT 1 +#else +#define __RS485CNT 0 +#endif + + +#if (__RF24CNT + __RFM69CNT + __RFM95CNT + __RS485CNT > 1) +#error Only one forward link driver can be activated +#endif + +#if defined(MY_RADIO_NRF24) +#if defined(MY_RF24_ENABLE_ENCRYPTION) +#include "drivers/AES/AES.cpp" +#endif +#include "drivers/RF24/RF24.cpp" +#include "core/MyTransportNRF24.cpp" +#elif defined(MY_RS485) +#if !defined(MY_RS485_HWSERIAL) +#if defined(__linux__) +#error You must specify MY_RS485_HWSERIAL for RS485 transport +#endif +#include "drivers/AltSoftSerial/AltSoftSerial.cpp" +#endif +#include "core/MyTransportRS485.cpp" +#elif defined(MY_RADIO_RFM69) +#include "drivers/RFM69/RFM69.cpp" +#include "core/MyTransportRFM69.cpp" +#elif defined(MY_RADIO_RFM95) +#include "drivers/RFM95/RFM95.cpp" +#include "core/MyTransportRFM95.cpp" +#endif #endif #if defined(MY_PARENT_NODE_IS_STATIC) && (MY_PARENT_NODE_ID == AUTO) - #error Parent is static but no parent ID defined. +#error Parent is static but no parent ID defined. #endif // Make sure to disable child features when parent feature is disabled #if !defined(MY_SENSOR_NETWORK) - #undef MY_OTA_FIRMWARE_FEATURE - #undef MY_REPEATER_FEATURE - #undef MY_SIGNING_NODE_WHITELISTING - #undef MY_SIGNING_FEATURE +#undef MY_OTA_FIRMWARE_FEATURE +#undef MY_REPEATER_FEATURE +#undef MY_SIGNING_NODE_WHITELISTING +#undef MY_SIGNING_FEATURE #endif #if !defined(MY_GATEWAY_FEATURE) - #undef MY_INCLUSION_MODE_FEATURE - #undef MY_INCLUSION_BUTTON_FEATURE +#undef MY_INCLUSION_MODE_FEATURE +#undef MY_INCLUSION_BUTTON_FEATURE #endif #if !defined(MY_CORE_ONLY) - #if !defined(MY_GATEWAY_FEATURE) && !defined(MY_SENSOR_NETWORK) - #error No forward link or gateway feature activated. This means nowhere to send messages! Pretty pointless. - #endif +#if !defined(MY_GATEWAY_FEATURE) && !defined(MY_SENSOR_NETWORK) +#error No forward link or gateway feature activated. This means nowhere to send messages! Pretty pointless. +#endif #endif #include "core/MyCapabilities.h" @@ -340,13 +340,13 @@ #include #if !defined(MY_CORE_ONLY) - #if defined(ARDUINO_ARCH_ESP8266) - #include "core/MyMainESP8266.cpp" - #elif defined(__linux__) - #include "core/MyMainLinux.cpp" - #else - #include "core/MyMainDefault.cpp" - #endif +#if defined(ARDUINO_ARCH_ESP8266) +#include "core/MyMainESP8266.cpp" +#elif defined(__linux__) +#include "core/MyMainLinux.cpp" +#else +#include "core/MyMainDefault.cpp" +#endif #endif #endif diff --git a/core/MyCapabilities.h b/core/MyCapabilities.h index 8b8abccec..3b45fecac 100644 --- a/core/MyCapabilities.h +++ b/core/MyCapabilities.h @@ -22,60 +22,60 @@ #define MyCapabilities_h #if defined(MY_DISABLE_REMOTE_RESET) - #define MY_CAP_RESET "N" +#define MY_CAP_RESET "N" #else - #define MY_CAP_RESET "R" +#define MY_CAP_RESET "R" #endif #if defined(MY_OTA_FIRMWARE_FEATURE) - #define MY_CAP_OTA_FW "O" +#define MY_CAP_OTA_FW "O" #else - #define MY_CAP_OTA_FW "N" +#define MY_CAP_OTA_FW "N" #endif #if defined(MY_RADIO_NRF24) - #define MY_CAP_RADIO "N" +#define MY_CAP_RADIO "N" #elif defined(MY_RADIO_RFM69) - #define MY_CAP_RADIO "R" +#define MY_CAP_RADIO "R" #elif defined(MY_RADIO_RFM95) - #define MY_CAP_RADIO "L" +#define MY_CAP_RADIO "L" #elif defined(MY_RS485) - #define MY_CAP_RADIO "S" +#define MY_CAP_RADIO "S" #else - #define MY_CAP_RADIO "-" +#define MY_CAP_RADIO "-" #endif #if defined(MY_GATEWAY_FEATURE) - #define MY_CAP_TYPE "G" +#define MY_CAP_TYPE "G" #elif defined(MY_REPEATER_FEATURE) - #define MY_CAP_TYPE "R" +#define MY_CAP_TYPE "R" #else - #define MY_CAP_TYPE "N" +#define MY_CAP_TYPE "N" #endif #if defined(ARDUINO_ARCH_SAMD) - #define MY_CAP_ARCH "S" +#define MY_CAP_ARCH "S" #elif defined(ARDUINO_ARCH_ESP8266) - #define MY_CAP_ARCH "E" +#define MY_CAP_ARCH "E" #elif defined(ARDUINO_ARCH_AVR) - #define MY_CAP_ARCH "A" +#define MY_CAP_ARCH "A" #else - #define MY_CAP_ARCH "-" +#define MY_CAP_ARCH "-" #endif #if defined(MY_SIGNING_ATSHA204) - #define MY_CAP_SIGN "A" +#define MY_CAP_SIGN "A" #elif defined(MY_SIGNING_SOFT) - #define MY_CAP_SIGN "S" +#define MY_CAP_SIGN "S" #else - #define MY_CAP_SIGN "-" +#define MY_CAP_SIGN "-" #endif #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) - #define MY_CAP_RXBUF "Q" +#define MY_CAP_RXBUF "Q" #else - #define MY_CAP_RXBUF "-" +#define MY_CAP_RXBUF "-" #endif diff --git a/core/MyEepromAddresses.h b/core/MyEepromAddresses.h index 417ffa858..11502332b 100644 --- a/core/MyEepromAddresses.h +++ b/core/MyEepromAddresses.h @@ -17,17 +17,17 @@ * version 2 as published by the Free Software Foundation. */ - /** - * @file MyEepromAddresses.h - * @brief Eeprom addresses for MySensors library data - * - * @defgroup MyEepromAddressesgrp MyEepromAddresses - * @ingroup internals - * @{ - * - */ +/** +* @file MyEepromAddresses.h +* @brief Eeprom addresses for MySensors library data +* +* @defgroup MyEepromAddressesgrp MyEepromAddresses +* @ingroup internals +* @{ +* +*/ + - #ifndef MyEepromAddresses_h #define MyEepromAddresses_h @@ -60,7 +60,7 @@ /** @brief Address routing table */ #define EEPROM_ROUTES_ADDRESS (EEPROM_DISTANCE_ADDRESS + SIZE_DISTANCE) /** @brief Address configuration bytes sent by controller */ -#define EEPROM_CONTROLLER_CONFIG_ADDRESS (EEPROM_ROUTES_ADDRESS + SIZE_ROUTES) +#define EEPROM_CONTROLLER_CONFIG_ADDRESS (EEPROM_ROUTES_ADDRESS + SIZE_ROUTES) /** @brief Address firmware type */ #define EEPROM_FIRMWARE_TYPE_ADDRESS (EEPROM_CONTROLLER_CONFIG_ADDRESS + SIZE_CONTROLLER_CONFIG) /** @brief Address firmware version */ @@ -76,13 +76,13 @@ /** @brief Address soft signing HMAC key. This is set with @ref SecurityPersonalizer.ino */ #define EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS (EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS + SIZE_WHITELIST_REQUIREMENT_TABLE) /** @brief Address soft signing serial key. This is set with @ref SecurityPersonalizer.ino */ -#define EEPROM_SIGNING_SOFT_SERIAL_ADDRESS (EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS + SIZE_SIGNING_SOFT_HMAC_KEY) +#define EEPROM_SIGNING_SOFT_SERIAL_ADDRESS (EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS + SIZE_SIGNING_SOFT_HMAC_KEY) /** @brief Address RF AES encryption key. This is set with @ref SecurityPersonalizer.ino */ #define EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS (EEPROM_SIGNING_SOFT_SERIAL_ADDRESS + SIZE_SIGNING_SOFT_SERIAL) /** @brief Address node lock couner. This is set with @ref SecurityPersonalizer.ino */ #define EEPROM_NODE_LOCK_COUNTER (EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS + SIZE_RF_ENCRYPTION_AES_KEY) /** @brief First free address for sketch static configuration */ -#define EEPROM_LOCAL_CONFIG_ADDRESS (EEPROM_NODE_LOCK_COUNTER + SIZE_NODE_LOCK_COUNTER) +#define EEPROM_LOCAL_CONFIG_ADDRESS (EEPROM_NODE_LOCK_COUNTER + SIZE_NODE_LOCK_COUNTER) #endif // MyEepromAddresses_h diff --git a/core/MyGatewayTransport.cpp b/core/MyGatewayTransport.cpp index c4aad2715..1b76324e6 100644 --- a/core/MyGatewayTransport.cpp +++ b/core/MyGatewayTransport.cpp @@ -25,7 +25,8 @@ extern bool transportSendRoute(MyMessage &message); extern MyMessage _msg; extern MyMessage _msgTmp; -inline void gatewayTransportProcess() { +inline void gatewayTransportProcess() +{ if (gatewayTransportAvailable()) { _msg = gatewayTransportReceive(); if (_msg.destination == GATEWAY_ADDRESS) { @@ -34,7 +35,8 @@ inline void gatewayTransportProcess() { if (mGetRequestAck(_msg)) { // Copy message _msgTmp = _msg; - mSetRequestAck(_msgTmp, false); // Reply without ack flag (otherwise we would end up in an eternal loop) + mSetRequestAck(_msgTmp, + false); // Reply without ack flag (otherwise we would end up in an eternal loop) mSetAck(_msgTmp, true); _msgTmp.sender = getNodeId(); _msgTmp.destination = _msg.sender; @@ -44,11 +46,11 @@ inline void gatewayTransportProcess() { if (_msg.type == I_VERSION) { // Request for version. Create the response gatewayTransportSend(buildGw(_msgTmp, I_VERSION).set(MYSENSORS_LIBRARY_VERSION)); - #ifdef MY_INCLUSION_MODE_FEATURE +#ifdef MY_INCLUSION_MODE_FEATURE } else if (_msg.type == I_INCLUSION_MODE) { // Request to change inclusion mode inclusionModeSet(atoi(_msg.data) == 1); - #endif +#endif } else { _processInternalMessages(); } @@ -59,9 +61,9 @@ inline void gatewayTransportProcess() { } } } else { - #if defined(MY_SENSOR_NETWORK) - transportSendRoute(_msg); - #endif +#if defined(MY_SENSOR_NETWORK) + transportSendRoute(_msg); +#endif } } } diff --git a/core/MyGatewayTransport.h b/core/MyGatewayTransport.h index 8df4b59d3..a23178e63 100644 --- a/core/MyGatewayTransport.h +++ b/core/MyGatewayTransport.h @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Tomas Hozza - * Copyright (C) 2015 Tomas Hozza + * Copyright (C) 2015 Tomas Hozza * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org diff --git a/core/MyGatewayTransportEthernet.cpp b/core/MyGatewayTransportEthernet.cpp index a6abe9132..6c77c9425 100644 --- a/core/MyGatewayTransportEthernet.cpp +++ b/core/MyGatewayTransportEthernet.cpp @@ -19,15 +19,15 @@ #include "MyGatewayTransport.h" - // global variables +// global variables extern MyMessage _msgTmp; #if defined(MY_CONTROLLER_IP_ADDRESS) - IPAddress _ethernetControllerIP(MY_CONTROLLER_IP_ADDRESS); +IPAddress _ethernetControllerIP(MY_CONTROLLER_IP_ADDRESS); #endif #if defined(MY_IP_ADDRESS) - IPAddress _ethernetGatewayIP(MY_IP_ADDRESS); +IPAddress _ethernetGatewayIP(MY_IP_ADDRESS); #endif uint8_t _ethernetGatewayMAC[] = { MY_MAC_ADDRESS }; uint16_t _ethernetGatewayPort = MY_PORT; @@ -35,137 +35,133 @@ MyMessage _ethernetMsg; #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) -typedef struct -{ +typedef struct { char string[MY_GATEWAY_MAX_RECEIVE_LENGTH]; uint8_t idx; } inputBuffer; #if defined(MY_GATEWAY_ESP8266) - // Some re-defines to make code more readable below - #define EthernetServer WiFiServer - #define EthernetClient WiFiClient - #define EthernetUDP WiFiUDP +// Some re-defines to make code more readable below +#define EthernetServer WiFiServer +#define EthernetClient WiFiClient +#define EthernetUDP WiFiUDP - #if defined(MY_IP_ADDRESS) - IPAddress _gatewayIp(MY_IP_GATEWAY_ADDRESS); - IPAddress _subnetIp(MY_IP_SUBNET_ADDRESS); - #endif +#if defined(MY_IP_ADDRESS) +IPAddress _gatewayIp(MY_IP_GATEWAY_ADDRESS); +IPAddress _subnetIp(MY_IP_SUBNET_ADDRESS); +#endif #endif #if defined(MY_USE_UDP) - EthernetUDP _ethernetServer; +EthernetUDP _ethernetServer; #elif defined(MY_GATEWAY_LINUX) - EthernetServer _ethernetServer(_ethernetGatewayPort, MY_GATEWAY_MAX_CLIENTS); +EthernetServer _ethernetServer(_ethernetGatewayPort, MY_GATEWAY_MAX_CLIENTS); #elif defined(MY_GATEWAY_CLIENT_MODE) - // Nothing to do here +// Nothing to do here #else - EthernetServer _ethernetServer(_ethernetGatewayPort); +EthernetServer _ethernetServer(_ethernetGatewayPort); #endif #if defined(MY_GATEWAY_CLIENT_MODE) - static EthernetClient client = EthernetClient(); - static inputBuffer inputString; +static EthernetClient client = EthernetClient(); +static inputBuffer inputString; #elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX) - static EthernetClient clients[MY_GATEWAY_MAX_CLIENTS]; - static bool clientsConnected[MY_GATEWAY_MAX_CLIENTS]; - static inputBuffer inputString[MY_GATEWAY_MAX_CLIENTS]; +static EthernetClient clients[MY_GATEWAY_MAX_CLIENTS]; +static bool clientsConnected[MY_GATEWAY_MAX_CLIENTS]; +static inputBuffer inputString[MY_GATEWAY_MAX_CLIENTS]; #else - static EthernetClient client = EthernetClient(); - static inputBuffer inputString; +static EthernetClient client = EthernetClient(); +static inputBuffer inputString; #endif #ifndef MY_IP_ADDRESS - void gatewayTransportRenewIP(); +void gatewayTransportRenewIP(); #endif // On W5100 boards with SPI_EN exposed we can use the real SPI bus together with radio // (if we enable it during usage) #ifdef MY_W5100_SPI_EN - void _w5100_spi_en(bool enable) - { - if (enable) - { - // Pull up pin - hwPinMode(MY_W5100_SPI_EN, INPUT); - hwDigitalWrite(MY_W5100_SPI_EN, HIGH); - } - else - { - // Ground pin - hwPinMode(MY_W5100_SPI_EN, OUTPUT); - hwDigitalWrite(MY_W5100_SPI_EN, LOW); - } +void _w5100_spi_en(bool enable) +{ + if (enable) { + // Pull up pin + hwPinMode(MY_W5100_SPI_EN, INPUT); + hwDigitalWrite(MY_W5100_SPI_EN, HIGH); + } else { + // Ground pin + hwPinMode(MY_W5100_SPI_EN, OUTPUT); + hwDigitalWrite(MY_W5100_SPI_EN, LOW); } +} #else - #define _w5100_spi_en(x) +#define _w5100_spi_en(x) #endif -bool gatewayTransportInit() { +bool gatewayTransportInit() +{ _w5100_spi_en(true); - #if defined(MY_GATEWAY_ESP8266) - #if defined(MY_ESP8266_SSID) - // Turn off access point - WiFi.mode (WIFI_STA); - #if defined(MY_ESP8266_HOSTNAME) - WiFi.hostname(MY_ESP8266_HOSTNAME); - #endif - #ifdef MY_IP_ADDRESS - WiFi.config(_ethernetGatewayIP, _gatewayIp, _subnetIp); - #endif - (void)WiFi.begin(MY_ESP8266_SSID, MY_ESP8266_PASSWORD); - while (WiFi.status() != WL_CONNECTED) - { - wait(500); - MY_SERIALDEVICE.print(F(".")); - } - MY_SERIALDEVICE.print(F("IP: ")); - MY_SERIALDEVICE.println(WiFi.localIP()); - #endif - #elif defined(MY_GATEWAY_LINUX) - // Nothing to do here - #else - #ifdef MY_IP_ADDRESS - Ethernet.begin(_ethernetGatewayMAC, _ethernetGatewayIP); - #else - // Get IP address from DHCP - if (!Ethernet.begin(_ethernetGatewayMAC)) { - MY_SERIALDEVICE.print(F("DHCP FAILURE...")); - _w5100_spi_en(false); - return false; - } - #endif - MY_SERIALDEVICE.print(F("IP: ")); - MY_SERIALDEVICE.println(Ethernet.localIP()); - // give the Ethernet interface a second to initialize - delay(1000); - #endif /* MY_GATEWAY_ESP8266 */ +#if defined(MY_GATEWAY_ESP8266) +#if defined(MY_ESP8266_SSID) + // Turn off access point + WiFi.mode (WIFI_STA); +#if defined(MY_ESP8266_HOSTNAME) + WiFi.hostname(MY_ESP8266_HOSTNAME); +#endif +#ifdef MY_IP_ADDRESS + WiFi.config(_ethernetGatewayIP, _gatewayIp, _subnetIp); +#endif + (void)WiFi.begin(MY_ESP8266_SSID, MY_ESP8266_PASSWORD); + while (WiFi.status() != WL_CONNECTED) { + wait(500); + MY_SERIALDEVICE.print(F(".")); + } + MY_SERIALDEVICE.print(F("IP: ")); + MY_SERIALDEVICE.println(WiFi.localIP()); +#endif +#elif defined(MY_GATEWAY_LINUX) + // Nothing to do here +#else +#ifdef MY_IP_ADDRESS + Ethernet.begin(_ethernetGatewayMAC, _ethernetGatewayIP); +#else + // Get IP address from DHCP + if (!Ethernet.begin(_ethernetGatewayMAC)) { + MY_SERIALDEVICE.print(F("DHCP FAILURE...")); + _w5100_spi_en(false); + return false; + } +#endif + MY_SERIALDEVICE.print(F("IP: ")); + MY_SERIALDEVICE.println(Ethernet.localIP()); + // give the Ethernet interface a second to initialize + delay(1000); +#endif /* MY_GATEWAY_ESP8266 */ - #ifdef MY_USE_UDP - _ethernetServer.begin(_ethernetGatewayPort); - #elif defined(MY_GATEWAY_CLIENT_MODE) - #if defined(MY_CONTROLLER_URL_ADDRESS) - if (client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) { - #else - if (client.connect(_ethernetControllerIP, MY_PORT)) { - #endif - debug(PSTR("Eth: connect\n")); - _w5100_spi_en(false); - gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete.")); - _w5100_spi_en(true); - presentNode(); - } else { - client.stop(); - debug(PSTR("Eth: Failed to connect\n")); - } - #else - #if defined(MY_GATEWAY_LINUX) && defined(MY_IP_ADDRESS) - _ethernetServer.begin(_ethernetGatewayIP); - #else - // we have to use pointers due to the constructor of EthernetServer - _ethernetServer.begin(); - #endif - #endif /* USE_UDP */ +#ifdef MY_USE_UDP + _ethernetServer.begin(_ethernetGatewayPort); +#elif defined(MY_GATEWAY_CLIENT_MODE) +#if defined(MY_CONTROLLER_URL_ADDRESS) + if (client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) { +#else + if (client.connect(_ethernetControllerIP, MY_PORT)) { +#endif + debug(PSTR("Eth: connect\n")); + _w5100_spi_en(false); + gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete.")); + _w5100_spi_en(true); + presentNode(); + } else { + client.stop(); + debug(PSTR("Eth: Failed to connect\n")); + } +#else +#if defined(MY_GATEWAY_LINUX) && defined(MY_IP_ADDRESS) + _ethernetServer.begin(_ethernetGatewayIP); +#else + // we have to use pointers due to the constructor of EthernetServer + _ethernetServer.begin(); +#endif +#endif /* USE_UDP */ _w5100_spi_en(false); return true; } @@ -178,240 +174,239 @@ bool gatewayTransportSend(MyMessage &message) setIndication(INDICATION_GW_TX); _w5100_spi_en(true); - #if defined(MY_GATEWAY_CLIENT_MODE) - #if defined(MY_USE_UDP) - #if defined(MY_CONTROLLER_URL_ADDRESS) - _ethernetServer.beginPacket(MY_CONTROLLER_URL_ADDRESS, MY_PORT); - #else - _ethernetServer.beginPacket(_ethernetControllerIP, MY_PORT); - #endif - _ethernetServer.write(_ethernetMsg, strlen(_ethernetMsg)); - // returns 1 if the packet was sent successfully - nbytes = _ethernetServer.endPacket(); - #else - if (!client.connected()) { - client.stop(); - #if defined(MY_CONTROLLER_URL_ADDRESS) - if (client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) { - #else - if (client.connect(_ethernetControllerIP, MY_PORT)) { - #endif - debug(PSTR("Eth: connect\n")); - _w5100_spi_en(false); - gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete.")); - _w5100_spi_en(true); - presentNode(); - } else { - // connecting to the server failed! - debug(PSTR("Eth: Failed to connect\n")); - _w5100_spi_en(false); - return false; - } - } - nbytes = client.write(_ethernetMsg, strlen(_ethernetMsg)); - #endif - #else - // Send message to connected clients - #if defined(MY_GATEWAY_ESP8266) - for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++) - { - if (clients[i] && clients[i].connected()) - { - nbytes += clients[i].write((uint8_t*)_ethernetMsg, strlen(_ethernetMsg)); - } - } - #else - nbytes = _ethernetServer.write(_ethernetMsg); - #endif - #endif /* MY_GATEWAY_CLIENT_MODE */ +#if defined(MY_GATEWAY_CLIENT_MODE) +#if defined(MY_USE_UDP) +#if defined(MY_CONTROLLER_URL_ADDRESS) + _ethernetServer.beginPacket(MY_CONTROLLER_URL_ADDRESS, MY_PORT); +#else + _ethernetServer.beginPacket(_ethernetControllerIP, MY_PORT); +#endif + _ethernetServer.write(_ethernetMsg, strlen(_ethernetMsg)); + // returns 1 if the packet was sent successfully + nbytes = _ethernetServer.endPacket(); +#else + if (!client.connected()) { + client.stop(); +#if defined(MY_CONTROLLER_URL_ADDRESS) + if (client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) { +#else + if (client.connect(_ethernetControllerIP, MY_PORT)) { +#endif + debug(PSTR("Eth: connect\n")); + _w5100_spi_en(false); + gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete.")); + _w5100_spi_en(true); + presentNode(); + } else { + // connecting to the server failed! + debug(PSTR("Eth: Failed to connect\n")); + _w5100_spi_en(false); + return false; + } + } + nbytes = client.write(_ethernetMsg, strlen(_ethernetMsg)); +#endif +#else + // Send message to connected clients +#if defined(MY_GATEWAY_ESP8266) + for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++) { + if (clients[i] && clients[i].connected()) { + nbytes += clients[i].write((uint8_t*)_ethernetMsg, strlen(_ethernetMsg)); + } + } +#else + nbytes = _ethernetServer.write(_ethernetMsg); +#endif +#endif /* MY_GATEWAY_CLIENT_MODE */ _w5100_spi_en(false); return (nbytes > 0); } #if (defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX)) && !defined(MY_GATEWAY_CLIENT_MODE) - bool _readFromClient(uint8_t i) { - while (clients[i].connected() && clients[i].available()) { - char inChar = clients[i].read(); - if (inputString[i].idx < MY_GATEWAY_MAX_RECEIVE_LENGTH - 1) { - // if newline then command is complete - if (inChar == '\n' || inChar == '\r') { - // Add string terminator and prepare for the next message - inputString[i].string[inputString[i].idx] = 0; - debug(PSTR("Client %d: %s\n"), i, inputString[i].string); - inputString[i].idx = 0; - if (protocolParse(_ethernetMsg, inputString[i].string)) { - return true; - } - - } else { - // add it to the inputString: - inputString[i].string[inputString[i].idx++] = inChar; +bool _readFromClient(uint8_t i) +{ + while (clients[i].connected() && clients[i].available()) { + char inChar = clients[i].read(); + if (inputString[i].idx < MY_GATEWAY_MAX_RECEIVE_LENGTH - 1) { + // if newline then command is complete + if (inChar == '\n' || inChar == '\r') { + // Add string terminator and prepare for the next message + inputString[i].string[inputString[i].idx] = 0; + debug(PSTR("Client %d: %s\n"), i, inputString[i].string); + inputString[i].idx = 0; + if (protocolParse(_ethernetMsg, inputString[i].string)) { + return true; } + } else { - // Incoming message too long. Throw away - debug(PSTR("Client %d: Message too long\n"), i); - inputString[i].idx = 0; - // Finished with this client's message. Next loop() we'll see if there's more to read. - break; + // add it to the inputString: + inputString[i].string[inputString[i].idx++] = inChar; } + } else { + // Incoming message too long. Throw away + debug(PSTR("Client %d: Message too long\n"), i); + inputString[i].idx = 0; + // Finished with this client's message. Next loop() we'll see if there's more to read. + break; } - return false; } + return false; +} #else - bool _readFromClient() { - while (client.connected() && client.available()) { - char inChar = client.read(); - if (inputString.idx < MY_GATEWAY_MAX_RECEIVE_LENGTH - 1) { - // if newline then command is complete - if (inChar == '\n' || inChar == '\r') { - // Add string terminator and prepare for the next message - inputString.string[inputString.idx] = 0; - debug(PSTR("Eth: %s\n"), inputString.string); - inputString.idx = 0; - if (protocolParse(_ethernetMsg, inputString.string)) { - return true; - } - - } else { - // add it to the inputString: - inputString.string[inputString.idx++] = inChar; +bool _readFromClient() +{ + while (client.connected() && client.available()) { + char inChar = client.read(); + if (inputString.idx < MY_GATEWAY_MAX_RECEIVE_LENGTH - 1) { + // if newline then command is complete + if (inChar == '\n' || inChar == '\r') { + // Add string terminator and prepare for the next message + inputString.string[inputString.idx] = 0; + debug(PSTR("Eth: %s\n"), inputString.string); + inputString.idx = 0; + if (protocolParse(_ethernetMsg, inputString.string)) { + return true; } + } else { - // Incoming message too long. Throw away - debug(PSTR("Eth: Message too long\n")); - inputString.idx = 0; - // Finished with this client's message. Next loop() we'll see if there's more to read. - break; + // add it to the inputString: + inputString.string[inputString.idx++] = inChar; } + } else { + // Incoming message too long. Throw away + debug(PSTR("Eth: Message too long\n")); + inputString.idx = 0; + // Finished with this client's message. Next loop() we'll see if there's more to read. + break; } - return false; } + return false; +} #endif bool gatewayTransportAvailable() { _w5100_spi_en(true); - #if !defined(MY_IP_ADDRESS) && defined(MY_GATEWAY_W5100) - // renew IP address using DHCP - gatewayTransportRenewIP(); - #endif +#if !defined(MY_IP_ADDRESS) && defined(MY_GATEWAY_W5100) + // renew IP address using DHCP + gatewayTransportRenewIP(); +#endif - #ifdef MY_USE_UDP - int packet_size = _ethernetServer.parsePacket(); +#ifdef MY_USE_UDP + int packet_size = _ethernetServer.parsePacket(); - if (packet_size) { - //debug(PSTR("UDP packet available. Size:%d\n"), packet_size); - #if defined(MY_GATEWAY_ESP8266) - _ethernetServer.read(inputString[0].string, MY_GATEWAY_MAX_RECEIVE_LENGTH); - inputString[0].string[packet_size] = 0; - debug(PSTR("UDP packet received: %s\n"), inputString[0].string); - const bool ok = protocolParse(_ethernetMsg, inputString[0].string); - #else - _ethernetServer.read(inputString.string, MY_GATEWAY_MAX_RECEIVE_LENGTH); - inputString.string[packet_size] = 0; - debug(PSTR("UDP packet received: %s\n"), inputString.string); - _w5100_spi_en(false); - const bool ok = protocolParse(_ethernetMsg, inputString.string); - #endif - if (ok) - { - setIndication(INDICATION_GW_RX); - } - return ok; + if (packet_size) { + //debug(PSTR("UDP packet available. Size:%d\n"), packet_size); +#if defined(MY_GATEWAY_ESP8266) + _ethernetServer.read(inputString[0].string, MY_GATEWAY_MAX_RECEIVE_LENGTH); + inputString[0].string[packet_size] = 0; + debug(PSTR("UDP packet received: %s\n"), inputString[0].string); + const bool ok = protocolParse(_ethernetMsg, inputString[0].string); +#else + _ethernetServer.read(inputString.string, MY_GATEWAY_MAX_RECEIVE_LENGTH); + inputString.string[packet_size] = 0; + debug(PSTR("UDP packet received: %s\n"), inputString.string); + _w5100_spi_en(false); + const bool ok = protocolParse(_ethernetMsg, inputString.string); +#endif + if (ok) { + setIndication(INDICATION_GW_RX); } - #elif defined(MY_GATEWAY_CLIENT_MODE) - if (!client.connected()) { - client.stop(); - #if defined(MY_CONTROLLER_URL_ADDRESS) - if (client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) { - #else - if (client.connect(_ethernetControllerIP, MY_PORT)) { - #endif - debug(PSTR("Eth: connect\n")); - _w5100_spi_en(false); + return ok; + } +#elif defined(MY_GATEWAY_CLIENT_MODE) + if (!client.connected()) { + client.stop(); +#if defined(MY_CONTROLLER_URL_ADDRESS) + if (client.connect(MY_CONTROLLER_URL_ADDRESS, MY_PORT)) { +#else + if (client.connect(_ethernetControllerIP, MY_PORT)) { +#endif + debug(PSTR("Eth: connect\n")); + _w5100_spi_en(false); + gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete.")); + _w5100_spi_en(true); + presentNode(); + } else { + debug(PSTR("Eth: Failed to connect\n")); + _w5100_spi_en(false); + return false; + } + } + if (_readFromClient()) { + setIndication(INDICATION_GW_RX); + _w5100_spi_en(false); + return true; + } +#else +#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX) + // ESP8266: Go over list of clients and stop any that are no longer connected. + // If the server has a new client connection it will be assigned to a free slot. + bool allSlotsOccupied = true; + for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++) { + if (!clients[i].connected()) { + if (clientsConnected[i]) { + debug(PSTR("Client %d disconnected\n"), i); + clients[i].stop(); + } + //check if there are any new clients + if (_ethernetServer.hasClient()) { + clients[i] = _ethernetServer.available(); + inputString[i].idx = 0; + debug(PSTR("Client %d connected\n"), i); gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete.")); - _w5100_spi_en(true); + // Send presentation of locally attached sensors (and node if applicable) presentNode(); - } else { - debug(PSTR("Eth: Failed to connect\n")); - _w5100_spi_en(false); - return false; } } - if (_readFromClient()) { + bool connected = clients[i].connected(); + clientsConnected[i] = connected; + allSlotsOccupied &= connected; + } + if (allSlotsOccupied && _ethernetServer.hasClient()) { + //no free/disconnected spot so reject + debug(PSTR("No free slot available\n")); + EthernetClient c = _ethernetServer.available(); + c.stop(); + } + // Loop over clients connect and read available data + for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++) { + if (_readFromClient(i)) { setIndication(INDICATION_GW_RX); _w5100_spi_en(false); return true; } - #else - #if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX) - // ESP8266: Go over list of clients and stop any that are no longer connected. - // If the server has a new client connection it will be assigned to a free slot. - bool allSlotsOccupied = true; - for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++) { - if (!clients[i].connected()) { - if (clientsConnected[i]) { - debug(PSTR("Client %d disconnected\n"), i); - clients[i].stop(); - } - //check if there are any new clients - if (_ethernetServer.hasClient()) { - clients[i] = _ethernetServer.available(); - inputString[i].idx = 0; - debug(PSTR("Client %d connected\n"), i); - gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete.")); - // Send presentation of locally attached sensors (and node if applicable) - presentNode(); - } - } - bool connected = clients[i].connected(); - clientsConnected[i] = connected; - allSlotsOccupied &= connected; - } - if (allSlotsOccupied && _ethernetServer.hasClient()) { - //no free/disconnected spot so reject - debug(PSTR("No free slot available\n")); - EthernetClient c = _ethernetServer.available(); - c.stop(); - } - // Loop over clients connect and read available data - for (uint8_t i = 0; i < ARRAY_SIZE(clients); i++) { - if (_readFromClient(i)) { - setIndication(INDICATION_GW_RX); - _w5100_spi_en(false); - return true; - } - } - #else - // W5100/ENC module does not have hasClient-method. We can only serve one client at the time. - EthernetClient newclient = _ethernetServer.available(); - // if a new client connects make sure to dispose any previous existing sockets - if (newclient) { - if (client != newclient) { - client.stop(); - client = newclient; - debug(PSTR("Eth: connect\n")); - _w5100_spi_en(false); - gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete.")); - _w5100_spi_en(true); - presentNode(); - } - } - if (client) { - if (!client.connected()) { - debug(PSTR("Eth: disconnect\n")); - client.stop(); - } else { - if (_readFromClient()) { - setIndication(INDICATION_GW_RX); - _w5100_spi_en(false); - return true; - } - } + } +#else + // W5100/ENC module does not have hasClient-method. We can only serve one client at the time. + EthernetClient newclient = _ethernetServer.available(); + // if a new client connects make sure to dispose any previous existing sockets + if (newclient) { + if (client != newclient) { + client.stop(); + client = newclient; + debug(PSTR("Eth: connect\n")); + _w5100_spi_en(false); + gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete.")); + _w5100_spi_en(true); + presentNode(); + } + } + if (client) { + if (!client.connected()) { + debug(PSTR("Eth: disconnect\n")); + client.stop(); + } else { + if (_readFromClient()) { + setIndication(INDICATION_GW_RX); + _w5100_spi_en(false); + return true; } - #endif /* MY_GATEWAY_ESP8266 */ - #endif + } + } +#endif /* MY_GATEWAY_ESP8266 */ +#endif _w5100_spi_en(false); return false; } diff --git a/core/MyGatewayTransportMQTTClient.cpp b/core/MyGatewayTransportMQTTClient.cpp index 339d1aa7a..dc3634c08 100644 --- a/core/MyGatewayTransportMQTTClient.cpp +++ b/core/MyGatewayTransportMQTTClient.cpp @@ -23,23 +23,23 @@ #include "MyGatewayTransport.h" #if defined MY_CONTROLLER_IP_ADDRESS - IPAddress _brokerIp(MY_CONTROLLER_IP_ADDRESS); +IPAddress _brokerIp(MY_CONTROLLER_IP_ADDRESS); #endif #if defined(MY_GATEWAY_ESP8266) - #define EthernetClient WiFiClient - #if defined(MY_IP_ADDRESS) - IPAddress _gatewayIp(MY_IP_GATEWAY_ADDRESS); - IPAddress _subnetIp(MY_IP_SUBNET_ADDRESS); - #endif +#define EthernetClient WiFiClient +#if defined(MY_IP_ADDRESS) +IPAddress _gatewayIp(MY_IP_GATEWAY_ADDRESS); +IPAddress _subnetIp(MY_IP_SUBNET_ADDRESS); +#endif #elif defined(MY_GATEWAY_LINUX) - // Nothing to do here +// Nothing to do here #else - uint8_t _MQTT_clientMAC[] = { MY_MAC_ADDRESS }; +uint8_t _MQTT_clientMAC[] = { MY_MAC_ADDRESS }; #endif #if defined(MY_IP_ADDRESS) - IPAddress _MQTT_clientIp(MY_IP_ADDRESS); +IPAddress _MQTT_clientIp(MY_IP_ADDRESS); #endif static EthernetClient _MQTT_ethClient; @@ -48,7 +48,8 @@ static bool _MQTT_connecting = true; static bool _MQTT_available = false; static MyMessage _MQTT_msg; -bool gatewayTransportSend(MyMessage &message) { +bool gatewayTransportSend(MyMessage &message) +{ if (!_MQTT_client.connected()) { return false; } @@ -58,19 +59,21 @@ bool gatewayTransportSend(MyMessage &message) { return _MQTT_client.publish(topic, message.getString(_convBuffer)); } -void incomingMQTT(char* topic, uint8_t* payload, unsigned int length) { +void incomingMQTT(char* topic, uint8_t* payload, unsigned int length) +{ debug(PSTR("Message arrived on topic: %s\n"), topic); _MQTT_available = protocolMQTTParse(_MQTT_msg, topic, payload, length); } -bool reconnectMQTT() { +bool reconnectMQTT() +{ debug(PSTR("Attempting MQTT connection...\n")); // Attempt to connect if (_MQTT_client.connect(MY_MQTT_CLIENT_ID #if defined(MY_MQTT_USER) && defined(MY_MQTT_PASSWORD) - , MY_MQTT_USER, MY_MQTT_PASSWORD + , MY_MQTT_USER, MY_MQTT_PASSWORD #endif - )) { + )) { debug(PSTR("MQTT connected\n")); // Send presentation of locally attached sensors (and node if applicable) @@ -85,58 +88,60 @@ bool reconnectMQTT() { return false; } -bool gatewayTransportConnect() { - #if defined(MY_GATEWAY_ESP8266) - while (WiFi.status() != WL_CONNECTED) { - wait(500); - MY_SERIALDEVICE.print("."); - } - MY_SERIALDEVICE.print("IP: "); - MY_SERIALDEVICE.println(WiFi.localIP()); - #elif defined(MY_GATEWAY_LINUX) - #if defined(MY_IP_ADDRESS) - //TODO - #endif - #else - #ifdef MY_IP_ADDRESS - Ethernet.begin(_MQTT_clientMAC, _MQTT_clientIp); - #else - // Get IP address from DHCP - if (!Ethernet.begin(_MQTT_clientMAC)) { - MY_SERIALDEVICE.print("DHCP FAILURE..."); - _MQTT_connecting = false; - return false; - } - #endif - MY_SERIALDEVICE.print("IP: "); - MY_SERIALDEVICE.println(Ethernet.localIP()); - // give the Ethernet interface a second to initialize - delay(1000); - #endif +bool gatewayTransportConnect() +{ +#if defined(MY_GATEWAY_ESP8266) + while (WiFi.status() != WL_CONNECTED) { + wait(500); + MY_SERIALDEVICE.print("."); + } + MY_SERIALDEVICE.print("IP: "); + MY_SERIALDEVICE.println(WiFi.localIP()); +#elif defined(MY_GATEWAY_LINUX) +#if defined(MY_IP_ADDRESS) + //TODO +#endif +#else +#ifdef MY_IP_ADDRESS + Ethernet.begin(_MQTT_clientMAC, _MQTT_clientIp); +#else + // Get IP address from DHCP + if (!Ethernet.begin(_MQTT_clientMAC)) { + MY_SERIALDEVICE.print("DHCP FAILURE..."); + _MQTT_connecting = false; + return false; + } +#endif + MY_SERIALDEVICE.print("IP: "); + MY_SERIALDEVICE.println(Ethernet.localIP()); + // give the Ethernet interface a second to initialize + delay(1000); +#endif return true; } -bool gatewayTransportInit() { +bool gatewayTransportInit() +{ _MQTT_connecting = true; - #if defined(MY_CONTROLLER_IP_ADDRESS) - _MQTT_client.setServer(_brokerIp, MY_PORT); - #else - _MQTT_client.setServer(MY_CONTROLLER_URL_ADDRESS, MY_PORT); - #endif - - _MQTT_client.setCallback(incomingMQTT); - - #if defined(MY_GATEWAY_ESP8266) - // Turn off access point - WiFi.mode(WIFI_STA); - #if defined(MY_ESP8266_HOSTNAME) - WiFi.hostname(MY_ESP8266_HOSTNAME); - #endif - (void)WiFi.begin(MY_ESP8266_SSID, MY_ESP8266_PASSWORD); - #ifdef MY_IP_ADDRESS - WiFi.config(_MQTT_clientIp, _gatewayIp, _subnetIp); - #endif - #endif +#if defined(MY_CONTROLLER_IP_ADDRESS) + _MQTT_client.setServer(_brokerIp, MY_PORT); +#else + _MQTT_client.setServer(MY_CONTROLLER_URL_ADDRESS, MY_PORT); +#endif + + _MQTT_client.setCallback(incomingMQTT); + +#if defined(MY_GATEWAY_ESP8266) + // Turn off access point + WiFi.mode(WIFI_STA); +#if defined(MY_ESP8266_HOSTNAME) + WiFi.hostname(MY_ESP8266_HOSTNAME); +#endif + (void)WiFi.begin(MY_ESP8266_SSID, MY_ESP8266_PASSWORD); +#ifdef MY_IP_ADDRESS + WiFi.config(_MQTT_clientIp, _gatewayIp, _subnetIp); +#endif +#endif gatewayTransportConnect(); @@ -144,10 +149,11 @@ bool gatewayTransportInit() { return true; } -bool gatewayTransportAvailable() { +bool gatewayTransportAvailable() +{ if (_MQTT_connecting) { return false; - } + } //keep lease on dhcp address //Ethernet.maintain(); if (!_MQTT_client.connected()) { @@ -161,7 +167,8 @@ bool gatewayTransportAvailable() { return _MQTT_available; } -MyMessage & gatewayTransportReceive() { +MyMessage & gatewayTransportReceive() +{ // Return the last parsed message _MQTT_available = false; return _MQTT_msg; diff --git a/core/MyGatewayTransportSerial.cpp b/core/MyGatewayTransportSerial.cpp index 45f05e62a..4528d6e95 100644 --- a/core/MyGatewayTransportSerial.cpp +++ b/core/MyGatewayTransportSerial.cpp @@ -23,21 +23,23 @@ #include "MyMessage.h" #include "MyProtocol.h" - // global variables +// global variables extern MyMessage _msgTmp; char _serialInputString[MY_GATEWAY_MAX_RECEIVE_LENGTH]; // A buffer for incoming commands from serial interface uint8_t _serialInputPos; MyMessage _serialMsg; -bool gatewayTransportSend(MyMessage &message) { - setIndication(INDICATION_GW_TX); +bool gatewayTransportSend(MyMessage &message) +{ + setIndication(INDICATION_GW_TX); MY_SERIALDEVICE.print(protocolFormat(message)); // Serial print is always successful return true; } -bool gatewayTransportInit() { +bool gatewayTransportInit() +{ gatewayTransportSend(buildGw(_msgTmp, I_GATEWAY_READY).set("Gateway startup complete.")); // Send presentation of locally attached sensors (and node if applicable) presentNode(); @@ -45,7 +47,8 @@ bool gatewayTransportInit() { return true; } -bool gatewayTransportAvailable() { +bool gatewayTransportAvailable() +{ while (MY_SERIALDEVICE.available()) { // get the new byte: char inChar = (char) MY_SERIALDEVICE.read(); @@ -55,11 +58,10 @@ bool gatewayTransportAvailable() { if (inChar == '\n') { _serialInputString[_serialInputPos] = 0; bool ok = protocolParse(_serialMsg, _serialInputString); - if (ok) - { - setIndication(INDICATION_GW_RX); - } - _serialInputPos = 0; + if (ok) { + setIndication(INDICATION_GW_RX); + } + _serialInputPos = 0; return ok; } else { // add it to the inputString: @@ -74,7 +76,8 @@ bool gatewayTransportAvailable() { return false; } -MyMessage & gatewayTransportReceive() { +MyMessage & gatewayTransportReceive() +{ // Return the last parsed message return _serialMsg; } diff --git a/core/MyHw.h b/core/MyHw.h index 99bfcc653..3b4cfbae3 100644 --- a/core/MyHw.h +++ b/core/MyHw.h @@ -17,12 +17,12 @@ * version 2 as published by the Free Software Foundation. */ - /** - * @file MyHw.h - * - * MySensors hardware abstraction layer - */ - +/** +* @file MyHw.h +* +* MySensors hardware abstraction layer +*/ + #ifndef MyHw_h #define MyHw_h @@ -76,7 +76,8 @@ int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms); * @param ms Time to sleep, in [ms]. * @return -1 when woken by timer, or interrupt number when woken by interrupt. */ -int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms); +int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, + unsigned long ms); #if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG) /** @@ -102,7 +103,7 @@ uint16_t hwFreeMem(); void hwDebugPrint(const char *fmt, ... ); #endif -/** +/** * @def MY_CRITICAL_SECTION * @brief Creates a block of code that is guaranteed to be executed atomically. * Upon entering the block all interrupts are disabled, and re-enabled upon @@ -112,12 +113,12 @@ void hwDebugPrint(const char *fmt, ... ); * platform (e.g AVR): * @code * volatile uint16_t val = 0; - * + * * void interrupHandler() * { * val = ~val; * } - * + * * void loop() * { * uint16_t copy_val; @@ -131,7 +132,7 @@ void hwDebugPrint(const char *fmt, ... ); * interrupted during execution. */ #ifdef DOXYGEN - #define MY_CRITICAL_SECTION +#define MY_CRITICAL_SECTION #endif /* DOXYGEN */ #endif // #ifdef MyHw_h diff --git a/core/MyHwATMega328.cpp b/core/MyHwATMega328.cpp index 6619747bb..50c2e5115 100644 --- a/core/MyHwATMega328.cpp +++ b/core/MyHwATMega328.cpp @@ -23,32 +23,33 @@ #define INVALID_INTERRUPT_NUM (0xFFu) -volatile uint8_t _wokeUpByInterrupt = INVALID_INTERRUPT_NUM; // Interrupt number that woke the mcu. -volatile uint8_t _wakeUp1Interrupt = INVALID_INTERRUPT_NUM; // Interrupt number for wakeUp1-callback. -volatile uint8_t _wakeUp2Interrupt = INVALID_INTERRUPT_NUM; // Interrupt number for wakeUp2-callback. +volatile uint8_t _wokeUpByInterrupt = + INVALID_INTERRUPT_NUM; // Interrupt number that woke the mcu. +volatile uint8_t _wakeUp1Interrupt = + INVALID_INTERRUPT_NUM; // Interrupt number for wakeUp1-callback. +volatile uint8_t _wakeUp2Interrupt = + INVALID_INTERRUPT_NUM; // Interrupt number for wakeUp2-callback. void wakeUp1() //place to send the interrupts { detachInterrupt(_wakeUp1Interrupt); - if (_wakeUp2Interrupt != INVALID_INTERRUPT_NUM) - { - detachInterrupt(_wakeUp2Interrupt); - } + if (_wakeUp2Interrupt != INVALID_INTERRUPT_NUM) { + detachInterrupt(_wakeUp2Interrupt); + } _wokeUpByInterrupt = _wakeUp1Interrupt; } void wakeUp2() //place to send the second interrupts { detachInterrupt(_wakeUp2Interrupt); - if (_wakeUp1Interrupt != INVALID_INTERRUPT_NUM) - { - detachInterrupt(_wakeUp1Interrupt); - } + if (_wakeUp1Interrupt != INVALID_INTERRUPT_NUM) { + detachInterrupt(_wakeUp1Interrupt); + } _wokeUpByInterrupt = _wakeUp2Interrupt; } bool interruptWakeUp() { - return _wokeUpByInterrupt != INVALID_INTERRUPT_NUM; + return _wokeUpByInterrupt != INVALID_INTERRUPT_NUM; } // Watchdog Timer interrupt service routine. This routine is required @@ -57,13 +58,13 @@ ISR (WDT_vect) { } -void hwPowerDown(period_t period) { +void hwPowerDown(period_t period) +{ // disable ADC for power saving ADCSRA &= ~(1 << ADEN); // save WDT settings uint8_t WDTsave = WDTCSR; - if (period != SLEEP_FOREVER) - { + if (period != SLEEP_FOREVER) { wdt_enable(period); // enable WDT interrupt before system reset WDTCSR |= (1 << WDCE) | (1 << WDIE); @@ -74,14 +75,14 @@ void hwPowerDown(period_t period) { set_sleep_mode(SLEEP_MODE_PWR_DOWN); cli(); sleep_enable(); - #if defined __AVR_ATmega328P__ - sleep_bod_disable(); - #endif +#if defined __AVR_ATmega328P__ + sleep_bod_disable(); +#endif // Enable interrupts & sleep until WDT or ext. interrupt sei(); - // Directly sleep CPU, to prevent race conditions! (see chapter 7.7 of ATMega328P datasheet) + // Directly sleep CPU, to prevent race conditions! (see chapter 7.7 of ATMega328P datasheet) sleep_cpu(); - sleep_disable(); + sleep_disable(); // restore previous WDT settings cli(); wdt_reset(); @@ -94,42 +95,77 @@ void hwPowerDown(period_t period) { ADCSRA |= (1 << ADEN); } -void hwInternalSleep(unsigned long ms) { +void hwInternalSleep(unsigned long ms) +{ // Let serial prints finish (debug, log etc) - #ifndef MY_DISABLED_SERIAL - MY_SERIALDEVICE.flush(); - #endif - while (!interruptWakeUp() && ms >= 8000) { hwPowerDown(SLEEP_8S); ms -= 8000; } - if (!interruptWakeUp() && ms >= 4000) { hwPowerDown(SLEEP_4S); ms -= 4000; } - if (!interruptWakeUp() && ms >= 2000) { hwPowerDown(SLEEP_2S); ms -= 2000; } - if (!interruptWakeUp() && ms >= 1000) { hwPowerDown(SLEEP_1S); ms -= 1000; } - if (!interruptWakeUp() && ms >= 500) { hwPowerDown(SLEEP_500MS); ms -= 500; } - if (!interruptWakeUp() && ms >= 250) { hwPowerDown(SLEEP_250MS); ms -= 250; } - if (!interruptWakeUp() && ms >= 125) { hwPowerDown(SLEEP_120MS); ms -= 120; } - if (!interruptWakeUp() && ms >= 64) { hwPowerDown(SLEEP_60MS); ms -= 60; } - if (!interruptWakeUp() && ms >= 32) { hwPowerDown(SLEEP_30MS); ms -= 30; } - if (!interruptWakeUp() && ms >= 16) { hwPowerDown(SLEEP_15MS); ms -= 15; } +#ifndef MY_DISABLED_SERIAL + MY_SERIALDEVICE.flush(); +#endif + while (!interruptWakeUp() && ms >= 8000) { + hwPowerDown(SLEEP_8S); + ms -= 8000; + } + if (!interruptWakeUp() && ms >= 4000) { + hwPowerDown(SLEEP_4S); + ms -= 4000; + } + if (!interruptWakeUp() && ms >= 2000) { + hwPowerDown(SLEEP_2S); + ms -= 2000; + } + if (!interruptWakeUp() && ms >= 1000) { + hwPowerDown(SLEEP_1S); + ms -= 1000; + } + if (!interruptWakeUp() && ms >= 500) { + hwPowerDown(SLEEP_500MS); + ms -= 500; + } + if (!interruptWakeUp() && ms >= 250) { + hwPowerDown(SLEEP_250MS); + ms -= 250; + } + if (!interruptWakeUp() && ms >= 125) { + hwPowerDown(SLEEP_120MS); + ms -= 120; + } + if (!interruptWakeUp() && ms >= 64) { + hwPowerDown(SLEEP_60MS); + ms -= 60; + } + if (!interruptWakeUp() && ms >= 32) { + hwPowerDown(SLEEP_30MS); + ms -= 30; + } + if (!interruptWakeUp() && ms >= 16) { + hwPowerDown(SLEEP_15MS); + ms -= 15; + } } -int8_t hwSleep(unsigned long ms) { +int8_t hwSleep(unsigned long ms) +{ hwInternalSleep(ms); return MY_WAKE_UP_BY_TIMER; } -int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { +int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) +{ return hwSleep(interrupt,mode,INVALID_INTERRUPT_NUM,0u,ms); } -int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { - // Disable interrupts until going to sleep, otherwise interrupts occurring between attachInterrupt() - // and sleep might cause the ATMega to not wakeup from sleep as interrupt has already be handled! +int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, + unsigned long ms) +{ + // Disable interrupts until going to sleep, otherwise interrupts occurring between attachInterrupt() + // and sleep might cause the ATMega to not wakeup from sleep as interrupt has already be handled! cli(); // attach interrupts - _wakeUp1Interrupt = interrupt1; - _wakeUp2Interrupt = interrupt2; - if (interrupt1 != INVALID_INTERRUPT_NUM) { - attachInterrupt(interrupt1, wakeUp1, mode1); - } + _wakeUp1Interrupt = interrupt1; + _wakeUp2Interrupt = interrupt2; + if (interrupt1 != INVALID_INTERRUPT_NUM) { + attachInterrupt(interrupt1, wakeUp1, mode1); + } if (interrupt2 != INVALID_INTERRUPT_NUM) { attachInterrupt(interrupt2, wakeUp2, mode2); } @@ -139,40 +175,41 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo hwInternalSleep(ms); } else { // sleep until ext interrupt triggered - hwPowerDown(SLEEP_FOREVER); + hwPowerDown(SLEEP_FOREVER); } - // Assure any interrupts attached, will get detached when they did not occur. - if (interrupt1 != INVALID_INTERRUPT_NUM) { - detachInterrupt(interrupt1); - } + // Assure any interrupts attached, will get detached when they did not occur. + if (interrupt1 != INVALID_INTERRUPT_NUM) { + detachInterrupt(interrupt1); + } if (interrupt2 != INVALID_INTERRUPT_NUM) { detachInterrupt(interrupt2); } - // Return what woke the mcu. - int8_t ret = MY_WAKE_UP_BY_TIMER; // default: no interrupt triggered, timer wake up - if (interruptWakeUp()) { - ret = static_cast(_wokeUpByInterrupt); - } - // Clear woke-up-by-interrupt flag, so next sleeps won't return immediately. - _wokeUpByInterrupt = INVALID_INTERRUPT_NUM; + // Return what woke the mcu. + int8_t ret = MY_WAKE_UP_BY_TIMER; // default: no interrupt triggered, timer wake up + if (interruptWakeUp()) { + ret = static_cast(_wokeUpByInterrupt); + } + // Clear woke-up-by-interrupt flag, so next sleeps won't return immediately. + _wokeUpByInterrupt = INVALID_INTERRUPT_NUM; return ret; } #if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG) -uint16_t hwCPUVoltage() { +uint16_t hwCPUVoltage() +{ // Measure Vcc against 1.1V Vref - #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - ADMUX = (_BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1)); - #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) - ADMUX = (_BV(MUX5) | _BV(MUX0)); - #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) - ADMUX = (_BV(MUX3) | _BV(MUX2)); - #else - ADMUX = (_BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1)); - #endif +#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + ADMUX = (_BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1)); +#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) + ADMUX = (_BV(MUX5) | _BV(MUX0)); +#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) + ADMUX = (_BV(MUX3) | _BV(MUX2)); +#else + ADMUX = (_BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1)); +#endif // Vref settle delay(70); // Do conversion @@ -182,7 +219,8 @@ uint16_t hwCPUVoltage() { return (1125300UL) / ADC; } -uint16_t hwCPUFrequency() { +uint16_t hwCPUFrequency() +{ cli(); // setup timer1 TIFR1 = 0xFF; @@ -210,7 +248,8 @@ uint16_t hwCPUFrequency() { return TCNT1 * 2048UL / 100000UL; } -uint16_t hwFreeMem() { +uint16_t hwFreeMem() +{ extern int __heap_start, *__brkval; int v; return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); @@ -218,27 +257,28 @@ uint16_t hwFreeMem() { #endif #ifdef MY_DEBUG -void hwDebugPrint(const char *fmt, ... ) { +void hwDebugPrint(const char *fmt, ... ) +{ char fmtBuffer[MY_SERIAL_OUTPUT_SIZE]; - #ifdef MY_GATEWAY_FEATURE - // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) - snprintf_P(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); - MY_SERIALDEVICE.print(fmtBuffer); - #else - // prepend timestamp (AVR nodes) - MY_SERIALDEVICE.print(hwMillis()); - MY_SERIALDEVICE.print(" "); - #endif +#ifdef MY_GATEWAY_FEATURE + // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) + snprintf_P(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); + MY_SERIALDEVICE.print(fmtBuffer); +#else + // prepend timestamp (AVR nodes) + MY_SERIALDEVICE.print(hwMillis()); + MY_SERIALDEVICE.print(" "); +#endif va_list args; va_start (args, fmt ); - #ifdef MY_GATEWAY_FEATURE - // Truncate message if this is gateway node - vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args); - fmtBuffer[sizeof(fmtBuffer) - 2] = '\n'; - fmtBuffer[sizeof(fmtBuffer) - 1] = '\0'; - #else - vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args); - #endif +#ifdef MY_GATEWAY_FEATURE + // Truncate message if this is gateway node + vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args); + fmtBuffer[sizeof(fmtBuffer) - 2] = '\n'; + fmtBuffer[sizeof(fmtBuffer) - 1] = '\0'; +#else + vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args); +#endif va_end (args); MY_SERIALDEVICE.print(fmtBuffer); MY_SERIALDEVICE.flush(); diff --git a/core/MyHwATMega328.h b/core/MyHwATMega328.h index bb5962f75..7be0d4770 100644 --- a/core/MyHwATMega328.h +++ b/core/MyHwATMega328.h @@ -39,18 +39,18 @@ #if defined __AVR_ATmega328P__ #ifndef sleep_bod_disable #define sleep_bod_disable() \ -do { \ - unsigned char tempreg; \ - __asm__ __volatile__("in %[tempreg], %[mcucr]" "\n\t" \ - "ori %[tempreg], %[bods_bodse]" "\n\t" \ - "out %[mcucr], %[tempreg]" "\n\t" \ - "andi %[tempreg], %[not_bodse]" "\n\t" \ - "out %[mcucr], %[tempreg]" \ - : [tempreg] "=&d" (tempreg) \ - : [mcucr] "I" _SFR_IO_ADDR(MCUCR), \ - [bods_bodse] "i" (_BV(BODS) | _BV(BODSE)), \ - [not_bodse] "i" (~_BV(BODSE))); \ -} while (0) + do { \ + unsigned char tempreg; \ + __asm__ __volatile__("in %[tempreg], %[mcucr]" "\n\t" \ + "ori %[tempreg], %[bods_bodse]" "\n\t" \ + "out %[mcucr], %[tempreg]" "\n\t" \ + "andi %[tempreg], %[not_bodse]" "\n\t" \ + "out %[mcucr], %[tempreg]" \ + : [tempreg] "=&d" (tempreg) \ + : [mcucr] "I" _SFR_IO_ADDR(MCUCR), \ + [bods_bodse] "i" (_BV(BODS) | _BV(BODSE)), \ + [not_bodse] "i" (~_BV(BODSE))); \ + } while (0) #endif #endif @@ -63,9 +63,9 @@ do { \ #if defined(MY_DISABLED_SERIAL) - #define hwInit() +#define hwInit() #else - #define hwInit() MY_SERIALDEVICE.begin(MY_BAUD_RATE) +#define hwInit() MY_SERIALDEVICE.begin(MY_BAUD_RATE) #endif #define hwWatchdogReset() wdt_reset() @@ -96,7 +96,7 @@ enum period_t { void hwInternalSleep(unsigned long ms); #ifndef DOXYGEN - #define MY_CRITICAL_SECTION ATOMIC_BLOCK(ATOMIC_RESTORESTATE) +#define MY_CRITICAL_SECTION ATOMIC_BLOCK(ATOMIC_RESTORESTATE) #endif /* DOXYGEN */ #endif diff --git a/core/MyHwESP8266.cpp b/core/MyHwESP8266.cpp index c4d39d141..398576903 100644 --- a/core/MyHwESP8266.cpp +++ b/core/MyHwESP8266.cpp @@ -23,7 +23,7 @@ void hwInit(void) { #if !defined(MY_DISABLED_SERIAL) - MY_SERIALDEVICE.begin(MY_BAUD_RATE, SERIAL_8N1, MY_ESP8266_SERIAL_MODE, 1); + MY_SERIALDEVICE.begin(MY_BAUD_RATE, SERIAL_8N1, MY_ESP8266_SERIAL_MODE, 1); MY_SERIALDEVICE.setDebugOutput(true); #endif EEPROM.begin(EEPROM_size); @@ -31,12 +31,11 @@ void hwInit(void) void hwReadConfigBlock(void* buf, void* addr, size_t length) { - uint8_t* dst = static_cast(buf); - int pos = reinterpret_cast(addr); - while (length-- > 0) - { - *dst++ = EEPROM.read(pos++); - } + uint8_t* dst = static_cast(buf); + int pos = reinterpret_cast(addr); + while (length-- > 0) { + *dst++ = EEPROM.read(pos++); + } } void hwWriteConfigBlock(void* buf, void* addr, size_t length) @@ -52,9 +51,9 @@ void hwWriteConfigBlock(void* buf, void* addr, size_t length) uint8_t hwReadConfig(const int addr) { - uint8_t value; - hwReadConfigBlock(&value, reinterpret_cast(addr), 1); - return value; + uint8_t value; + hwReadConfigBlock(&value, reinterpret_cast(addr), 1); + return value; } void hwWriteConfig(const int addr, uint8_t value) @@ -63,13 +62,15 @@ void hwWriteConfig(const int addr, uint8_t value) } -int8_t hwSleep(unsigned long ms) { +int8_t hwSleep(unsigned long ms) +{ // TODO: Not supported! (void)ms; return MY_SLEEP_NOT_POSSIBLE; } -int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { +int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) +{ // TODO: Not supported! (void)interrupt; (void)mode; @@ -77,7 +78,9 @@ int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { return MY_SLEEP_NOT_POSSIBLE; } -int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { +int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, + unsigned long ms) +{ // TODO: Not supported! (void)interrupt1; (void)mode1; @@ -90,39 +93,43 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo #if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG) ADC_MODE(ADC_VCC); -uint16_t hwCPUVoltage() { +uint16_t hwCPUVoltage() +{ // in mV return ESP.getVcc(); } -uint16_t hwCPUFrequency() { +uint16_t hwCPUFrequency() +{ // in 1/10Mhz return ESP.getCpuFreqMHz()*10; } -uint16_t hwFreeMem() { +uint16_t hwFreeMem() +{ return ESP.getFreeHeap(); } #endif #ifdef MY_DEBUG -void hwDebugPrint(const char *fmt, ... ) { +void hwDebugPrint(const char *fmt, ... ) +{ char fmtBuffer[MY_SERIAL_OUTPUT_SIZE]; - #ifdef MY_GATEWAY_FEATURE - // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) - snprintf_P(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); - MY_SERIALDEVICE.print(fmtBuffer); - #endif +#ifdef MY_GATEWAY_FEATURE + // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) + snprintf_P(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); + MY_SERIALDEVICE.print(fmtBuffer); +#endif va_list args; va_start (args, fmt ); - #ifdef MY_GATEWAY_FEATURE - // Truncate message if this is gateway node - vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args); - fmtBuffer[sizeof(fmtBuffer) - 2] = '\n'; - fmtBuffer[sizeof(fmtBuffer) - 1] = '\0'; - #else - vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args); - #endif +#ifdef MY_GATEWAY_FEATURE + // Truncate message if this is gateway node + vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args); + fmtBuffer[sizeof(fmtBuffer) - 2] = '\n'; + fmtBuffer[sizeof(fmtBuffer) - 1] = '\0'; +#else + vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args); +#endif va_end (args); MY_SERIALDEVICE.print(fmtBuffer); MY_SERIALDEVICE.flush(); diff --git a/core/MyHwESP8266.h b/core/MyHwESP8266.h index f95ace0bd..03f622510 100644 --- a/core/MyHwESP8266.h +++ b/core/MyHwESP8266.h @@ -54,11 +54,11 @@ uint8_t hwReadConfig(const int addr); */ static __inline__ void __psRestore(const uint32_t *__s) { - xt_wsr_ps( *__s ); + xt_wsr_ps( *__s ); } - + #ifndef DOXYGEN - #define MY_CRITICAL_SECTION for ( uint32_t __psSaved __attribute__((__cleanup__(__psRestore))) = xt_rsil(15), __ToDo = 1; __ToDo ; __ToDo = 0 ) +#define MY_CRITICAL_SECTION for ( uint32_t __psSaved __attribute__((__cleanup__(__psRestore))) = xt_rsil(15), __ToDo = 1; __ToDo ; __ToDo = 0 ) #endif /* DOXYGEN */ #endif // #ifdef ARDUINO_ARCH_ESP8266 diff --git a/core/MyHwLinuxGeneric.cpp b/core/MyHwLinuxGeneric.cpp index ea7a47cde..e90b596a1 100644 --- a/core/MyHwLinuxGeneric.cpp +++ b/core/MyHwLinuxGeneric.cpp @@ -30,12 +30,12 @@ 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 +#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 } @@ -88,14 +88,15 @@ int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) } // Not supported! -int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) +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; } @@ -105,13 +106,13 @@ uint16_t hwCPUVoltage() // TODO: Not supported! return 0; } - + uint16_t hwCPUFrequency() { // TODO: Not supported! return 0; } - + uint16_t hwFreeMem() { // TODO: Not supported! diff --git a/core/MyHwLinuxGeneric.h b/core/MyHwLinuxGeneric.h index 460317687..d10cd17bb 100644 --- a/core/MyHwLinuxGeneric.h +++ b/core/MyHwLinuxGeneric.h @@ -16,7 +16,7 @@ * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. */ - + #ifndef MyHwLinuxGeneric_h #define MyHwLinuxGeneric_h @@ -26,9 +26,9 @@ #include "SerialPort.h" #ifdef MY_IS_SERIAL_PTY - SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PTY, true); +SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PTY, true); #else - SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PORT); +SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PORT); #endif #define MY_SERIALDEVICE Serial @@ -50,38 +50,40 @@ inline void hwRandomNumberInit(); inline unsigned long hwMillis(); #ifdef MY_RF24_IRQ_PIN - static pthread_mutex_t hw_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t hw_mutex = PTHREAD_MUTEX_INITIALIZER; - static __inline__ void __hwUnlock(const uint8_t *__s) { - pthread_mutex_unlock(&hw_mutex); - (void)__s; - } +static __inline__ void __hwUnlock(const uint8_t *__s) +{ + pthread_mutex_unlock(&hw_mutex); + (void)__s; +} - static __inline__ void __hwLock() { - pthread_mutex_lock(&hw_mutex); - } +static __inline__ void __hwLock() +{ + pthread_mutex_lock(&hw_mutex); +} #endif #if defined(DOXYGEN) - #define ATOMIC_BLOCK_CLEANUP +#define ATOMIC_BLOCK_CLEANUP #elif defined(MY_RF24_IRQ_PIN) - #define ATOMIC_BLOCK_CLEANUP uint8_t __atomic_loop \ - __attribute__((__cleanup__( __hwUnlock ))) = 1 +#define ATOMIC_BLOCK_CLEANUP uint8_t __atomic_loop \ + __attribute__((__cleanup__( __hwUnlock ))) = 1 #else - #define ATOMIC_BLOCK_CLEANUP +#define ATOMIC_BLOCK_CLEANUP #endif /* DOXYGEN */ #if defined(DOXYGEN) - #define ATOMIC_BLOCK +#define ATOMIC_BLOCK #elif defined(MY_RF24_IRQ_PIN) - #define ATOMIC_BLOCK for ( ATOMIC_BLOCK_CLEANUP, __hwLock(); \ - __atomic_loop ; __atomic_loop = 0 ) +#define ATOMIC_BLOCK for ( ATOMIC_BLOCK_CLEANUP, __hwLock(); \ + __atomic_loop ; __atomic_loop = 0 ) #else - #define ATOMIC_BLOCK +#define ATOMIC_BLOCK #endif /* DOXYGEN */ #ifndef DOXYGEN - #define MY_CRITICAL_SECTION ATOMIC_BLOCK +#define MY_CRITICAL_SECTION ATOMIC_BLOCK #endif /* DOXYGEN */ #endif diff --git a/core/MyHwRPi.cpp b/core/MyHwRPi.cpp index 79c04cec7..989af5fa9 100644 --- a/core/MyHwRPi.cpp +++ b/core/MyHwRPi.cpp @@ -29,12 +29,12 @@ 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 +#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 } @@ -87,46 +87,47 @@ int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) } // Not supported! -int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) +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; - } +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; +void hwDebugPrint(const char *fmt, ...) +{ + va_list args; - va_start(args, fmt); - vlogDebug(fmt, args); - va_end(args); - } + va_start(args, fmt); + vlogDebug(fmt, args); + va_end(args); +} #endif void hwDigitalWrite(uint8_t pin, uint8_t value) diff --git a/core/MyHwRPi.h b/core/MyHwRPi.h index a4f3c6426..2e39d136a 100644 --- a/core/MyHwRPi.h +++ b/core/MyHwRPi.h @@ -16,7 +16,7 @@ * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. */ - + #ifndef MyHwRPi_h #define MyHwRPi_h @@ -26,15 +26,18 @@ #include "log.h" #include "bcm2835.h" -class Bcm2835Init { +class Bcm2835Init +{ public: - Bcm2835Init() { + Bcm2835Init() + { if (!bcm2835_init()) { logError("Failed to initialized bcm2835.\n"); exit(1); } } - ~Bcm2835Init() { + ~Bcm2835Init() + { bcm2835_close(); } }; diff --git a/core/MyHwSAMD.cpp b/core/MyHwSAMD.cpp index 1cf3662e6..b5c220757 100644 --- a/core/MyHwSAMD.cpp +++ b/core/MyHwSAMD.cpp @@ -42,118 +42,125 @@ ISR (WDT_vect) -void i2c_eeprom_write_byte(unsigned int eeaddress, byte data ) { - int rdata = data; - Wire.beginTransmission(I2C_EEP_ADDRESS); - Wire.write((int)(eeaddress >> 8)); // MSB - Wire.write((int)(eeaddress & 0xFF)); // LSB - Wire.write(rdata); - Wire.endTransmission(); -} - -byte i2c_eeprom_read_byte(unsigned int eeaddress ) { - byte rdata = 0xFF; - Wire.beginTransmission(I2C_EEP_ADDRESS); - Wire.write((int)(eeaddress >> 8)); // MSB - Wire.write((int)(eeaddress & 0xFF)); // LSB - Wire.endTransmission(); - Wire.requestFrom(I2C_EEP_ADDRESS,1); - if (Wire.available()) { - rdata = Wire.read(); - } - return rdata; +void i2c_eeprom_write_byte(unsigned int eeaddress, byte data ) +{ + int rdata = data; + Wire.beginTransmission(I2C_EEP_ADDRESS); + Wire.write((int)(eeaddress >> 8)); // MSB + Wire.write((int)(eeaddress & 0xFF)); // LSB + Wire.write(rdata); + Wire.endTransmission(); +} + +byte i2c_eeprom_read_byte(unsigned int eeaddress ) +{ + byte rdata = 0xFF; + Wire.beginTransmission(I2C_EEP_ADDRESS); + Wire.write((int)(eeaddress >> 8)); // MSB + Wire.write((int)(eeaddress & 0xFF)); // LSB + Wire.endTransmission(); + Wire.requestFrom(I2C_EEP_ADDRESS,1); + if (Wire.available()) { + rdata = Wire.read(); + } + return rdata; } void hwReadConfigBlock(void* buf, void* adr, size_t length) { - uint8_t* dst = static_cast(buf); - int offs = reinterpret_cast(adr); - while (length-- > 0) - { - *dst++ = i2c_eeprom_read_byte(offs++); - } + uint8_t* dst = static_cast(buf); + int offs = reinterpret_cast(adr); + while (length-- > 0) { + *dst++ = i2c_eeprom_read_byte(offs++); + } } void hwWriteConfigBlock(void* buf, void* adr, size_t length) { - uint8_t* src = static_cast(buf); - int offs = reinterpret_cast(adr); - while (length-- > 0) - { - i2c_eeprom_write_byte(offs++, *src++); - } + uint8_t* src = static_cast(buf); + int offs = reinterpret_cast(adr); + while (length-- > 0) { + i2c_eeprom_write_byte(offs++, *src++); + } } uint8_t hwReadConfig(int adr) { - uint8_t value; - hwReadConfigBlock(&value, reinterpret_cast(adr), 1); - return value; + uint8_t value; + hwReadConfigBlock(&value, reinterpret_cast(adr), 1); + return value; } void hwWriteConfig(int adr, uint8_t value) { - uint8_t curr = hwReadConfig(adr); - if (curr != value) - { - hwWriteConfigBlock(&value, reinterpret_cast(adr), 1); - } + uint8_t curr = hwReadConfig(adr); + if (curr != value) { + hwWriteConfigBlock(&value, reinterpret_cast(adr), 1); + } } -void hwInit() { - MY_SERIALDEVICE.begin(MY_BAUD_RATE); - #if defined(MY_GATEWAY_SERIAL) - while (!MY_SERIALDEVICE) {} - #endif - Wire.begin(); +void hwInit() +{ + MY_SERIALDEVICE.begin(MY_BAUD_RATE); +#if defined(MY_GATEWAY_SERIAL) + while (!MY_SERIALDEVICE) {} +#endif + Wire.begin(); } -void hwWatchdogReset() { - // TODO: Not supported! +void hwWatchdogReset() +{ + // TODO: Not supported! } -void hwReboot() { +void hwReboot() +{ NVIC_SystemReset(); while (true); } -int8_t hwSleep(unsigned long ms) { - // TODO: Not supported! - (void)ms; - return MY_SLEEP_NOT_POSSIBLE; +int8_t hwSleep(unsigned long ms) +{ + // TODO: Not supported! + (void)ms; + return MY_SLEEP_NOT_POSSIBLE; } -int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) { - // TODO: Not supported! - (void)interrupt; - (void)mode; - (void)ms; - return MY_SLEEP_NOT_POSSIBLE; +int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms) +{ + // TODO: Not supported! + (void)interrupt; + (void)mode; + (void)ms; + return MY_SLEEP_NOT_POSSIBLE; } -int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, unsigned long ms) { - // TODO: Not supported! - (void)interrupt1; - (void)mode1; - (void)interrupt2; - (void)mode2; - (void)ms; - return MY_SLEEP_NOT_POSSIBLE; +int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2, + unsigned long ms) +{ + // TODO: Not supported! + (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() { +uint16_t hwCPUVoltage() +{ // disable ADC while (ADC->STATUS.bit.SYNCBUSY); ADC->CTRLA.bit.ENABLE = 0x00; - + // internal 1V reference (default) analogReference(AR_INTERNAL1V0); // 12 bit resolution (default) analogWriteResolution(12); // MUXp 0x1B = SCALEDIOVCC/4 => connected to Vcc - ADC->INPUTCTRL.bit.MUXPOS = 0x1B ; + ADC->INPUTCTRL.bit.MUXPOS = 0x1B ; // enable ADC while (ADC->STATUS.bit.SYNCBUSY); @@ -178,41 +185,44 @@ uint16_t hwCPUVoltage() { return valueRead * 4; } -uint16_t hwCPUFrequency() { +uint16_t hwCPUFrequency() +{ // TODO: currently reporting compile time frequency (in 1/10MHz) return F_CPU / 100000UL; } -uint16_t hwFreeMem() { +uint16_t hwFreeMem() +{ // TODO: Not supported! return 0; } #endif #ifdef MY_DEBUG -void hwDebugPrint(const char *fmt, ... ) { - if (MY_SERIALDEVICE) { - char fmtBuffer[MY_SERIAL_OUTPUT_SIZE]; - #ifdef MY_GATEWAY_FEATURE +void hwDebugPrint(const char *fmt, ... ) +{ + if (MY_SERIALDEVICE) { + char fmtBuffer[MY_SERIAL_OUTPUT_SIZE]; +#ifdef MY_GATEWAY_FEATURE // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) snprintf(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); MY_SERIALDEVICE.print(fmtBuffer); - #endif - va_list args; - va_start (args, fmt ); - #ifdef MY_GATEWAY_FEATURE +#endif + va_list args; + va_start (args, fmt ); +#ifdef MY_GATEWAY_FEATURE // Truncate message if this is gateway node vsnprintf(fmtBuffer, sizeof(fmtBuffer), fmt, args); fmtBuffer[sizeof(fmtBuffer) - 2] = '\n'; fmtBuffer[sizeof(fmtBuffer) - 1] = '\0'; - #else +#else vsnprintf(fmtBuffer, sizeof(fmtBuffer), fmt, args); - #endif - va_end (args); - MY_SERIALDEVICE.print(fmtBuffer); -// MY_SERIALDEVICE.flush(); +#endif + va_end (args); + MY_SERIALDEVICE.print(fmtBuffer); + // MY_SERIALDEVICE.flush(); - //MY_SERIALDEVICE.write(freeRam()); - } + //MY_SERIALDEVICE.write(freeRam()); + } } #endif diff --git a/core/MyHwSAMD.h b/core/MyHwSAMD.h index 7d23e0712..f8ce6eee4 100644 --- a/core/MyHwSAMD.h +++ b/core/MyHwSAMD.h @@ -59,21 +59,21 @@ uint8_t hwReadConfig(int adr); */ static __inline__ uint8_t __disableIntsRetVal(void) { - __disable_irq(); - return 1; + __disable_irq(); + return 1; } - -/** + +/** * Restore priority mask register. * Helper function for MY_CRITICAL_SECTION. */ static __inline__ void __priMaskRestore(const uint32_t *priMask) { - __set_PRIMASK(*priMask); + __set_PRIMASK(*priMask); } #ifndef DOXYGEN - #define MY_CRITICAL_SECTION for ( uint32_t __savePriMask __attribute__((__cleanup__(__priMaskRestore))) = __get_PRIMASK(), __ToDo = __disableIntsRetVal(); __ToDo ; __ToDo = 0 ) +#define MY_CRITICAL_SECTION for ( uint32_t __savePriMask __attribute__((__cleanup__(__priMaskRestore))) = __get_PRIMASK(), __ToDo = __disableIntsRetVal(); __ToDo ; __ToDo = 0 ) #endif /* DOXYGEN */ #endif // #ifdef ARDUINO_ARCH_SAMD diff --git a/core/MyInclusionMode.cpp b/core/MyInclusionMode.cpp index c9dbfa67d..a3a2319f8 100644 --- a/core/MyInclusionMode.cpp +++ b/core/MyInclusionMode.cpp @@ -19,41 +19,44 @@ #include "MyInclusionMode.h" - // global variables +// global variables extern MyMessage _msgTmp; unsigned long _inclusionStartTime; bool _inclusionMode; -inline void inclusionInit() { +inline void inclusionInit() +{ _inclusionMode = false; - #if defined(MY_INCLUSION_BUTTON_FEATURE) - // Setup digital in that triggers inclusion mode - hwPinMode(MY_INCLUSION_MODE_BUTTON_PIN, INPUT); - hwDigitalWrite(MY_INCLUSION_MODE_BUTTON_PIN, HIGH); - #endif +#if defined(MY_INCLUSION_BUTTON_FEATURE) + // Setup digital in that triggers inclusion mode + hwPinMode(MY_INCLUSION_MODE_BUTTON_PIN, INPUT); + hwDigitalWrite(MY_INCLUSION_MODE_BUTTON_PIN, HIGH); +#endif } -void inclusionModeSet(bool newMode) { - if (newMode != _inclusionMode) { - _inclusionMode = newMode; - // Send back mode change to controller - gatewayTransportSend(buildGw(_msgTmp, I_INCLUSION_MODE).set((uint8_t)(_inclusionMode?1:0))); - if (_inclusionMode) { - _inclusionStartTime = hwMillis(); - } - } +void inclusionModeSet(bool newMode) +{ + if (newMode != _inclusionMode) { + _inclusionMode = newMode; + // Send back mode change to controller + gatewayTransportSend(buildGw(_msgTmp, I_INCLUSION_MODE).set((uint8_t)(_inclusionMode?1:0))); + if (_inclusionMode) { + _inclusionStartTime = hwMillis(); + } + } } -inline void inclusionProcess() { - #ifdef MY_INCLUSION_BUTTON_FEATURE +inline void inclusionProcess() +{ +#ifdef MY_INCLUSION_BUTTON_FEATURE if (!_inclusionMode && hwDigitalRead(MY_INCLUSION_MODE_BUTTON_PIN) == MY_INCLUSION_BUTTON_PRESSED) { // Start inclusion mode inclusionModeSet(true); } - #endif +#endif if (_inclusionMode && hwMillis()-_inclusionStartTime>MY_INCLUSION_MODE_DURATION*1000L) { // inclusionTimeInMinutes minute(s) has passed.. stop inclusion mode diff --git a/core/MyIndication.cpp b/core/MyIndication.cpp index 94478235e..72faa2285 100644 --- a/core/MyIndication.cpp +++ b/core/MyIndication.cpp @@ -25,25 +25,22 @@ void setIndication( const indication_t ind ) { #if defined(MY_DEFAULT_TX_LED_PIN) - if ((INDICATION_TX == ind) || (INDICATION_GW_TX == ind)) - { - ledsBlinkTx(1); - } else + if ((INDICATION_TX == ind) || (INDICATION_GW_TX == ind)) { + ledsBlinkTx(1); + } else #endif #if defined(MY_DEFAULT_RX_LED_PIN) - if ((INDICATION_RX == ind) || (INDICATION_GW_RX == ind)) - { - ledsBlinkRx(1); - } else + if ((INDICATION_RX == ind) || (INDICATION_GW_RX == ind)) { + ledsBlinkRx(1); + } else #endif #if defined(MY_DEFAULT_ERR_LED_PIN) - if (ind > INDICATION_ERR_START) - { - // Number of blinks indicates which error occurred. - ledsBlinkErr(ind-INDICATION_ERR_START); - } + if (ind > INDICATION_ERR_START) { + // Number of blinks indicates which error occurred. + ledsBlinkErr(ind-INDICATION_ERR_START); + } #endif - if (indication) { - indication(ind); - } + if (indication) { + indication(ind); + } } diff --git a/core/MyIndication.h b/core/MyIndication.h index 7e9cd0733..0e2f8ea2b 100644 --- a/core/MyIndication.h +++ b/core/MyIndication.h @@ -24,44 +24,44 @@ * Indication type */ typedef enum { - INDICATION_TX = 0, //!< Sent a message. - INDICATION_RX, //!< Received a message. - - INDICATION_GW_TX, //!< Gateway transmit message. - INDICATION_GW_RX, //!< Gateway receive message. - - INDICATION_FIND_PARENT, //!< Start finding parent node. - INDICATION_GOT_PARENT, //!< Found parent node. - INDICATION_REQ_NODEID, //!< Request node ID. - INDICATION_GOT_NODEID, //!< Got a node ID. + INDICATION_TX = 0, //!< Sent a message. + INDICATION_RX, //!< Received a message. + + INDICATION_GW_TX, //!< Gateway transmit message. + INDICATION_GW_RX, //!< Gateway receive message. + + INDICATION_FIND_PARENT, //!< Start finding parent node. + INDICATION_GOT_PARENT, //!< Found parent node. + INDICATION_REQ_NODEID, //!< Request node ID. + INDICATION_GOT_NODEID, //!< Got a node ID. INDICATION_CHECK_UPLINK, //!< Check uplink - INDICATION_REQ_REGISTRATION, //!< Request node registration. - INDICATION_GOT_REGISTRATION, //!< Got registration reponse. - INDICATION_REBOOT, //!< Rebooting node. - INDICATION_PRESENT, //!< Presenting node to gateway. - INDICATION_CLEAR_ROUTING, //!< Clear routing table requested. - INDICATION_SLEEP, //!< Node goes to sleep. - 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_REQ_REGISTRATION, //!< Request node registration. + INDICATION_GOT_REGISTRATION, //!< Got registration reponse. + INDICATION_REBOOT, //!< Rebooting node. + INDICATION_PRESENT, //!< Presenting node to gateway. + INDICATION_CLEAR_ROUTING, //!< Clear routing table requested. + INDICATION_SLEEP, //!< Node goes to sleep. + 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_ERR_START = 100, - INDICATION_ERR_TX, //!< Failed to transmit message. + INDICATION_ERR_START = 100, + INDICATION_ERR_TX, //!< Failed to transmit message. INDICATION_ERR_TRANSPORT_FAILURE, //!< Transport failure. - INDICATION_ERR_INIT_TRANSPORT, //!< MySensors transport hardware (radio) init failure. - INDICATION_ERR_FIND_PARENT, //!< Failed to find parent node. - INDICATION_ERR_GET_NODEID, //!< Failed to receive node ID. + INDICATION_ERR_INIT_TRANSPORT, //!< MySensors transport hardware (radio) init failure. + INDICATION_ERR_FIND_PARENT, //!< Failed to find parent node. + INDICATION_ERR_GET_NODEID, //!< Failed to receive node ID. INDICATION_ERR_CHECK_UPLINK, //!< Failed to check uplink - INDICATION_ERR_SIGN, //!< Error signing. + INDICATION_ERR_SIGN, //!< Error signing. INDICATION_ERR_LENGTH, //!< Invalid message length. - INDICATION_ERR_VERSION, //!< Protocol version mismatch. - INDICATION_ERR_NET_FULL, //!< Network full. All node ID's are taken. - INDICATION_ERR_INIT_GWTRANSPORT, //!< Gateway transport hardware init failure. - INDICATION_ERR_LOCKED, //!< Node is locked. - INDICATION_ERR_FW_FLASH_INIT, //!< Firmware update flash initialisation failure. - INDICATION_ERR_FW_TIMEOUT, //!< Firmware update timeout. - INDICATION_ERR_FW_CHECKSUM, //!< Firmware update checksum mismatch. - INDICATION_ERR_END + INDICATION_ERR_VERSION, //!< Protocol version mismatch. + INDICATION_ERR_NET_FULL, //!< Network full. All node ID's are taken. + INDICATION_ERR_INIT_GWTRANSPORT, //!< Gateway transport hardware init failure. + INDICATION_ERR_LOCKED, //!< Node is locked. + INDICATION_ERR_FW_FLASH_INIT, //!< Firmware update flash initialisation failure. + INDICATION_ERR_FW_TIMEOUT, //!< Firmware update timeout. + INDICATION_ERR_FW_CHECKSUM, //!< Firmware update checksum mismatch. + INDICATION_ERR_END } indication_t; /** diff --git a/core/MyLeds.cpp b/core/MyLeds.cpp index 3138be3a1..f27f71857 100644 --- a/core/MyLeds.cpp +++ b/core/MyLeds.cpp @@ -34,22 +34,24 @@ inline void ledsInit() countRx = 0; countTx = 0; countErr = 0; - + // Setup led pins - #if defined(MY_DEFAULT_RX_LED_PIN) - hwPinMode(MY_DEFAULT_RX_LED_PIN, OUTPUT); - #endif - #if defined(MY_DEFAULT_TX_LED_PIN) - hwPinMode(MY_DEFAULT_TX_LED_PIN, OUTPUT); - #endif - #if defined(MY_DEFAULT_ERR_LED_PIN) - hwPinMode(MY_DEFAULT_ERR_LED_PIN, OUTPUT); - #endif - prevTime = hwMillis() - LED_PROCESS_INTERVAL_MS; // Substract some, to make sure leds gets updated on first run. +#if defined(MY_DEFAULT_RX_LED_PIN) + hwPinMode(MY_DEFAULT_RX_LED_PIN, OUTPUT); +#endif +#if defined(MY_DEFAULT_TX_LED_PIN) + hwPinMode(MY_DEFAULT_TX_LED_PIN, OUTPUT); +#endif +#if defined(MY_DEFAULT_ERR_LED_PIN) + hwPinMode(MY_DEFAULT_ERR_LED_PIN, OUTPUT); +#endif + prevTime = hwMillis() - + LED_PROCESS_INTERVAL_MS; // Substract some, to make sure leds gets updated on first run. ledsProcess(); } -void ledsProcess() { +void ledsProcess() +{ // Just return if it is not the time... if ((hwMillis() - prevTime) < LED_PROCESS_INTERVAL_MS) { return; @@ -60,52 +62,56 @@ void ledsProcess() { // For an On/Off ratio of 4, the pattern repeated will be [on, on, on, off] // until the counter becomes 0. - #if defined(MY_DEFAULT_RX_LED_PIN) - if (countRx) { - --countRx; - } - state = (countRx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF; - hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, state); - #endif +#if defined(MY_DEFAULT_RX_LED_PIN) + if (countRx) { + --countRx; + } + state = (countRx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF; + hwDigitalWrite(MY_DEFAULT_RX_LED_PIN, state); +#endif - #if defined(MY_DEFAULT_TX_LED_PIN) - if (countTx) { - --countTx; - } - state = (countTx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF; - hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, state); - #endif +#if defined(MY_DEFAULT_TX_LED_PIN) + if (countTx) { + --countTx; + } + state = (countTx & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF; + hwDigitalWrite(MY_DEFAULT_TX_LED_PIN, state); +#endif - #if defined(MY_DEFAULT_ERR_LED_PIN) - if (countErr) { - --countErr; - } - state = (countErr & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF; - hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, state); - #endif +#if defined(MY_DEFAULT_ERR_LED_PIN) + if (countErr) { + --countErr; + } + state = (countErr & (LED_ON_OFF_RATIO-1)) ? LED_ON : LED_OFF; + hwDigitalWrite(MY_DEFAULT_ERR_LED_PIN, state); +#endif } -void ledsBlinkRx(uint8_t cnt) { +void ledsBlinkRx(uint8_t cnt) +{ if (!countRx) { countRx = cnt*LED_ON_OFF_RATIO; } ledsProcess(); } -void ledsBlinkTx(uint8_t cnt) { +void ledsBlinkTx(uint8_t cnt) +{ if(!countTx) { countTx = cnt*LED_ON_OFF_RATIO; } ledsProcess(); } -void ledsBlinkErr(uint8_t cnt) { +void ledsBlinkErr(uint8_t cnt) +{ if(!countErr) { countErr = cnt*LED_ON_OFF_RATIO; } ledsProcess(); } -bool ledsBlinking() { +bool ledsBlinking() +{ return countRx || countTx || countErr; } diff --git a/core/MyLeds.h b/core/MyLeds.h index e0fb121f4..ab78ab2e6 100644 --- a/core/MyLeds.h +++ b/core/MyLeds.h @@ -30,30 +30,30 @@ #endif #if defined(MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) - #define ledBlinkTx(x,...) ledsBlinkTx(x) - #define ledBlinkRx(x,...) ledsBlinkRx(x) - #define ledBlinkErr(x,...) ledsBlinkErr(x) +#define ledBlinkTx(x,...) ledsBlinkTx(x) +#define ledBlinkRx(x,...) ledsBlinkRx(x) +#define ledBlinkErr(x,...) ledsBlinkErr(x) - /** - * Blink with LEDs - * @param cnt how many blink cycles to keep the LED on. Default cycle is 300ms - */ - void ledsInit(); - void ledsBlinkRx(uint8_t cnt); - void ledsBlinkTx(uint8_t cnt); - void ledsBlinkErr(uint8_t cnt); - void ledsProcess(); // do the actual blinking - /** - * Test if any LED is currently blinking. - * @return true when one or more LEDs are blinking, false otherwise. - */ - bool ledsBlinking(); +/** + * Blink with LEDs + * @param cnt how many blink cycles to keep the LED on. Default cycle is 300ms + */ +void ledsInit(); +void ledsBlinkRx(uint8_t cnt); +void ledsBlinkTx(uint8_t cnt); +void ledsBlinkErr(uint8_t cnt); +void ledsProcess(); // do the actual blinking +/** + * Test if any LED is currently blinking. + * @return true when one or more LEDs are blinking, false otherwise. + */ +bool ledsBlinking(); #else - // Remove led functions if feature is disabled - #define ledBlinkTx(x,...) - #define ledBlinkRx(x,...) - #define ledBlinkErr(x,...) +// Remove led functions if feature is disabled +#define ledBlinkTx(x,...) +#define ledBlinkRx(x,...) +#define ledBlinkErr(x,...) #endif #endif diff --git a/core/MyMainDefault.cpp b/core/MyMainDefault.cpp index c4aa0e630..0e006fd5a 100644 --- a/core/MyMainDefault.cpp +++ b/core/MyMainDefault.cpp @@ -16,20 +16,21 @@ * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. */ - + // Initialize library and handle sketch functions like we want to extern "C" void __libc_init_array(void); -int main(void) { +int main(void) +{ init(); - #if defined(USBCON) - #if defined(ARDUINO_ARCH_SAMD) - __libc_init_array(); - USBDevice.init(); - #endif - USBDevice.attach(); - #endif +#if defined(USBCON) +#if defined(ARDUINO_ARCH_SAMD) + __libc_init_array(); + USBDevice.init(); +#endif + USBDevice.attach(); +#endif _begin(); // Startup MySensors library for(;;) { diff --git a/core/MyMainESP8266.cpp b/core/MyMainESP8266.cpp index 2b76eec41..608a60f02 100644 --- a/core/MyMainESP8266.cpp +++ b/core/MyMainESP8266.cpp @@ -16,7 +16,7 @@ * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. */ - + //This may be used to change user task stack size: //#define CONT_STACKSIZE 4096 #include "Schedule.h" @@ -38,27 +38,31 @@ extern "C" { struct rst_info resetInfo; extern "C" { - extern const uint32_t __attribute__((section(".ver_number"))) core_version = ARDUINO_ESP8266_GIT_VER; + extern const uint32_t __attribute__((section(".ver_number"))) core_version = + ARDUINO_ESP8266_GIT_VER; const char* core_release = #ifdef ARDUINO_ESP8266_RELEASE - ARDUINO_ESP8266_RELEASE; + ARDUINO_ESP8266_RELEASE; #else - NULL; + NULL; #endif } // extern "C" -int atexit(void(*func)()) { +int atexit(void(*func)()) +{ (void)func; return 0; } extern "C" void ets_update_cpu_frequency(int freqmhz); void initVariant() __attribute__((weak)); -void initVariant() { +void initVariant() +{ } void preloop_update_frequency() __attribute__((weak)); -void preloop_update_frequency() { +void preloop_update_frequency() +{ #if defined(F_CPU) && (F_CPU == 160000000L) REG_SET_BIT(0x3ff00014, BIT(0)); ets_update_cpu_frequency(160); @@ -73,37 +77,40 @@ static os_event_t g_loop_queue[LOOP_QUEUE_SIZE]; static uint32_t g_micros_at_task_start; -extern "C" void esp_yield() { +extern "C" void esp_yield() +{ if (cont_can_yield(&g_cont)) { cont_yield(&g_cont); } } -extern "C" void esp_schedule() { +extern "C" void esp_schedule() +{ ets_post(LOOP_TASK_PRIORITY, 0, 0); } -extern "C" void __yield() { +extern "C" void __yield() +{ if (cont_can_yield(&g_cont)) { esp_schedule(); esp_yield(); - } - else { + } else { panic(); } } extern "C" void yield(void) __attribute__((weak, alias("__yield"))); -extern "C" void optimistic_yield(uint32_t interval_us) { +extern "C" void optimistic_yield(uint32_t interval_us) +{ if (cont_can_yield(&g_cont) && - (system_get_time() - g_micros_at_task_start) > interval_us) - { + (system_get_time() - g_micros_at_task_start) > interval_us) { yield(); } } -static void loop_wrapper() { +static void loop_wrapper() +{ static bool setup_done = false; preloop_update_frequency(); if (!setup_done) { @@ -116,7 +123,8 @@ static void loop_wrapper() { esp_schedule(); } -static void loop_task(os_event_t *events) { +static void loop_task(os_event_t *events) +{ (void)events; g_micros_at_task_start = system_get_time(); cont_run(&g_cont, &loop_wrapper); @@ -125,7 +133,8 @@ static void loop_task(os_event_t *events) { } } -static void do_global_ctors(void) { +static void do_global_ctors(void) +{ void(**p)(void) = &__init_array_end; while (p != &__init_array_start) { (*--p)(); @@ -138,7 +147,8 @@ extern "C" void gdb_init(void) __attribute__((weak, alias("__gdb_init"))); extern "C" void __gdb_do_break() {} extern "C" void gdb_do_break(void) __attribute__((weak, alias("__gdb_do_break"))); -void init_done() { +void init_done() +{ system_set_os_print(1); gdb_init(); do_global_ctors(); @@ -146,7 +156,8 @@ void init_done() { } -extern "C" void user_init(void) { +extern "C" void user_init(void) +{ struct rst_info *rtc_info_ptr = system_get_rst_info(); memcpy((void *)&resetInfo, (void *)rtc_info_ptr, sizeof(resetInfo)); @@ -159,8 +170,8 @@ extern "C" void user_init(void) { cont_init(&g_cont); ets_task(loop_task, - LOOP_TASK_PRIORITY, g_loop_queue, - LOOP_QUEUE_SIZE); + LOOP_TASK_PRIORITY, g_loop_queue, + LOOP_QUEUE_SIZE); system_init_done_cb(&init_done); } diff --git a/core/MyMainLinux.cpp b/core/MyMainLinux.cpp index 7c4ec6be4..5e875ecea 100644 --- a/core/MyMainLinux.cpp +++ b/core/MyMainLinux.cpp @@ -16,7 +16,7 @@ * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. */ - // Initialize library and handle sketch functions like we want to +// Initialize library and handle sketch functions like we want to #include #include @@ -40,13 +40,13 @@ void handle_sigint(int sig) return; } - #ifdef MY_RF24_IRQ_PIN - detachInterrupt(MY_RF24_IRQ_PIN); - #endif +#ifdef MY_RF24_IRQ_PIN + detachInterrupt(MY_RF24_IRQ_PIN); +#endif - #if defined(MY_GATEWAY_SERIAL) - MY_SERIALDEVICE.end(); - #endif +#if defined(MY_GATEWAY_SERIAL) + MY_SERIALDEVICE.end(); +#endif closelog(); @@ -103,19 +103,19 @@ static int daemonize(void) void print_usage() { printf("Usage: mysgw [options]\n\n" \ - "Options:\n" \ - " -h, --help Display a short summary of all program options.\n" \ - " -d, --debug Enable debug.\n" \ - " -b, --background Run as a background process.\n" - " --gen-soft-hmac-key Generate and print a soft hmac key.\n" - " --gen-soft-serial-key Generate and print a soft serial key.\n" - " --gen-aes-key Generate and print an aes encryption key.\n" - " --print-soft-hmac-key Print the soft hmac key from the config file.\n" - " --print-soft-serial-key Print the soft serial key from the config file.\n" - " --print-aes-key Print the aes encryption key from the config file.\n" - " --set-soft-hmac-key Write a soft hmac key to the config file.\n" - " --set-soft-serial-key Write a soft serial key to the config file.\n" - " --set-aes-key Write an aes encryption key to the config file.\n"); + "Options:\n" \ + " -h, --help Display a short summary of all program options.\n" \ + " -d, --debug Enable debug.\n" \ + " -b, --background Run as a background process.\n" + " --gen-soft-hmac-key Generate and print a soft hmac key.\n" + " --gen-soft-serial-key Generate and print a soft serial key.\n" + " --gen-aes-key Generate and print an aes encryption key.\n" + " --print-soft-hmac-key Print the soft hmac key from the config file.\n" + " --print-soft-serial-key Print the soft serial key from the config file.\n" + " --print-aes-key Print the aes encryption key from the config file.\n" + " --set-soft-hmac-key Write a soft hmac key to the config file.\n" + " --set-soft-serial-key Write a soft serial key to the config file.\n" + " --set-aes-key Write an aes encryption key to the config file.\n"); } void print_soft_sign_hmac_key(uint8_t *key_ptr = NULL) @@ -137,7 +137,9 @@ void print_soft_sign_hmac_key(uint8_t *key_ptr = NULL) printf("#define MY_SOFT_HMAC_KEY "); for (int i=0; i<32; i++) { printf("%#02X", key_ptr[i]); - if (i < 31) printf(","); + if (i < 31) { + printf(","); + } } printf("\n\n"); } @@ -155,7 +157,7 @@ void generate_soft_sign_hmac_key() print_soft_sign_hmac_key(key); printf("To use this key, run mysgw with:\n" - " --set-soft-hmac-key="); + " --set-soft-hmac-key="); for (int i = 0; i < 32; i++) { printf("%02X", key[i]); } @@ -172,12 +174,13 @@ void set_soft_sign_hmac_key(char *key_str) } else { for (int i = 0; i < 64; ++i) { char c = key_str[i]; - if (c <= '9') + if (c <= '9') { n = c - '0'; - else if (c >= 'a') + } else if (c >= 'a') { n = c - 'a' + 10; - else + } else { n = c - 'A' + 10; + } if ((i & 0x1) == 0) { key[i/2] = n * 16; @@ -209,7 +212,9 @@ void print_soft_sign_serial_key(uint8_t *key_ptr = NULL) printf("#define MY_SOFT_SERIAL "); for (int i=0; i<9; i++) { printf("%#02X", key_ptr[i]); - if (i < 8) printf(","); + if (i < 8) { + printf(","); + } } printf("\n\n"); } @@ -227,7 +232,7 @@ void generate_soft_sign_serial_key() print_soft_sign_serial_key(key); printf("To use this key, run mysgw with:\n" - " --set-soft-serial-key="); + " --set-soft-serial-key="); for (int i = 0; i < 9; i++) { printf("%02X", key[i]); } @@ -244,12 +249,13 @@ void set_soft_sign_serial_key(char *key_str) } else { for (int i = 0; i < 18; ++i) { char c = key_str[i]; - if (c <= '9') + if (c <= '9') { n = c - '0'; - else if (c >= 'a') + } else if (c >= 'a') { n = c - 'a' + 10; - else + } else { n = c - 'A' + 10; + } if ((i & 0x1) == 0) { key[i/2] = n * 16; @@ -281,7 +287,9 @@ void print_aes_key(uint8_t *key_ptr = NULL) printf("#define MY_AES_KEY "); for (int i=0; i<16; i++) { printf("%#02X", key_ptr[i]); - if (i < 15) printf(","); + if (i < 15) { + printf(","); + } } printf("\n\n"); } @@ -299,7 +307,7 @@ void generate_aes_key() print_aes_key(key); printf("To use this key, run mysgw with:\n" - " --set-aes-key="); + " --set-aes-key="); for (int i = 0; i < 16; i++) { printf("%02X", key[i]); } @@ -316,12 +324,13 @@ void set_aes_key(char *key_str) } else { for (int i = 0; i < 32; ++i) { char c = key_str[i]; - if (c <= '9') + if (c <= '9') { n = c - '0'; - else if (c >= 'a') + } else if (c >= 'a') { n = c - 'a' + 10; - else + } else { n = c - 'A' + 10; + } if ((i & 0x1) == 0) { key[i/2] = n * 16; @@ -364,48 +373,48 @@ int main(int argc, char *argv[]) int long_index = 0; while ((opt = getopt_long(argc, argv,"hdbABCDEFGHI", long_options, &long_index )) != -1) { switch (opt) { - case 'h': - print_usage(); - exit(0); - case 'd': - debug = 1; - break; - case 'b': - foreground = 0; - break; - case 'A': - generate_soft_sign_hmac_key(); - exit(0); - case 'B': - generate_soft_sign_serial_key(); - exit(0); - case 'C': - generate_aes_key(); - exit(0); - case 'D': - print_soft_sign_hmac_key(); - exit(0); - case 'E': - print_soft_sign_serial_key(); - exit(0); - case 'F': - print_aes_key(); - exit(0); - case 'G': - key = strdup(optarg); - set_soft_sign_hmac_key(key); - exit(0); - case 'H': - key = strdup(optarg); - set_soft_sign_serial_key(key); - exit(0); - case 'I': - key = strdup(optarg); - set_aes_key(key); - exit(0); - default: - print_usage(); - exit(0); + case 'h': + print_usage(); + exit(0); + case 'd': + debug = 1; + break; + case 'b': + foreground = 0; + break; + case 'A': + generate_soft_sign_hmac_key(); + exit(0); + case 'B': + generate_soft_sign_serial_key(); + exit(0); + case 'C': + generate_aes_key(); + exit(0); + case 'D': + print_soft_sign_hmac_key(); + exit(0); + case 'E': + print_soft_sign_serial_key(); + exit(0); + case 'F': + print_aes_key(); + exit(0); + case 'G': + key = strdup(optarg); + set_soft_sign_hmac_key(key); + exit(0); + case 'H': + key = strdup(optarg); + set_soft_sign_serial_key(key); + exit(0); + case 'I': + key = strdup(optarg); + set_aes_key(key); + exit(0); + default: + print_usage(); + exit(0); } } diff --git a/core/MyMessage.cpp b/core/MyMessage.cpp index bce0ae88a..c5baf5177 100644 --- a/core/MyMessage.cpp +++ b/core/MyMessage.cpp @@ -25,45 +25,49 @@ MyMessage::MyMessage() { - clear(); + clear(); } MyMessage::MyMessage(uint8_t _sensor, uint8_t _type) { - clear(); + clear(); sensor = _sensor; type = _type; } void MyMessage::clear() { - last = 0u; - sender = 0u; + last = 0u; + sender = 0u; destination = 0u; // Gateway is default destination - version_length = 0u; - command_ack_payload = 0u; - type = 0u; - sensor = 0u; - (void)memset(data, 0u, sizeof(data)); + version_length = 0u; + command_ack_payload = 0u; + type = 0u; + sensor = 0u; + (void)memset(data, 0u, sizeof(data)); // set message protocol version miSetVersion(PROTOCOL_VERSION); } -bool MyMessage::isAck() const { +bool MyMessage::isAck() const +{ return miGetAck(); } -uint8_t MyMessage::getCommand() const { +uint8_t MyMessage::getCommand() const +{ return miGetCommand(); } /* Getters for payload converted to desired form */ -void* MyMessage::getCustom() const { +void* MyMessage::getCustom() const +{ return (void *)data; } -const char* MyMessage::getString() const { +const char* MyMessage::getString() const +{ uint8_t payloadType = miGetPayloadType(); if (payloadType == P_STRING) { return data; @@ -73,19 +77,19 @@ const char* MyMessage::getString() const { } // handles single character hex (0 - 15) -char MyMessage::i2h(uint8_t i) const { +char MyMessage::i2h(uint8_t i) const +{ uint8_t k = i & 0x0F; if (k <= 9) { return '0' + k; - } - else { + } else { return 'A' + k - 10; - } + } } -char* MyMessage::getCustomString(char *buffer) const { - for (uint8_t i = 0; i < miGetLength(); i++) - { +char* MyMessage::getCustomString(char *buffer) const +{ + for (uint8_t i = 0; i < miGetLength(); i++) { buffer[i * 2] = i2h(data[i] >> 4); buffer[(i * 2) + 1] = i2h(data[i]); } @@ -93,7 +97,8 @@ char* MyMessage::getCustomString(char *buffer) const { return buffer; } -char* MyMessage::getStream(char *buffer) const { +char* MyMessage::getStream(char *buffer) const +{ uint8_t cmd = miGetCommand(); if ((cmd == C_STREAM) && (buffer != NULL)) { return getCustomString(buffer); @@ -102,7 +107,8 @@ char* MyMessage::getStream(char *buffer) const { } } -char* MyMessage::getString(char *buffer) const { +char* MyMessage::getString(char *buffer) const +{ uint8_t payloadType = miGetPayloadType(); if (buffer != NULL) { if (payloadType == P_STRING) { @@ -129,11 +135,13 @@ char* MyMessage::getString(char *buffer) const { } } -bool MyMessage::getBool() const { +bool MyMessage::getBool() const +{ return getByte(); } -uint8_t MyMessage::getByte() const { +uint8_t MyMessage::getByte() const +{ if (miGetPayloadType() == P_BYTE) { return data[0]; } else if (miGetPayloadType() == P_STRING) { @@ -144,7 +152,8 @@ uint8_t MyMessage::getByte() const { } -float MyMessage::getFloat() const { +float MyMessage::getFloat() const +{ if (miGetPayloadType() == P_FLOAT32) { return fValue; } else if (miGetPayloadType() == P_STRING) { @@ -154,7 +163,8 @@ float MyMessage::getFloat() const { } } -int32_t MyMessage::getLong() const { +int32_t MyMessage::getLong() const +{ if (miGetPayloadType() == P_LONG32) { return lValue; } else if (miGetPayloadType() == P_STRING) { @@ -164,7 +174,8 @@ int32_t MyMessage::getLong() const { } } -uint32_t MyMessage::getULong() const { +uint32_t MyMessage::getULong() const +{ if (miGetPayloadType() == P_ULONG32) { return ulValue; } else if (miGetPayloadType() == P_STRING) { @@ -174,7 +185,8 @@ uint32_t MyMessage::getULong() const { } } -int16_t MyMessage::getInt() const { +int16_t MyMessage::getInt() const +{ if (miGetPayloadType() == P_INT16) { return iValue; } else if (miGetPayloadType() == P_STRING) { @@ -184,7 +196,8 @@ int16_t MyMessage::getInt() const { } } -uint16_t MyMessage::getUInt() const { +uint16_t MyMessage::getUInt() const +{ if (miGetPayloadType() == P_UINT16) { return uiValue; } else if (miGetPayloadType() == P_STRING) { @@ -195,23 +208,27 @@ uint16_t MyMessage::getUInt() const { } -MyMessage& MyMessage::setType(uint8_t _type) { +MyMessage& MyMessage::setType(uint8_t _type) +{ type = _type; return *this; } -MyMessage& MyMessage::setSensor(uint8_t _sensor) { +MyMessage& MyMessage::setSensor(uint8_t _sensor) +{ sensor = _sensor; return *this; } -MyMessage& MyMessage::setDestination(uint8_t _destination) { +MyMessage& MyMessage::setDestination(uint8_t _destination) +{ destination = _destination; return *this; } // Set payload -MyMessage& MyMessage::set(void* value, uint8_t length) { +MyMessage& MyMessage::set(void* value, uint8_t length) +{ uint8_t payloadLength = value == NULL ? 0 : min(length, (uint8_t)MAX_PAYLOAD); miSetLength(payloadLength); miSetPayloadType(P_CUSTOM); @@ -219,7 +236,8 @@ MyMessage& MyMessage::set(void* value, uint8_t length) { return *this; } -MyMessage& MyMessage::set(const char* value) { +MyMessage& MyMessage::set(const char* value) +{ uint8_t length = value == NULL ? 0 : min(strlen(value), (size_t)MAX_PAYLOAD); miSetLength(length); miSetPayloadType(P_STRING); @@ -231,21 +249,24 @@ MyMessage& MyMessage::set(const char* value) { return *this; } -MyMessage& MyMessage::set(bool value) { +MyMessage& MyMessage::set(bool value) +{ miSetLength(1); miSetPayloadType(P_BYTE); data[0] = value; return *this; } -MyMessage& MyMessage::set(uint8_t value) { +MyMessage& MyMessage::set(uint8_t value) +{ miSetLength(1); miSetPayloadType(P_BYTE); data[0] = value; return *this; } -MyMessage& MyMessage::set(float value, uint8_t decimals) { +MyMessage& MyMessage::set(float value, uint8_t decimals) +{ miSetLength(5); // 32 bit float + persi miSetPayloadType(P_FLOAT32); fValue=value; @@ -253,28 +274,32 @@ MyMessage& MyMessage::set(float value, uint8_t decimals) { return *this; } -MyMessage& MyMessage::set(uint32_t value) { +MyMessage& MyMessage::set(uint32_t value) +{ miSetPayloadType(P_ULONG32); miSetLength(4); ulValue = value; return *this; } -MyMessage& MyMessage::set(int32_t value) { +MyMessage& MyMessage::set(int32_t value) +{ miSetPayloadType(P_LONG32); miSetLength(4); lValue = value; return *this; } -MyMessage& MyMessage::set(uint16_t value) { +MyMessage& MyMessage::set(uint16_t value) +{ miSetPayloadType(P_UINT16); miSetLength(2); uiValue = value; return *this; } -MyMessage& MyMessage::set(int16_t value) { +MyMessage& MyMessage::set(int16_t value) +{ miSetPayloadType(P_INT16); miSetLength(2); iValue = value; diff --git a/core/MyMessage.h b/core/MyMessage.h index 890e5f2a9..822dc19df 100644 --- a/core/MyMessage.h +++ b/core/MyMessage.h @@ -52,11 +52,11 @@ typedef enum { /// @brief Type of sensor (used when presenting sensors) typedef enum { S_DOOR = 0, //!< Door sensor, V_TRIPPED, V_ARMED - S_MOTION = 1, //!< Motion sensor, V_TRIPPED, V_ARMED + S_MOTION = 1, //!< Motion sensor, V_TRIPPED, V_ARMED S_SMOKE = 2, //!< Smoke sensor, V_TRIPPED, V_ARMED S_BINARY = 3, //!< Binary light or relay, V_STATUS, V_WATT S_LIGHT = 3, //!< \deprecated Same as S_BINARY, **** DEPRECATED, DO NOT USE **** - S_DIMMER = 4, //!< Dimmable light or fan device, V_STATUS (on/off), V_PERCENTAGE (dimmer level 0-100), V_WATT + S_DIMMER = 4, //!< Dimmable light or fan device, V_STATUS (on/off), V_PERCENTAGE (dimmer level 0-100), V_WATT S_COVER = 5, //!< Blinds or window cover, V_UP, V_DOWN, V_STOP, V_PERCENTAGE (open/close to a percentage) S_TEMP = 6, //!< Temperature sensor, V_TEMP S_HUM = 7, //!< Humidity sensor, V_HUM @@ -70,38 +70,38 @@ typedef enum { S_DISTANCE = 15, //!< Distance sensor, V_DISTANCE S_LIGHT_LEVEL = 16, //!< Light level sensor, V_LIGHT_LEVEL (uncalibrated in percentage), V_LEVEL (light level in lux) S_ARDUINO_NODE = 17, //!< Used (internally) for presenting a non-repeating Arduino node - S_ARDUINO_REPEATER_NODE = 18, //!< Used (internally) for presenting a repeating Arduino node + S_ARDUINO_REPEATER_NODE = 18, //!< Used (internally) for presenting a repeating Arduino node S_LOCK = 19, //!< Lock device, V_LOCK_STATUS S_IR = 20, //!< IR device, V_IR_SEND, V_IR_RECEIVE S_WATER = 21, //!< Water meter, V_FLOW, V_VOLUME S_AIR_QUALITY = 22, //!< Air quality sensor, V_LEVEL - S_CUSTOM = 23, //!< Custom sensor + S_CUSTOM = 23, //!< Custom sensor S_DUST = 24, //!< Dust sensor, V_LEVEL - S_SCENE_CONTROLLER = 25, //!< Scene controller device, V_SCENE_ON, V_SCENE_OFF. - S_RGB_LIGHT = 26, //!< RGB light. Send color component data using V_RGB. Also supports V_WATT + S_SCENE_CONTROLLER = 25, //!< Scene controller device, V_SCENE_ON, V_SCENE_OFF. + S_RGB_LIGHT = 26, //!< RGB light. Send color component data using V_RGB. Also supports V_WATT S_RGBW_LIGHT = 27, //!< RGB light with an additional White component. Send data using V_RGBW. Also supports V_WATT S_COLOR_SENSOR = 28, //!< Color sensor, send color information using V_RGB S_HVAC = 29, //!< Thermostat/HVAC device. V_HVAC_SETPOINT_HEAT, V_HVAC_SETPOINT_COLD, V_HVAC_FLOW_STATE, V_HVAC_FLOW_MODE, V_TEMP - S_MULTIMETER = 30, //!< Multimeter device, V_VOLTAGE, V_CURRENT, V_IMPEDANCE + S_MULTIMETER = 30, //!< Multimeter device, V_VOLTAGE, V_CURRENT, V_IMPEDANCE S_SPRINKLER = 31, //!< Sprinkler, V_STATUS (turn on/off), V_TRIPPED (if fire detecting device) S_WATER_LEAK = 32, //!< Water leak sensor, V_TRIPPED, V_ARMED S_SOUND = 33, //!< Sound sensor, V_TRIPPED, V_ARMED, V_LEVEL (sound level in dB) S_VIBRATION = 34, //!< Vibration sensor, V_TRIPPED, V_ARMED, V_LEVEL (vibration in Hz) - S_MOISTURE = 35, //!< Moisture sensor, V_TRIPPED, V_ARMED, V_LEVEL (water content or moisture in percentage?) + S_MOISTURE = 35, //!< Moisture sensor, V_TRIPPED, V_ARMED, V_LEVEL (water content or moisture in percentage?) S_INFO = 36, //!< LCD text device / Simple information device on controller, V_TEXT S_GAS = 37, //!< Gas meter, V_FLOW, V_VOLUME S_GPS = 38, //!< GPS Sensor, V_POSITION - S_WATER_QUALITY = 39 //!< V_TEMP, V_PH, V_ORP, V_EC, V_STATUS + S_WATER_QUALITY = 39 //!< V_TEMP, V_PH, V_ORP, V_EC, V_STATUS } mysensor_sensor; /// @brief Type of sensor data (for set/req/ack messages) typedef enum { V_TEMP = 0, //!< S_TEMP. Temperature S_TEMP, S_HEATER, S_HVAC V_HUM = 1, //!< S_HUM. Humidity - V_STATUS = 2, //!< S_BINARY, S_DIMMER, S_SPRINKLER, S_HVAC, S_HEATER. Used for setting/reporting binary (on/off) status. 1=on, 0=off + V_STATUS = 2, //!< S_BINARY, S_DIMMER, S_SPRINKLER, S_HVAC, S_HEATER. Used for setting/reporting binary (on/off) status. 1=on, 0=off V_LIGHT = 2, //!< \deprecated Same as V_STATUS, **** DEPRECATED, DO NOT USE **** - V_PERCENTAGE = 3, //!< S_DIMMER. Used for sending a percentage value 0-100 (%). - V_DIMMER = 3, //!< \deprecated Same as V_PERCENTAGE, **** DEPRECATED, DO NOT USE **** + V_PERCENTAGE = 3, //!< S_DIMMER. Used for sending a percentage value 0-100 (%). + V_DIMMER = 3, //!< \deprecated Same as V_PERCENTAGE, **** DEPRECATED, DO NOT USE **** V_PRESSURE = 4, //!< S_BARO. Atmospheric Pressure V_FORECAST = 5, //!< S_BARO. Whether forecast. string of "stable", "sunny", "cloudy", "unstable", "thunderstorm" or "unknown" V_RAIN = 6, //!< S_RAIN. Amount of rain @@ -119,12 +119,12 @@ typedef enum { V_KWH = 18, //!< S_POWER. Accumulated number of KWH for a power meter V_SCENE_ON = 19, //!< S_SCENE_CONTROLLER. Turn on a scene V_SCENE_OFF = 20, //!< S_SCENE_CONTROLLER. Turn of a scene - V_HVAC_FLOW_STATE = 21, //!< S_HEATER, S_HVAC. HVAC flow state ("Off", "HeatOn", "CoolOn", or "AutoChangeOver") + V_HVAC_FLOW_STATE = 21, //!< S_HEATER, S_HVAC. HVAC flow state ("Off", "HeatOn", "CoolOn", or "AutoChangeOver") V_HEATER = 21, //!< \deprecated Same as V_HVAC_FLOW_STATE, **** DEPRECATED, DO NOT USE **** - V_HVAC_SPEED = 22, //!< S_HVAC, S_HEATER. HVAC/Heater fan speed ("Min", "Normal", "Max", "Auto") + V_HVAC_SPEED = 22, //!< S_HVAC, S_HEATER. HVAC/Heater fan speed ("Min", "Normal", "Max", "Auto") V_LIGHT_LEVEL = 23, //!< S_LIGHT_LEVEL. Uncalibrated light level. 0-100%. Use V_LEVEL for light level in lux - V_VAR1 = 24, //!< VAR1 - V_VAR2 = 25, //!< VAR2 + V_VAR1 = 24, //!< VAR1 + V_VAR2 = 25, //!< VAR2 V_VAR3 = 26, //!< VAR3 V_VAR4 = 27, //!< VAR4 V_VAR5 = 28, //!< VAR5 @@ -137,11 +137,11 @@ typedef enum { V_VOLUME = 35, //!< S_WATER. Water volume V_LOCK_STATUS = 36, //!< S_LOCK. Set or get lock status. 1=Locked, 0=Unlocked V_LEVEL = 37, //!< S_DUST, S_AIR_QUALITY, S_SOUND (dB), S_VIBRATION (hz), S_LIGHT_LEVEL (lux) - V_VOLTAGE = 38, //!< S_MULTIMETER + V_VOLTAGE = 38, //!< S_MULTIMETER V_CURRENT = 39, //!< S_MULTIMETER V_RGB = 40, //!< S_RGB_LIGHT, S_COLOR_SENSOR. Sent as ASCII hex: RRGGBB (RR=red, GG=green, BB=blue component) V_RGBW = 41, //!< S_RGBW_LIGHT. Sent as ASCII hex: RRGGBBWW (WW=white component) - V_ID = 42, //!< Used for sending in sensors hardware ids (i.e. OneWire DS1820b). + V_ID = 42, //!< Used for sending in sensors hardware ids (i.e. OneWire DS1820b). V_UNIT_PREFIX = 43, //!< Allows sensors to send in a string representing the unit prefix to be displayed in GUI, not parsed by controller! E.g. cm, m, km, inch. V_HVAC_SETPOINT_COOL = 44, //!< S_HVAC. HVAC cool setpoint (Integer between 0-100) V_HVAC_SETPOINT_HEAT = 45, //!< S_HEATER, S_HVAC. HVAC/Heater setpoint (Integer between 0-100) @@ -151,11 +151,11 @@ typedef enum { V_POSITION = 49, //!< GPS position and altitude. Payload: latitude;longitude;altitude(m). E.g. "55.722526;13.017972;18" V_IR_RECORD = 50, //!< Record IR codes S_IR for playback V_PH = 51, //!< S_WATER_QUALITY, water PH - V_ORP = 52, //!< S_WATER_QUALITY, water ORP : redox potential in mV - V_EC = 53, //!< S_WATER_QUALITY, water electric conductivity μS/cm (microSiemens/cm) - V_VAR = 54, //!< S_POWER, Reactive power: volt-ampere reactive (var) - V_VA = 55, //!< S_POWER, Apparent power: volt-ampere (VA) - V_POWER_FACTOR = 56, //!< S_POWER, Ratio of real power to apparent power: floating point value in the range [-1,..,1] + V_ORP = 52, //!< S_WATER_QUALITY, water ORP : redox potential in mV + V_EC = 53, //!< S_WATER_QUALITY, water electric conductivity μS/cm (microSiemens/cm) + V_VAR = 54, //!< S_POWER, Reactive power: volt-ampere reactive (var) + V_VA = 55, //!< S_POWER, Apparent power: volt-ampere (VA) + V_POWER_FACTOR = 56, //!< S_POWER, Ratio of real power to apparent power: floating point value in the range [-1,..,1] } mysensor_data; @@ -284,10 +284,10 @@ class MyMessage char i2h(uint8_t i) const; - /** - * Clear message contents. - */ - void clear(); + /** + * Clear message contents. + */ + void clear(); /** * If payload is something else than P_STRING you can have the payload value converted @@ -331,8 +331,7 @@ class MyMessage #else typedef union { -struct -{ + struct { #endif uint8_t last; // 8 bit - Id of last node this message passed @@ -340,12 +339,12 @@ struct uint8_t destination; // 8 bit - Id of destination node uint8_t version_length; // 2 bit - Protocol version - // 1 bit - Signed flag - // 5 bit - Length of payload + // 1 bit - Signed flag + // 5 bit - Length of payload uint8_t command_ack_payload; // 3 bit - Command type - // 1 bit - Request an ack - Indicator that receiver should send an ack back. - // 1 bit - Is ack messsage - Indicator that this is the actual ack message. - // 3 bit - Payload data type + // 1 bit - Request an ack - Indicator that receiver should send an ack back. + // 1 bit - Is ack messsage - Indicator that this is the actual ack message. + // 3 bit - Payload data type uint8_t type; // 8 bit - Type varies depending on command uint8_t sensor; // 8 bit - Id of sensor that this message concerns. @@ -364,7 +363,7 @@ struct }; struct { // Presentation messages uint8_t version; // Library version - uint8_t sensorType; // Sensor type hint for controller, see table above + uint8_t sensorType; // Sensor type hint for controller, see table above }; char data[MAX_PAYLOAD + 1]; } __attribute__((packed)); @@ -372,7 +371,7 @@ struct } __attribute__((packed)); #else }; -uint8_t array[HEADER_SIZE + MAX_PAYLOAD + 1]; +uint8_t array[HEADER_SIZE + MAX_PAYLOAD + 1]; } __attribute__((packed)) MyMessage; #endif #endif diff --git a/core/MyOTAFirmwareUpdate.cpp b/core/MyOTAFirmwareUpdate.cpp index 02749c1aa..31f212e2c 100644 --- a/core/MyOTAFirmwareUpdate.cpp +++ b/core/MyOTAFirmwareUpdate.cpp @@ -33,7 +33,8 @@ uint8_t _firmwareRetry; void readFirmwareSettings(void) { - hwReadConfigBlock((void*)&_nodeFirmwareConfig, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(nodeFirmwareConfig_t)); + hwReadConfigBlock((void*)&_nodeFirmwareConfig, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, + sizeof(nodeFirmwareConfig_t)); } void firmwareOTAUpdateRequest(void) @@ -41,7 +42,7 @@ void firmwareOTAUpdateRequest(void) const uint32_t enterMS = hwMillis(); if (_firmwareUpdateOngoing && (enterMS - _firmwareLastRequest > MY_OTA_RETRY_DELAY)) { if (!_firmwareRetry) { - setIndication(INDICATION_ERR_FW_TIMEOUT); + setIndication(INDICATION_ERR_FW_TIMEOUT); OTA_DEBUG(PSTR("!OTA:FRQ:FW UPD FAIL\n")); // fw update failed // Give up. We have requested MY_OTA_RETRY times without any packet in return. _firmwareUpdateOngoing = false; @@ -54,8 +55,10 @@ void firmwareOTAUpdateRequest(void) firmwareRequest.type = _nodeFirmwareConfig.type; firmwareRequest.version = _nodeFirmwareConfig.version; firmwareRequest.block = (_firmwareBlock - 1); - OTA_DEBUG(PSTR("OTA:FRQ:FW REQ,T=%04X,V=%04X,B=%04X\n"), _nodeFirmwareConfig.type, _nodeFirmwareConfig.version, _firmwareBlock - 1); // request FW update block - (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_REQUEST, false).set(&firmwareRequest, sizeof(requestFirmwareBlock_t))); + OTA_DEBUG(PSTR("OTA:FRQ:FW REQ,T=%04X,V=%04X,B=%04X\n"), _nodeFirmwareConfig.type, + _nodeFirmwareConfig.version, _firmwareBlock - 1); // request FW update block + (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_REQUEST, + false).set(&firmwareRequest, sizeof(requestFirmwareBlock_t))); } } @@ -65,13 +68,13 @@ bool firmwareOTAUpdateProcess(void) nodeFirmwareConfig_t *firmwareConfigResponse = (nodeFirmwareConfig_t *)_msg.data; // compare with current node configuration, if they differ, start FW fetch process if (memcmp(&_nodeFirmwareConfig, firmwareConfigResponse, sizeof(nodeFirmwareConfig_t))) { - setIndication(INDICATION_FW_UPDATE_START); + setIndication(INDICATION_FW_UPDATE_START); OTA_DEBUG(PSTR("OTA:FWP:UPDATE\n")); // FW update initiated // copy new FW config (void)memcpy(&_nodeFirmwareConfig, firmwareConfigResponse, sizeof(nodeFirmwareConfig_t)); // Init flash if (!_flash.initialize()) { - setIndication(INDICATION_ERR_FW_FLASH_INIT); + setIndication(INDICATION_ERR_FW_FLASH_INIT); OTA_DEBUG(PSTR("!OTA:FWP:FLASH INIT FAIL\n")); // failed to initialise flash _firmwareUpdateOngoing = false; } else { @@ -91,12 +94,13 @@ bool firmwareOTAUpdateProcess(void) } else if (_msg.type == ST_FIRMWARE_RESPONSE) { if (_firmwareUpdateOngoing) { // Save block to flash - setIndication(INDICATION_FW_UPDATE_RX); + 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 - _flash.writeBytes( ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, firmwareResponse->data, FIRMWARE_BLOCK_SIZE); + _flash.writeBytes( ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, + firmwareResponse->data, FIRMWARE_BLOCK_SIZE); // wait until flash written while (_flash.busy()) {} _firmwareBlock--; @@ -107,7 +111,8 @@ bool firmwareOTAUpdateProcess(void) if (transportIsValidFirmware()) { OTA_DEBUG(PSTR("OTA:FWP:CRC OK\n")); // FW checksum ok // Write the new firmware config to eeprom - hwWriteConfigBlock((void*)&_nodeFirmwareConfig, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(nodeFirmwareConfig_t)); + hwWriteConfigBlock((void*)&_nodeFirmwareConfig, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, + sizeof(nodeFirmwareConfig_t)); // All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it) const uint16_t firmwareSize = FIRMWARE_BLOCK_SIZE * _nodeFirmwareConfig.blocks; const uint8_t OTAbuffer[FIRMWARE_START_OFFSET] = {'F','L','X','I','M','G',':', (uint8_t)(firmwareSize >> 8), (uint8_t)(firmwareSize & 0xff),':'}; @@ -116,7 +121,7 @@ bool firmwareOTAUpdateProcess(void) while (_flash.busy()) {} hwReboot(); } else { - setIndication(INDICATION_ERR_FW_CHECKSUM); + setIndication(INDICATION_ERR_FW_CHECKSUM); OTA_DEBUG(PSTR("!OTA:FWP:CRC FAIL\n")); } } @@ -142,7 +147,8 @@ void presentBootloaderInformation(void) // add bootloader information requestFirmwareConfig->BLVersion = MY_OTA_BOOTLOADER_VERSION; _firmwareUpdateOngoing = false; - (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_CONFIG_REQUEST, false)); + (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, + ST_FIRMWARE_CONFIG_REQUEST, false)); } bool isFirmwareUpdateOngoing(void) { @@ -158,8 +164,7 @@ bool transportIsValidFirmware(void) for (int8_t j = 0; j < 8; ++j) { if (crc & 1) { crc = (crc >> 1) ^ 0xA001; - } - else { + } else { crc = (crc >> 1); } } diff --git a/core/MyOTAFirmwareUpdate.h b/core/MyOTAFirmwareUpdate.h index 24846d800..6f9d12d8a 100644 --- a/core/MyOTAFirmwareUpdate.h +++ b/core/MyOTAFirmwareUpdate.h @@ -17,38 +17,38 @@ * version 2 as published by the Free Software Foundation. */ - /** - * @file MyOTAFirmwareUpdate.h - * - * @defgroup MyOTAFirmwaregrp MyOTAFirmwareUpdate - * @ingroup internals - * @{ - * - * MyOTAFirmwareUpdate-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE - * - [!] Exclamation mark is prepended in case of error or warning - * - SYSTEM: - * - OTA messages emitted by MyOTAFirmwareUpdate - * - SUB SYSTEMS: - * - OTA:FRQ from @ref firmwareOTAUpdateRequest() - * - OTA:FWP from @ref firmwareOTAUpdateProcess() - * - * MyOTAFirmwareUpdate debug log messages: - * - * |E| SYS | SUB | Message | Comment - * |-|------|-------|-------------------------------------------|---------------------------------------------------------------------------- - * | | OTA | FWP | UPDATE | FW update initiated - * |!| 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 | FW END | FW received, proceed to CRC verification - * | | OTA | FWP | CRC OK | FW CRC verification OK - * |!| OTA | FWP | CRC FAIL | FW CRC verification failed - * | | OTA | FRQ | FW REQ,T=%04X,V=%04X,B=%04X | Request FW update, FW type (T), version (V), block (B) - * |!| OTA | FRQ | FW UPD FAIL | FW update failed - * - * - * @brief API declaration for MyOTAFirmwareUpdate - */ +/** +* @file MyOTAFirmwareUpdate.h +* +* @defgroup MyOTAFirmwaregrp MyOTAFirmwareUpdate +* @ingroup internals +* @{ +* +* MyOTAFirmwareUpdate-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE +* - [!] Exclamation mark is prepended in case of error or warning +* - SYSTEM: +* - OTA messages emitted by MyOTAFirmwareUpdate +* - SUB SYSTEMS: +* - OTA:FRQ from @ref firmwareOTAUpdateRequest() +* - OTA:FWP from @ref firmwareOTAUpdateProcess() +* +* MyOTAFirmwareUpdate debug log messages: +* +* |E| SYS | SUB | Message | Comment +* |-|------|-------|-------------------------------------------|---------------------------------------------------------------------------- +* | | OTA | FWP | UPDATE | FW update initiated +* |!| 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 | FW END | FW received, proceed to CRC verification +* | | OTA | FWP | CRC OK | FW CRC verification OK +* |!| OTA | FWP | CRC FAIL | FW CRC verification failed +* | | OTA | FRQ | FW REQ,T=%04X,V=%04X,B=%04X | Request FW update, FW type (T), version (V), block (B) +* |!| OTA | FRQ | FW UPD FAIL | FW update failed +* +* +* @brief API declaration for MyOTAFirmwareUpdate +*/ #ifndef MyOTAFirmwareUpdate_h @@ -67,9 +67,9 @@ #define MY_OTA_BOOTLOADER_VERSION (MY_OTA_BOOTLOADER_MINOR_VERSION * 256 + MY_OTA_BOOTLOADER_MAJOR_VERSION) //!< Bootloader version #if defined(MY_DEBUG) - #define OTA_DEBUG(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug +#define OTA_DEBUG(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug #else - #define OTA_DEBUG(x,...) //!< debug NULL +#define OTA_DEBUG(x,...) //!< debug NULL #endif /** * @brief FW config structure, stored in eeprom diff --git a/core/MyProtocolMySensors.cpp b/core/MyProtocolMySensors.cpp index d046e57f4..a591891db 100755 --- a/core/MyProtocolMySensors.cpp +++ b/core/MyProtocolMySensors.cpp @@ -27,7 +27,8 @@ uint8_t protocolH2i(char c); char _fmtBuffer[MY_GATEWAY_MAX_SEND_LENGTH]; char _convBuffer[MAX_PAYLOAD*2+1]; -bool protocolParse(MyMessage &message, char *inputString) { +bool protocolParse(MyMessage &message, char *inputString) +{ char *str, *p, *value=NULL; uint8_t bvalue[MAX_PAYLOAD]; uint8_t blen = 0; @@ -36,48 +37,48 @@ bool protocolParse(MyMessage &message, char *inputString) { // Extract command data coming on serial line for (str = strtok_r(inputString, ";", &p); // split using semicolon - str && i < 6; // loop while str is not null an max 5 times - str = strtok_r(NULL, ";", &p) // get subsequent tokens - ) { + str && i < 6; // loop while str is not null an max 5 times + str = strtok_r(NULL, ";", &p) // get subsequent tokens + ) { switch (i) { - case 0: // Radioid (destination) - message.destination = atoi(str); - break; - case 1: // Childid - message.sensor = atoi(str); - break; - case 2: // Message type - command = atoi(str); - mSetCommand(message, command); - break; - case 3: // Should we request ack from destination? - mSetRequestAck(message, atoi(str)?1:0); - break; - case 4: // Data type - message.type = atoi(str); - break; - case 5: // Variable value - if (command == C_STREAM) { - blen = 0; - uint8_t val; - while (*str) { - val = protocolH2i(*str++) << 4; - val += protocolH2i(*str++); - bvalue[blen] = val; - blen++; - } - } else { - value = str; - // Remove trailing carriage return and newline character (if it exists) - uint8_t lastCharacter = strlen(value)-1; - if (value[lastCharacter] == '\r') { - value[lastCharacter] = 0; - } - if (value[lastCharacter] == '\n') { - value[lastCharacter] = 0; - } + case 0: // Radioid (destination) + message.destination = atoi(str); + break; + case 1: // Childid + message.sensor = atoi(str); + break; + case 2: // Message type + command = atoi(str); + mSetCommand(message, command); + break; + case 3: // Should we request ack from destination? + mSetRequestAck(message, atoi(str)?1:0); + break; + case 4: // Data type + message.type = atoi(str); + break; + case 5: // Variable value + if (command == C_STREAM) { + blen = 0; + uint8_t val; + while (*str) { + val = protocolH2i(*str++) << 4; + val += protocolH2i(*str++); + bvalue[blen] = val; + blen++; } - break; + } else { + value = str; + // Remove trailing carriage return and newline character (if it exists) + uint8_t lastCharacter = strlen(value)-1; + if (value[lastCharacter] == '\r') { + value[lastCharacter] = 0; + } + if (value[lastCharacter] == '\n') { + value[lastCharacter] = 0; + } + } + break; } i++; } @@ -91,68 +92,74 @@ bool protocolParse(MyMessage &message, char *inputString) { mSetAck(message, false); if (command == C_STREAM) { message.set(bvalue, blen); - } - else { + } else { message.set(value); } return true; } -char * protocolFormat(MyMessage &message) { - snprintf_P(_fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, PSTR("%d;%d;%d;%d;%d;%s\n"), message.sender, message.sensor, (uint8_t)mGetCommand(message), (uint8_t)mGetAck(message), message.type, message.getString(_convBuffer)); +char * protocolFormat(MyMessage &message) +{ + snprintf_P(_fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, PSTR("%d;%d;%d;%d;%d;%s\n"), message.sender, + message.sensor, (uint8_t)mGetCommand(message), (uint8_t)mGetAck(message), message.type, + message.getString(_convBuffer)); return _fmtBuffer; } -char * protocolFormatMQTTTopic(const char* prefix, MyMessage &message) { - snprintf_P(_fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, PSTR("%s/%d/%d/%d/%d/%d"), prefix, message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type); +char * protocolFormatMQTTTopic(const char* prefix, MyMessage &message) +{ + snprintf_P(_fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, PSTR("%s/%d/%d/%d/%d/%d"), prefix, + message.sender, message.sensor, mGetCommand(message), mGetAck(message), message.type); return _fmtBuffer; } -char * protocolFormatMQTTSubscribe(const char* prefix) { +char * protocolFormatMQTTSubscribe(const char* prefix) +{ snprintf_P(_fmtBuffer, MY_GATEWAY_MAX_SEND_LENGTH, PSTR("%s/+/+/+/+/+"), prefix); return _fmtBuffer; } #ifdef MY_GATEWAY_MQTT_CLIENT -bool protocolMQTTParse(MyMessage &message, char* topic, uint8_t* payload, unsigned int length) { +bool protocolMQTTParse(MyMessage &message, char* topic, uint8_t* payload, unsigned int length) +{ char *str, *p; uint8_t i = 0; uint8_t bvalue[MAX_PAYLOAD]; uint8_t blen = 0; uint8_t command = 0; - if (topic != strstr(topic, MY_MQTT_SUBSCRIBE_TOPIC_PREFIX)) { + if (topic != strstr(topic, MY_MQTT_SUBSCRIBE_TOPIC_PREFIX)) { // Prefix doesn't match incoming topic return false; } for (str = strtok_r(topic + strlen(MY_MQTT_SUBSCRIBE_TOPIC_PREFIX) + 1, "/", &p); str && i <= 5; - str = strtok_r(NULL, "/", &p)) { + str = strtok_r(NULL, "/", &p)) { switch (i) { - case 0: { - // Node id - message.destination = atoi(str); - break; - } - case 1: { - // Sensor id - message.sensor = atoi(str); - break; - } - case 2: { - // Command type - command = atoi(str); - mSetCommand(message, command); - break; - } - case 3: { - // Ack flag - mSetRequestAck(message, atoi(str)?1:0); - break; - } - case 4: { - // Sub type - message.type = atoi(str); - break; - } + case 0: { + // Node id + message.destination = atoi(str); + break; + } + case 1: { + // Sensor id + message.sensor = atoi(str); + break; + } + case 2: { + // Command type + command = atoi(str); + mSetCommand(message, command); + break; + } + case 3: { + // Ack flag + mSetRequestAck(message, atoi(str)?1:0); + break; + } + case 4: { + // Sub type + message.type = atoi(str); + break; + } } i++; } @@ -188,15 +195,14 @@ bool protocolMQTTParse(MyMessage &message, char* topic, uint8_t* payload, unsign } #endif -uint8_t protocolH2i(char c) { +uint8_t protocolH2i(char c) +{ uint8_t i = 0; if (c <= '9') { i += c - '0'; - } - else if (c >= 'a') { + } else if (c >= 'a') { i += c - 'a' + 10; - } - else { + } else { i += c - 'A' + 10; } return i; diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index be567a5e1..934eeb137 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -20,8 +20,8 @@ #include "MySensorsCore.h" #if defined(__linux__) - #include - #include +#include +#include #endif // message buffers @@ -32,7 +32,7 @@ MyMessage _msgTmp; // Buffer for temporary messages (acks and nonces among othe static coreConfig_t _coreConfig; #if defined(MY_DEBUG) - char _convBuf[MAX_PAYLOAD*2+1]; +char _convBuf[MAX_PAYLOAD*2+1]; #endif // Callback for transport=ok transition @@ -47,37 +47,40 @@ void _callbackTransportReady(void) } } -void _process(void) { +void _process(void) +{ doYield(); - #if defined(MY_INCLUSION_MODE_FEATURE) - inclusionProcess(); - #endif +#if defined(MY_INCLUSION_MODE_FEATURE) + inclusionProcess(); +#endif - #if defined(MY_GATEWAY_FEATURE) - gatewayTransportProcess(); - #endif +#if defined(MY_GATEWAY_FEATURE) + gatewayTransportProcess(); +#endif - #if defined(MY_SENSOR_NETWORK) - transportProcess(); - #endif +#if defined(MY_SENSOR_NETWORK) + transportProcess(); +#endif - #if defined(__linux__) - // To avoid high cpu usage - usleep(10000); // 10ms - #endif +#if defined(__linux__) + // To avoid high cpu usage + usleep(10000); // 10ms +#endif } -void _infiniteLoop(void) { +void _infiniteLoop(void) +{ while(1) { doYield(); - #if defined(__linux__) - exit(1); - #endif +#if defined(__linux__) + exit(1); +#endif } } -void _begin(void) { +void _begin(void) +{ // reset wdt hwWatchdogReset(); @@ -87,58 +90,60 @@ void _begin(void) { hwInit(); - CORE_DEBUG(PSTR("MCO:BGN:INIT " MY_NODE_TYPE ",CP=" MY_CAPABILITIES ",VER=" MYSENSORS_LIBRARY_VERSION "\n")); + CORE_DEBUG(PSTR("MCO:BGN:INIT " MY_NODE_TYPE ",CP=" MY_CAPABILITIES ",VER=" + MYSENSORS_LIBRARY_VERSION "\n")); // set defaults _coreConfig.presentationSent = false; - + // Call before() in sketch (if it exists) if (before) { CORE_DEBUG(PSTR("MCO:BGN:BFR\n")); // before callback before(); } - #if defined(MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) - ledsInit(); - #endif +#if defined(MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) + ledsInit(); +#endif signerInit(); // Read latest received controller configuration from EEPROM // Note: _coreConfig.isMetric is bool, hence empty EEPROM (=0xFF) evaluates to true (default) - hwReadConfigBlock((void*)&_coreConfig.controllerConfig, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(controllerConfig_t)); - - #if defined(MY_OTA_FIRMWARE_FEATURE) - // Read firmware config from EEPROM, i.e. type, version, CRC, blocks - readFirmwareSettings(); - #endif - - #if defined(MY_SENSOR_NETWORK) - // Save static parent ID in eeprom (used by bootloader) - hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, MY_PARENT_NODE_ID); - // Initialise transport layer - transportInitialise(); - // Register transport=ready callback - transportRegisterReadyCallback(_callbackTransportReady); - // wait until transport is ready - (void)transportWaitUntilReady(MY_TRANSPORT_WAIT_READY_MS); - #endif - + hwReadConfigBlock((void*)&_coreConfig.controllerConfig, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, + sizeof(controllerConfig_t)); + +#if defined(MY_OTA_FIRMWARE_FEATURE) + // Read firmware config from EEPROM, i.e. type, version, CRC, blocks + readFirmwareSettings(); +#endif + +#if defined(MY_SENSOR_NETWORK) + // Save static parent ID in eeprom (used by bootloader) + hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, MY_PARENT_NODE_ID); + // Initialise transport layer + transportInitialise(); + // Register transport=ready callback + transportRegisterReadyCallback(_callbackTransportReady); + // wait until transport is ready + (void)transportWaitUntilReady(MY_TRANSPORT_WAIT_READY_MS); +#endif + _checkNodeLock(); - - #if defined(MY_GATEWAY_FEATURE) - #if defined(MY_INCLUSION_BUTTON_FEATURE) - inclusionInit(); - #endif - - // initialise the transport driver - if (!gatewayTransportInit()) { - setIndication(INDICATION_ERR_INIT_GWTRANSPORT); - CORE_DEBUG(PSTR("!MCO:BGN:TSP FAIL\n")); - // Nothing more we can do - _infiniteLoop(); - } - #endif + +#if defined(MY_GATEWAY_FEATURE) +#if defined(MY_INCLUSION_BUTTON_FEATURE) + inclusionInit(); +#endif + + // initialise the transport driver + if (!gatewayTransportInit()) { + setIndication(INDICATION_ERR_INIT_GWTRANSPORT); + CORE_DEBUG(PSTR("!MCO:BGN:TSP FAIL\n")); + // Nothing more we can do + _infiniteLoop(); + } +#endif // Call sketch setup if (setup) { @@ -164,7 +169,8 @@ void _registerNode(void) uint8_t counter = MY_REGISTRATION_RETRIES; // only proceed if register response received or retries exceeded do { - (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_REGISTRATION_REQUEST).set(MY_CORE_VERSION)); + (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, + I_REGISTRATION_REQUEST).set(MY_CORE_VERSION)); } while (!wait(2000, C_INTERNAL, I_REGISTRATION_RESPONSE) && counter--); #else _coreConfig.nodeRegistered = true; @@ -172,40 +178,42 @@ void _registerNode(void) #endif } -void presentNode(void) { +void presentNode(void) +{ setIndication(INDICATION_PRESENT); // Present node and request config - #if defined(MY_GATEWAY_FEATURE) - // Send presentation for this gateway device - #if defined(MY_REPEATER_FEATURE) - (void)present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE); - #else - (void)present(NODE_SENSOR_ID, S_ARDUINO_NODE); - #endif - #else - - #if defined(MY_OTA_FIRMWARE_FEATURE) - presentBootloaderInformation(); - #endif - - // Send signing preferences for this node to the GW - signerPresentation(_msgTmp, GATEWAY_ADDRESS); - - // Send presentation for this radio node - #if defined(MY_REPEATER_FEATURE) - (void)present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE); - #else - (void)present(NODE_SENSOR_ID, S_ARDUINO_NODE); - #endif - - // Send a configuration exchange request to controller - // Node sends parent node. Controller answers with latest node configuration - (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CONFIG).set(getParentNodeId())); - - // Wait configuration reply. - (void)wait(2000, C_INTERNAL, I_CONFIG); - - #endif +#if defined(MY_GATEWAY_FEATURE) + // Send presentation for this gateway device +#if defined(MY_REPEATER_FEATURE) + (void)present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE); +#else + (void)present(NODE_SENSOR_ID, S_ARDUINO_NODE); +#endif +#else + +#if defined(MY_OTA_FIRMWARE_FEATURE) + presentBootloaderInformation(); +#endif + + // Send signing preferences for this node to the GW + signerPresentation(_msgTmp, GATEWAY_ADDRESS); + + // Send presentation for this radio node +#if defined(MY_REPEATER_FEATURE) + (void)present(NODE_SENSOR_ID, S_ARDUINO_REPEATER_NODE); +#else + (void)present(NODE_SENSOR_ID, S_ARDUINO_NODE); +#endif + + // Send a configuration exchange request to controller + // Node sends parent node. Controller answers with latest node configuration + (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, + I_CONFIG).set(getParentNodeId())); + + // Wait configuration reply. + (void)wait(2000, C_INTERNAL, I_CONFIG); + +#endif if (presentation) { presentation(); @@ -240,213 +248,229 @@ uint8_t getDistanceGW(void) #endif } -controllerConfig_t getConfig(void) { +controllerConfig_t getConfig(void) +{ return _coreConfig.controllerConfig; } -bool _sendRoute(MyMessage &message) { - #if defined(MY_CORE_ONLY) - (void)message; - #endif - #if defined(MY_GATEWAY_FEATURE) - if (message.destination == getNodeId()) { - // This is a message sent from a sensor attached on the gateway node. - // Pass it directly to the gateway transport layer. - return gatewayTransportSend(message); - } - #endif - #if defined(MY_SENSOR_NETWORK) - return transportSendRoute(message); - #else - return false; - #endif +bool _sendRoute(MyMessage &message) +{ +#if defined(MY_CORE_ONLY) + (void)message; +#endif +#if defined(MY_GATEWAY_FEATURE) + if (message.destination == getNodeId()) { + // This is a message sent from a sensor attached on the gateway node. + // Pass it directly to the gateway transport layer. + return gatewayTransportSend(message); + } +#endif +#if defined(MY_SENSOR_NETWORK) + return transportSendRoute(message); +#else + return false; +#endif } -bool send(MyMessage &message, const bool enableAck) { +bool send(MyMessage &message, const bool enableAck) +{ message.sender = getNodeId(); mSetCommand(message, C_SET); mSetRequestAck(message, enableAck); - #if defined(MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE) - if (_coreConfig.nodeRegistered) { - return _sendRoute(message); - } - else { - CORE_DEBUG(PSTR("!MCO:SND:NODE NOT REG\n")); // node not registered - return false; - } - #else +#if defined(MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE) + if (_coreConfig.nodeRegistered) { return _sendRoute(message); - #endif + } else { + CORE_DEBUG(PSTR("!MCO:SND:NODE NOT REG\n")); // node not registered + return false; } +#else + return _sendRoute(message); +#endif +} -bool sendBatteryLevel(const uint8_t value, const bool ack) { - return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL, ack).set(value)); +bool sendBatteryLevel(const uint8_t value, const bool ack) +{ + return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_BATTERY_LEVEL, + ack).set(value)); } -bool sendHeartbeat(const bool ack) { - #if defined(MY_SENSOR_NETWORK) - const uint32_t heartbeat = transportGetHeartbeat(); - return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_HEARTBEAT_RESPONSE, ack).set(heartbeat)); - #else - (void)ack; - return false; - #endif +bool sendHeartbeat(const bool ack) +{ +#if defined(MY_SENSOR_NETWORK) + const uint32_t heartbeat = transportGetHeartbeat(); + return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_HEARTBEAT_RESPONSE, + ack).set(heartbeat)); +#else + (void)ack; + return false; +#endif } -bool present(const uint8_t childSensorId, const uint8_t sensorType, const char *description, const bool ack) { - return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, ack).set(childSensorId==NODE_SENSOR_ID?MYSENSORS_LIBRARY_VERSION:description)); +bool present(const uint8_t childSensorId, const uint8_t sensorType, const char *description, + const bool ack) +{ + return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, childSensorId, C_PRESENTATION, sensorType, + ack).set(childSensorId==NODE_SENSOR_ID?MYSENSORS_LIBRARY_VERSION:description)); } -bool sendSketchInfo(const char *name, const char *version, const bool ack) { +bool sendSketchInfo(const char *name, const char *version, const bool ack) +{ bool result = true; if (name) { - result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME, ack).set(name)); + result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_NAME, + ack).set(name)); } if (version) { - result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION, ack).set(version)); + result &= _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_SKETCH_VERSION, + ack).set(version)); } return result; } -bool request(const uint8_t childSensorId, const uint8_t variableType, const uint8_t destination) { +bool request(const uint8_t childSensorId, const uint8_t variableType, const uint8_t destination) +{ return _sendRoute(build(_msgTmp, destination, childSensorId, C_REQ, variableType).set("")); } -bool requestTime(const bool ack) { +bool requestTime(const bool ack) +{ return _sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_TIME, ack).set("")); } // Message delivered through _msg -bool _processInternalMessages(void) { +bool _processInternalMessages(void) +{ const uint8_t type = _msg.type; if (_msg.sender == GATEWAY_ADDRESS) { if (type == I_REBOOT) { - #if !defined(MY_DISABLE_REMOTE_RESET) - // Requires MySensors or other bootloader with watchdogs enabled - setIndication(INDICATION_REBOOT); - hwReboot(); - #endif - } - else if (type == I_REGISTRATION_RESPONSE) { - #if defined (MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE) - _coreConfig.nodeRegistered = _msg.getBool(); - setIndication(INDICATION_GOT_REGISTRATION); - CORE_DEBUG(PSTR("MCO:PIM:NODE REG=%d\n"), _coreConfig.nodeRegistered); // node registration - #endif - } - else if (type == I_CONFIG) { +#if !defined(MY_DISABLE_REMOTE_RESET) + // Requires MySensors or other bootloader with watchdogs enabled + setIndication(INDICATION_REBOOT); + hwReboot(); +#endif + } else if (type == I_REGISTRATION_RESPONSE) { +#if defined (MY_REGISTRATION_FEATURE) && !defined(MY_GATEWAY_FEATURE) + _coreConfig.nodeRegistered = _msg.getBool(); + setIndication(INDICATION_GOT_REGISTRATION); + CORE_DEBUG(PSTR("MCO:PIM:NODE REG=%d\n"), _coreConfig.nodeRegistered); // node registration +#endif + } else if (type == I_CONFIG) { // Pick up configuration from controller (currently only metric/imperial) and store it in eeprom if changed - _coreConfig.controllerConfig.isMetric = _msg.data[0] == 0x00 || _msg.data[0] == 'M'; // metric if null terminated or M - hwWriteConfigBlock((void*)&_coreConfig.controllerConfig, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, sizeof(controllerConfig_t)); - } - else if (type == I_PRESENTATION) { + _coreConfig.controllerConfig.isMetric = _msg.data[0] == 0x00 || + _msg.data[0] == 'M'; // metric if null terminated or M + hwWriteConfigBlock((void*)&_coreConfig.controllerConfig, (void*)EEPROM_CONTROLLER_CONFIG_ADDRESS, + sizeof(controllerConfig_t)); + } else if (type == I_PRESENTATION) { // Re-send node presentation to controller presentNode(); - } - else if (type == I_HEARTBEAT_REQUEST) { + } else if (type == I_HEARTBEAT_REQUEST) { (void)sendHeartbeat(); - } - else if (type == I_TIME) { + } else if (type == I_TIME) { // Deliver time to callback if (receiveTime) { receiveTime(_msg.getULong()); } - } - else if (type == I_CHILDREN) { - #if defined(MY_REPEATER_FEATURE) - if (_msg.data[0] == 'C') { - // Clears child relay data for this node - setIndication(INDICATION_CLEAR_ROUTING); - transportClearRoutingTable(); - (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN).set("OK")); - } - #endif - } - else if (type == I_DEBUG) { - #if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG) - const char debug_msg = _msg.data[0]; - if (debug_msg == 'R') { // routing table - #if defined(MY_REPEATER_FEATURE) - for (uint16_t cnt = 0; cnt < SIZE_ROUTES; cnt++) { - const uint8_t route = transportGetRoute(cnt); - if (route != BROADCAST_ADDRESS) { - CORE_DEBUG(PSTR("MCO:PIM:ROUTE N=%d,R=%d\n"), cnt, route); - uint8_t outBuf[2] = { (uint8_t)cnt,route }; - (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG).set(outBuf, 2)); - wait(200); - } + } else if (type == I_CHILDREN) { +#if defined(MY_REPEATER_FEATURE) + if (_msg.data[0] == 'C') { + // Clears child relay data for this node + setIndication(INDICATION_CLEAR_ROUTING); + transportClearRoutingTable(); + (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_CHILDREN).set("OK")); + } +#endif + } else if (type == I_DEBUG) { +#if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG) + const char debug_msg = _msg.data[0]; + if (debug_msg == 'R') { // routing table +#if defined(MY_REPEATER_FEATURE) + for (uint16_t cnt = 0; cnt < SIZE_ROUTES; cnt++) { + const uint8_t route = transportGetRoute(cnt); + if (route != BROADCAST_ADDRESS) { + CORE_DEBUG(PSTR("MCO:PIM:ROUTE N=%d,R=%d\n"), cnt, route); + uint8_t outBuf[2] = { (uint8_t)cnt,route }; + (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG).set(outBuf, + 2)); + wait(200); } - #endif - } - else if (debug_msg == 'V') { // CPU voltage - (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG).set(hwCPUVoltage())); - } - else if (debug_msg == 'F') { // CPU frequency in 1/10Mhz - (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG).set(hwCPUFrequency())); - } - else if (debug_msg == 'M') { // free memory - (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG).set(hwFreeMem())); } - else if (debug_msg == 'E') { // clear MySensors eeprom area and reboot - (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DEBUG).set("OK")); - for (int i = EEPROM_START; i= MY_CORE_MIN_VERSION); - #endif - - #if (F_CPU>16000000) - // delay for fast GW and slow nodes - delay(5); - #endif - (void)_sendRoute(build(_msgTmp, _msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_REGISTRATION_RESPONSE).set(approveRegistration)); - #else - return false; // processing of this request via controller - #endif - #endif +#if defined(MY_GATEWAY_FEATURE) + // registeration requests are exclusively handled by GW/Controller +#if !defined(MY_REGISTRATION_CONTROLLER) + // auto registration if version compatible + bool approveRegistration = true; + +#if defined(MY_CORE_COMPATIBILITY_CHECK) + approveRegistration = (_msg.getByte() >= MY_CORE_MIN_VERSION); +#endif + +#if (F_CPU>16000000) + // delay for fast GW and slow nodes + delay(5); +#endif + (void)_sendRoute(build(_msgTmp, _msg.sender, NODE_SENSOR_ID, C_INTERNAL, + I_REGISTRATION_RESPONSE).set(approveRegistration)); +#else + return false; // processing of this request via controller +#endif +#endif + } else { + return false; } - else return false; } return true; } -void saveState(const uint8_t pos, const uint8_t value) { +void saveState(const uint8_t pos, const uint8_t value) +{ hwWriteConfig(EEPROM_LOCAL_CONFIG_ADDRESS+pos, value); } -uint8_t loadState(const uint8_t pos) { +uint8_t loadState(const uint8_t pos) +{ return hwReadConfig(EEPROM_LOCAL_CONFIG_ADDRESS+pos); } -void wait(const uint32_t waitingMS) { +void wait(const uint32_t waitingMS) +{ const uint32_t enteringMS = hwMillis(); while (hwMillis() - enteringMS < waitingMS) { _process(); } } -bool wait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t msgType) { +bool wait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t msgType) +{ const uint32_t enteringMS = hwMillis(); // invalidate msg type _msg.type = !msgType; @@ -458,127 +482,138 @@ bool wait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t msgType) { return expectedResponse; } -void doYield(void) { +void doYield(void) +{ hwWatchdogReset(); yield(); - #if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) - ledsProcess(); - #endif +#if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) + ledsProcess(); +#endif } -int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep, const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, const uint8_t mode2) { - CORE_DEBUG(PSTR("MCO:SLP:MS=%lu,SMS=%d,I1=%d,M1=%d,I2=%d,M2=%d\n"), sleepingMS, smartSleep, interrupt1, mode1, interrupt2, mode2); +int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep, const uint8_t interrupt1, + const uint8_t mode1, const uint8_t interrupt2, const uint8_t mode2) +{ + CORE_DEBUG(PSTR("MCO:SLP:MS=%lu,SMS=%d,I1=%d,M1=%d,I2=%d,M2=%d\n"), sleepingMS, smartSleep, + interrupt1, mode1, interrupt2, mode2); // OTA FW feature: do not sleep if FW update ongoing - #if defined(MY_OTA_FIRMWARE_FEATURE) - if (isFirmwareUpdateOngoing()) { - debug(PSTR("!MCO:SLP:FWUPD\n")); // sleeping not possible, FW update ongoing - wait(sleepingMS); - return MY_SLEEP_NOT_POSSIBLE; - } - #endif - // repeater feature: sleeping not possible - #if defined(MY_REPEATER_FEATURE) - (void)smartSleep; - (void)interrupt1; - (void)mode1; - (void)interrupt2; - (void)mode2; - - CORE_DEBUG(PSTR("!MCO:SLP:REP\n")); // sleeping not possible, repeater feature enabled +#if defined(MY_OTA_FIRMWARE_FEATURE) + if (isFirmwareUpdateOngoing()) { + debug(PSTR("!MCO:SLP:FWUPD\n")); // sleeping not possible, FW update ongoing wait(sleepingMS); return MY_SLEEP_NOT_POSSIBLE; - #else - uint32_t sleepingTimeMS = sleepingMS; - #if defined(MY_SENSOR_NETWORK) - // Do not sleep if transport not ready - if (!isTransportReady()) { - CORE_DEBUG(PSTR("!MCO:SLP:TNR\n")); // sleeping not possible, transport not ready - const uint32_t sleepEnterMS = hwMillis(); - uint32_t sleepDeltaMS = 0; - while (!isTransportReady() && (sleepDeltaMS < sleepingTimeMS) && (sleepDeltaMS < MY_SLEEP_TRANSPORT_RECONNECT_TIMEOUT_MS)) { - _process(); - sleepDeltaMS = hwMillis() - sleepEnterMS; - } - // sleep remainder - if (sleepDeltaMS < sleepingTimeMS) { - sleepingTimeMS -= sleepDeltaMS; // calculate remaining sleeping time - CORE_DEBUG(PSTR("MCO:SLP:MS=%lu\n"), sleepingTimeMS); - } - else { - // no sleeping time left - return MY_SLEEP_NOT_POSSIBLE; - } - } - #endif - - if (smartSleep) { - // notify controller about going to sleep - (void)sendHeartbeat(); - wait(MY_SMART_SLEEP_WAIT_DURATION_MS); // listen for incoming messages + } +#endif + // repeater feature: sleeping not possible +#if defined(MY_REPEATER_FEATURE) + (void)smartSleep; + (void)interrupt1; + (void)mode1; + (void)interrupt2; + (void)mode2; + + CORE_DEBUG(PSTR("!MCO:SLP:REP\n")); // sleeping not possible, repeater feature enabled + wait(sleepingMS); + return MY_SLEEP_NOT_POSSIBLE; +#else + uint32_t sleepingTimeMS = sleepingMS; +#if defined(MY_SENSOR_NETWORK) + // Do not sleep if transport not ready + if (!isTransportReady()) { + CORE_DEBUG(PSTR("!MCO:SLP:TNR\n")); // sleeping not possible, transport not ready + const uint32_t sleepEnterMS = hwMillis(); + uint32_t sleepDeltaMS = 0; + while (!isTransportReady() && (sleepDeltaMS < sleepingTimeMS) && + (sleepDeltaMS < MY_SLEEP_TRANSPORT_RECONNECT_TIMEOUT_MS)) { + _process(); + sleepDeltaMS = hwMillis() - sleepEnterMS; + } + // sleep remainder + if (sleepDeltaMS < sleepingTimeMS) { + sleepingTimeMS -= sleepDeltaMS; // calculate remaining sleeping time + CORE_DEBUG(PSTR("MCO:SLP:MS=%lu\n"), sleepingTimeMS); + } else { + // no sleeping time left + return MY_SLEEP_NOT_POSSIBLE; } + } +#endif - #if defined(MY_SENSOR_NETWORK) - CORE_DEBUG(PSTR("MCO:SLP:TPD\n")); // sleep, power down transport - transportPowerDown(); - #endif + if (smartSleep) { + // notify controller about going to sleep + (void)sendHeartbeat(); + wait(MY_SMART_SLEEP_WAIT_DURATION_MS); // listen for incoming messages + } - #if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) - // Wait until leds finish their blinking pattern - while (ledsBlinking()) { - doYield(); - } - #endif +#if defined(MY_SENSOR_NETWORK) + CORE_DEBUG(PSTR("MCO:SLP:TPD\n")); // sleep, power down transport + transportPowerDown(); +#endif - setIndication(INDICATION_SLEEP); +#if defined (MY_DEFAULT_TX_LED_PIN) || defined(MY_DEFAULT_RX_LED_PIN) || defined(MY_DEFAULT_ERR_LED_PIN) + // Wait until leds finish their blinking pattern + while (ledsBlinking()) { + doYield(); + } +#endif - int8_t result = MY_SLEEP_NOT_POSSIBLE; // default + setIndication(INDICATION_SLEEP); - if (interrupt1 != INTERRUPT_NOT_DEFINED && interrupt2 != INTERRUPT_NOT_DEFINED) { - // both IRQs - result = hwSleep(interrupt1, mode1, interrupt2, mode2, sleepingTimeMS); - } - else if (interrupt1 != INTERRUPT_NOT_DEFINED && interrupt2 == INTERRUPT_NOT_DEFINED) { - // one IRQ - result = hwSleep(interrupt1, mode1, sleepingTimeMS); - } - else if (interrupt1 == INTERRUPT_NOT_DEFINED && interrupt2 == INTERRUPT_NOT_DEFINED) { - // no IRQ - result = hwSleep(sleepingTimeMS); - } + int8_t result = MY_SLEEP_NOT_POSSIBLE; // default - setIndication(INDICATION_WAKEUP); - CORE_DEBUG(PSTR("MCO:SLP:WUP=%d\n"), result); // sleep wake-up - return result; - #endif + if (interrupt1 != INTERRUPT_NOT_DEFINED && interrupt2 != INTERRUPT_NOT_DEFINED) { + // both IRQs + result = hwSleep(interrupt1, mode1, interrupt2, mode2, sleepingTimeMS); + } else if (interrupt1 != INTERRUPT_NOT_DEFINED && interrupt2 == INTERRUPT_NOT_DEFINED) { + // one IRQ + result = hwSleep(interrupt1, mode1, sleepingTimeMS); + } else if (interrupt1 == INTERRUPT_NOT_DEFINED && interrupt2 == INTERRUPT_NOT_DEFINED) { + // no IRQ + result = hwSleep(sleepingTimeMS); + } + + setIndication(INDICATION_WAKEUP); + CORE_DEBUG(PSTR("MCO:SLP:WUP=%d\n"), result); // sleep wake-up + return result; +#endif } // sleep functions -int8_t sleep(const uint32_t sleepingMS, const bool smartSleep) { +int8_t sleep(const uint32_t sleepingMS, const bool smartSleep) +{ return _sleep(sleepingMS, smartSleep); } -int8_t sleep(const uint8_t interrupt, const uint8_t mode, const uint32_t sleepingMS, const bool smartSleep) { +int8_t sleep(const uint8_t interrupt, const uint8_t mode, const uint32_t sleepingMS, + const bool smartSleep) +{ return _sleep(sleepingMS, smartSleep, interrupt, mode); } -int8_t sleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, const uint8_t mode2, const uint32_t sleepingMS, const bool smartSleep) { +int8_t sleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, + const uint8_t mode2, const uint32_t sleepingMS, const bool smartSleep) +{ return _sleep(sleepingMS, smartSleep, interrupt1, mode1, interrupt2, mode2); } // deprecated smartSleep() functions -int8_t smartSleep(const uint32_t sleepingMS) { +int8_t smartSleep(const uint32_t sleepingMS) +{ // compatibility return _sleep(sleepingMS, true); } -int8_t smartSleep(const uint8_t interrupt, const uint8_t mode, const uint32_t sleepingMS) { +int8_t smartSleep(const uint8_t interrupt, const uint8_t mode, const uint32_t sleepingMS) +{ // compatibility return _sleep(sleepingMS, true, interrupt, mode); } -int8_t smartSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, const uint8_t mode2, const uint32_t sleepingMS) { +int8_t smartSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, + const uint8_t mode2, const uint32_t sleepingMS) +{ // compatibility return _sleep(sleepingMS, true, interrupt1, mode1, interrupt2, mode2); } @@ -595,10 +630,10 @@ void _nodeLock(const char* str) CORE_DEBUG(PSTR("MCO:NLK:NODE LOCKED. TO UNLOCK, GND PIN %d AND RESET\n"), MY_NODE_UNLOCK_PIN); doYield(); (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID,C_INTERNAL, I_LOCKED).set(str)); - #if defined(MY_SENSOR_NETWORK) - transportPowerDown(); - CORE_DEBUG(PSTR("MCO:NLK:TPD\n")); // power down transport - #endif +#if defined(MY_SENSOR_NETWORK) + transportPowerDown(); + CORE_DEBUG(PSTR("MCO:NLK:TPD\n")); // power down transport +#endif setIndication(INDICATION_SLEEP); (void)hwSleep((unsigned long)1000*60*30); // Sleep for 30 min before resending LOCKED message setIndication(INDICATION_WAKEUP); @@ -625,14 +660,12 @@ void _checkNodeLock(void) hwPinMode(MY_NODE_UNLOCK_PIN, INPUT); setIndication(INDICATION_ERR_LOCKED); CORE_DEBUG(PSTR("MCO:BGN:NODE UNLOCKED\n")); - } - else { + } else { // Disable pullup hwPinMode(MY_NODE_UNLOCK_PIN, INPUT); _nodeLock("LDB"); //Locked during boot } - } - else if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER) == 0xFF) { + } else if (hwReadConfig(EEPROM_NODE_LOCK_COUNTER) == 0xFF) { // Reset walue hwWriteConfig(EEPROM_NODE_LOCK_COUNTER, MY_NODE_LOCK_COUNTER_MAX); } diff --git a/core/MySensorsCore.h b/core/MySensorsCore.h index 1c82e0bc4..6ae969d43 100644 --- a/core/MySensorsCore.h +++ b/core/MySensorsCore.h @@ -17,51 +17,51 @@ * version 2 as published by the Free Software Foundation. */ - /** - * @file MySensorsCore.h - * - * @defgroup MySensorsCoregrp MySensorsCore - * @ingroup internals - * @{ - * - * MySensorsCore-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE - * - [!] Exclamation mark is prepended in case of error or warning - * - SYSTEM: - * - MCO messages emitted by MySensorsCore - * - SUB SYSTEMS: - * - MCO:BGN from @ref _begin() - * - MCO:REG from @ref _registerNode() - * - MCO:SND from @ref send() - * - MCO:PIM from @ref _processInternalMessages() - * - MCO:NLK from nodeLock() - * - * MySensorsCore debug log messages: - * - * |E| SYS | SUB | Message | Comment - * |-|------|-------|-----------------------------------------------|---------------------------------------------------------------------------- - * | | MCO | BGN | INIT %%s,CP=%%s,LIB=%%s | Core initialization, capabilities (CP), library version (VER) - * | | MCO | BGN | BFR | Callback before() - * | | MCO | BGN | MTR | MY_TRANSPORT_RELAXED enabled - * | | MCO | BGN | STP | Callback setup() - * | | MCO | BGN | INIT OK,TSP=%%d | Core initialised, transport status (TSP), 1=initialised, 0=not initialised, NA=not available - * | | MCO | BGN | NODE UNLOCKED | Node successfully unlocked (see signing chapter) - * |!| MCO | BGN | TSP FAIL | Transport initialization failed - * | | MCO | REG | REQ | Registration request - * | | MCO | REG | NOT NEEDED | No registration needed (i.e. GW) - * |!| MCO | SND | NODE NOT REG | Node is not registered, cannot send message - * | | MCO | PIM | NODE REG=%%d | Registration response received, registration status (REG) - * | | MCO | PIM | ROUTE N=%%d,R=%%d | Routing table, messages to node (N) are routed via node (R) - * | | MCO | SLP | MS=%%lu,SMS=%%d,I1=%%d,M1=%%d,I2=%%d,M2=%%d | Sleep node, time (MS), smartSleep (SMS), Int1/M1, Int2/M2 - * | | MCO | SLP | TPD | Sleep node, powerdown transport - * | | MCO | SLP | WUP=%%d | Node woke-up, reason/IRQ (WUP) - * |!| MCO | SLP | FWUPD | Sleeping not possible, FW update ongoing - * |!| MCO | SLP | REP | Sleeping not possible, repeater feature enabled - * | | MCO | NLK | NODE LOCKED. UNLOCK: GND PIN %%d AND RESET | Node locked during booting, see signing chapter for additional information - * | | MCO | NLK | TPD | Powerdown transport - * - * - * @brief API declaration for MySensorsCore - */ +/** +* @file MySensorsCore.h +* +* @defgroup MySensorsCoregrp MySensorsCore +* @ingroup internals +* @{ +* +* MySensorsCore-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE +* - [!] Exclamation mark is prepended in case of error or warning +* - SYSTEM: +* - MCO messages emitted by MySensorsCore +* - SUB SYSTEMS: +* - MCO:BGN from @ref _begin() +* - MCO:REG from @ref _registerNode() +* - MCO:SND from @ref send() +* - MCO:PIM from @ref _processInternalMessages() +* - MCO:NLK from nodeLock() +* +* MySensorsCore debug log messages: +* +* |E| SYS | SUB | Message | Comment +* |-|------|-------|-----------------------------------------------|---------------------------------------------------------------------------- +* | | MCO | BGN | INIT %%s,CP=%%s,LIB=%%s | Core initialization, capabilities (CP), library version (VER) +* | | MCO | BGN | BFR | Callback before() +* | | MCO | BGN | MTR | MY_TRANSPORT_RELAXED enabled +* | | MCO | BGN | STP | Callback setup() +* | | MCO | BGN | INIT OK,TSP=%%d | Core initialised, transport status (TSP), 1=initialised, 0=not initialised, NA=not available +* | | MCO | BGN | NODE UNLOCKED | Node successfully unlocked (see signing chapter) +* |!| MCO | BGN | TSP FAIL | Transport initialization failed +* | | MCO | REG | REQ | Registration request +* | | MCO | REG | NOT NEEDED | No registration needed (i.e. GW) +* |!| MCO | SND | NODE NOT REG | Node is not registered, cannot send message +* | | MCO | PIM | NODE REG=%%d | Registration response received, registration status (REG) +* | | MCO | PIM | ROUTE N=%%d,R=%%d | Routing table, messages to node (N) are routed via node (R) +* | | MCO | SLP | MS=%%lu,SMS=%%d,I1=%%d,M1=%%d,I2=%%d,M2=%%d | Sleep node, time (MS), smartSleep (SMS), Int1/M1, Int2/M2 +* | | MCO | SLP | TPD | Sleep node, powerdown transport +* | | MCO | SLP | WUP=%%d | Node woke-up, reason/IRQ (WUP) +* |!| MCO | SLP | FWUPD | Sleeping not possible, FW update ongoing +* |!| MCO | SLP | REP | Sleeping not possible, repeater feature enabled +* | | MCO | NLK | NODE LOCKED. UNLOCK: GND PIN %%d AND RESET | Node locked during booting, see signing chapter for additional information +* | | MCO | NLK | TPD | Powerdown transport +* +* +* @brief API declaration for MySensorsCore +*/ #ifndef MySensorsCore_h @@ -86,11 +86,11 @@ #ifdef MY_DEBUG - #define debug(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug, to be removed (follow-up PR) - #define CORE_DEBUG(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug +#define debug(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug, to be removed (follow-up PR) +#define CORE_DEBUG(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug #else - #define debug(x,...) //!< debug NULL, to be removed (follow-up PR) - #define CORE_DEBUG(x,...) //!< debug NULL +#define debug(x,...) //!< debug NULL, to be removed (follow-up PR) +#define CORE_DEBUG(x,...) //!< debug NULL #endif @@ -143,7 +143,8 @@ void presentNode(void); * @param description A textual description of the sensor. * @return true Returns true if message reached the first stop on its way to destination. */ -bool present(const uint8_t sensorId, const uint8_t sensorType, const char *description="", const bool ack = false); +bool present(const uint8_t sensorId, const uint8_t sensorType, const char *description="", + const bool ack = false); /** * Sends sketch meta information to the gateway. Not mandatory but a nice thing to do. @@ -189,7 +190,8 @@ bool sendHeartbeat(const bool ack = false); * @param destination The nodeId of other node in radio network. Default is gateway * @return true Returns true if message reached the first stop on its way to destination. */ -bool request(const uint8_t childSensorId, const uint8_t variableType, const uint8_t destination = GATEWAY_ADDRESS); +bool request(const uint8_t childSensorId, const uint8_t variableType, + const uint8_t destination = GATEWAY_ADDRESS); /** * Requests time from controller. Answer will be delivered to receiveTime function in sketch. @@ -269,7 +271,8 @@ int8_t sleep(const uint32_t sleepingMS, const bool smartSleep = false); * @param smartSleep Set True if sending heartbeat and process incoming messages before going to sleep * @return Interrupt number if wake up was triggered by pin change, @ref MY_WAKE_UP_BY_TIMER if wake up was triggered by timer, @ref MY_SLEEP_NOT_POSSIBLE if sleep was not possible (e.g. ongoing FW update) */ -int8_t sleep(const uint8_t interrupt, const uint8_t mode, const uint32_t sleepingMS = 0, const bool smartSleep = false); +int8_t sleep(const uint8_t interrupt, const uint8_t mode, const uint32_t sleepingMS = 0, + const bool smartSleep = false); /** * Sleep (PowerDownMode) the MCU and radio. Wake up on timer or pin change for two separate interrupts. @@ -283,7 +286,8 @@ int8_t sleep(const uint8_t interrupt, const uint8_t mode, const uint32_t sleepin * @param smartSleep Set True if sending heartbeat and process incoming messages before going to sleep. * @return Interrupt number if wake up was triggered by pin change, @ref MY_WAKE_UP_BY_TIMER if wake up was triggered by timer, @ref MY_SLEEP_NOT_POSSIBLE if sleep was not possible (e.g. ongoing FW update) */ -int8_t sleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, const uint8_t mode2, const uint32_t sleepingMS = 0, const bool smartSleep = false); +int8_t sleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, + const uint8_t mode2, const uint32_t sleepingMS = 0, const bool smartSleep = false); /** * \deprecated Use sleep(ms, true) instead @@ -316,7 +320,8 @@ int8_t smartSleep(const uint8_t interrupt, const uint8_t mode, const uint32_t sl * @param sleepingMS Number of milliseconds to sleep or 0 to sleep forever * @return Interrupt number if wake up was triggered by pin change, @ref MY_WAKE_UP_BY_TIMER if wake up was triggered by timer, @ref MY_SLEEP_NOT_POSSIBLE if sleep was not possible (e.g. ongoing FW update) */ -int8_t smartSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, const uint8_t mode2, const uint32_t sleepingMS = 0); +int8_t smartSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, + const uint8_t mode2, const uint32_t sleepingMS = 0); /** * Sleep (PowerDownMode) the MCU and radio. Wake up on timer or pin change for two separate interrupts. @@ -330,7 +335,9 @@ int8_t smartSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t i * @param smartSleep (optional) Set True if sending heartbeat and process incoming messages before going to sleep. * @return Interrupt number if wake up was triggered by pin change, @ref MY_WAKE_UP_BY_TIMER if wake up was triggered by timer, @ref MY_SLEEP_NOT_POSSIBLE if sleep was not possible (e.g. ongoing FW update) */ -int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep = false, const uint8_t interrupt1 = INTERRUPT_NOT_DEFINED, const uint8_t mode1 = MODE_NOT_DEFINED, const uint8_t interrupt2 = INTERRUPT_NOT_DEFINED, const uint8_t mode2 = MODE_NOT_DEFINED); +int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep = false, + const uint8_t interrupt1 = INTERRUPT_NOT_DEFINED, const uint8_t mode1 = MODE_NOT_DEFINED, + const uint8_t interrupt2 = INTERRUPT_NOT_DEFINED, const uint8_t mode2 = MODE_NOT_DEFINED); /** @@ -412,7 +419,9 @@ void loop(void) __attribute__((weak)); // Inline function and macros -static inline MyMessage& build(MyMessage &msg, const uint8_t destination, const uint8_t sensor, const uint8_t command, const uint8_t type, const bool ack = false) { +static inline MyMessage& build(MyMessage &msg, const uint8_t destination, const uint8_t sensor, + const uint8_t command, const uint8_t type, const bool ack = false) +{ msg.sender = getNodeId(); msg.destination = destination; msg.sensor = sensor; @@ -423,7 +432,8 @@ static inline MyMessage& build(MyMessage &msg, const uint8_t destination, const return msg; } -static inline MyMessage& buildGw(MyMessage &msg, const uint8_t type) { +static inline MyMessage& buildGw(MyMessage &msg, const uint8_t type) +{ msg.sender = GATEWAY_ADDRESS; msg.destination = GATEWAY_ADDRESS; msg.sensor = NODE_SENSOR_ID; diff --git a/core/MySigning.cpp b/core/MySigning.cpp index bdfa4e9cb..872cb4b67 100644 --- a/core/MySigning.cpp +++ b/core/MySigning.cpp @@ -82,22 +82,24 @@ extern bool signerAtsha204SignMsg(MyMessage &msg); #endif // Helper function to centralize signing/verification exceptions -static bool skipSign(MyMessage &msg) { +static bool skipSign(MyMessage &msg) +{ if mGetAck(msg) { SIGN_DEBUG(PSTR("Skipping security for ACK on command %d type %d\n"), mGetCommand(msg), msg.type); return true; } else if (mGetCommand(msg) == C_INTERNAL && - (msg.type == I_NONCE_REQUEST || msg.type == I_NONCE_RESPONSE || msg.type == I_SIGNING_PRESENTATION || - msg.type == I_ID_REQUEST || msg.type == I_ID_RESPONSE || - 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_NONCE_REQUEST || msg.type == I_NONCE_RESPONSE || + msg.type == I_SIGNING_PRESENTATION || + msg.type == I_ID_REQUEST || msg.type == I_ID_RESPONSE || + 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 )) { SIGN_DEBUG(PSTR("Skipping security for command %d type %d\n"), mGetCommand(msg), msg.type); return true; } else if (mGetCommand(msg) == C_STREAM && - (msg.type == ST_FIRMWARE_REQUEST || msg.type == ST_FIRMWARE_RESPONSE || - msg.type == ST_SOUND || msg.type == ST_IMAGE)) { + (msg.type == ST_FIRMWARE_REQUEST || msg.type == ST_FIRMWARE_RESPONSE || + msg.type == ST_SOUND || msg.type == ST_IMAGE)) { SIGN_DEBUG(PSTR("Skipping security for command %d type %d\n"), mGetCommand(msg), msg.type); return true; } else { @@ -107,7 +109,8 @@ static bool skipSign(MyMessage &msg) { #endif // MY_SIGNING_FEATURE // Helper to prepare a signing presentation message -static void prepareSigningPresentation(MyMessage &msg, uint8_t destination) { +static void prepareSigningPresentation(MyMessage &msg, uint8_t destination) +{ // Only supports version 1 for now (void)build(msg, destination, NODE_SENSOR_ID, C_INTERNAL, I_SIGNING_PRESENTATION).set(""); mSetLength(msg, 2); @@ -116,15 +119,16 @@ static void prepareSigningPresentation(MyMessage &msg, uint8_t destination) { msg.data[1] = 0; } -void signerInit(void) { +void signerInit(void) +{ #if defined(MY_SIGNING_FEATURE) // Read out the signing requirements from EEPROM hwReadConfigBlock((void*)_doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, - sizeof(_doSign)); + sizeof(_doSign)); // Read out the whitelist requirements from EEPROM hwReadConfigBlock((void*)_doWhitelist, (void*)EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS, - sizeof(_doWhitelist)); + sizeof(_doWhitelist)); #if defined(MY_SIGNING_SOFT) signerAtsha204SoftInit(); @@ -135,7 +139,8 @@ void signerInit(void) { #endif } -void signerPresentation(MyMessage &msg, uint8_t destination) { +void signerPresentation(MyMessage &msg, uint8_t destination) +{ prepareSigningPresentation(msg, destination); #if defined(MY_SIGNING_REQUEST_SIGNATURES) @@ -157,7 +162,8 @@ void signerPresentation(MyMessage &msg, uint8_t destination) { } } -bool signerProcessInternal(MyMessage &msg) { +bool signerProcessInternal(MyMessage &msg) +{ uint8_t sender = msg.sender; (void)sender; #if !defined(MY_SIGNING_FEATURE) @@ -166,8 +172,9 @@ bool signerProcessInternal(MyMessage &msg) { // 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, sender); - SIGN_DEBUG(PSTR("Informing node %d that we do not require signatures because we do not support it\n"), - sender); + SIGN_DEBUG( + PSTR("Informing node %d that we do not require signatures because we do not support it\n"), + sender); if (!_sendRoute(msg)) { SIGN_DEBUG(PSTR("Failed to transmit signing presentation!\n")); } @@ -183,7 +190,8 @@ bool signerProcessInternal(MyMessage &msg) { if (msg.type == I_NONCE_REQUEST) { #if defined(MY_NODE_LOCK_FEATURE) nof_nonce_requests++; - SIGN_DEBUG(PSTR("Nonce requests left until lockdown: %d\n"), MY_NODE_LOCK_COUNTER_MAX-nof_nonce_requests); + SIGN_DEBUG(PSTR("Nonce requests left until lockdown: %d\n"), + MY_NODE_LOCK_COUNTER_MAX-nof_nonce_requests); if (nof_nonce_requests >= MY_NODE_LOCK_COUNTER_MAX) { _nodeLock("TMNR"); //Too many nonces requested } @@ -192,113 +200,113 @@ bool signerProcessInternal(MyMessage &msg) { if (signerAtsha204SoftGetNonce(msg)) { #endif #if defined(MY_SIGNING_ATSHA204) - if (signerAtsha204GetNonce(msg)) { + if (signerAtsha204GetNonce(msg)) { #endif - if (!_sendRoute(build(msg, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_NONCE_RESPONSE))) { - SIGN_DEBUG(PSTR("Failed to transmit nonce!\n")); + if (!_sendRoute(build(msg, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_NONCE_RESPONSE))) { + SIGN_DEBUG(PSTR("Failed to transmit nonce!\n")); + } else { + SIGN_DEBUG(PSTR("Transmitted nonce\n")); + } } else { - SIGN_DEBUG(PSTR("Transmitted nonce\n")); + SIGN_DEBUG(PSTR("Failed to generate nonce!\n")); + } + return true; // No need to further process I_NONCE_REQUEST + } else if (msg.type == I_SIGNING_PRESENTATION) { + if (msg.data[0] != SIGNING_PRESENTATION_VERSION_1) { + SIGN_DEBUG(PSTR("Unsupported signing presentation version (%d)!\n"), msg.data[0]); + return true; // Just drop this presentation message } - } else { - SIGN_DEBUG(PSTR("Failed to generate nonce!\n")); - } - return true; // No need to further process I_NONCE_REQUEST - } else if (msg.type == I_SIGNING_PRESENTATION) { - if (msg.data[0] != SIGNING_PRESENTATION_VERSION_1) { - SIGN_DEBUG(PSTR("Unsupported signing presentation version (%d)!\n"), msg.data[0]); - return true; // Just drop this presentation message - } // 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); - } 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); - } + 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); + } 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); + } 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); - } 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); - } + // 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); + } 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); + } - // Save updated tables - hwWriteConfigBlock((void*)_doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, - sizeof(_doSign)); - hwWriteConfigBlock((void*)_doWhitelist, (void*)EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS, - sizeof(_doWhitelist)); + // Save updated tables + hwWriteConfigBlock((void*)_doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, + sizeof(_doSign)); + hwWriteConfigBlock((void*)_doWhitelist, (void*)EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS, + sizeof(_doWhitelist)); - // 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 - // We do not want a gateway to require signing from all nodes in a network just because it wants one node - // to sign it's messages unless we explicitly configure it to + // 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 + // We do not want a gateway to require signing from all nodes in a network just because it wants one node + // to sign it's messages unless we explicitly configure it to #if defined(MY_GATEWAY_FEATURE) - prepareSigningPresentation(msg, sender); + prepareSigningPresentation(msg, sender); #if defined(MY_SIGNING_REQUEST_SIGNATURES) - if (DO_SIGN(sender)) { - msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES; - } + if (DO_SIGN(sender)) { + msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES; + } #if defined(MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL) - msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES; + msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES; #endif #endif #if defined(MY_SIGNING_NODE_WHITELISTING) - if (DO_WHITELIST(sender)) { - msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING; - } + if (DO_WHITELIST(sender)) { + msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING; + } #if defined(MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL) - msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING; + msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING; #endif #endif - if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_SIGNATURES) { - 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"), sender); - } - if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_WHITELISTING) { - 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"), sender); - } - if (!_sendRoute(msg)) { - SIGN_DEBUG(PSTR("Failed to transmit signing presentation!\n")); - } + if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_SIGNATURES) { + 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"), sender); + } + if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_WHITELISTING) { + 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"), sender); + } + if (!_sendRoute(msg)) { + SIGN_DEBUG(PSTR("Failed to transmit signing presentation!\n")); + } #endif // MY_GATEWAY_FEATURE - return true; // No need to further process I_SIGNING_PRESENTATION - } else if (msg.type == I_NONCE_RESPONSE) { - // Proceed with signing if nonce has been received - SIGN_DEBUG(PSTR("Nonce received from %d. Proceeding with signing...\n"), sender); - if (sender != _msgSign.destination) { - SIGN_DEBUG(PSTR("Nonce did not come from the destination (%d) of the message to be signed! " - "It came from %d.\n"), _msgSign.destination, sender); - SIGN_DEBUG(PSTR("Silently discarding this nonce\n")); - return true; // No need to further process I_NONCE_RESPONSE - } + return true; // No need to further process I_SIGNING_PRESENTATION + } else if (msg.type == I_NONCE_RESPONSE) { + // Proceed with signing if nonce has been received + SIGN_DEBUG(PSTR("Nonce received from %d. Proceeding with signing...\n"), sender); + if (sender != _msgSign.destination) { + SIGN_DEBUG(PSTR("Nonce did not come from the destination (%d) of the message to be signed! " + "It came from %d.\n"), _msgSign.destination, sender); + SIGN_DEBUG(PSTR("Silently discarding this nonce\n")); + return true; // No need to further process I_NONCE_RESPONSE + } #if defined(MY_SIGNING_SOFT) - signerAtsha204SoftPutNonce(msg); + signerAtsha204SoftPutNonce(msg); #endif #if defined(MY_SIGNING_ATSHA204) - signerAtsha204PutNonce(msg); + signerAtsha204PutNonce(msg); #endif #if defined(MY_SIGNING_SOFT) - if (!signerAtsha204SoftSignMsg(_msgSign)) { + if (!signerAtsha204SoftSignMsg(_msgSign)) { #endif #if defined(MY_SIGNING_ATSHA204) - if (!signerAtsha204SignMsg(_msgSign)) { + if (!signerAtsha204SignMsg(_msgSign)) { #endif - SIGN_DEBUG(PSTR("Failed to sign message!\n")); - } else { - SIGN_DEBUG(PSTR("Message signed\n")); - _signingNonceStatus = SIGN_OK; // _msgSign now contains the signed message pending transmission - } - return true; // No need to further process I_NONCE_RESPONSE - } + SIGN_DEBUG(PSTR("Failed to sign message!\n")); + } else { + SIGN_DEBUG(PSTR("Message signed\n")); + _signingNonceStatus = SIGN_OK; // _msgSign now contains the signed message pending transmission + } + return true; // No need to further process I_NONCE_RESPONSE + } #endif // MY_SIGNING_FEATURE return false; } @@ -323,7 +331,8 @@ bool signerSignMsg(MyMessage &msg) { } else { // Send nonce-request _signingNonceStatus=SIGN_WAITING_FOR_NONCE; - if (!_sendRoute(build(_msgSign, msg.destination, msg.sensor, C_INTERNAL, I_NONCE_REQUEST).set(""))) { + if (!_sendRoute(build(_msgSign, msg.destination, msg.sensor, C_INTERNAL, + I_NONCE_REQUEST).set(""))) { SIGN_DEBUG(PSTR("Failed to transmit nonce request!\n")); return false; } @@ -332,7 +341,8 @@ bool signerSignMsg(MyMessage &msg) { // Other messages could come in-between. We trust _process() takes care of them unsigned long enter = hwMillis(); _msgSign = msg; // Copy the message to sign since message buffer might be touched in _process() - while (hwMillis() - enter < MY_VERIFICATION_TIMEOUT_MS && _signingNonceStatus==SIGN_WAITING_FOR_NONCE) { + while (hwMillis() - enter < MY_VERIFICATION_TIMEOUT_MS && + _signingNonceStatus==SIGN_WAITING_FOR_NONCE) { _process(); } if (hwMillis() - enter > MY_VERIFICATION_TIMEOUT_MS) { @@ -375,8 +385,7 @@ bool signerVerifyMsg(MyMessage &msg) { // Internal messages of certain types are not verified if (skipSign(msg)) { verificationResult = true; - } - else if (!mGetSigned(msg)) { + } else if (!mGetSigned(msg)) { // Got unsigned message that should have been signed SIGN_DEBUG(PSTR("Message is not signed, but it should have been!\n")); verificationResult = false; @@ -397,7 +406,8 @@ bool signerVerifyMsg(MyMessage &msg) { nof_failed_verifications = 0; } else { nof_failed_verifications++; - SIGN_DEBUG(PSTR("Failed verification attempts left until lockdown: %d\n"), MY_NODE_LOCK_COUNTER_MAX-nof_failed_verifications); + SIGN_DEBUG(PSTR("Failed verification attempts left until lockdown: %d\n"), + MY_NODE_LOCK_COUNTER_MAX-nof_failed_verifications); if (nof_failed_verifications >= MY_NODE_LOCK_COUNTER_MAX) { _nodeLock("TMFV"); //Too many failed verifications } diff --git a/core/MySigning.h b/core/MySigning.h index 761f3e38b..4efacf7b8 100644 --- a/core/MySigning.h +++ b/core/MySigning.h @@ -99,7 +99,7 @@ * scramble into “garbage” when transmitted over the air and then reassembled by a receiving node before being fed in “the clear” up the stack * at the receiving end. * - * There are methods and possibilities to provide encryption also in software, but if this is done, it is my recommendation that this is done + * There are methods and possibilities to provide encryption also in software, but if this is done, it is my recommendation that this is done * after integrity- and authentication information has been provided to the message (if this is desired). Integrity and authentication is of * course not mandatory and some might be happy with only having encryption to cover their need for security. I, however, have only focused on * integrity and authenticity while at the same time keeping the current message routing mechanisms intact and therefore leave @@ -313,7 +313,7 @@ * The whitelist is stored on the node that require signatures. When a received message is verified, the serial of the sender is looked up in a * list stored on the receiving node, and the corresponding serial stored in the list for that sender is then included in the signature verification * process. The list is stored as the value of the flag that enables whitelisting, @ref MY_SIGNING_NODE_WHITELISTING.
- * + * * Whitelisting is achieved by 'salting' the signature with some node-unique information known to the receiver. In the case of ATSHA204A this is the * unique serial number programmed into the circuit. This unique number is never transmitted over the air in clear text, so Eve will not be able to * figure out a "trusted" serial by snooping on the traffic.
@@ -523,7 +523,7 @@ void signerInit(void); * @param destination Node ID of the destination. */ void signerPresentation(MyMessage &msg, uint8_t destination); - + /** * @brief Manages internal signing message handshaking. * @@ -574,7 +574,7 @@ bool signerPutNonce(MyMessage &msg); * deinitializations and enter a power saving state within this call. * \n@b Usage: This function is typically called as action when receiving a @ref I_NONCE_RESPONSE * message and after @ref signerPutNonce() has successfully been executed. - * + * * @param msg The message to sign. * @returns @c true if successful, else @c false. */ diff --git a/core/MySigningAtsha204.cpp b/core/MySigningAtsha204.cpp index 3b53069fa..87b2e19e0 100644 --- a/core/MySigningAtsha204.cpp +++ b/core/MySigningAtsha204.cpp @@ -41,7 +41,7 @@ uint8_t _signing_tx_buffer[SHA204_CMD_SIZE_MAX]; extern uint8_t _doWhitelist[32]; #ifdef MY_SIGNING_NODE_WHITELISTING - const whitelist_entry_t _signing_whitelist[] = MY_SIGNING_NODE_WHITELISTING; +const whitelist_entry_t _signing_whitelist[] = MY_SIGNING_NODE_WHITELISTING; #endif static void signerCalculateSignature(MyMessage &msg, bool signing); @@ -54,21 +54,20 @@ static char i2h(uint8_t i) uint8_t k = i & 0x0F; if (k <= 9) { return '0' + k; - } - else { + } else { return 'A' + k - 10; } } -static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, uint8_t sz) { +static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, uint8_t sz) +{ static char printBuffer[300]; #ifdef MY_GATEWAY_FEATURE // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) snprintf_P(printBuffer, 299, PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); MY_SERIALDEVICE.print(printBuffer); #endif - for (int i=0; i> 4); printBuffer[(i * 2) + 1] = i2h(buf[i]); } @@ -78,8 +77,7 @@ static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, printBuffer[MY_GATEWAY_MAX_SEND_LENGTH-1-strlen_P((const char*)str)] = '\0'; #endif MY_SERIALDEVICE.print(str); - if (sz > 0) - { + if (sz > 0) { MY_SERIALDEVICE.print(printBuffer); } MY_SERIALDEVICE.println(""); @@ -88,13 +86,16 @@ static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, #define DEBUG_SIGNING_PRINTBUF(str, buf, sz) #endif -void signerAtsha204Init(void) { +void signerAtsha204Init(void) +{ atsha204_init(MY_SIGNING_ATSHA204_PIN); } -bool signerAtsha204CheckTimer(void) { +bool signerAtsha204CheckTimer(void) +{ if (_signing_verification_ongoing) { - if (hwMillis() < _signing_timestamp || hwMillis() > _signing_timestamp + MY_VERIFICATION_TIMEOUT_MS) { + if (hwMillis() < _signing_timestamp || + hwMillis() > _signing_timestamp + MY_VERIFICATION_TIMEOUT_MS) { DEBUG_SIGNING_PRINTBUF(F("Verification timeout"), NULL, 0); // Purge nonce memset(_signing_signing_nonce, 0x00, NONCE_NUMIN_SIZE_PASSTHROUGH); @@ -106,14 +107,15 @@ bool signerAtsha204CheckTimer(void) { return true; } -bool signerAtsha204GetNonce(MyMessage &msg) { +bool signerAtsha204GetNonce(MyMessage &msg) +{ DEBUG_SIGNING_PRINTBUF(F("Signing backend: ATSHA204"), NULL, 0); // Generate random number for use as nonce // We used a basic whitening technique that XORs each byte in a 32byte random value with current hwMillis() counter // This 32-byte random value is then hashed (SHA256) to produce the resulting nonce (void)atsha204_wakeup(_signing_temp_message); if (atsha204_execute(SHA204_RANDOM, RANDOM_SEED_UPDATE, 0, 0, NULL, - RANDOM_COUNT, _signing_tx_buffer, RANDOM_RSP_SIZE, _signing_rx_buffer) != SHA204_SUCCESS) { + RANDOM_COUNT, _signing_tx_buffer, RANDOM_RSP_SIZE, _signing_rx_buffer) != SHA204_SUCCESS) { DEBUG_SIGNING_PRINTBUF(F("Failed to generate nonce"), NULL, 0); return false; } @@ -140,7 +142,8 @@ bool signerAtsha204GetNonce(MyMessage &msg) { return true; } -void signerAtsha204PutNonce(MyMessage &msg) { +void signerAtsha204PutNonce(MyMessage &msg) +{ DEBUG_SIGNING_PRINTBUF(F("Signing backend: ATSHA204"), NULL, 0); memcpy(_signing_signing_nonce, (uint8_t*)msg.getCustom(), MAX_PAYLOAD); @@ -148,7 +151,8 @@ void signerAtsha204PutNonce(MyMessage &msg) { memset(&_signing_signing_nonce[MAX_PAYLOAD], 0xAA, sizeof(_signing_signing_nonce)-MAX_PAYLOAD); } -bool signerAtsha204SignMsg(MyMessage &msg) { +bool signerAtsha204SignMsg(MyMessage &msg) +{ // If we cannot fit any signature in the message, refuse to sign it if (mGetLength(msg) > MAX_PAYLOAD-2) { DEBUG_SIGNING_PRINTBUF(F("Message too large"), NULL, 0); @@ -161,10 +165,12 @@ bool signerAtsha204SignMsg(MyMessage &msg) { if (DO_WHITELIST(msg.destination)) { // Salt the signature with the senders nodeId and the unique serial of the ATSHA device - memcpy(_signing_signing_nonce, &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], 32); // We can reuse the nonce buffer now since it is no longer needed + memcpy(_signing_signing_nonce, &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], + 32); // We can reuse the nonce buffer now since it is no longer needed _signing_signing_nonce[32] = msg.sender; atsha204_getSerialNumber(&_signing_signing_nonce[33]); - (void)signerSha256(_signing_signing_nonce, 32+1+SHA204_SERIAL_SZ); // we can 'void' sha256 because the hash is already put in the correct place + (void)signerSha256(_signing_signing_nonce, + 32+1+SHA204_SERIAL_SZ); // we can 'void' sha256 because the hash is already put in the correct place DEBUG_SIGNING_PRINTBUF(F("Signature salted with serial"), NULL, 0); } @@ -175,13 +181,16 @@ bool signerAtsha204SignMsg(MyMessage &msg) { _signing_rx_buffer[SHA204_BUFFER_POS_DATA] = SIGNING_IDENTIFIER; // Transfer as much signature data as the remaining space in the message permits - memcpy(&msg.data[mGetLength(msg)], &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg)); - DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)], MAX_PAYLOAD-mGetLength(msg)); + memcpy(&msg.data[mGetLength(msg)], &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], + MAX_PAYLOAD-mGetLength(msg)); + DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)], + MAX_PAYLOAD-mGetLength(msg)); return true; } -bool signerAtsha204VerifyMsg(MyMessage &msg) { +bool signerAtsha204VerifyMsg(MyMessage &msg) +{ if (!_signing_verification_ongoing) { DEBUG_SIGNING_PRINTBUF(F("No active verification session"), NULL, 0); return false; @@ -198,7 +207,8 @@ bool signerAtsha204VerifyMsg(MyMessage &msg) { return false; } - DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)], MAX_PAYLOAD-mGetLength(msg)); + DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)], + MAX_PAYLOAD-mGetLength(msg)); signerCalculateSignature(msg, false); // Get signature of message #ifdef MY_SIGNING_NODE_WHITELISTING @@ -207,10 +217,12 @@ bool signerAtsha204VerifyMsg(MyMessage &msg) { for (j=0; j < NUM_OF(_signing_whitelist); j++) { if (_signing_whitelist[j].nodeId == msg.sender) { DEBUG_SIGNING_PRINTBUF(F("Sender found in whitelist"), NULL, 0); - memcpy(_signing_verifying_nonce, &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], 32); // We can reuse the nonce buffer now since it is no longer needed + memcpy(_signing_verifying_nonce, &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], + 32); // We can reuse the nonce buffer now since it is no longer needed _signing_verifying_nonce[32] = msg.sender; memcpy(&_signing_verifying_nonce[33], _signing_whitelist[j].serial, SHA204_SERIAL_SZ); - (void)signerSha256(_signing_verifying_nonce, 32+1+SHA204_SERIAL_SZ); // we can 'void' sha256 because the hash is already put in the correct place + (void)signerSha256(_signing_verifying_nonce, + 32+1+SHA204_SERIAL_SZ); // we can 'void' sha256 because the hash is already put in the correct place break; } } @@ -229,8 +241,10 @@ bool signerAtsha204VerifyMsg(MyMessage &msg) { _signing_rx_buffer[SHA204_BUFFER_POS_DATA] = SIGNING_IDENTIFIER; // Compare the caluclated signature with the provided signature - if (signerMemcmp(&msg.data[mGetLength(msg)], &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg))) { - DEBUG_SIGNING_PRINTBUF(F("Signature bad: "), &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], MAX_PAYLOAD-mGetLength(msg)); + if (signerMemcmp(&msg.data[mGetLength(msg)], &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], + MAX_PAYLOAD-mGetLength(msg))) { + DEBUG_SIGNING_PRINTBUF(F("Signature bad: "), &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], + MAX_PAYLOAD-mGetLength(msg)); #ifdef MY_SIGNING_NODE_WHITELISTING DEBUG_SIGNING_PRINTBUF(F("Is the sender whitelisted and serial correct?"), NULL, 0); #endif @@ -243,42 +257,49 @@ bool signerAtsha204VerifyMsg(MyMessage &msg) { } // Helper to calculate signature of msg (returned in _signing_rx_buffer[SHA204_BUFFER_POS_DATA]) -static void signerCalculateSignature(MyMessage &msg, bool signing) { +static void signerCalculateSignature(MyMessage &msg, bool signing) +{ (void)atsha204_wakeup(_signing_temp_message); memset(_signing_temp_message, 0, 32); - memcpy(_signing_temp_message, (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); + memcpy(_signing_temp_message, (uint8_t*)&msg.data[1-HEADER_SIZE], + MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); // Program the data to sign into the ATSHA204 - DEBUG_SIGNING_PRINTBUF(F("Message to process: "), (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); - DEBUG_SIGNING_PRINTBUF(F("Current nonce: "), signing ? _signing_signing_nonce : _signing_verifying_nonce, 32); - (void)atsha204_execute(SHA204_WRITE, SHA204_ZONE_DATA | SHA204_ZONE_COUNT_FLAG, 8 << 3, 32, _signing_temp_message, - WRITE_COUNT_LONG, _signing_tx_buffer, WRITE_RSP_SIZE, _signing_rx_buffer); + DEBUG_SIGNING_PRINTBUF(F("Message to process: "), (uint8_t*)&msg.data[1-HEADER_SIZE], + MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); + DEBUG_SIGNING_PRINTBUF(F("Current nonce: "), + signing ? _signing_signing_nonce : _signing_verifying_nonce, 32); + (void)atsha204_execute(SHA204_WRITE, SHA204_ZONE_DATA | SHA204_ZONE_COUNT_FLAG, 8 << 3, 32, + _signing_temp_message, + WRITE_COUNT_LONG, _signing_tx_buffer, WRITE_RSP_SIZE, _signing_rx_buffer); // Program the nonce to use for the signature (has to be done just before GENDIG due to chip limitations) (void)atsha204_execute(SHA204_NONCE, NONCE_MODE_PASSTHROUGH, 0, NONCE_NUMIN_SIZE_PASSTHROUGH, - signing ? _signing_signing_nonce : _signing_verifying_nonce, - NONCE_COUNT_LONG, _signing_tx_buffer, NONCE_RSP_SIZE_SHORT, _signing_rx_buffer); + signing ? _signing_signing_nonce : _signing_verifying_nonce, + NONCE_COUNT_LONG, _signing_tx_buffer, NONCE_RSP_SIZE_SHORT, _signing_rx_buffer); // Purge nonce when used - memset(signing ? _signing_signing_nonce : _signing_verifying_nonce, 0x00, NONCE_NUMIN_SIZE_PASSTHROUGH); + memset(signing ? _signing_signing_nonce : _signing_verifying_nonce, 0x00, + NONCE_NUMIN_SIZE_PASSTHROUGH); // Generate digest of data and nonce (void)atsha204_execute(SHA204_GENDIG, GENDIG_ZONE_DATA, 8, 0, NULL, - GENDIG_COUNT_DATA, _signing_tx_buffer, GENDIG_RSP_SIZE, _signing_rx_buffer); + GENDIG_COUNT_DATA, _signing_tx_buffer, GENDIG_RSP_SIZE, _signing_rx_buffer); // Calculate HMAC of message+nonce digest and secret key (void)atsha204_execute(SHA204_HMAC, HMAC_MODE_SOURCE_FLAG_MATCH, 0, 0, NULL, - HMAC_COUNT, _signing_tx_buffer, HMAC_RSP_SIZE, _signing_rx_buffer); + HMAC_COUNT, _signing_tx_buffer, HMAC_RSP_SIZE, _signing_rx_buffer); DEBUG_SIGNING_PRINTBUF(F("HMAC: "), &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], 32); } // Helper to calculate a generic SHA256 digest of provided buffer (only supports one block) // The pointer to the hash is returned, but the hash is also stored in _signing_rx_buffer[SHA204_BUFFER_POS_DATA]) -static uint8_t* signerSha256(const uint8_t* data, size_t sz) { +static uint8_t* signerSha256(const uint8_t* data, size_t sz) +{ // Initiate SHA256 calculator (void)atsha204_execute(SHA204_SHA, SHA_INIT, 0, 0, NULL, - SHA_COUNT_SHORT, _signing_tx_buffer, SHA_RSP_SIZE_SHORT, _signing_rx_buffer); + SHA_COUNT_SHORT, _signing_tx_buffer, SHA_RSP_SIZE_SHORT, _signing_rx_buffer); // Calculate a hash memset(_signing_temp_message, 0x00, SHA_MSG_SIZE); @@ -288,7 +309,7 @@ static uint8_t* signerSha256(const uint8_t* data, size_t sz) { _signing_temp_message[SHA_MSG_SIZE-2] = (sz >> 5); _signing_temp_message[SHA_MSG_SIZE-1] = (sz << 3); (void)atsha204_execute(SHA204_SHA, SHA_CALC, 0, SHA_MSG_SIZE, _signing_temp_message, - SHA_COUNT_LONG, _signing_tx_buffer, SHA_RSP_SIZE_LONG, _signing_rx_buffer); + SHA_COUNT_LONG, _signing_tx_buffer, SHA_RSP_SIZE_LONG, _signing_rx_buffer); DEBUG_SIGNING_PRINTBUF(F("SHA256: "), &_signing_rx_buffer[SHA204_BUFFER_POS_DATA], 32); return &_signing_rx_buffer[SHA204_BUFFER_POS_DATA]; diff --git a/core/MySigningAtsha204Soft.cpp b/core/MySigningAtsha204Soft.cpp index cec7ad6aa..a24da6cce 100644 --- a/core/MySigningAtsha204Soft.cpp +++ b/core/MySigningAtsha204Soft.cpp @@ -47,49 +47,47 @@ extern uint8_t _doWhitelist[32]; static uint8_t _signing_node_serial_info[9]; #ifdef MY_SIGNING_NODE_WHITELISTING - const whitelist_entry_t _signing_whitelist[] = MY_SIGNING_NODE_WHITELISTING; +const whitelist_entry_t _signing_whitelist[] = MY_SIGNING_NODE_WHITELISTING; #endif static void signerCalculateSignature(MyMessage &msg, bool signing); #ifdef MY_DEBUG_VERBOSE_SIGNING static char i2h(uint8_t i) - { +{ uint8_t k = i & 0x0F; if (k <= 9) { return '0' + k; - } - else { + } else { return 'A' + k - 10; } } #ifdef __linux__ -static void DEBUG_SIGNING_PRINTBUF(const char *str, uint8_t* buf, uint8_t sz) { +static void DEBUG_SIGNING_PRINTBUF(const char *str, uint8_t* buf, uint8_t sz) +{ static char printBuffer[300]; - for (int i=0; i> 4); printBuffer[(i * 2) + 1] = i2h(buf[i]); } printBuffer[sz * 2] = '\0'; debug(str); - if (sz > 0) - { + if (sz > 0) { debug(printBuffer); } } #else -static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, uint8_t sz) { +static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, uint8_t sz) +{ static char printBuffer[300]; #ifdef MY_GATEWAY_FEATURE // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) snprintf_P(printBuffer, 299, PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); MY_SERIALDEVICE.print(printBuffer); #endif - for (int i=0; i> 4); printBuffer[(i * 2) + 1] = i2h(buf[i]); } @@ -99,8 +97,7 @@ static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, printBuffer[MY_GATEWAY_MAX_SEND_LENGTH-1-strlen_P((const char*)str)] = '\0'; #endif MY_SERIALDEVICE.print(str); - if (sz > 0) - { + if (sz > 0) { MY_SERIALDEVICE.print(printBuffer); } MY_SERIALDEVICE.println(""); @@ -110,7 +107,8 @@ static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, #define DEBUG_SIGNING_PRINTBUF(str, buf, sz) #endif -void signerAtsha204SoftInit(void) { +void signerAtsha204SoftInit(void) +{ // initialize pseudo-RNG hwRandomNumberInit(); // Set secrets @@ -118,9 +116,11 @@ void signerAtsha204SoftInit(void) { hwReadConfigBlock((void*)_signing_node_serial_info, (void*)EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9); } -bool signerAtsha204SoftCheckTimer(void) { +bool signerAtsha204SoftCheckTimer(void) +{ if (_signing_verification_ongoing) { - if (hwMillis() < _signing_timestamp || hwMillis() > _signing_timestamp + MY_VERIFICATION_TIMEOUT_MS) { + if (hwMillis() < _signing_timestamp || + hwMillis() > _signing_timestamp + MY_VERIFICATION_TIMEOUT_MS) { DEBUG_SIGNING_PRINTBUF(F("Verification timeout"), NULL, 0); // Purge nonce memset(_signing_signing_nonce, 0xAA, 32); @@ -132,7 +132,8 @@ bool signerAtsha204SoftCheckTimer(void) { return true; } -bool signerAtsha204SoftGetNonce(MyMessage &msg) { +bool signerAtsha204SoftGetNonce(MyMessage &msg) +{ DEBUG_SIGNING_PRINTBUF(F("Signing backend: ATSHA204Soft"), NULL, 0); // We used a basic whitening technique that XORs a random byte with the current hwMillis() counter and then the byte is @@ -160,7 +161,8 @@ bool signerAtsha204SoftGetNonce(MyMessage &msg) { return true; } -void signerAtsha204SoftPutNonce(MyMessage &msg) { +void signerAtsha204SoftPutNonce(MyMessage &msg) +{ DEBUG_SIGNING_PRINTBUF(F("Signing backend: ATSHA204Soft"), NULL, 0); memcpy(_signing_signing_nonce, (uint8_t*)msg.getCustom(), MAX_PAYLOAD); @@ -168,7 +170,8 @@ void signerAtsha204SoftPutNonce(MyMessage &msg) { memset(&_signing_signing_nonce[MAX_PAYLOAD], 0xAA, sizeof(_signing_signing_nonce)-MAX_PAYLOAD); } -bool signerAtsha204SoftSignMsg(MyMessage &msg) { +bool signerAtsha204SoftSignMsg(MyMessage &msg) +{ // If we cannot fit any signature in the message, refuse to sign it if (mGetLength(msg) > MAX_PAYLOAD-2) { DEBUG_SIGNING_PRINTBUF(F("Message too large"), NULL, 0); @@ -199,12 +202,14 @@ bool signerAtsha204SoftSignMsg(MyMessage &msg) { // Transfer as much signature data as the remaining space in the message permits memcpy(&msg.data[mGetLength(msg)], _signing_hmac, MAX_PAYLOAD-mGetLength(msg)); - DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)], MAX_PAYLOAD-mGetLength(msg)); + DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)], + MAX_PAYLOAD-mGetLength(msg)); return true; } -bool signerAtsha204SoftVerifyMsg(MyMessage &msg) { +bool signerAtsha204SoftVerifyMsg(MyMessage &msg) +{ if (!_signing_verification_ongoing) { DEBUG_SIGNING_PRINTBUF(F("No active verification session"), NULL, 0); return false; @@ -222,7 +227,8 @@ bool signerAtsha204SoftVerifyMsg(MyMessage &msg) { } // Get signature of message - DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)], MAX_PAYLOAD-mGetLength(msg)); + DEBUG_SIGNING_PRINTBUF(F("Signature in message: "), (uint8_t*)&msg.data[mGetLength(msg)], + MAX_PAYLOAD-mGetLength(msg)); signerCalculateSignature(msg, false); #ifdef MY_SIGNING_NODE_WHITELISTING @@ -268,11 +274,15 @@ bool signerAtsha204SoftVerifyMsg(MyMessage &msg) { } // Helper to calculate signature of msg (returned in hmac) -static void signerCalculateSignature(MyMessage &msg, bool signing) { +static void signerCalculateSignature(MyMessage &msg, bool signing) +{ memset(_signing_temp_message, 0, 32); - memcpy(_signing_temp_message, (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); - DEBUG_SIGNING_PRINTBUF(F("Message to process: "), (uint8_t*)&msg.data[1-HEADER_SIZE], MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); - DEBUG_SIGNING_PRINTBUF(F("Current nonce: "), signing ? _signing_signing_nonce : _signing_verifying_nonce, 32); + memcpy(_signing_temp_message, (uint8_t*)&msg.data[1-HEADER_SIZE], + MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); + DEBUG_SIGNING_PRINTBUF(F("Message to process: "), (uint8_t*)&msg.data[1-HEADER_SIZE], + MAX_MESSAGE_LENGTH-1-(MAX_PAYLOAD-mGetLength(msg))); + DEBUG_SIGNING_PRINTBUF(F("Current nonce: "), + signing ? _signing_signing_nonce : _signing_verifying_nonce, 32); // ATSHA204 calculates the HMAC with a PSK and a SHA256 digest of the following data: // 32 bytes zeroes diff --git a/core/MyTransport.cpp b/core/MyTransport.cpp index 5d3a1ca86..969e2994c 100644 --- a/core/MyTransport.cpp +++ b/core/MyTransport.cpp @@ -31,7 +31,7 @@ static transportState_t stFailure = { stFailureTransition, stFailureUpdate }; static transportSM_t _transportSM; // transport configuration -static transportConfig_t _transportConfig; +static transportConfig_t _transportConfig; // callback transportOk transportCallback_t transportReady_cb = NULL; @@ -41,167 +41,170 @@ extern MyMessage _msg; // incoming message extern MyMessage _msgTmp; // outgoing message #if defined(MY_RAM_ROUTING_TABLE_ENABLED) - static routingTable_t _transportRoutingTable; //!< routing table - static uint32_t _lastRoutingTableSave; //!< last routing table dump +static routingTable_t _transportRoutingTable; //!< routing table +static uint32_t _lastRoutingTableSave; //!< last routing table dump #endif // regular sanity check, activated by default on GW and repeater nodes #if defined(MY_TRANSPORT_SANITY_CHECK) - static uint32_t _lastSanityCheck; //!< last sanity check +static uint32_t _lastSanityCheck; //!< last sanity check #endif // regular network discovery, sends I_DISCOVER_REQUESTS to update routing table // sufficient to have GW triggering requests to also update repeater nodes #if defined(MY_GATEWAY_FEATURE) - static uint32_t _lastNetworkDiscovery; //! last network discovery +static uint32_t _lastNetworkDiscovery; //! last network discovery #endif // stInit: initialise transport HW -void stInitTransition(void) { +void stInitTransition(void) +{ TRANSPORT_DEBUG(PSTR("TSM:INIT\n")); // initialise status variables _transportSM.pingActive = false; _transportSM.transportActive = false; _transportSM.lastUplinkCheck = 0ul; - #if defined(MY_TRANSPORT_SANITY_CHECK) - _lastSanityCheck = hwMillis(); - #endif - #if defined(MY_GATEWAY_FEATURE) - _lastNetworkDiscovery = 0ul; - #endif - #if defined(MY_RAM_ROUTING_TABLE_ENABLED) - _lastRoutingTableSave = hwMillis(); - #endif +#if defined(MY_TRANSPORT_SANITY_CHECK) + _lastSanityCheck = hwMillis(); +#endif +#if defined(MY_GATEWAY_FEATURE) + _lastNetworkDiscovery = 0ul; +#endif +#if defined(MY_RAM_ROUTING_TABLE_ENABLED) + _lastRoutingTableSave = hwMillis(); +#endif // Read node settings (ID, parent ID, GW distance) from EEPROM - hwReadConfigBlock((void*)&_transportConfig, (void*)EEPROM_NODE_ID_ADDRESS, sizeof(transportConfig_t)); + hwReadConfigBlock((void*)&_transportConfig, (void*)EEPROM_NODE_ID_ADDRESS, + sizeof(transportConfig_t)); } -void stInitUpdate(void) { +void stInitUpdate(void) +{ // initialise radio if (!transportInit()) { TRANSPORT_DEBUG(PSTR("!TSM:INIT:TSP FAIL\n")); setIndication(INDICATION_ERR_INIT_TRANSPORT); transportSwitchSM(stFailure); - } - else { + } else { TRANSPORT_DEBUG(PSTR("TSM:INIT:TSP OK\n")); _transportSM.transportActive = true; - #if defined(MY_GATEWAY_FEATURE) - // Set configuration for gateway - TRANSPORT_DEBUG(PSTR("TSM:INIT:GW MODE\n")); - _transportConfig.parentNodeId = GATEWAY_ADDRESS; - _transportConfig.distanceGW = 0u; - _transportConfig.nodeId = GATEWAY_ADDRESS; - transportSetAddress(GATEWAY_ADDRESS); - // GW mode: skip FPAR,ID,UPL states - transportSwitchSM(stReady); - #else - if (MY_NODE_ID != AUTO) { - TRANSPORT_DEBUG(PSTR("TSM:INIT:STATID=%d\n"),(uint8_t)MY_NODE_ID); - // Set static ID - _transportConfig.nodeId = (uint8_t)MY_NODE_ID; - // Save static ID to eeprom (for bootloader) - hwWriteConfig(EEPROM_NODE_ID_ADDRESS, (uint8_t)MY_NODE_ID); - } - // assign ID if set - if (_transportConfig.nodeId == AUTO || transportAssignNodeID(_transportConfig.nodeId)) { - // if node ID valid (>0 and <255), proceed to next state - transportSwitchSM(stParent); - } - else { - // ID invalid (0 or 255) - transportSwitchSM(stFailure); - } - #endif +#if defined(MY_GATEWAY_FEATURE) + // Set configuration for gateway + TRANSPORT_DEBUG(PSTR("TSM:INIT:GW MODE\n")); + _transportConfig.parentNodeId = GATEWAY_ADDRESS; + _transportConfig.distanceGW = 0u; + _transportConfig.nodeId = GATEWAY_ADDRESS; + transportSetAddress(GATEWAY_ADDRESS); + // GW mode: skip FPAR,ID,UPL states + transportSwitchSM(stReady); +#else + if (MY_NODE_ID != AUTO) { + TRANSPORT_DEBUG(PSTR("TSM:INIT:STATID=%d\n"),(uint8_t)MY_NODE_ID); + // Set static ID + _transportConfig.nodeId = (uint8_t)MY_NODE_ID; + // Save static ID to eeprom (for bootloader) + hwWriteConfig(EEPROM_NODE_ID_ADDRESS, (uint8_t)MY_NODE_ID); + } + // assign ID if set + if (_transportConfig.nodeId == AUTO || transportAssignNodeID(_transportConfig.nodeId)) { + // if node ID valid (>0 and <255), proceed to next state + transportSwitchSM(stParent); + } else { + // ID invalid (0 or 255) + transportSwitchSM(stFailure); + } +#endif } } // stParent: find parent -void stParentTransition(void) { +void stParentTransition(void) +{ TRANSPORT_DEBUG(PSTR("TSM:FPAR\n")); // find parent setIndication(INDICATION_FIND_PARENT); _transportSM.uplinkOk = false; _transportSM.preferredParentFound = false; - #if defined(MY_PARENT_NODE_IS_STATIC) - TRANSPORT_DEBUG(PSTR("TSM:FPAR:STATP=%d\n"), (uint8_t)MY_PARENT_NODE_ID); // static parent - _transportSM.findingParentNode = false; - _transportConfig.distanceGW = 1u; // assumption, CHKUPL:GWDC will update this variable - _transportConfig.parentNodeId = (uint8_t)MY_PARENT_NODE_ID; - // save parent ID to eeprom (for bootloader) - hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, (uint8_t)MY_PARENT_NODE_ID); - #else - _transportSM.findingParentNode = true; - _transportConfig.distanceGW = DISTANCE_INVALID; // Set distance to max and invalidate parent node ID - _transportConfig.parentNodeId = AUTO; - // Broadcast find parent request - (void)transportRouteMessage(build(_msgTmp, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_REQUEST).set("")); - #endif +#if defined(MY_PARENT_NODE_IS_STATIC) + TRANSPORT_DEBUG(PSTR("TSM:FPAR:STATP=%d\n"), (uint8_t)MY_PARENT_NODE_ID); // static parent + _transportSM.findingParentNode = false; + _transportConfig.distanceGW = 1u; // assumption, CHKUPL:GWDC will update this variable + _transportConfig.parentNodeId = (uint8_t)MY_PARENT_NODE_ID; + // save parent ID to eeprom (for bootloader) + hwWriteConfig(EEPROM_PARENT_NODE_ID_ADDRESS, (uint8_t)MY_PARENT_NODE_ID); +#else + _transportSM.findingParentNode = true; + _transportConfig.distanceGW = DISTANCE_INVALID; // Set distance to max and invalidate parent node ID + _transportConfig.parentNodeId = AUTO; + // Broadcast find parent request + (void)transportRouteMessage(build(_msgTmp, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, + I_FIND_PARENT_REQUEST).set("")); +#endif } // stParentUpdate -void stParentUpdate(void) { - #if defined(MY_PARENT_NODE_IS_STATIC) - // skipping find parent - setIndication(INDICATION_GOT_PARENT); - transportSwitchSM(stID); - #else - if (transportTimeInState() > MY_TRANSPORT_STATE_TIMEOUT_MS || _transportSM.preferredParentFound) { - // timeout or preferred parent found - if (_transportConfig.parentNodeId != AUTO) { - // parent assigned - TRANSPORT_DEBUG(PSTR("TSM:FPAR:OK\n")); // find parent ok - _transportSM.findingParentNode = false; - setIndication(INDICATION_GOT_PARENT); - // go to next state - transportSwitchSM(stID); - } - else { - // timeout w/o reply or valid parent - if (_transportSM.stateRetries < MY_TRANSPORT_STATE_RETRIES) { - // retries left - TRANSPORT_DEBUG(PSTR("!TSM:FPAR:NO REPLY\n")); // find parent, no reply - // reenter state - transportSwitchSM(stParent); - } - else { - // no retries left, finding parent failed - TRANSPORT_DEBUG(PSTR("!TSM:FPAR:FAIL\n")); - setIndication(INDICATION_ERR_FIND_PARENT); - transportSwitchSM(stFailure); - } +void stParentUpdate(void) +{ +#if defined(MY_PARENT_NODE_IS_STATIC) + // skipping find parent + setIndication(INDICATION_GOT_PARENT); + transportSwitchSM(stID); +#else + if (transportTimeInState() > MY_TRANSPORT_STATE_TIMEOUT_MS || _transportSM.preferredParentFound) { + // timeout or preferred parent found + if (_transportConfig.parentNodeId != AUTO) { + // parent assigned + TRANSPORT_DEBUG(PSTR("TSM:FPAR:OK\n")); // find parent ok + _transportSM.findingParentNode = false; + setIndication(INDICATION_GOT_PARENT); + // go to next state + transportSwitchSM(stID); + } else { + // timeout w/o reply or valid parent + if (_transportSM.stateRetries < MY_TRANSPORT_STATE_RETRIES) { + // retries left + TRANSPORT_DEBUG(PSTR("!TSM:FPAR:NO REPLY\n")); // find parent, no reply + // reenter state + transportSwitchSM(stParent); + } else { + // no retries left, finding parent failed + TRANSPORT_DEBUG(PSTR("!TSM:FPAR:FAIL\n")); + setIndication(INDICATION_ERR_FIND_PARENT); + transportSwitchSM(stFailure); } } - #endif + } +#endif } // stID: verify and request ID if necessary -void stIDTransition(void) { +void stIDTransition(void) +{ TRANSPORT_DEBUG(PSTR("TSM:ID\n")); // verify/request node ID if (_transportConfig.nodeId == AUTO) { // send ID request setIndication(INDICATION_REQ_NODEID); TRANSPORT_DEBUG(PSTR("TSM:ID:REQ\n")); // request node ID - (void)transportRouteMessage(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_ID_REQUEST).set("")); + (void)transportRouteMessage(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, + I_ID_REQUEST).set("")); } } -void stIDUpdate(void) { +void stIDUpdate(void) +{ if (_transportConfig.nodeId != AUTO) { // current node ID is valid TRANSPORT_DEBUG(PSTR("TSM:ID:OK\n")); setIndication(INDICATION_GOT_NODEID); // proceed to next state transportSwitchSM(stUplink); - } - else if (transportTimeInState() > MY_TRANSPORT_STATE_TIMEOUT_MS) { + } else if (transportTimeInState() > MY_TRANSPORT_STATE_TIMEOUT_MS) { // timeout if (_transportSM.stateRetries < MY_TRANSPORT_STATE_RETRIES) { // retries left: reenter state transportSwitchSM(stID); - } - else { + } else { // no retries left TRANSPORT_DEBUG(PSTR("!TSM:ID:FAIL\n")); setIndication(INDICATION_ERR_GET_NODEID); @@ -210,51 +213,55 @@ void stIDUpdate(void) { } } -void stUplinkTransition(void) { - #if !defined(MY_TRANSPORT_UPLINK_CHECK_DISABLED) - TRANSPORT_DEBUG(PSTR("TSM:UPL\n")); - setIndication(INDICATION_CHECK_UPLINK); - _transportSM.pingResponse = INVALID_HOPS; - _transportSM.pingActive = true; - (void)transportRouteMessage(build(_msgTmp,GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_PING).set((uint8_t)0x01)); - #endif +void stUplinkTransition(void) +{ +#if !defined(MY_TRANSPORT_UPLINK_CHECK_DISABLED) + TRANSPORT_DEBUG(PSTR("TSM:UPL\n")); + setIndication(INDICATION_CHECK_UPLINK); + _transportSM.pingResponse = INVALID_HOPS; + _transportSM.pingActive = true; + (void)transportRouteMessage(build(_msgTmp,GATEWAY_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, + I_PING).set((uint8_t)0x01)); +#endif } -void stUplinkUpdate(void) { - #if !defined(MY_TRANSPORT_UPLINK_CHECK_DISABLED) - if (_transportSM.pingResponse != INVALID_HOPS) { - _transportSM.lastUplinkCheck = hwMillis(); - // uplink ok, i.e. GW replied - TRANSPORT_DEBUG(PSTR("TSM:UPL:OK\n")); // uplink ok - if (_transportSM.pingResponse != _transportConfig.distanceGW) { - TRANSPORT_DEBUG(PSTR("TSM:UPL:DGWC,O=%d,N=%d\n"), _transportConfig.distanceGW, _transportSM.pingResponse); // distance to GW changed - _transportConfig.distanceGW = _transportSM.pingResponse; - } - transportSwitchSM(stReady); // proceed to next state +void stUplinkUpdate(void) +{ +#if !defined(MY_TRANSPORT_UPLINK_CHECK_DISABLED) + if (_transportSM.pingResponse != INVALID_HOPS) { + _transportSM.lastUplinkCheck = hwMillis(); + // uplink ok, i.e. GW replied + TRANSPORT_DEBUG(PSTR("TSM:UPL:OK\n")); // uplink ok + if (_transportSM.pingResponse != _transportConfig.distanceGW) { + TRANSPORT_DEBUG(PSTR("TSM:UPL:DGWC,O=%d,N=%d\n"), _transportConfig.distanceGW, + _transportSM.pingResponse); // distance to GW changed + _transportConfig.distanceGW = _transportSM.pingResponse; } - else if (transportTimeInState() > MY_TRANSPORT_STATE_TIMEOUT_MS) { - // timeout - if (_transportSM.stateRetries < MY_TRANSPORT_STATE_RETRIES) { - // retries left: reenter state - transportSwitchSM(stUplink); - } - else { - // no retries left - TRANSPORT_DEBUG(PSTR("!TSM:UPL:FAIL\n")); // uplink check failed - _transportSM.pingActive = false; - setIndication(INDICATION_ERR_CHECK_UPLINK); - transportSwitchSM(stParent); // go back to stParent - } + transportSwitchSM(stReady); // proceed to next state + } else if (transportTimeInState() > MY_TRANSPORT_STATE_TIMEOUT_MS) { + // timeout + if (_transportSM.stateRetries < MY_TRANSPORT_STATE_RETRIES) { + // retries left: reenter state + transportSwitchSM(stUplink); + } else { + // no retries left + TRANSPORT_DEBUG(PSTR("!TSM:UPL:FAIL\n")); // uplink check failed + _transportSM.pingActive = false; + setIndication(INDICATION_ERR_CHECK_UPLINK); + transportSwitchSM(stParent); // go back to stParent } - #else - TRANSPORT_DEBUG(PSTR("TSM:UPL:DISABLED\n")); // uplink check disabled - transportSwitchSM(stReady); - #endif + } +#else + TRANSPORT_DEBUG(PSTR("TSM:UPL:DISABLED\n")); // uplink check disabled + transportSwitchSM(stReady); +#endif } -void stReadyTransition(void) { +void stReadyTransition(void) +{ // transport is ready and fully operational - TRANSPORT_DEBUG(PSTR("TSM:READY:ID=%d,PAR=%d,DIS=%d\n"), _transportConfig.nodeId, _transportConfig.parentNodeId, _transportConfig.distanceGW); + TRANSPORT_DEBUG(PSTR("TSM:READY:ID=%d,PAR=%d,DIS=%d\n"), _transportConfig.nodeId, + _transportConfig.parentNodeId, _transportConfig.distanceGW); _transportSM.uplinkOk = true; _transportSM.failureCounter = 0u; // reset failure counter _transportSM.failedUplinkTransmissions = 0u; // reset failed uplink TX counter @@ -265,37 +272,40 @@ void stReadyTransition(void) { } // stReadyUpdate: monitors link -void stReadyUpdate(void) { - #if defined(MY_GATEWAY_FEATURE) - if (hwMillis() - _lastNetworkDiscovery > MY_TRANSPORT_DISCOVERY_INTERVAL_MS) { - _lastNetworkDiscovery = hwMillis(); - TRANSPORT_DEBUG(PSTR("TSM:READY:NWD REQ\n")); // send transport network discovery - (void)transportRouteMessage(build(_msgTmp, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, I_DISCOVER_REQUEST).set("")); - } - #else - if (_transportSM.failedUplinkTransmissions > MY_TRANSPORT_MAX_TX_FAILURES) { - // too many uplink transmissions failed, find new parent (if non-static) - #if !defined(MY_PARENT_NODE_IS_STATIC) - TRANSPORT_DEBUG(PSTR("!TSM:READY:UPL FAIL,SNP\n")); // uplink failed, search new parent - transportSwitchSM(stParent); - #else - TRANSPORT_DEBUG(PSTR("!TSM:READY:UPL FAIL,STATP\n")); // uplink failed, static parent - // reset counter - _transportSM.failedUplinkTransmissions = 0u; - #endif - } - #endif +void stReadyUpdate(void) +{ +#if defined(MY_GATEWAY_FEATURE) + if (hwMillis() - _lastNetworkDiscovery > MY_TRANSPORT_DISCOVERY_INTERVAL_MS) { + _lastNetworkDiscovery = hwMillis(); + TRANSPORT_DEBUG(PSTR("TSM:READY:NWD REQ\n")); // send transport network discovery + (void)transportRouteMessage(build(_msgTmp, BROADCAST_ADDRESS, NODE_SENSOR_ID, C_INTERNAL, + I_DISCOVER_REQUEST).set("")); + } +#else + if (_transportSM.failedUplinkTransmissions > MY_TRANSPORT_MAX_TX_FAILURES) { + // too many uplink transmissions failed, find new parent (if non-static) +#if !defined(MY_PARENT_NODE_IS_STATIC) + TRANSPORT_DEBUG(PSTR("!TSM:READY:UPL FAIL,SNP\n")); // uplink failed, search new parent + transportSwitchSM(stParent); +#else + TRANSPORT_DEBUG(PSTR("!TSM:READY:UPL FAIL,STATP\n")); // uplink failed, static parent + // reset counter + _transportSM.failedUplinkTransmissions = 0u; +#endif + } +#endif - #if defined(MY_RAM_ROUTING_TABLE_ENABLED) - if (hwMillis() - _lastRoutingTableSave > MY_ROUTING_TABLE_SAVE_INTERVAL_MS) { - _lastRoutingTableSave = hwMillis(); - transportSaveRoutingTable(); - } - #endif +#if defined(MY_RAM_ROUTING_TABLE_ENABLED) + if (hwMillis() - _lastRoutingTableSave > MY_ROUTING_TABLE_SAVE_INTERVAL_MS) { + _lastRoutingTableSave = hwMillis(); + transportSaveRoutingTable(); + } +#endif } // stFailure: entered upon HW init failure or max retries exceeded -void stFailureTransition(void) { +void stFailureTransition(void) +{ if (_transportSM.failureCounter < MY_TRANSPORT_MAX_TSM_FAILURES) { _transportSM.failureCounter++; // increment consecutive TSM failure counter } @@ -303,25 +313,27 @@ void stFailureTransition(void) { _transportSM.uplinkOk = false; // uplink nok _transportSM.transportActive = false; // transport inactive setIndication(INDICATION_ERR_INIT_TRANSPORT); - #if defined(MY_SENSOR_NETWORK) - TRANSPORT_DEBUG(PSTR("TSM:FAIL:PDT\n")); // power down transport, no need until re-init - transportPowerDown(); - #endif +#if defined(MY_SENSOR_NETWORK) + TRANSPORT_DEBUG(PSTR("TSM:FAIL:PDT\n")); // power down transport, no need until re-init + transportPowerDown(); +#endif } -void stFailureUpdate(void) { - if (transportTimeInState() > ( isTransportExtendedFailure()? MY_TRANSPORT_TIMEOUT_EXT_FAILURE_STATE: MY_TRANSPORT_TIMEOUT_FAILURE_STATE) ) { +void stFailureUpdate(void) +{ + if (transportTimeInState() > ( isTransportExtendedFailure()? MY_TRANSPORT_TIMEOUT_EXT_FAILURE_STATE: + MY_TRANSPORT_TIMEOUT_FAILURE_STATE) ) { TRANSPORT_DEBUG(PSTR("TSM:FAIL:RE-INIT\n")); // attempt to re-initialise transport transportSwitchSM(stInit); } } -void transportSwitchSM(transportState_t& newState) { +void transportSwitchSM(transportState_t& newState) +{ if (_transportSM.currentState != &newState) { _transportSM.stateRetries = 0u; // state change, reset retry counter _transportSM.currentState = &newState; // change state - } - else { + } else { _transportSM.stateRetries++; // increment retries } if (_transportSM.currentState->Transition) { @@ -330,38 +342,46 @@ void transportSwitchSM(transportState_t& newState) { _transportSM.stateEnter = hwMillis(); // save time } -uint32_t transportTimeInState(void) { +uint32_t transportTimeInState(void) +{ return hwMillis() - _transportSM.stateEnter; } -void transportUpdateSM(void) { +void transportUpdateSM(void) +{ if (_transportSM.currentState->Update) { _transportSM.currentState->Update(); } } -bool isTransportReady(void) { +bool isTransportReady(void) +{ return _transportSM.uplinkOk; } -bool isTransportExtendedFailure(void) { +bool isTransportExtendedFailure(void) +{ return _transportSM.failureCounter == MY_TRANSPORT_MAX_TSM_FAILURES; } -bool isTransportSearchingParent(void) { +bool isTransportSearchingParent(void) +{ return _transportSM.findingParentNode; } -bool isMessageReceived(void) { +bool isMessageReceived(void) +{ return _transportSM.msgReceived; } -void resetMessageReceived(void) { +void resetMessageReceived(void) +{ _transportSM.msgReceived = false; } -void transportInitialise(void) { +void transportInitialise(void) +{ _transportSM.failureCounter = 0u; // reset failure counter transportLoadRoutingTable(); // load routing table to RAM (if feature enabled) // intial state @@ -369,7 +389,8 @@ void transportInitialise(void) { transportSwitchSM(stInit); } -bool transportWaitUntilReady(const uint32_t waitingMS) { +bool transportWaitUntilReady(const uint32_t waitingMS) +{ // check if transport ready TRANSPORT_DEBUG(PSTR("TSF:WUR:MS=%lu\n"), waitingMS); // timeout uint32_t enterMS = hwMillis(); @@ -383,7 +404,8 @@ bool transportWaitUntilReady(const uint32_t waitingMS) { } // update TSM and process incoming messages -void transportProcess(void) { +void transportProcess(void) +{ // update state machine transportUpdateSM(); // process transport FIFO @@ -391,7 +413,8 @@ void transportProcess(void) { } -bool transportCheckUplink(const bool force) { +bool transportCheckUplink(const bool force) +{ if (!force && (hwMillis() - _transportSM.lastUplinkCheck) < MY_TRANSPORT_CHKUPL_INTERVAL_MS) { TRANSPORT_DEBUG(PSTR("TSF:CKU:OK,FCTRL\n")); // flood control return true; @@ -405,18 +428,19 @@ bool transportCheckUplink(const bool force) { TRANSPORT_DEBUG(PSTR("TSF:CKU:OK\n")); // did distance to GW change upstream, eg. re-routing of uplink nodes if (hopsCount != _transportConfig.distanceGW) { - TRANSPORT_DEBUG(PSTR("TSF:CKU:DGWC,O=%d,N=%d\n"), _transportConfig.distanceGW, hopsCount); // distance to GW changed + TRANSPORT_DEBUG(PSTR("TSF:CKU:DGWC,O=%d,N=%d\n"), _transportConfig.distanceGW, + hopsCount); // distance to GW changed _transportConfig.distanceGW = hopsCount; } return true; - } - else { + } else { TRANSPORT_DEBUG(PSTR("TSF:CKU:FAIL\n")); return false; } } -bool transportAssignNodeID(const uint8_t newNodeId) { +bool transportAssignNodeID(const uint8_t newNodeId) +{ // verify if ID valid if (newNodeId != GATEWAY_ADDRESS && newNodeId != AUTO) { _transportConfig.nodeId = newNodeId; @@ -425,8 +449,7 @@ bool transportAssignNodeID(const uint8_t newNodeId) { hwWriteConfig(EEPROM_NODE_ID_ADDRESS, newNodeId); TRANSPORT_DEBUG(PSTR("TSF:SID:OK,ID=%d\n"),newNodeId); // Node ID assigned return true; - } - else { + } else { TRANSPORT_DEBUG(PSTR("!TSF:SID:FAIL,ID=%d\n"),newNodeId); // ID is invalid, cannot assign ID setIndication(INDICATION_ERR_NET_FULL); _transportConfig.nodeId = AUTO; @@ -434,7 +457,8 @@ bool transportAssignNodeID(const uint8_t newNodeId) { } } -bool transportRouteMessage(MyMessage &message) { +bool transportRouteMessage(MyMessage &message) +{ const uint8_t destination = message.destination; uint8_t route = _transportConfig.parentNodeId; // by default, all traffic is routed via parent node @@ -446,60 +470,58 @@ bool transportRouteMessage(MyMessage &message) { if (destination == GATEWAY_ADDRESS) { route = _transportConfig.parentNodeId; // message to GW always routes via parent - } - else if (destination == BROADCAST_ADDRESS) { + } else if (destination == BROADCAST_ADDRESS) { route = BROADCAST_ADDRESS; // message to BC does not require routing - } - else { - #if defined(MY_REPEATER_FEATURE) - // destination not GW & not BC, get route - route = transportGetRoute(destination); - if (route == AUTO) { - TRANSPORT_DEBUG(PSTR("!TSF:RTE:%d UNKNOWN\n"), destination); // route unknown - #if !defined(MY_GATEWAY_FEATURE) - if (message.last != _transportConfig.parentNodeId) { - // message not from parent, i.e. child node - route it to parent - route = _transportConfig.parentNodeId; - } - else { - // route unknown and msg received from parent, send it to destination assuming in rx radius - route = destination; - } - #else - // if GW, all unknown destinations are directly addressed - route = destination; - #endif + } else { +#if defined(MY_REPEATER_FEATURE) + // destination not GW & not BC, get route + route = transportGetRoute(destination); + if (route == AUTO) { + TRANSPORT_DEBUG(PSTR("!TSF:RTE:%d UNKNOWN\n"), destination); // route unknown +#if !defined(MY_GATEWAY_FEATURE) + if (message.last != _transportConfig.parentNodeId) { + // message not from parent, i.e. child node - route it to parent + route = _transportConfig.parentNodeId; + } else { + // route unknown and msg received from parent, send it to destination assuming in rx radius + route = destination; } - #else - route = _transportConfig.parentNodeId; // not a repeater, all traffic routed via parent - #endif +#else + // if GW, all unknown destinations are directly addressed + route = destination; +#endif + } +#else + route = _transportConfig.parentNodeId; // not a repeater, all traffic routed via parent +#endif } // send message const bool result = transportSendWrite(route, message); - #if !defined(MY_GATEWAY_FEATURE) - // update counter - if (route == _transportConfig.parentNodeId) { - if (!result) { - setIndication(INDICATION_ERR_TX); - _transportSM.failedUplinkTransmissions++; - } - else _transportSM.failedUplinkTransmissions = 0u; - } - #else - if(!result) { +#if !defined(MY_GATEWAY_FEATURE) + // update counter + if (route == _transportConfig.parentNodeId) { + if (!result) { setIndication(INDICATION_ERR_TX); + _transportSM.failedUplinkTransmissions++; + } else { + _transportSM.failedUplinkTransmissions = 0u; } - #endif + } +#else + if(!result) { + setIndication(INDICATION_ERR_TX); + } +#endif return result; } -bool transportSendRoute(MyMessage &message) { +bool transportSendRoute(MyMessage &message) +{ bool result = false; if (isTransportReady()) { result = transportRouteMessage(message); - } - else { + } else { // TNR: transport not ready TRANSPORT_DEBUG(PSTR("!TSF:SND:TNR\n")); } @@ -507,7 +529,8 @@ bool transportSendRoute(MyMessage &message) { } // only be used inside transport -bool transportWait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t msgType){ +bool transportWait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t msgType) +{ const uint32_t enterMS = hwMillis(); // invalidate msg type _msg.type = !msgType; @@ -521,35 +544,37 @@ bool transportWait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t ms return expectedResponse; } -uint8_t transportPingNode(const uint8_t targetId) { - if(!_transportSM.pingActive){ +uint8_t transportPingNode(const uint8_t targetId) +{ + if(!_transportSM.pingActive) { TRANSPORT_DEBUG(PSTR("TSF:PNG:SEND,TO=%d\n"), targetId); if(targetId == _transportConfig.nodeId) { // pinging self _transportSM.pingResponse = 0u; - } - else { + } else { _transportSM.pingActive = true; _transportSM.pingResponse = INVALID_HOPS; - (void)transportRouteMessage(build(_msgTmp, targetId, NODE_SENSOR_ID, C_INTERNAL, I_PING).set((uint8_t)0x01)); + (void)transportRouteMessage(build(_msgTmp, targetId, NODE_SENSOR_ID, C_INTERNAL, + I_PING).set((uint8_t)0x01)); // Wait for ping reply or timeout (void)transportWait(2000, C_INTERNAL, I_PONG); } // make sure missing I_PONG msg does not block pinging function by leaving pignActive=true _transportSM.pingActive = false; return _transportSM.pingResponse; - } - else { + } else { TRANSPORT_DEBUG(PSTR("!TSF:PNG:ACTIVE\n")); // ping active, cannot start new ping return INVALID_HOPS; } } -uint32_t transportGetHeartbeat(void) { +uint32_t transportGetHeartbeat(void) +{ return transportTimeInState(); } -void transportProcessMessage(void) { +void transportProcessMessage(void) +{ // Manage signing timeout (void)signerCheckTimer(); // receive message @@ -560,7 +585,7 @@ void transportProcessMessage(void) { const uint8_t msgLength = min(mGetLength(_msg), (uint8_t)MAX_PAYLOAD); // calculate expected length const uint8_t expectedMessageLength = HEADER_SIZE + (mGetSigned(_msg) ? MAX_PAYLOAD : msgLength); -#if defined(MY_RF24_ENABLE_ENCRYPTION) +#if defined(MY_RF24_ENABLE_ENCRYPTION) // payload length = a multiple of blocksize length for decrypted messages, i.e. cannot be used for payload length check payloadLength = expectedMessageLength; #endif @@ -571,19 +596,22 @@ void transportProcessMessage(void) { const uint8_t destination = _msg.destination; TRANSPORT_DEBUG(PSTR("TSF:MSG:READ,%d-%d-%d,s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d:%s\n"), - sender, last, destination, _msg.sensor, command, type, mGetPayloadType(_msg), msgLength, mGetSigned(_msg), _msg.getString(_convBuf)); + sender, last, destination, _msg.sensor, command, type, mGetPayloadType(_msg), msgLength, + mGetSigned(_msg), _msg.getString(_convBuf)); // Reject payloads with incorrect length if (payloadLength != expectedMessageLength) { setIndication(INDICATION_ERR_LENGTH); - TRANSPORT_DEBUG(PSTR("!TSF:MSG:LEN,%d!=%d\n"), payloadLength, expectedMessageLength); // invalid payload length + TRANSPORT_DEBUG(PSTR("!TSF:MSG:LEN,%d!=%d\n"), payloadLength, + expectedMessageLength); // invalid payload length return; } // Reject messages with incorrect protocol version if (mGetVersion(_msg) != PROTOCOL_VERSION) { setIndication(INDICATION_ERR_VERSION); - TRANSPORT_DEBUG(PSTR("!TSF:MSG:PVER,%d=%d\n"), mGetVersion(_msg), PROTOCOL_VERSION); // protocol version mismatch + TRANSPORT_DEBUG(PSTR("!TSF:MSG:PVER,%d=%d\n"), mGetVersion(_msg), + PROTOCOL_VERSION); // protocol version mismatch return; } @@ -595,20 +623,20 @@ void transportProcessMessage(void) { } // update routing table if msg not from parent - #if defined(MY_REPEATER_FEATURE) - #if !defined(MY_GATEWAY_FEATURE) - if (last != getParentNodeId()) - { - #else - // GW doesn't have parent +#if defined(MY_REPEATER_FEATURE) +#if !defined(MY_GATEWAY_FEATURE) + if (last != getParentNodeId()) { +#else + // GW doesn't have parent + { +#endif + // Message is from one of the child nodes and not sent from this node. Add it to routing table. + if (sender != getNodeId()) { - #endif - // Message is from one of the child nodes and not sent from this node. Add it to routing table. - if (sender != getNodeId()) { - transportSetRoute(sender, last); - } + transportSetRoute(sender, last); } - #endif // MY_REPEATER_FEATURE + } +#endif // MY_REPEATER_FEATURE // set message received flag _transportSM.msgReceived = true; @@ -623,7 +651,8 @@ void transportProcessMessage(void) { if (mGetRequestAck(_msg)) { TRANSPORT_DEBUG(PSTR("TSF:MSG:ACK REQ\n")); // ACK requested _msgTmp = _msg; // Copy message - mSetRequestAck(_msgTmp, false); // Reply without ack flag (otherwise we would end up in an eternal loop) + mSetRequestAck(_msgTmp, + false); // Reply without ack flag (otherwise we would end up in an eternal loop) mSetAck(_msgTmp, true); // set ACK flag _msgTmp.sender = _transportConfig.nodeId; _msgTmp.destination = sender; @@ -637,49 +666,51 @@ void transportProcessMessage(void) { if (signerProcessInternal(_msg)) { return; // Signer processing indicated no further action needed } - #if !defined(MY_GATEWAY_FEATURE) - if (type == I_ID_RESPONSE) { - #if (MY_NODE_ID == AUTO) - // only active if node ID dynamic - (void)transportAssignNodeID(_msg.getByte()); - #endif - return; // no further processing required - } - if (type == I_FIND_PARENT_RESPONSE) { - #if !defined(MY_GATEWAY_FEATURE) && !defined(MY_PARENT_NODE_IS_STATIC) - if (_transportSM.findingParentNode) { // only process if find parent active - // Reply to a I_FIND_PARENT_REQUEST message. Check if the distance is shorter than we already have. - uint8_t distance = _msg.getByte(); - if (isValidDistance(distance)) { - distance++; // Distance to gateway is one more for us w.r.t. parent - // update settings if distance shorter or preferred parent found - if (((isValidDistance(distance) && distance < _transportConfig.distanceGW) || (!_autoFindParent && sender == (uint8_t)MY_PARENT_NODE_ID)) && !_transportSM.preferredParentFound) { - // Found a neighbor closer to GW than previously found - if (!_autoFindParent && sender == (uint8_t)MY_PARENT_NODE_ID) { - _transportSM.preferredParentFound = true; - TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR PREF\n")); // find parent, preferred parent found - } - _transportConfig.distanceGW = distance; - _transportConfig.parentNodeId = sender; - TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR OK,ID=%d,D=%d\n"), _transportConfig.parentNodeId, _transportConfig.distanceGW); - } +#if !defined(MY_GATEWAY_FEATURE) + if (type == I_ID_RESPONSE) { +#if (MY_NODE_ID == AUTO) + // only active if node ID dynamic + (void)transportAssignNodeID(_msg.getByte()); +#endif + return; // no further processing required + } + if (type == I_FIND_PARENT_RESPONSE) { +#if !defined(MY_GATEWAY_FEATURE) && !defined(MY_PARENT_NODE_IS_STATIC) + if (_transportSM.findingParentNode) { // only process if find parent active + // Reply to a I_FIND_PARENT_REQUEST message. Check if the distance is shorter than we already have. + uint8_t distance = _msg.getByte(); + if (isValidDistance(distance)) { + distance++; // Distance to gateway is one more for us w.r.t. parent + // update settings if distance shorter or preferred parent found + if (((isValidDistance(distance) && distance < _transportConfig.distanceGW) || (!_autoFindParent && + sender == (uint8_t)MY_PARENT_NODE_ID)) && !_transportSM.preferredParentFound) { + // Found a neighbor closer to GW than previously found + if (!_autoFindParent && sender == (uint8_t)MY_PARENT_NODE_ID) { + _transportSM.preferredParentFound = true; + TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR PREF\n")); // find parent, preferred parent found } + _transportConfig.distanceGW = distance; + _transportConfig.parentNodeId = sender; + TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR OK,ID=%d,D=%d\n"), _transportConfig.parentNodeId, + _transportConfig.distanceGW); } - else { - TRANSPORT_DEBUG(PSTR("!TSF:MSG:FPAR INACTIVE\n")); // find parent response received, but inactive - } - return; - #endif + } + } else { + TRANSPORT_DEBUG(PSTR("!TSF:MSG:FPAR INACTIVE\n")); // find parent response received, but inactive } - #endif + return; +#endif + } +#endif // general if (type == I_PING) { TRANSPORT_DEBUG(PSTR("TSF:MSG:PINGED,ID=%d,HP=%d\n"), sender, _msg.getByte()); // node pinged - #if defined(MY_GATEWAY_FEATURE) && (F_CPU>16000000) - // delay for fast GW and slow nodes - delay(5); - #endif - (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, I_PONG).set((uint8_t)1)); +#if defined(MY_GATEWAY_FEATURE) && (F_CPU>16000000) + // delay for fast GW and slow nodes + delay(5); +#endif + (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, + I_PONG).set((uint8_t)1)); return; // no further processing required } if (type == I_PONG) { @@ -687,8 +718,7 @@ void transportProcessMessage(void) { _transportSM.pingActive = false; _transportSM.pingResponse = _msg.getByte(); TRANSPORT_DEBUG(PSTR("TSF:MSG:PONG RECV,HP=%d\n"), _transportSM.pingResponse); // pong received - } - else { + } else { TRANSPORT_DEBUG(PSTR("!TSF:MSG:PONG RECV,INACTIVE\n")); // pong received, but !pingActive } return; // no further processing required @@ -697,32 +727,31 @@ void transportProcessMessage(void) { return; // no further processing required } } else if (command == C_STREAM) { - #if defined(MY_OTA_FIRMWARE_FEATURE) - if(firmwareOTAUpdateProcess()){ - return; // OTA FW update processing indicated no further action needed - } - #endif +#if defined(MY_OTA_FIRMWARE_FEATURE) + if(firmwareOTAUpdateProcess()) { + return; // OTA FW update processing indicated no further action needed + } +#endif } + } else { + TRANSPORT_DEBUG( + PSTR("TSF:MSG:ACK\n")); // received message is ACK, no internal processing, handover to msg callback } - else { - TRANSPORT_DEBUG(PSTR("TSF:MSG:ACK\n")); // received message is ACK, no internal processing, handover to msg callback - } - #if defined(MY_GATEWAY_FEATURE) - // Hand over message to controller - (void)gatewayTransportSend(_msg); - #endif +#if defined(MY_GATEWAY_FEATURE) + // Hand over message to controller + (void)gatewayTransportSend(_msg); +#endif // Call incoming message callback if available if (receive) { receive(_msg); } - } - else if (destination == BROADCAST_ADDRESS) { + } else if (destination == BROADCAST_ADDRESS) { TRANSPORT_DEBUG(PSTR("TSF:MSG:BC\n")); // broadcast msg if (command == C_INTERNAL) { if (isTransportReady()) { // only reply if node is fully operational if (type == I_FIND_PARENT_REQUEST) { - #if defined(MY_REPEATER_FEATURE) +#if defined(MY_REPEATER_FEATURE) if (sender != _transportConfig.parentNodeId) { // no circular reference TRANSPORT_DEBUG(PSTR("TSF:MSG:FPAR REQ,ID=%d\n"), sender); // FPAR: find parent request // check if uplink functional - node can only be parent node if link to GW functional @@ -732,60 +761,61 @@ void transportProcessMessage(void) { TRANSPORT_DEBUG(PSTR("TSF:MSG:GWL OK\n")); // GW uplink ok // random delay minimizes collisions delay(hwMillis() & 0x3ff); - (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, I_FIND_PARENT_RESPONSE).set(_transportConfig.distanceGW)); - } - else { + (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, + I_FIND_PARENT_RESPONSE).set(_transportConfig.distanceGW)); + } else { TRANSPORT_DEBUG(PSTR("!TSF:MSG:GWL FAIL\n")); // GW uplink fail, do not respond to parent request } } - #endif +#endif return; // no further processing required, do not forward } } // isTransportReady if (type == I_FIND_PARENT_RESPONSE) { return; // no further processing required, do not forward } - #if !defined(MY_GATEWAY_FEATURE) - if (type == I_DISCOVER_REQUEST) { - if (last == _transportConfig.parentNodeId) { - // random wait to minimize collisions - delay(hwMillis() & 0x3ff); - (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, I_DISCOVER_RESPONSE).set(_transportConfig.parentNodeId)); - // no return here (for fwd if repeater) - } +#if !defined(MY_GATEWAY_FEATURE) + if (type == I_DISCOVER_REQUEST) { + if (last == _transportConfig.parentNodeId) { + // random wait to minimize collisions + delay(hwMillis() & 0x3ff); + (void)transportRouteMessage(build(_msgTmp, sender, NODE_SENSOR_ID, C_INTERNAL, + I_DISCOVER_RESPONSE).set(_transportConfig.parentNodeId)); + // no return here (for fwd if repeater) } - #endif + } +#endif } // controlled BC relay - #if defined(MY_REPEATER_FEATURE) - // controlled BC repeating: forward only if message received from parent and sender not self to prevent circular fwds - if(last == _transportConfig.parentNodeId && sender != _transportConfig.nodeId && isTransportReady()){ - TRANSPORT_DEBUG(PSTR("TSF:MSG:FWD BC MSG\n")); // controlled broadcast msg forwarding - (void)transportRouteMessage(_msg); - } - #endif +#if defined(MY_REPEATER_FEATURE) + // controlled BC repeating: forward only if message received from parent and sender not self to prevent circular fwds + if(last == _transportConfig.parentNodeId && sender != _transportConfig.nodeId && + isTransportReady()) { + TRANSPORT_DEBUG(PSTR("TSF:MSG:FWD BC MSG\n")); // controlled broadcast msg forwarding + (void)transportRouteMessage(_msg); + } +#endif // Callback for BC, only for non-internal messages if (command != C_INTERNAL) { - #if !defined(MY_GATEWAY_FEATURE) - // only proceed if message received from parent - if (last != _transportConfig.parentNodeId) { - return; - } - #endif - #if defined(MY_GATEWAY_FEATURE) - // Hand over message to controller - (void)gatewayTransportSend(_msg); - #endif +#if !defined(MY_GATEWAY_FEATURE) + // only proceed if message received from parent + if (last != _transportConfig.parentNodeId) { + return; + } +#endif +#if defined(MY_GATEWAY_FEATURE) + // Hand over message to controller + (void)gatewayTransportSend(_msg); +#endif if (receive) { receive(_msg); } } - } - else { + } else { // msg not to us and not BC, relay msg - #if defined(MY_REPEATER_FEATURE) +#if defined(MY_REPEATER_FEATURE) if (isTransportReady()) { TRANSPORT_DEBUG(PSTR("TSF:MSG:REL MSG\n")); // relay msg if (command == C_INTERNAL) { @@ -801,49 +831,51 @@ void transportProcessMessage(void) { // Relay this message to another node (void)transportRouteMessage(_msg); } - #else - TRANSPORT_DEBUG(PSTR("!TSF:MSG:REL MSG,NREP\n")); // message relaying request, but not a repeater - #endif +#else + TRANSPORT_DEBUG(PSTR("!TSF:MSG:REL MSG,NREP\n")); // message relaying request, but not a repeater +#endif } } -void transportInvokeSanityCheck(void) { +void transportInvokeSanityCheck(void) +{ if (!transportSanityCheck()) { TRANSPORT_DEBUG(PSTR("!TSF:SNK:FAIL\n")); // sanity check fail transportSwitchSM(stFailure); - } - else { + } else { TRANSPORT_DEBUG(PSTR("TSF:SNK:OK\n")); // sanity check ok } } -void transportProcessFIFO(void) { +void transportProcessFIFO(void) +{ if (!_transportSM.transportActive) { // transport not active, no further processing required return; } - #if defined(MY_TRANSPORT_SANITY_CHECK) - if (hwMillis() - _lastSanityCheck > MY_TRANSPORT_SANITY_CHECK_INTERVAL_MS) { - _lastSanityCheck = hwMillis(); - transportInvokeSanityCheck(); - } - #endif +#if defined(MY_TRANSPORT_SANITY_CHECK) + if (hwMillis() - _lastSanityCheck > MY_TRANSPORT_SANITY_CHECK_INTERVAL_MS) { + _lastSanityCheck = hwMillis(); + transportInvokeSanityCheck(); + } +#endif uint8_t _processedMessages = MAX_SUBSEQ_MSGS; // process all msgs in FIFO or counter exit while (transportAvailable() && _processedMessages--) { transportProcessMessage(); } - #if defined(MY_OTA_FIRMWARE_FEATURE) - if (isTransportReady()) { - // only process if transport ok - firmwareOTAUpdateRequest(); - } - #endif +#if defined(MY_OTA_FIRMWARE_FEATURE) + if (isTransportReady()) { + // only process if transport ok + firmwareOTAUpdateRequest(); + } +#endif } -bool transportSendWrite(const uint8_t to, MyMessage &message) { +bool transportSendWrite(const uint8_t to, MyMessage &message) +{ message.last = _transportConfig.nodeId; // Update last // sign message if required if (!signerSignMsg(message)) { @@ -853,7 +885,8 @@ bool transportSendWrite(const uint8_t to, MyMessage &message) { } // msg length changes if signed - const uint8_t totalMsgLength = HEADER_SIZE + ( mGetSigned(message) ? MAX_PAYLOAD : mGetLength(message) ); + const uint8_t totalMsgLength = HEADER_SIZE + ( mGetSigned(message) ? MAX_PAYLOAD : mGetLength( + message) ); // send setIndication(INDICATION_TX); @@ -862,8 +895,10 @@ bool transportSendWrite(const uint8_t to, MyMessage &message) { result |= (to == BROADCAST_ADDRESS); TRANSPORT_DEBUG(PSTR("%sTSF:MSG:SEND,%d-%d-%d-%d,s=%d,c=%d,t=%d,pt=%d,l=%d,sg=%d,ft=%d,st=%s:%s\n"), - (result ? "" : "!"), message.sender, message.last, to, message.destination, message.sensor, mGetCommand(message), message.type, - mGetPayloadType(message), mGetLength(message), mGetSigned(message), _transportSM.failedUplinkTransmissions, (result ? "OK" : "NACK"), message.getString(_convBuf)); + (result ? "" : "!"), message.sender, message.last, to, message.destination, message.sensor, + mGetCommand(message), message.type, + mGetPayloadType(message), mGetLength(message), mGetSigned(message), + _transportSM.failedUplinkTransmissions, (result ? "OK" : "NACK"), message.getString(_convBuf)); return result; } @@ -887,7 +922,8 @@ uint8_t transportGetDistanceGW(void) } -void transportClearRoutingTable(void) { +void transportClearRoutingTable(void) +{ for (uint16_t i = 0; i < SIZE_ROUTES; i++) { transportSetRoute((uint8_t)i, BROADCAST_ADDRESS); } @@ -895,34 +931,38 @@ void transportClearRoutingTable(void) { TRANSPORT_DEBUG(PSTR("TSF:CRT:OK\n")); // clear routing table } -void transportLoadRoutingTable(void) { - #if defined(MY_RAM_ROUTING_TABLE_ENABLED) - hwReadConfigBlock((void*)&_transportRoutingTable.route, (void*)EEPROM_ROUTES_ADDRESS, SIZE_ROUTES); - TRANSPORT_DEBUG(PSTR("TSF:LRT:OK\n")); // load routing table - #endif +void transportLoadRoutingTable(void) +{ +#if defined(MY_RAM_ROUTING_TABLE_ENABLED) + hwReadConfigBlock((void*)&_transportRoutingTable.route, (void*)EEPROM_ROUTES_ADDRESS, SIZE_ROUTES); + TRANSPORT_DEBUG(PSTR("TSF:LRT:OK\n")); // load routing table +#endif } -void transportSaveRoutingTable(void) { - #if defined(MY_RAM_ROUTING_TABLE_ENABLED) - hwWriteConfigBlock((void*)&_transportRoutingTable.route, (void*)EEPROM_ROUTES_ADDRESS, SIZE_ROUTES); - TRANSPORT_DEBUG(PSTR("TSF:SRT:OK\n")); // save routing table - #endif +void transportSaveRoutingTable(void) +{ +#if defined(MY_RAM_ROUTING_TABLE_ENABLED) + hwWriteConfigBlock((void*)&_transportRoutingTable.route, (void*)EEPROM_ROUTES_ADDRESS, SIZE_ROUTES); + TRANSPORT_DEBUG(PSTR("TSF:SRT:OK\n")); // save routing table +#endif } -void transportSetRoute(const uint8_t node, const uint8_t route) { - #if defined(MY_RAM_ROUTING_TABLE_ENABLED) - _transportRoutingTable.route[node] = route; - #else - hwWriteConfig(EEPROM_ROUTES_ADDRESS + node, route); - #endif +void transportSetRoute(const uint8_t node, const uint8_t route) +{ +#if defined(MY_RAM_ROUTING_TABLE_ENABLED) + _transportRoutingTable.route[node] = route; +#else + hwWriteConfig(EEPROM_ROUTES_ADDRESS + node, route); +#endif } -uint8_t transportGetRoute(const uint8_t node) { +uint8_t transportGetRoute(const uint8_t node) +{ uint8_t result; - #if defined(MY_RAM_ROUTING_TABLE_ENABLED) - result = _transportRoutingTable.route[node]; - #else - result = hwReadConfig(EEPROM_ROUTES_ADDRESS + node); - #endif +#if defined(MY_RAM_ROUTING_TABLE_ENABLED) + result = _transportRoutingTable.route[node]; +#else + result = hwReadConfig(EEPROM_ROUTES_ADDRESS + node); +#endif return result; } diff --git a/core/MyTransport.h b/core/MyTransport.h index 4508cc9c2..52cdd48b8 100644 --- a/core/MyTransport.h +++ b/core/MyTransport.h @@ -17,166 +17,166 @@ * version 2 as published by the Free Software Foundation. */ - /** - * @file MyTransport.h - * - * @defgroup MyTransportgrp MyTransport - * @ingroup internals - * @{ - * - * Transport-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE - * - [!] Exclamation mark is prepended in case of error - * - SYSTEM: - * - TSM: messages emitted by the transport state machine - * - TSF: messages emitted by transport support functions - * - SUB SYSTEMS: - * - Transport state machine (TSM) - * - TSM:INIT from stInit Initialize transport and radio - * - TSM:FPAR from stParent Find parent - * - TSM:ID from stID Check/request node ID, if dynamic node ID set - * - TSM:UPL from stUplink Verify uplink connection by pinging GW - * - TSM:READY from stReady Transport is ready and fully operational - * - TSM:FAIL from stFailure Failure in transport link or transport HW - * - Transport support function (TSF) - * - TSF:CHKUPL from @ref transportCheckUplink(), checks connection to GW - * - TSF:ASID from @ref transportAssignNodeID(), assigns node ID - * - TSF:PING from @ref transportPingNode(), pings a node - * - TSF:WUR from @ref transportWaitUntilReady(), waits until transport is ready - * - TSF:CRT from @ref transportClearRoutingTable(), clears routing table stored in EEPROM - * - TSF:LRT from @ref transportLoadRoutingTable(), loads RAM routing table from EEPROM (only GW/repeaters) - * - TSF:SRT from @ref transportSaveRoutingTable(), saves RAM routing table to EEPROM (only GW/repeaters) - * - TSF:MSG from @ref transportProcessMessage(), processes incoming message - * - TSF:SANCHK from @ref transportInvokeSanityCheck(), calls transport-specific sanity check - * - TSF:ROUTE from @ref transportRouteMessage(), sends message - * - TSF:SEND from @ref transportSendRoute(), sends message if transport is ready (exposed) +/** +* @file MyTransport.h +* +* @defgroup MyTransportgrp MyTransport +* @ingroup internals +* @{ +* +* Transport-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE +* - [!] Exclamation mark is prepended in case of error +* - SYSTEM: +* - TSM: messages emitted by the transport state machine +* - TSF: messages emitted by transport support functions +* - SUB SYSTEMS: +* - Transport state machine (TSM) +* - TSM:INIT from stInit Initialize transport and radio +* - TSM:FPAR from stParent Find parent +* - TSM:ID from stID Check/request node ID, if dynamic node ID set +* - TSM:UPL from stUplink Verify uplink connection by pinging GW +* - TSM:READY from stReady Transport is ready and fully operational +* - TSM:FAIL from stFailure Failure in transport link or transport HW +* - Transport support function (TSF) +* - TSF:CHKUPL from @ref transportCheckUplink(), checks connection to GW +* - TSF:ASID from @ref transportAssignNodeID(), assigns node ID +* - TSF:PING from @ref transportPingNode(), pings a node +* - TSF:WUR from @ref transportWaitUntilReady(), waits until transport is ready +* - TSF:CRT from @ref transportClearRoutingTable(), clears routing table stored in EEPROM +* - TSF:LRT from @ref transportLoadRoutingTable(), loads RAM routing table from EEPROM (only GW/repeaters) +* - TSF:SRT from @ref transportSaveRoutingTable(), saves RAM routing table to EEPROM (only GW/repeaters) +* - TSF:MSG from @ref transportProcessMessage(), processes incoming message +* - TSF:SANCHK from @ref transportInvokeSanityCheck(), calls transport-specific sanity check +* - TSF:ROUTE from @ref transportRouteMessage(), sends message +* - TSF:SEND from @ref transportSendRoute(), sends message if transport is ready (exposed) - * - * Transport debug log messages: - * - * |E| SYS | SUB | Message | Comment - * |-|------|-----------|-----------------------|--------------------------------------------------------------------- - * | | TSM | INIT | | Transition to stInit state - * | | TSM | INIT | STATID=%%d | Node ID is static - * | | TSM | INIT | TSP OK | Transport device configured and fully operational - * | | TSM | INIT | GW MODE | Node is set up as GW, thus omitting ID and findParent states - * |!| TSM | INIT | TSP FAIL | Transport device initialization failed - * | | TSM | FPAR | | Transition to stParent state - * | | TSM | FPAR | STATP=%%d | Static parent set, skip finding parent - * | | TSM | FPAR | OK | Parent node identified - * |!| TSM | FPAR | NO REPLY | No potential parents replied to find parent request - * |!| TSM | FPAR | FAIL | Finding parent failed - * | | TSM | ID | | Transition to stID state - * | | TSM | ID | OK,ID=%%d | Node ID is valid - * | | TSM | ID | REQ | Request node ID from controller - * |!| TSM | ID | FAIL,ID=%%d | ID verification failed, ID invalid - * | | TSM | UPL | | Transition to stUplink state - * | | TSM | UPL | OK | Uplink OK, GW returned ping - * | | TSF | UPL | DGWC,O=%%d,N=%%d | Uplink check revealed changed network topology, old distance (O), new distance (N) - * |!| TSM | UPL | FAIL | Uplink check failed, i.e. GW could not be pinged - * | | TSM | READY | SRT | Save routing table - * | | TSM | READY | ID=%%d,PAR=%%d,DIS=%%d| Transition to stReady Transport ready, node ID (ID), parent node ID (PAR), distance to GW (DIS) - * |!| TSM | READY | UPL FAIL,SNP | Too many failed uplink transmissions, search new parent - * |!| TSM | READY | FAIL,STATP | Too many failed uplink transmissions, static parent enforced - * | | TSM | FAIL | CNT=%%d | Transition to stFailure state, consecutive failure counter (CNT) - * | | TSM | FAIL | PDT | Power-down transport - * | | TSM | FAIL | RE-INIT | Attempt to re-initialize transport - * | | TSF | CHKUPL | OK | Uplink OK - * | | TSF | CHKUPL | OK,FCTRL | Uplink OK, flood control prevents pinging GW in too short intervals - * | | TSF | CHKUPL | DGWC,O=%%d,N=%%d | Uplink check revealed changed network topology, old distance (O), new distance (N) - * | | TSF | CHKUPL | FAIL | No reply received when checking uplink - * | | TSF | ASID | OK,ID=%%d | Node ID assigned - * |!| TSF | ASID | FAIL,ID=%%d | Assigned ID is invalid - * | | TSF | PING | SEND,TO=%%d | Send ping to destination (TO) - * | | TSF | WUR | MS=%%lu | Wait until transport ready, timeout (MS) - * | | TSF | MSG | ACK REQ | ACK message requested - * | | TSF | MSG | ACK | ACK message, do not proceed but forward to callback - * | | TSF | MSG | FPAR RES,ID=%%d,D=%%d | Response to find parent received from node (ID) with distance (D) to GW - * | | TSF | MSG | FPAR PREF FOUND | Preferred parent found, i.e. parent defined via MY_PARENT_NODE_ID - * | | TSF | MSG | FPAR OK,ID=%%d,D=%%d | Find parent response from node (ID) is valid, distance (D) to GW - * | | TSF | MSG | FPAR INACTIVE | Find parent response received, but no find parent request active, skip response - * | | TSF | MSG | FPAR REQ,ID=%%d | Find parent request from node (ID) - * | | TSF | MSG | PINGED,ID=%%d,HP=%%d | Node pinged by node (ID) with (HP) hops - * | | TSF | MSG | PONG RECV,HP=%%d | Pinged node replied with (HP) hops - * | | TSF | MSG | BC | Broadcast message received - * | | TSF | MSG | GWL OK | Link to GW ok - * | | TSF | MSG | FWD BC MSG | Controlled broadcast message forwarding - * | | TSF | MSG | REL MSG | Relay message - * | | TSF | MSG | REL PxNG,HP=%%d | Relay PING/PONG message, increment hop counter (HP) - * |!| TSF | MSG | LEN,%%d!=%%d | Invalid message length, (actual!=expected) - * |!| TSF | MSG | PVER,%%d!=%%d | Message protocol version mismatch (actual!=expected) - * |!| TSF | MSG | SIGN VERIFY FAIL | Signing verification failed - * |!| TSF | MSG | REL MSG,NORP | Node received a message for relaying, but node is not a repeater, message skipped - * |!| TSF | MSG | SIGN FAIL | Signing message failed - * |!| TSF | MSG | GWL FAIL | GW uplink failed - * | | TSF | SANCHK | OK | Sanity check passed - * |!| TSF | SANCHK | FAIL | Sanity check failed, attempt to re-initialize radio - * | | TSF | CRT | OK | Clearing routing table successful - * | | TSF | LRT | OK | Loading routing table successful - * | | TSF | SRT | OK | Saving routing table successful - * |!| TSF | ROUTE | FPAR ACTIVE | Finding parent active, message not sent - * |!| TSF | ROUTE | DST %%d UNKNOWN | Routing for destination (DST) unknown, send message to parent - * |!| TSF | SEND | TNR | Transport not ready, message cannot be sent - * - * Incoming / outgoing messages: - * - * See here for more detail on the format and definitons. - * - * Receiving a message - * - TSF:MSG:READ,sender-last-destination,s=%%d,c=%%d,t=%%d,pt=%%d,l=%%d,sg=%%d:%%s - * - * Sending a message - * - [!]TSF:MSG:SEND,sender-last-next-destination,s=%%d,c=%%d,t=%%d,pt=%%d,l=%%d,sg=%%d,ft=%%d,st=%%s:%%s - * - * Message fields: - * - s=sensor ID - * - c=command - * - t=msg type - * - pt=payload type - * - l=length - * - sg=signing flag - * - ft=failed uplink transmission counter - * - st=send status, OK=success, NACK=no radio ACK received - * - * @brief API declaration for MyTransport - * - */ +* +* Transport debug log messages: +* +* |E| SYS | SUB | Message | Comment +* |-|------|-----------|-----------------------|--------------------------------------------------------------------- +* | | TSM | INIT | | Transition to stInit state +* | | TSM | INIT | STATID=%%d | Node ID is static +* | | TSM | INIT | TSP OK | Transport device configured and fully operational +* | | TSM | INIT | GW MODE | Node is set up as GW, thus omitting ID and findParent states +* |!| TSM | INIT | TSP FAIL | Transport device initialization failed +* | | TSM | FPAR | | Transition to stParent state +* | | TSM | FPAR | STATP=%%d | Static parent set, skip finding parent +* | | TSM | FPAR | OK | Parent node identified +* |!| TSM | FPAR | NO REPLY | No potential parents replied to find parent request +* |!| TSM | FPAR | FAIL | Finding parent failed +* | | TSM | ID | | Transition to stID state +* | | TSM | ID | OK,ID=%%d | Node ID is valid +* | | TSM | ID | REQ | Request node ID from controller +* |!| TSM | ID | FAIL,ID=%%d | ID verification failed, ID invalid +* | | TSM | UPL | | Transition to stUplink state +* | | TSM | UPL | OK | Uplink OK, GW returned ping +* | | TSF | UPL | DGWC,O=%%d,N=%%d | Uplink check revealed changed network topology, old distance (O), new distance (N) +* |!| TSM | UPL | FAIL | Uplink check failed, i.e. GW could not be pinged +* | | TSM | READY | SRT | Save routing table +* | | TSM | READY | ID=%%d,PAR=%%d,DIS=%%d| Transition to stReady Transport ready, node ID (ID), parent node ID (PAR), distance to GW (DIS) +* |!| TSM | READY | UPL FAIL,SNP | Too many failed uplink transmissions, search new parent +* |!| TSM | READY | FAIL,STATP | Too many failed uplink transmissions, static parent enforced +* | | TSM | FAIL | CNT=%%d | Transition to stFailure state, consecutive failure counter (CNT) +* | | TSM | FAIL | PDT | Power-down transport +* | | TSM | FAIL | RE-INIT | Attempt to re-initialize transport +* | | TSF | CHKUPL | OK | Uplink OK +* | | TSF | CHKUPL | OK,FCTRL | Uplink OK, flood control prevents pinging GW in too short intervals +* | | TSF | CHKUPL | DGWC,O=%%d,N=%%d | Uplink check revealed changed network topology, old distance (O), new distance (N) +* | | TSF | CHKUPL | FAIL | No reply received when checking uplink +* | | TSF | ASID | OK,ID=%%d | Node ID assigned +* |!| TSF | ASID | FAIL,ID=%%d | Assigned ID is invalid +* | | TSF | PING | SEND,TO=%%d | Send ping to destination (TO) +* | | TSF | WUR | MS=%%lu | Wait until transport ready, timeout (MS) +* | | TSF | MSG | ACK REQ | ACK message requested +* | | TSF | MSG | ACK | ACK message, do not proceed but forward to callback +* | | TSF | MSG | FPAR RES,ID=%%d,D=%%d | Response to find parent received from node (ID) with distance (D) to GW +* | | TSF | MSG | FPAR PREF FOUND | Preferred parent found, i.e. parent defined via MY_PARENT_NODE_ID +* | | TSF | MSG | FPAR OK,ID=%%d,D=%%d | Find parent response from node (ID) is valid, distance (D) to GW +* | | TSF | MSG | FPAR INACTIVE | Find parent response received, but no find parent request active, skip response +* | | TSF | MSG | FPAR REQ,ID=%%d | Find parent request from node (ID) +* | | TSF | MSG | PINGED,ID=%%d,HP=%%d | Node pinged by node (ID) with (HP) hops +* | | TSF | MSG | PONG RECV,HP=%%d | Pinged node replied with (HP) hops +* | | TSF | MSG | BC | Broadcast message received +* | | TSF | MSG | GWL OK | Link to GW ok +* | | TSF | MSG | FWD BC MSG | Controlled broadcast message forwarding +* | | TSF | MSG | REL MSG | Relay message +* | | TSF | MSG | REL PxNG,HP=%%d | Relay PING/PONG message, increment hop counter (HP) +* |!| TSF | MSG | LEN,%%d!=%%d | Invalid message length, (actual!=expected) +* |!| TSF | MSG | PVER,%%d!=%%d | Message protocol version mismatch (actual!=expected) +* |!| TSF | MSG | SIGN VERIFY FAIL | Signing verification failed +* |!| TSF | MSG | REL MSG,NORP | Node received a message for relaying, but node is not a repeater, message skipped +* |!| TSF | MSG | SIGN FAIL | Signing message failed +* |!| TSF | MSG | GWL FAIL | GW uplink failed +* | | TSF | SANCHK | OK | Sanity check passed +* |!| TSF | SANCHK | FAIL | Sanity check failed, attempt to re-initialize radio +* | | TSF | CRT | OK | Clearing routing table successful +* | | TSF | LRT | OK | Loading routing table successful +* | | TSF | SRT | OK | Saving routing table successful +* |!| TSF | ROUTE | FPAR ACTIVE | Finding parent active, message not sent +* |!| TSF | ROUTE | DST %%d UNKNOWN | Routing for destination (DST) unknown, send message to parent +* |!| TSF | SEND | TNR | Transport not ready, message cannot be sent +* +* Incoming / outgoing messages: +* +* See here for more detail on the format and definitons. +* +* Receiving a message +* - TSF:MSG:READ,sender-last-destination,s=%%d,c=%%d,t=%%d,pt=%%d,l=%%d,sg=%%d:%%s +* +* Sending a message +* - [!]TSF:MSG:SEND,sender-last-next-destination,s=%%d,c=%%d,t=%%d,pt=%%d,l=%%d,sg=%%d,ft=%%d,st=%%s:%%s +* +* Message fields: +* - s=sensor ID +* - c=command +* - t=msg type +* - pt=payload type +* - l=length +* - sg=signing flag +* - ft=failed uplink transmission counter +* - st=send status, OK=success, NACK=no radio ACK received +* +* @brief API declaration for MyTransport +* +*/ #ifndef MyTransport_h #define MyTransport_h #include "MySensorsCore.h" - // debug +// debug #if defined(MY_DEBUG) - #define TRANSPORT_DEBUG(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug - extern char _convBuf[MAX_PAYLOAD * 2 + 1]; +#define TRANSPORT_DEBUG(x,...) hwDebugPrint(x, ##__VA_ARGS__) //!< debug +extern char _convBuf[MAX_PAYLOAD * 2 + 1]; #else - #define TRANSPORT_DEBUG(x,...) //!< debug NULL +#define TRANSPORT_DEBUG(x,...) //!< debug NULL #endif #if defined(MY_REPEATER_FEATURE) - #define MY_TRANSPORT_MAX_TX_FAILURES (10u) //!< search for a new parent node after this many transmission failures, higher threshold for repeating nodes +#define MY_TRANSPORT_MAX_TX_FAILURES (10u) //!< search for a new parent node after this many transmission failures, higher threshold for repeating nodes #else - #define MY_TRANSPORT_MAX_TX_FAILURES (5u) //!< search for a new parent node after this many transmission failures, lower threshold for non-repeating nodes +#define MY_TRANSPORT_MAX_TX_FAILURES (5u) //!< search for a new parent node after this many transmission failures, lower threshold for non-repeating nodes #endif #define MY_TRANSPORT_MAX_TSM_FAILURES (7u) //!< Max. number of consecutive TSM failure state entries (3bits) #ifndef MY_TRANSPORT_TIMEOUT_FAILURE_STATE - #define MY_TRANSPORT_TIMEOUT_FAILURE_STATE (10*1000ul) //!< Duration failure state (in ms) +#define MY_TRANSPORT_TIMEOUT_FAILURE_STATE (10*1000ul) //!< Duration failure state (in ms) #endif #ifndef MY_TRANSPORT_TIMEOUT_EXT_FAILURE_STATE - #define MY_TRANSPORT_TIMEOUT_EXT_FAILURE_STATE (60*1000ul) //!< Duration extended failure state (in ms) +#define MY_TRANSPORT_TIMEOUT_EXT_FAILURE_STATE (60*1000ul) //!< Duration extended failure state (in ms) #endif #ifndef MY_TRANSPORT_STATE_TIMEOUT_MS - #define MY_TRANSPORT_STATE_TIMEOUT_MS (2*1000ul) //!< general state timeout (in ms) +#define MY_TRANSPORT_STATE_TIMEOUT_MS (2*1000ul) //!< general state timeout (in ms) #endif #ifndef MY_TRANSPORT_CHKUPL_INTERVAL_MS - #define MY_TRANSPORT_CHKUPL_INTERVAL_MS (10*1000ul) //!< Interval to re-check uplink (in ms) +#define MY_TRANSPORT_CHKUPL_INTERVAL_MS (10*1000ul) //!< Interval to re-check uplink (in ms) #endif #ifndef MY_TRANSPORT_STATE_RETRIES - #define MY_TRANSPORT_STATE_RETRIES (3u) //!< retries before switching to FAILURE +#define MY_TRANSPORT_STATE_RETRIES (3u) //!< retries before switching to FAILURE #endif #define AUTO (255u) //!< ID 255 is reserved @@ -188,7 +188,7 @@ // parent node check #if defined(MY_PARENT_NODE_IS_STATIC) && !defined(MY_PARENT_NODE_ID) - #error MY_PARENT_NODE_IS_STATIC but no MY_PARENT_NODE_ID defined! +#error MY_PARENT_NODE_IS_STATIC but no MY_PARENT_NODE_ID defined! #endif #define _autoFindParent (bool)(MY_PARENT_NODE_ID == AUTO) //!< returns true if static parent id is undefined @@ -197,14 +197,14 @@ // RX queue #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) - #if defined(MY_RADIO_RFM69) - #error Receive message buffering not supported for RFM69! - #endif - #if defined(MY_RS485) - #error Receive message buffering not supported for RS485! - #endif +#if defined(MY_RADIO_RFM69) +#error Receive message buffering not supported for RFM69! +#endif +#if defined(MY_RS485) +#error Receive message buffering not supported for RS485! +#endif #elif !defined(MY_RX_MESSAGE_BUFFER_FEATURE) && defined(MY_RX_MESSAGE_BUFFER_SIZE) - #error Receive message buffering requires message buffering feature enabled! +#error Receive message buffering requires message buffering feature enabled! #endif /** @@ -237,7 +237,7 @@ typedef struct { * @brief Status variables and SM state * * This structure stores transport status and SM variables - */ + */ typedef struct { // SM variables transportState_t* currentState; //!< pointer to current fsm state @@ -252,7 +252,7 @@ typedef struct { bool transportActive : 1; //!< flag transport active uint8_t stateRetries : 3; //!< retries / state re-enter (max 7) // 8 bits - uint8_t failedUplinkTransmissions : 4; //!< counter failed uplink transmissions (max 15) + uint8_t failedUplinkTransmissions : 4; //!< counter failed uplink transmissions (max 15) uint8_t failureCounter : 3; //!< counter for TSM failures (max 7) bool msgReceived : 1; //!< flag message received // 8 bits @@ -309,7 +309,7 @@ void stReadyTransition(void); */ void stReadyUpdate(void); /** -* @brief Transport failure and power down radio +* @brief Transport failure and power down radio */ void stFailureTransition(void); /** @@ -352,7 +352,7 @@ bool transportAssignNodeID(const uint8_t newNodeId); * @brief Wait and process messages for a defined amount of time until specified message received * @param waitingMS Time to wait and process incoming messages in ms * @param cmd Specific command -* @param msgType Specific message type +* @param msgType Specific message type * @return true if specified command received within waiting time */ bool transportWait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t msgType); @@ -364,7 +364,7 @@ bool transportWait(const uint32_t waitingMS, const uint8_t cmd, const uint8_t ms uint8_t transportPingNode(const uint8_t targetId); /** * @brief Send and route message according to destination -* +* * This function is used in MyTransport and omits the transport state check, i.e. message can be sent even if transport is not ready * * @param message @@ -381,7 +381,7 @@ bool transportSendRoute(MyMessage &message); * @brief Send message to recipient * @param to Recipient of message * @param message -* @return true if message sent successfully +* @return true if message sent successfully */ bool transportSendWrite(const uint8_t to, MyMessage &message); /** @@ -501,7 +501,7 @@ bool transportSanityCheck(); * @brief Receive message from FIFO * @return length of recevied message (header + payload) */ -uint8_t transportReceive(void* data); +uint8_t transportReceive(void* data); /** * @brief Power down transport HW */ diff --git a/core/MyTransportNRF24.cpp b/core/MyTransportNRF24.cpp index e1d6ba4bc..65230da36 100644 --- a/core/MyTransportNRF24.cpp +++ b/core/MyTransportNRF24.cpp @@ -30,33 +30,34 @@ #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) typedef struct _transportQueuedMessage { - uint8_t m_len; // Length of the data - uint8_t m_data[MAX_MESSAGE_LENGTH]; // The raw data + uint8_t m_len; // Length of the data + uint8_t m_data[MAX_MESSAGE_LENGTH]; // The raw data } transportQueuedMessage; /** Buffer to store queued messages in. */ static transportQueuedMessage transportRxQueueStorage[MY_RX_MESSAGE_BUFFER_SIZE]; /** Circular buffer, which uses the transportRxQueueStorage and administers stored messages. */ -static CircularBuffer transportRxQueue(transportRxQueueStorage, MY_RX_MESSAGE_BUFFER_SIZE); +static CircularBuffer transportRxQueue(transportRxQueueStorage, + MY_RX_MESSAGE_BUFFER_SIZE); static volatile uint8_t transportLostMessageCount = 0; static void transportRxCallback(void) { - // Called for each message received by radio, from interrupt context. - // This function _must_ call RF24_readMessage() to de-assert interrupt line! - if (!transportRxQueue.full()) { - transportQueuedMessage* msg = transportRxQueue.getFront(); - msg->m_len = RF24_readMessage(msg->m_data); // Read payload & clear RX_DR - (void)transportRxQueue.pushFront(msg); - } else { - // Queue is full. Discard message. - (void)RF24_readMessage(NULL); // Read payload & clear RX_DR - // Keep track of messages lost. Max 255, prevent wrapping. - if (transportLostMessageCount < 255) { - ++transportLostMessageCount; - } - } + // Called for each message received by radio, from interrupt context. + // This function _must_ call RF24_readMessage() to de-assert interrupt line! + if (!transportRxQueue.full()) { + transportQueuedMessage* msg = transportRxQueue.getFront(); + msg->m_len = RF24_readMessage(msg->m_data); // Read payload & clear RX_DR + (void)transportRxQueue.pushFront(msg); + } else { + // Queue is full. Discard message. + (void)RF24_readMessage(NULL); // Read payload & clear RX_DR + // Keep track of messages lost. Max 255, prevent wrapping. + if (transportLostMessageCount < 255) { + ++transportLostMessageCount; + } + } } #endif @@ -69,86 +70,86 @@ uint8_t _psk[16]; bool transportInit(void) { #if defined(MY_RF24_ENABLE_ENCRYPTION) - hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); - //set up AES-key - _aes.set_key(_psk, 16); - // Make sure it is purged from memory when set - memset(_psk, 0, 16); + hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); + //set up AES-key + _aes.set_key(_psk, 16); + // Make sure it is purged from memory when set + memset(_psk, 0, 16); #endif #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) - RF24_registerReceiveCallback( transportRxCallback ); + RF24_registerReceiveCallback( transportRxCallback ); #endif - return RF24_initialize(); + return RF24_initialize(); } void transportSetAddress(const uint8_t address) { - RF24_setNodeAddress(address); - RF24_startListening(); + RF24_setNodeAddress(address); + RF24_startListening(); } uint8_t transportGetAddress(void) { - return RF24_getNodeID(); + return RF24_getNodeID(); } bool transportSend(const uint8_t recipient, const void* data, uint8_t len) { #if defined(MY_RF24_ENABLE_ENCRYPTION) - // copy input data because it is read-only - (void)memcpy(_dataenc,data,len); - // has to be adjusted, WIP! - _aes.set_IV(0); - len = len > 16 ? 32 : 16; - //encrypt data - _aes.cbc_encrypt(_dataenc, _dataenc, len/16); - return RF24_sendMessage(recipient, _dataenc, len); + // copy input data because it is read-only + (void)memcpy(_dataenc,data,len); + // has to be adjusted, WIP! + _aes.set_IV(0); + len = len > 16 ? 32 : 16; + //encrypt data + _aes.cbc_encrypt(_dataenc, _dataenc, len/16); + return RF24_sendMessage(recipient, _dataenc, len); #else - return RF24_sendMessage(recipient, data, len); + return RF24_sendMessage(recipient, data, len); #endif } bool transportAvailable(void) { #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) - (void)RF24_isDataAvailable; // Prevent 'defined but not used' warning - return !transportRxQueue.empty(); + (void)RF24_isDataAvailable; // Prevent 'defined but not used' warning + return !transportRxQueue.empty(); #else - return RF24_isDataAvailable(); + return RF24_isDataAvailable(); #endif } bool transportSanityCheck(void) { - return RF24_sanityCheck(); + return RF24_sanityCheck(); } uint8_t transportReceive(void* data) { - uint8_t len = 0; + uint8_t len = 0; #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) - transportQueuedMessage* msg = transportRxQueue.getBack(); - if (msg) { - len = msg->m_len; - (void)memcpy(data, msg->m_data, len); - (void)transportRxQueue.popBack(); - } + transportQueuedMessage* msg = transportRxQueue.getBack(); + if (msg) { + len = msg->m_len; + (void)memcpy(data, msg->m_data, len); + (void)transportRxQueue.popBack(); + } #else - len = RF24_readMessage(data); + len = RF24_readMessage(data); #endif #if defined(MY_RF24_ENABLE_ENCRYPTION) - // has to be adjusted, WIP! - _aes.set_IV(0); - // decrypt data + // has to be adjusted, WIP! + _aes.set_IV(0); + // decrypt data if (_aes.cbc_decrypt((uint8_t*)(data), (uint8_t*)(data), len > 16 ? 2 : 1) != AES_SUCCESS) { len = 0; } #endif - return len; + return len; } void transportPowerDown(void) { - RF24_powerDown(); + RF24_powerDown(); } diff --git a/core/MyTransportRFM69.cpp b/core/MyTransportRFM69.cpp index 6ed728364..b5ff53fab 100644 --- a/core/MyTransportRFM69.cpp +++ b/core/MyTransportRFM69.cpp @@ -26,43 +26,50 @@ RFM69 _radio(MY_RF69_SPI_CS, MY_RF69_IRQ_PIN, MY_RFM69HW, MY_RF69_IRQ_NUM); uint8_t _address; -bool transportInit() { +bool transportInit() +{ // Start up the radio library (_address will be set later by the MySensors library) if (_radio.initialize(MY_RFM69_FREQUENCY, _address, MY_RFM69_NETWORKID)) { - #ifdef MY_RFM69_ENABLE_ENCRYPTION - uint8_t _psk[16]; - hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); - _radio.encrypt((const char*)_psk); - memset(_psk, 0, 16); // Make sure it is purged from memory when set - #endif +#ifdef MY_RFM69_ENABLE_ENCRYPTION + uint8_t _psk[16]; + hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); + _radio.encrypt((const char*)_psk); + memset(_psk, 0, 16); // Make sure it is purged from memory when set +#endif return true; } return false; } -void transportSetAddress(uint8_t address) { +void transportSetAddress(uint8_t address) +{ _address = address; _radio.setAddress(address); } -uint8_t transportGetAddress() { +uint8_t transportGetAddress() +{ return _address; } -bool transportSend(uint8_t to, const void* data, uint8_t len) { +bool transportSend(uint8_t to, const void* data, uint8_t len) +{ return _radio.sendWithRetry(to,data,len); } -bool transportAvailable() { +bool transportAvailable() +{ return _radio.receiveDone(); } -bool transportSanityCheck() { +bool transportSanityCheck() +{ // not implemented yet return true; } -uint8_t transportReceive(void* data) { +uint8_t transportReceive(void* data) +{ memcpy(data,(const void *)_radio.DATA, _radio.DATALEN); // save payload length const uint8_t dataLen = _radio.DATALEN; @@ -71,8 +78,9 @@ uint8_t transportReceive(void* data) { _radio.sendACK(); } return dataLen; -} +} -void transportPowerDown() { +void transportPowerDown() +{ _radio.sleep(); } diff --git a/core/MyTransportRFM95.cpp b/core/MyTransportRFM95.cpp index 1d3ec333f..8bdedf316 100644 --- a/core/MyTransportRFM95.cpp +++ b/core/MyTransportRFM95.cpp @@ -22,43 +22,52 @@ #include "MyTransport.h" #include "drivers/RFM95/RFM95.h" -bool transportInit(void) { +bool transportInit(void) +{ const bool result = RFM95_initialise(MY_RFM95_FREQUENCY); - #if !defined(MY_GATEWAY_FEATURE) && !defined(MY_RFM95_ATC_MODE_DISABLED) - // only enable ATC mode nodes - RFM95_ATCmode(true, MY_RFM95_ATC_TARGET_RSSI); - #endif +#if !defined(MY_GATEWAY_FEATURE) && !defined(MY_RFM95_ATC_MODE_DISABLED) + // only enable ATC mode nodes + RFM95_ATCmode(true, MY_RFM95_ATC_TARGET_RSSI); +#endif return result; } -void transportSetAddress(uint8_t address) { +void transportSetAddress(uint8_t address) +{ RFM95_setAddress(address); } -uint8_t transportGetAddress(void) { +uint8_t transportGetAddress(void) +{ return RFM95_getAddress(); } -bool transportSend(uint8_t to, const void* data, uint8_t len) { +bool transportSend(uint8_t to, const void* data, uint8_t len) +{ return RFM95_sendWithRetry(to, data, len); } -bool transportAvailable(void) { +bool transportAvailable(void) +{ return RFM95_available(); } -bool transportSanityCheck(void) { +bool transportSanityCheck(void) +{ return RFM95_sanityCheck(); } -uint8_t transportReceive(void* data) { +uint8_t transportReceive(void* data) +{ return RFM95_recv((uint8_t*)data); -} +} -void transportPowerDown(void) { +void transportPowerDown(void) +{ (void)RFM95_sleep(); } -int16_t transportGetSignalStrength(void) { +int16_t transportGetSignalStrength(void) +{ return RFM95_getRSSI(); } diff --git a/core/MyTransportRS485.cpp b/core/MyTransportRS485.cpp index 780301ac4..b86560222 100644 --- a/core/MyTransportRS485.cpp +++ b/core/MyTransportRS485.cpp @@ -62,16 +62,16 @@ #include "MyTransport.h" #ifdef __linux__ - #include "SerialPort.h" +#include "SerialPort.h" #endif #if defined(MY_RS485_DE_PIN) - #define assertDE() hwDigitalWrite(MY_RS485_DE_PIN, HIGH); delayMicroseconds(5) - #define deassertDE() hwDigitalWrite(MY_RS485_DE_PIN, LOW) +#define assertDE() hwDigitalWrite(MY_RS485_DE_PIN, HIGH); delayMicroseconds(5) +#define deassertDE() hwDigitalWrite(MY_RS485_DE_PIN, LOW) #else - #define assertDE() - #define deassertDE() +#define assertDE() +#define deassertDE() #endif // We only use SYS_PACK in this application @@ -114,13 +114,14 @@ bool _packet_received; //Reset the state machine and release the data pointer -void _serialReset(){ - _recPhase = 0; - _recPos = 0; - _recLen = 0; - _recCommand = 0; - _recCS = 0; - _recCalcCS = 0; +void _serialReset() +{ + _recPhase = 0; + _recPos = 0; + _recLen = 0; + _recCommand = 0; + _recCS = 0; + _recCalcCS = 0; } // This is the main reception state machine. Progress through the states @@ -132,118 +133,118 @@ void _serialReset(){ // function. bool _serialProcess() { - char inch; - unsigned char i; - if (!_dev.available()) { - return false; - } + char inch; + unsigned char i; + if (!_dev.available()) { + return false; + } - while(_dev.available()) { - inch = _dev.read(); - - switch(_recPhase) { - - // Case 0 looks for the header. Bytes arrive in the serial interface and get - // shifted through a header buffer. When the start and end characters in - // the buffer match the SOH/STX pair, and the destination station ID matches - // our ID, save the header information and progress to the next state. - case 0: - memcpy(&_header[0],&_header[1],5); - _header[5] = inch; - if ((_header[0] == SOH) && (_header[5] == STX) && (_header[1] != _header[2])) { - _recCalcCS = 0; - _recStation = _header[1]; - _recSender = _header[2]; - _recCommand = _header[3]; - _recLen = _header[4]; - - for (i=1; i<=4; i++) { - _recCalcCS += _header[i]; - } - _recPhase = 1; - _recPos = 0; - - //Check if we should process this message - //We reject the message if we are the sender - //We reject if we are not the receiver and message is not a broadcast - if ((_recSender == _nodeId) || - (_recStation != _nodeId && - _recStation != BROADCAST_ADDRESS)) { - _serialReset(); - break; - } - - if (_recLen == 0) { - _recPhase = 2; - } - - } - break; - - // Case 1 receives the data portion of the packet. Read in "_recLen" number - // of bytes and store them in the _data array. - case 1: - _data[_recPos++] = inch; - _recCalcCS += inch; - if (_recPos == _recLen) { - _recPhase = 2; - } - break; - - // After the data comes a single ETX character. Do we have it? If not, - // reset the state machine to default and start looking for a new header. - case 2: - // Packet properly terminated? - if (inch == ETX) { - _recPhase = 3; - } else { - _serialReset(); - } - break; - - // Next comes the checksum. We have already calculated it from the incoming - // data, so just store the incoming checksum byte for later. - case 3: - _recCS = inch; - _recPhase = 4; - break; - - // The final state - check the last character is EOT and that the checksum matches. - // If that test passes, then look for a valid command callback to execute. - // Execute it if found. - case 4: - if (inch == EOT) { - if (_recCS == _recCalcCS) { - // First, check for system level commands. It is possible - // to register your own callback as well for system level - // commands which will be called after the system default - // hook. - - switch (_recCommand) { - case ICSC_SYS_PACK: - _packet_from = _recSender; - _packet_len = _recLen; - _packet_received = true; - break; - } - } - } - //Clear the data - _serialReset(); - //Return true, we have processed one command - return true; - break; - } - } - return true; + while(_dev.available()) { + inch = _dev.read(); + + switch(_recPhase) { + + // Case 0 looks for the header. Bytes arrive in the serial interface and get + // shifted through a header buffer. When the start and end characters in + // the buffer match the SOH/STX pair, and the destination station ID matches + // our ID, save the header information and progress to the next state. + case 0: + memcpy(&_header[0],&_header[1],5); + _header[5] = inch; + if ((_header[0] == SOH) && (_header[5] == STX) && (_header[1] != _header[2])) { + _recCalcCS = 0; + _recStation = _header[1]; + _recSender = _header[2]; + _recCommand = _header[3]; + _recLen = _header[4]; + + for (i=1; i<=4; i++) { + _recCalcCS += _header[i]; + } + _recPhase = 1; + _recPos = 0; + + //Check if we should process this message + //We reject the message if we are the sender + //We reject if we are not the receiver and message is not a broadcast + if ((_recSender == _nodeId) || + (_recStation != _nodeId && + _recStation != BROADCAST_ADDRESS)) { + _serialReset(); + break; + } + + if (_recLen == 0) { + _recPhase = 2; + } + + } + break; + + // Case 1 receives the data portion of the packet. Read in "_recLen" number + // of bytes and store them in the _data array. + case 1: + _data[_recPos++] = inch; + _recCalcCS += inch; + if (_recPos == _recLen) { + _recPhase = 2; + } + break; + + // After the data comes a single ETX character. Do we have it? If not, + // reset the state machine to default and start looking for a new header. + case 2: + // Packet properly terminated? + if (inch == ETX) { + _recPhase = 3; + } else { + _serialReset(); + } + break; + + // Next comes the checksum. We have already calculated it from the incoming + // data, so just store the incoming checksum byte for later. + case 3: + _recCS = inch; + _recPhase = 4; + break; + + // The final state - check the last character is EOT and that the checksum matches. + // If that test passes, then look for a valid command callback to execute. + // Execute it if found. + case 4: + if (inch == EOT) { + if (_recCS == _recCalcCS) { + // First, check for system level commands. It is possible + // to register your own callback as well for system level + // commands which will be called after the system default + // hook. + + switch (_recCommand) { + case ICSC_SYS_PACK: + _packet_from = _recSender; + _packet_len = _recLen; + _packet_received = true; + break; + } + } + } + //Clear the data + _serialReset(); + //Return true, we have processed one command + return true; + break; + } + } + return true; } bool transportSend(uint8_t to, const void* data, uint8_t len) { const char *datap = static_cast(data); - unsigned char i; - unsigned char cs = 0; - unsigned char del; + unsigned char i; + unsigned char cs = 0; + unsigned char del; // This is how many times to try and transmit before failing. unsigned char timeout = 10; @@ -264,101 +265,107 @@ bool transportSend(uint8_t to, const void* data, uint8_t len) } } - #if defined(MY_RS485_DE_PIN) - hwDigitalWrite(MY_RS485_DE_PIN, HIGH); - delayMicroseconds(5); - #endif +#if defined(MY_RS485_DE_PIN) + hwDigitalWrite(MY_RS485_DE_PIN, HIGH); + delayMicroseconds(5); +#endif + + // Start of header by writing multiple SOH + for(byte w=0; w<1; w++) { + _dev.write(SOH); + } + _dev.write(to); // Destination address + cs += to; + _dev.write(_nodeId); // Source address + cs += _nodeId; + _dev.write(ICSC_SYS_PACK); // Command code + cs += ICSC_SYS_PACK; + _dev.write(len); // Length of text + cs += len; + _dev.write(STX); // Start of text + for(i=0; i= 100 - #if ARDUINO >= 104 - // Arduino 1.0.4 and upwards does it right - _dev.flush(); - #else - // Between 1.0.0 and 1.0.3 it almost does it - need to compensate - // for the hardware buffer. Delay for 2 bytes worth of transmission. - _dev.flush(); - delayMicroseconds((20000000UL/9600)+1); - #endif - #elif defined(__linux__) - _dev.flush(); - #endif - #endif - hwDigitalWrite(MY_RS485_DE_PIN, LOW); - #endif - return true; +#if defined(MY_RS485_DE_PIN) +#ifdef __PIC32MX__ + // MPIDE has nothing yet for this. It uses the hardware buffer, which + // could be up to 8 levels deep. For now, let's just delay for 8 + // characters worth. + delayMicroseconds((F_CPU/9600)+1); +#else +#if defined(ARDUINO) && ARDUINO >= 100 +#if ARDUINO >= 104 + // Arduino 1.0.4 and upwards does it right + _dev.flush(); +#else + // Between 1.0.0 and 1.0.3 it almost does it - need to compensate + // for the hardware buffer. Delay for 2 bytes worth of transmission. + _dev.flush(); + delayMicroseconds((20000000UL/9600)+1); +#endif +#elif defined(__linux__) + _dev.flush(); +#endif +#endif + hwDigitalWrite(MY_RS485_DE_PIN, LOW); +#endif + return true; } -bool transportInit() { - // Reset the state machine +bool transportInit() +{ + // Reset the state machine _dev.begin(MY_RS485_BAUD_RATE); - _serialReset(); - #if defined(MY_RS485_DE_PIN) - hwPinMode(MY_RS485_DE_PIN, OUTPUT); - hwDigitalWrite(MY_RS485_DE_PIN, LOW); - #endif - return true; + _serialReset(); +#if defined(MY_RS485_DE_PIN) + hwPinMode(MY_RS485_DE_PIN, OUTPUT); + hwDigitalWrite(MY_RS485_DE_PIN, LOW); +#endif + return true; } -void transportSetAddress(uint8_t address) { +void transportSetAddress(uint8_t address) +{ _nodeId = address; } -uint8_t transportGetAddress() { +uint8_t transportGetAddress() +{ return _nodeId; } -bool transportAvailable() { +bool transportAvailable() +{ _serialProcess(); return _packet_received; } -bool transportSanityCheck() { +bool transportSanityCheck() +{ // not implemented yet return true; } -uint8_t transportReceive(void* data) { +uint8_t transportReceive(void* data) +{ if (_packet_received) { memcpy(data,_data,_packet_len); _packet_received = false; return _packet_len; - } - else { + } else { return (0); } } -void transportPowerDown() { +void transportPowerDown() +{ // Nothing to shut down here } diff --git a/drivers/AES/AES.cpp b/drivers/AES/AES.cpp index 02fbfd8d7..06af427d0 100644 --- a/drivers/AES/AES.cpp +++ b/drivers/AES/AES.cpp @@ -65,44 +65,42 @@ #define WPOLY 0x011B #define DPOLY 0x008D -const static byte s_fwd [0x100] PROGMEM = -{ - 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, - 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, - 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, - 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, - 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, - 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, - 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, - 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, - 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, - 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, - 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, - 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, - 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, - 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, - 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, - 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, +const static byte s_fwd [0x100] PROGMEM = { + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16, } ; -const static byte s_inv [0x100] PROGMEM = -{ - 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, - 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, - 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, - 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, - 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, - 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, - 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, - 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, - 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, - 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, - 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, - 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, - 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, - 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, - 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, - 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d, +const static byte s_inv [0x100] PROGMEM = { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d, } ; // times 2 in the GF(2^8) @@ -111,38 +109,36 @@ const static byte s_inv [0x100] PROGMEM = static byte s_box (byte x) { - // return fwd_affine (pgm_read_byte (&inv [x])) ; - return pgm_read_byte (& s_fwd [x]) ; + // return fwd_affine (pgm_read_byte (&inv [x])) ; + return pgm_read_byte (& s_fwd [x]) ; } // Inverse Sbox static byte is_box (byte x) { - // return pgm_read_byte (&inv [inv_affine (x)]) ; - return pgm_read_byte (& s_inv [x]) ; + // return pgm_read_byte (&inv [inv_affine (x)]) ; + return pgm_read_byte (& s_inv [x]) ; } static void xor_block (byte * d, byte * s) { - for (byte i = 0 ; i < N_BLOCK ; i += 4) - { - *d++ ^= *s++ ; // some unrolling - *d++ ^= *s++ ; - *d++ ^= *s++ ; - *d++ ^= *s++ ; - } + for (byte i = 0 ; i < N_BLOCK ; i += 4) { + *d++ ^= *s++ ; // some unrolling + *d++ ^= *s++ ; + *d++ ^= *s++ ; + *d++ ^= *s++ ; + } } static void copy_and_key (byte * d, byte * s, byte * k) { - for (byte i = 0 ; i < N_BLOCK ; i += 4) - { - *d++ = *s++ ^ *k++ ; // some unrolling - *d++ = *s++ ^ *k++ ; - *d++ = *s++ ^ *k++ ; - *d++ = *s++ ^ *k++ ; - } + for (byte i = 0 ; i < N_BLOCK ; i += 4) { + *d++ = *s++ ^ *k++ ; // some unrolling + *d++ = *s++ ^ *k++ ; + *d++ = *s++ ^ *k++ ; + *d++ = *s++ ^ *k++ ; + } } // #define add_round_key(d, k) xor_block (d, k) @@ -151,88 +147,110 @@ static void copy_and_key (byte * d, byte * s, byte * k) static void shift_sub_rows (byte st [N_BLOCK]) { - st [0] = s_box (st [0]) ; st [4] = s_box (st [4]) ; - st [8] = s_box (st [8]) ; st [12] = s_box (st [12]) ; - - byte tt = st [1] ; - st [1] = s_box (st [5]) ; st [5] = s_box (st [9]) ; - st [9] = s_box (st [13]) ; st [13] = s_box (tt) ; - - tt = st[2] ; st [2] = s_box (st [10]) ; st [10] = s_box (tt) ; - tt = st[6] ; st [6] = s_box (st [14]) ; st [14] = s_box (tt) ; - - tt = st[15] ; - st [15] = s_box (st [11]) ; st [11] = s_box (st [7]) ; - st [7] = s_box (st [3]) ; st [3] = s_box (tt) ; + st [0] = s_box (st [0]) ; + st [4] = s_box (st [4]) ; + st [8] = s_box (st [8]) ; + st [12] = s_box (st [12]) ; + + byte tt = st [1] ; + st [1] = s_box (st [5]) ; + st [5] = s_box (st [9]) ; + st [9] = s_box (st [13]) ; + st [13] = s_box (tt) ; + + tt = st[2] ; + st [2] = s_box (st [10]) ; + st [10] = s_box (tt) ; + tt = st[6] ; + st [6] = s_box (st [14]) ; + st [14] = s_box (tt) ; + + tt = st[15] ; + st [15] = s_box (st [11]) ; + st [11] = s_box (st [7]) ; + st [7] = s_box (st [3]) ; + st [3] = s_box (tt) ; } static void inv_shift_sub_rows (byte st[N_BLOCK]) { - st [0] = is_box (st[0]) ; st [4] = is_box (st [4]); - st [8] = is_box (st[8]) ; st [12] = is_box (st [12]); - - byte tt = st[13] ; - st [13] = is_box (st [9]) ; st [9] = is_box (st [5]) ; - st [5] = is_box (st [1]) ; st [1] = is_box (tt) ; - - tt = st [2] ; st [2] = is_box (st [10]) ; st [10] = is_box (tt) ; - tt = st [6] ; st [6] = is_box (st [14]) ; st [14] = is_box (tt) ; - - tt = st [3] ; - st [3] = is_box (st [7]) ; st [7] = is_box (st [11]) ; - st [11] = is_box (st [15]) ; st [15] = is_box (tt) ; + st [0] = is_box (st[0]) ; + st [4] = is_box (st [4]); + st [8] = is_box (st[8]) ; + st [12] = is_box (st [12]); + + byte tt = st[13] ; + st [13] = is_box (st [9]) ; + st [9] = is_box (st [5]) ; + st [5] = is_box (st [1]) ; + st [1] = is_box (tt) ; + + tt = st [2] ; + st [2] = is_box (st [10]) ; + st [10] = is_box (tt) ; + tt = st [6] ; + st [6] = is_box (st [14]) ; + st [14] = is_box (tt) ; + + tt = st [3] ; + st [3] = is_box (st [7]) ; + st [7] = is_box (st [11]) ; + st [11] = is_box (st [15]) ; + st [15] = is_box (tt) ; } /* SUB COLUMNS PHASE */ static void mix_sub_columns (byte dt[N_BLOCK], byte st[N_BLOCK]) { - byte j = 5 ; - byte k = 10 ; - byte l = 15 ; - for (byte i = 0 ; i < N_BLOCK ; i += N_COL) - { - byte a = st [i] ; - byte b = st [j] ; j = (j+N_COL) & 15 ; - byte c = st [k] ; k = (k+N_COL) & 15 ; - byte d = st [l] ; l = (l+N_COL) & 15 ; - byte a1 = s_box (a), b1 = s_box (b), c1 = s_box (c), d1 = s_box (d) ; - byte a2 = f2(a1), b2 = f2(b1), c2 = f2(c1), d2 = f2(d1) ; - dt[i] = a2 ^ b2^b1 ^ c1 ^ d1 ; - dt[i+1] = a1 ^ b2 ^ c2^c1 ^ d1 ; - dt[i+2] = a1 ^ b1 ^ c2 ^ d2^d1 ; - dt[i+3] = a2^a1 ^ b1 ^ c1 ^ d2 ; - } + byte j = 5 ; + byte k = 10 ; + byte l = 15 ; + for (byte i = 0 ; i < N_BLOCK ; i += N_COL) { + byte a = st [i] ; + byte b = st [j] ; + j = (j+N_COL) & 15 ; + byte c = st [k] ; + k = (k+N_COL) & 15 ; + byte d = st [l] ; + l = (l+N_COL) & 15 ; + byte a1 = s_box (a), b1 = s_box (b), c1 = s_box (c), d1 = s_box (d) ; + byte a2 = f2(a1), b2 = f2(b1), c2 = f2(c1), d2 = f2(d1) ; + dt[i] = a2 ^ b2^b1 ^ c1 ^ d1 ; + dt[i+1] = a1 ^ b2 ^ c2^c1 ^ d1 ; + dt[i+2] = a1 ^ b1 ^ c2 ^ d2^d1 ; + dt[i+3] = a2^a1 ^ b1 ^ c1 ^ d2 ; + } } static void inv_mix_sub_columns (byte dt[N_BLOCK], byte st[N_BLOCK]) { - for (byte i = 0 ; i < N_BLOCK ; i += N_COL) - { - byte a1 = st [i] ; - byte b1 = st [i+1] ; - byte c1 = st [i+2] ; - byte d1 = st [i+3] ; - byte a2 = f2(a1), b2 = f2(b1), c2 = f2(c1), d2 = f2(d1) ; - byte a4 = f2(a2), b4 = f2(b2), c4 = f2(c2), d4 = f2(d2) ; - byte a8 = f2(a4), b8 = f2(b4), c8 = f2(c4), d8 = f2(d4) ; - byte a9 = a8 ^ a1,b9 = b8 ^ b1,c9 = c8 ^ c1,d9 = d8 ^ d1 ; - byte ac = a8 ^ a4,bc = b8 ^ b4,cc = c8 ^ c4,dc = d8 ^ d4 ; - - dt[i] = is_box (ac^a2 ^ b9^b2 ^ cc^c1 ^ d9) ; - dt[(i+5)&15] = is_box (a9 ^ bc^b2 ^ c9^c2 ^ dc^d1) ; - dt[(i+10)&15] = is_box (ac^a1 ^ b9 ^ cc^c2 ^ d9^d2) ; - dt[(i+15)&15] = is_box (a9^a2 ^ bc^b1 ^ c9 ^ dc^d2) ; - } + for (byte i = 0 ; i < N_BLOCK ; i += N_COL) { + byte a1 = st [i] ; + byte b1 = st [i+1] ; + byte c1 = st [i+2] ; + byte d1 = st [i+3] ; + byte a2 = f2(a1), b2 = f2(b1), c2 = f2(c1), d2 = f2(d1) ; + byte a4 = f2(a2), b4 = f2(b2), c4 = f2(c2), d4 = f2(d2) ; + byte a8 = f2(a4), b8 = f2(b4), c8 = f2(c4), d8 = f2(d4) ; + byte a9 = a8 ^ a1,b9 = b8 ^ b1,c9 = c8 ^ c1,d9 = d8 ^ d1 ; + byte ac = a8 ^ a4,bc = b8 ^ b4,cc = c8 ^ c4,dc = d8 ^ d4 ; + + dt[i] = is_box (ac^a2 ^ b9^b2 ^ cc^c1 ^ d9) ; + dt[(i+5)&15] = is_box (a9 ^ bc^b2 ^ c9^c2 ^ dc^d1) ; + dt[(i+10)&15] = is_box (ac^a1 ^ b9 ^ cc^c2 ^ d9^d2) ; + dt[(i+15)&15] = is_box (a9^a2 ^ bc^b1 ^ c9 ^ dc^d2) ; + } } /******************************************************************************/ -AES::AES(){ +AES::AES() +{ byte ar_iv[8] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 }; memcpy(iv,ar_iv,8); memcpy(iv+8,ar_iv,8); - arr_pad[0] = 0x01; + arr_pad[0] = 0x01; arr_pad[1] = 0x02; arr_pad[2] = 0x03; arr_pad[3] = 0x04; @@ -253,208 +271,196 @@ AES::AES(){ byte AES::set_key (byte key [], int keylen) { - byte hi ; - switch (keylen) - { - case 16: - case 128: - keylen = 16; // 10 rounds - round = 10 ; - break; - case 24: - case 192: - keylen = 24; // 12 rounds - round = 12 ; - break; - case 32: - case 256: - keylen = 32; // 14 rounds - round = 14 ; - break; - default: - round = 0; - return AES_FAILURE; - } - hi = (round + 1) << 4 ; - copy_n_bytes (key_sched, key, keylen) ; - byte t[4] ; - byte next = keylen ; - for (byte cc = keylen, rc = 1 ; cc < hi ; cc += N_COL) - { - for (byte i = 0 ; i < N_COL ; i++) { - t[i] = key_sched [cc-4+i] ; - } - if (cc == next) - { - next += keylen ; - byte ttt = t[0] ; - t[0] = s_box (t[1]) ^ rc ; - t[1] = s_box (t[2]) ; - t[2] = s_box (t[3]) ; - t[3] = s_box (ttt) ; - rc = f2 (rc) ; - } - else if (keylen == 32 && (cc & 31) == 16) - { - for (byte i = 0 ; i < 4 ; i++) { - t[i] = s_box (t[i]) ; - } - } - byte tt = cc - keylen ; - for (byte i = 0 ; i < N_COL ; i++) { - key_sched [cc + i] = key_sched [tt + i] ^ t[i] ; - } - } - return AES_SUCCESS ; + byte hi ; + switch (keylen) { + case 16: + case 128: + keylen = 16; // 10 rounds + round = 10 ; + break; + case 24: + case 192: + keylen = 24; // 12 rounds + round = 12 ; + break; + case 32: + case 256: + keylen = 32; // 14 rounds + round = 14 ; + break; + default: + round = 0; + return AES_FAILURE; + } + hi = (round + 1) << 4 ; + copy_n_bytes (key_sched, key, keylen) ; + byte t[4] ; + byte next = keylen ; + for (byte cc = keylen, rc = 1 ; cc < hi ; cc += N_COL) { + for (byte i = 0 ; i < N_COL ; i++) { + t[i] = key_sched [cc-4+i] ; + } + if (cc == next) { + next += keylen ; + byte ttt = t[0] ; + t[0] = s_box (t[1]) ^ rc ; + t[1] = s_box (t[2]) ; + t[2] = s_box (t[3]) ; + t[3] = s_box (ttt) ; + rc = f2 (rc) ; + } else if (keylen == 32 && (cc & 31) == 16) { + for (byte i = 0 ; i < 4 ; i++) { + t[i] = s_box (t[i]) ; + } + } + byte tt = cc - keylen ; + for (byte i = 0 ; i < N_COL ; i++) { + key_sched [cc + i] = key_sched [tt + i] ^ t[i] ; + } + } + return AES_SUCCESS ; } /******************************************************************************/ void AES::clean () { - for (byte i = 0 ; i < KEY_SCHEDULE_BYTES ; i++) { - key_sched [i] = 0 ; - } - round = 0 ; + for (byte i = 0 ; i < KEY_SCHEDULE_BYTES ; i++) { + key_sched [i] = 0 ; + } + round = 0 ; } /******************************************************************************/ void AES::copy_n_bytes (byte * d, byte * s, byte nn) { - while (nn >= 4) - { - *d++ = *s++ ; // some unrolling - *d++ = *s++ ; - *d++ = *s++ ; - *d++ = *s++ ; - nn -= 4 ; - } - while (nn--) - *d++ = *s++ ; + while (nn >= 4) { + *d++ = *s++ ; // some unrolling + *d++ = *s++ ; + *d++ = *s++ ; + *d++ = *s++ ; + nn -= 4 ; + } + while (nn--) { + *d++ = *s++ ; + } } /******************************************************************************/ byte AES::encrypt (byte plain [N_BLOCK], byte cipher [N_BLOCK]) { - if (round) - { - byte s1 [N_BLOCK], r ; - copy_and_key (s1, plain, (byte*) (key_sched)) ; - - for (r = 1 ; r < round ; r++) - { - byte s2 [N_BLOCK] ; - mix_sub_columns (s2, s1) ; - copy_and_key (s1, s2, (byte*) (key_sched + r * N_BLOCK)) ; - } - shift_sub_rows (s1) ; - copy_and_key (cipher, s1, (byte*) (key_sched + r * N_BLOCK)) ; - } - else - return AES_FAILURE ; - return AES_SUCCESS ; + if (round) { + byte s1 [N_BLOCK], r ; + copy_and_key (s1, plain, (byte*) (key_sched)) ; + + for (r = 1 ; r < round ; r++) { + byte s2 [N_BLOCK] ; + mix_sub_columns (s2, s1) ; + copy_and_key (s1, s2, (byte*) (key_sched + r * N_BLOCK)) ; + } + shift_sub_rows (s1) ; + copy_and_key (cipher, s1, (byte*) (key_sched + r * N_BLOCK)) ; + } else { + return AES_FAILURE ; + } + return AES_SUCCESS ; } /******************************************************************************/ byte AES::cbc_encrypt (byte * plain, byte * cipher, int n_block, byte iv [N_BLOCK]) { - while (n_block--) - { - xor_block (iv, plain) ; - if (encrypt (iv, iv) != AES_SUCCESS) { - return AES_FAILURE ; - } - copy_n_bytes (cipher, iv, N_BLOCK) ; - plain += N_BLOCK ; - cipher += N_BLOCK ; - } - return AES_SUCCESS ; + while (n_block--) { + xor_block (iv, plain) ; + if (encrypt (iv, iv) != AES_SUCCESS) { + return AES_FAILURE ; + } + copy_n_bytes (cipher, iv, N_BLOCK) ; + plain += N_BLOCK ; + cipher += N_BLOCK ; + } + return AES_SUCCESS ; } /******************************************************************************/ byte AES::cbc_encrypt (byte * plain, byte * cipher, int n_block) { - while (n_block--) - { - xor_block (iv, plain) ; - if (encrypt (iv, iv) != AES_SUCCESS) { - return AES_FAILURE ; - } - copy_n_bytes (cipher, iv, N_BLOCK) ; - plain += N_BLOCK ; - cipher += N_BLOCK ; - } - return AES_SUCCESS ; + while (n_block--) { + xor_block (iv, plain) ; + if (encrypt (iv, iv) != AES_SUCCESS) { + return AES_FAILURE ; + } + copy_n_bytes (cipher, iv, N_BLOCK) ; + plain += N_BLOCK ; + cipher += N_BLOCK ; + } + return AES_SUCCESS ; } /******************************************************************************/ byte AES::decrypt (byte plain [N_BLOCK], byte cipher [N_BLOCK]) { - if (round) - { - byte s1 [N_BLOCK] ; - copy_and_key (s1, plain, (byte*) (key_sched + round * N_BLOCK)) ; - inv_shift_sub_rows (s1) ; - - for (byte r = round ; --r ; ) - { - byte s2 [N_BLOCK] ; - copy_and_key (s2, s1, (byte*) (key_sched + r * N_BLOCK)) ; - inv_mix_sub_columns (s1, s2) ; - } - copy_and_key (cipher, s1, (byte*) (key_sched)) ; - } - else - return AES_FAILURE ; - return AES_SUCCESS ; + if (round) { + byte s1 [N_BLOCK] ; + copy_and_key (s1, plain, (byte*) (key_sched + round * N_BLOCK)) ; + inv_shift_sub_rows (s1) ; + + for (byte r = round ; --r ; ) { + byte s2 [N_BLOCK] ; + copy_and_key (s2, s1, (byte*) (key_sched + r * N_BLOCK)) ; + inv_mix_sub_columns (s1, s2) ; + } + copy_and_key (cipher, s1, (byte*) (key_sched)) ; + } else { + return AES_FAILURE ; + } + return AES_SUCCESS ; } /******************************************************************************/ byte AES::cbc_decrypt (byte * cipher, byte * plain, int n_block, byte iv [N_BLOCK]) { - while (n_block--) - { - byte tmp [N_BLOCK] ; - copy_n_bytes (tmp, cipher, N_BLOCK) ; - if (decrypt (cipher, plain) != AES_SUCCESS) { - return AES_FAILURE ; - } - xor_block (plain, iv) ; - copy_n_bytes (iv, tmp, N_BLOCK) ; - plain += N_BLOCK ; - cipher += N_BLOCK; - } - return AES_SUCCESS ; + while (n_block--) { + byte tmp [N_BLOCK] ; + copy_n_bytes (tmp, cipher, N_BLOCK) ; + if (decrypt (cipher, plain) != AES_SUCCESS) { + return AES_FAILURE ; + } + xor_block (plain, iv) ; + copy_n_bytes (iv, tmp, N_BLOCK) ; + plain += N_BLOCK ; + cipher += N_BLOCK; + } + return AES_SUCCESS ; } /******************************************************************************/ byte AES::cbc_decrypt (byte * cipher, byte * plain, int n_block) { - while (n_block--) - { - byte tmp [N_BLOCK] ; - copy_n_bytes (tmp, cipher, N_BLOCK) ; - if (decrypt (cipher, plain) != AES_SUCCESS) { - return AES_FAILURE ; - } - xor_block (plain, iv) ; - copy_n_bytes (iv, tmp, N_BLOCK) ; - plain += N_BLOCK ; - cipher += N_BLOCK; - } - return AES_SUCCESS ; + while (n_block--) { + byte tmp [N_BLOCK] ; + copy_n_bytes (tmp, cipher, N_BLOCK) ; + if (decrypt (cipher, plain) != AES_SUCCESS) { + return AES_FAILURE ; + } + xor_block (plain, iv) ; + copy_n_bytes (iv, tmp, N_BLOCK) ; + plain += N_BLOCK ; + cipher += N_BLOCK; + } + return AES_SUCCESS ; } /*****************************************************************************/ -void AES::set_IV(unsigned long long int IVCl){ +void AES::set_IV(unsigned long long int IVCl) +{ memcpy(iv,&IVCl,8); memcpy(iv+8,&IVCl,8); IVC = IVCl; @@ -462,7 +468,8 @@ void AES::set_IV(unsigned long long int IVCl){ /******************************************************************************/ -void AES::iv_inc(){ +void AES::iv_inc() +{ IVC += 1; memcpy(iv,&IVC,8); memcpy(iv+8,&IVC,8); @@ -470,31 +477,35 @@ void AES::iv_inc(){ /******************************************************************************/ -int AES::get_size(){ +int AES::get_size() +{ return size; } /******************************************************************************/ -void AES::set_size(int sizel){ +void AES::set_size(int sizel) +{ size = sizel; } /******************************************************************************/ -void AES::get_IV(byte *out){ +void AES::get_IV(byte *out) +{ memcpy(out,&IVC,8); memcpy(out+8,&IVC,8); } /******************************************************************************/ -void AES::calc_size_n_pad(int p_size){ +void AES::calc_size_n_pad(int p_size) +{ int s_of_p = p_size - 1; - if ( s_of_p % N_BLOCK == 0){ - size = s_of_p; - }else{ + if ( s_of_p % N_BLOCK == 0) { + size = s_of_p; + } else { size = s_of_p + (N_BLOCK-(s_of_p % N_BLOCK)); } pad = size - s_of_p; @@ -505,59 +516,63 @@ void AES::calc_size_n_pad(int p_size){ void AES::padPlaintext(void* in,byte* out) { memcpy(out,in,size); - for (int i = size-pad; i < size; i++){; + for (int i = size-pad; i < size; i++) { + ; out[i] = arr_pad[pad - 1]; } } /******************************************************************************/ -bool AES::CheckPad(byte* in,int lsize){ - if (in[lsize-1] <= 0x0f){ +bool AES::CheckPad(byte* in,int lsize) +{ + if (in[lsize-1] <= 0x0f) { int lpad = (int)in[lsize-1]; - for (int i = lsize - 1; i >= lsize-lpad; i--){ - if (arr_pad[lpad - 1] != in[i]){ + for (int i = lsize - 1; i >= lsize-lpad; i--) { + if (arr_pad[lpad - 1] != in[i]) { return false; } } - }else{ + } else { return true; } -return true; + return true; } /******************************************************************************/ void AES::printArray(byte output[],bool p_pad) { -uint8_t i,j; -uint8_t loops = size/N_BLOCK; -uint8_t outp = N_BLOCK; -for (j = 0; j < loops; j += 1){ - if (p_pad && (j == (loops - 1)) ) { outp = N_BLOCK - pad; } - for (i = 0; i < outp; i++) - { - printf_P(PSTR("%c"),output[j*N_BLOCK + i]); - } -} - printf_P(PSTR("\n")); + uint8_t i,j; + uint8_t loops = size/N_BLOCK; + uint8_t outp = N_BLOCK; + for (j = 0; j < loops; j += 1) { + if (p_pad && (j == (loops - 1)) ) { + outp = N_BLOCK - pad; + } + for (i = 0; i < outp; i++) { + printf_P(PSTR("%c"),output[j*N_BLOCK + i]); + } + } + printf_P(PSTR("\n")); } /******************************************************************************/ void AES::printArray(byte output[],int sizel) { - for (int i = 0; i < sizel; i++) - { - printf_P(PSTR("%x"),output[i]); - } - printf_P(PSTR("\n")); + for (int i = 0; i < sizel; i++) { + printf_P(PSTR("%x"),output[i]); + } + printf_P(PSTR("\n")); } /******************************************************************************/ -void AES::do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits, byte ivl [N_BLOCK]){ +void AES::do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits, + byte ivl [N_BLOCK]) +{ calc_size_n_pad(size_p); byte plain_p[get_size()]; padPlaintext(plain,plain_p); @@ -568,7 +583,8 @@ void AES::do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits /******************************************************************************/ -void AES::do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits){ +void AES::do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits) +{ calc_size_n_pad(size_p); byte plain_p[get_size()]; padPlaintext(plain,plain_p); @@ -579,7 +595,9 @@ void AES::do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits /******************************************************************************/ -void AES::do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits, byte ivl [N_BLOCK]){ +void AES::do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits, + byte ivl [N_BLOCK]) +{ set_size(size_c); int blocks = size_c / N_BLOCK; set_key (key, bits); @@ -588,7 +606,8 @@ void AES::do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits /******************************************************************************/ -void AES::do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits){ +void AES::do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits) +{ set_size(size_c); int blocks = size_c / N_BLOCK; set_key (key, bits); @@ -599,7 +618,8 @@ void AES::do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits /******************************************************************************/ #if defined(AES_LINUX) -double AES::millis(){ +double AES::millis() +{ gettimeofday(&tv, NULL); return (tv.tv_sec + 0.000001 * tv.tv_usec); } diff --git a/drivers/AES/AES.h b/drivers/AES/AES.h index 1d92c8c68..7ba5731c6 100644 --- a/drivers/AES/AES.h +++ b/drivers/AES/AES.h @@ -31,44 +31,44 @@ This is an AES implementation that uses only 8-bit byte operations on the cipher state. */ - - /* code was modified by george spanos - * 16/12/14 - */ + +/* code was modified by george spanos +* 16/12/14 +*/ /** AES class */ class AES { - public: +public: -/* The following calls are for a precomputed key schedule + /* The following calls are for a precomputed key schedule - NOTE: If the length_type used for the key length is an - unsigned 8-bit character, a key length of 256 bits must - be entered as a length in bytes (valid inputs are hence - 128, 192, 16, 24 and 32). -*/ + NOTE: If the length_type used for the key length is an + unsigned 8-bit character, a key length of 256 bits must + be entered as a length in bytes (valid inputs are hence + 128, 192, 16, 24 and 32). + */ /** \fn AES() * \brief AES constructor - * + * * This function initialized an instance of AES. */ AES(); - - /** Set the cipher key for the pre-keyed version. + + /** Set the cipher key for the pre-keyed version. * @param key[] pointer to the key string. * @param keylen Integer that indicates the length of the key. - * @note NOTE: If the length_type used for the key length is an unsigned 8-bit character, - * a key length of 256 bits must be entered as a length in bytes + * @note NOTE: If the length_type used for the key length is an unsigned 8-bit character, + * a key length of 256 bits must be entered as a length in bytes * (valid inputs are hence 128, 192, 16, 24 and 32). * */ byte set_key (byte key[], int keylen) ; - + /** clean up subkeys after use. - * - */ + * + */ void clean () ; // delete key schedule after use - + /** copying and xoring utilities. * @param *AESt byte pointer of the AEStination array. * @param *src byte pointer of the source array. @@ -92,9 +92,9 @@ class AES * */ byte encrypt (byte plain [N_BLOCK], byte cipher [N_BLOCK]) ; - + /** CBC encrypt a number of blocks (input and return an IV). - * + * * @param *plain Pointer, points to the plaintex. * @param *cipher Pointer, points to the ciphertext that will be created. * @param n_block integer, indicated the number of blocks to be ciphered. @@ -103,9 +103,9 @@ class AES * */ byte cbc_encrypt (byte * plain, byte * cipher, int n_block, byte iv [N_BLOCK]) ; - + /** CBC encrypt a number of blocks (input and return an IV). - * + * * @param *plain Pointer, points to the plaintex. * @param *cipher Pointer, points to the ciphertext that will be created. * @param n_block integer, indicated the number of blocks to be ciphered. @@ -115,7 +115,7 @@ class AES byte cbc_encrypt (byte * plain, byte * cipher, int n_block) ; - /** Decrypt a single block of 16 bytes + /** Decrypt a single block of 16 bytes * @param cipher Array of the ciphertext. * @param plain Array of the plaintext. * @note The N_BLOCK is defined in AES_config.h as, @@ -128,9 +128,9 @@ class AES * */ byte decrypt (byte cipher [N_BLOCK], byte plain [N_BLOCK]) ; - - /** CBC decrypt a number of blocks (input and return an IV) - * + + /** CBC decrypt a number of blocks (input and return an IV) + * * @param *cipher Pointer, points to the ciphertext that will be created. * @param *plain Pointer, points to the plaintex. * @param n_block integer, indicated the number of blocks to be ciphered. @@ -139,9 +139,9 @@ class AES * */ byte cbc_decrypt (byte * cipher, byte * plain, int n_block, byte iv [N_BLOCK]) ; - - /** CBC decrypt a number of blocks (input and return an IV) - * + + /** CBC decrypt a number of blocks (input and return an IV) + * * @param *cipher Pointer, points to the ciphertext that will be created. * @param *plain Pointer, points to the plaintex. * @param n_block integer, indicated the number of blocks to be ciphered. @@ -149,7 +149,7 @@ class AES * */ byte cbc_decrypt (byte * cipher, byte * plain, int n_block) ; - + /** Sets IV (initialization vector) and IVC (IV counter). * This function changes the ivc and iv variables needed for AES. * @@ -158,62 +158,62 @@ class AES * @code unsigned long long int my_iv = 01234567; @endcode */ void set_IV(unsigned long long int IVCl); - + /** increase the iv (initialization vector) and IVC (IV counter) by 1 - * + * * This function increased the VI by one step in order to have a different IV each time - * + * */ void iv_inc(); - + /** Getter method for size - * + * * This function return the size * @return an integer, that is the size of the of the padded plaintext, * thus, the size of the ciphertext. */ int get_size(); - + /** Setter method for size * * This function sets the size of the plaintext+pad - * + * */ void set_size(int sizel); - + /** Getter method for IV - * + * * This function return the IV * @param out byte pointer that gets the IV. * @return none, the IV is writed to the out pointer. */ void get_IV(byte *out); - + /** Calculates the size of the plaintext and the padding. - * + * * Calculates the size of theplaintext with the padding * and the size of the padding needed. Moreover it stores them in their class variables. - * + * * @param p_size the size of the byte array ex sizeof(plaintext) */ void calc_size_n_pad(int p_size); - + /** Pads the plaintext - * - * This function pads the plaintext and returns an char array with the - * plaintext and the padding in order for the plaintext to be compatible with + * + * This function pads the plaintext and returns an char array with the + * plaintext and the padding in order for the plaintext to be compatible with * 16bit size blocks required by AES - * + * * @param in the string of the plaintext in a byte array * @param out The string of the out array. * @return no return, The padded plaintext is stored in the out pointer. */ void padPlaintext(void* in,byte* out); - + /** Check the if the padding is correct. - * + * * This functions checks the padding of the plaintext. - * + * * @param in the string of the plaintext in a byte array * @param size the size of the string * @return true if correct / false if not @@ -221,26 +221,26 @@ class AES bool CheckPad(byte* in,int size); /** Prints the array given. - * - * This function prints the given array and pad, + * + * This function prints the given array and pad, * It is mainlly used for debugging purpuses or to output the string. - * + * * @param output[] the string of the text in a byte array * @param p_pad optional, used to print with out the padding characters */ void printArray(byte output[],bool p_pad = true); - + /** Prints the array given. - * + * * This function prints the given array in Hexadecimal. - * + * * @param output[] the string of the text in a byte array * @param sizel the size of the array. */ void printArray(byte output[],int sizel); - + /** User friendly implementation of AES-CBC encryption. - * + * * @param *plain pointer to the plaintext * @param size_p size of the plaintext * @param *cipher pointer to the ciphertext @@ -250,9 +250,9 @@ class AES * @note The key will be stored in class variable. */ void do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits, byte ivl [N_BLOCK]); - + /** User friendly implementation of AES-CBC encryption. - * + * * @param *plain pointer to the plaintext * @param size_p size of the plaintext * @param *cipher pointer to the ciphertext @@ -261,9 +261,9 @@ class AES * @note The key will be stored in class variable. */ void do_aes_encrypt(byte *plain,int size_p,byte *cipher,byte *key, int bits); - + /** User friendly implementation of AES-CBC decryption. - * + * * @param *cipher pointer to the ciphertext * @param size_c size of the ciphertext * @param *plain pointer to the plaintext @@ -273,9 +273,9 @@ class AES * @note The key will be stored in class variable. */ void do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits, byte ivl [N_BLOCK]); - + /** User friendly implementation of AES-CBC decryption. - * + * * @param *cipher pointer to the ciphertext * @param size_c size of the ciphertext * @param *plain pointer to the plaintext @@ -285,27 +285,28 @@ class AES */ void do_aes_decrypt(byte *cipher,int size_c,byte *plain,byte *key, int bits); - #if defined(AES_LINUX) - /** - * used in linux in order to retrieve the time in milliseconds. - * - * @return returns the milliseconds in a double format. - */ - double millis(); - #endif - private: - int round ;/**< holds the number of rounds to be used. */ - byte key_sched [KEY_SCHEDULE_BYTES] ;/**< holds the pre-computed key for the encryption/decrpytion. */ - unsigned long long int IVC;/**< holds the initialization vector counter in numerical format. */ - byte iv[16];/**< holds the initialization vector that will be used in the cipher. */ - int pad;/**< holds the size of the padding. */ - int size;/**< hold the size of the plaintext to be ciphered */ - #if defined(AES_LINUX) +#if defined(AES_LINUX) + /** + * used in linux in order to retrieve the time in milliseconds. + * + * @return returns the milliseconds in a double format. + */ + double millis(); +#endif +private: + int round ;/**< holds the number of rounds to be used. */ + byte key_sched [KEY_SCHEDULE_BYTES] + ;/**< holds the pre-computed key for the encryption/decrpytion. */ + unsigned long long int IVC;/**< holds the initialization vector counter in numerical format. */ + byte iv[16];/**< holds the initialization vector that will be used in the cipher. */ + int pad;/**< holds the size of the padding. */ + int size;/**< hold the size of the plaintext to be ciphered */ +#if defined(AES_LINUX) timeval tv;/**< holds the time value on linux */ byte arr_pad[15];/**< holds the hexadecimal padding values on linux */ - #else +#else byte arr_pad[15];// = { 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f };/**< holds the hexadecimal padding values */ - #endif +#endif } ; @@ -319,33 +320,33 @@ class AES * This is an example of how to use AES in CBC mode easily. * The text and keys can be either in HEX or String format.
*/ - - /** - * @example aes.cpp - * For Rasberry pi
- * Updated: spaniakos 2015
- * - * This is an example of how to use AES in CBC mode easily. - * The text and keys can be either in HEX or String format.
- */ - - /** - * @example test_vectors.pde - * For Arduino
- * Updated: spaniakos 2015
- * - * This is an example of monte carlo test vectors, in order to justify the effectiveness of the algorithm.
- * plus is a classical approach to the AES encryption library with out the easy to use add-on modifications. - */ - - /** - * @example test_vectors.cpp - * For Rasberry pi
- * Updated: spaniakos 2015
- * - * This is an example of monte carlo test vectors, in order to justify the effectiveness of the algorithm.
- * plus is a classical approach to the AES encryption library with out the easy to use add-on modifications. - */ + +/** +* @example aes.cpp +* For Rasberry pi
+* Updated: spaniakos 2015
+* +* This is an example of how to use AES in CBC mode easily. +* The text and keys can be either in HEX or String format.
+*/ + +/** +* @example test_vectors.pde +* For Arduino
+* Updated: spaniakos 2015
+* +* This is an example of monte carlo test vectors, in order to justify the effectiveness of the algorithm.
+* plus is a classical approach to the AES encryption library with out the easy to use add-on modifications. +*/ + +/** +* @example test_vectors.cpp +* For Rasberry pi
+* Updated: spaniakos 2015
+* +* This is an example of monte carlo test vectors, in order to justify the effectiveness of the algorithm.
+* plus is a classical approach to the AES encryption library with out the easy to use add-on modifications. +*/ /** * @defgroup aeslib AES library for Arduino and Raspberry pi @@ -362,21 +363,21 @@ class AES * * @section Acknowledgements Acknowledgements * This is an AES library for the Arduino, based on tzikis's AES library, which you can find here:.
- * Tzikis library was based on scottmac`s library, which you can find here:
- * + * Tzikis library was based on scottmac`s library, which you can find here:
+ * * @section Installation Installation *

Arduino

- * Create a folder named _AES_ in the _libraries_ folder inside your Arduino sketch folder. If the + * Create a folder named _AES_ in the _libraries_ folder inside your Arduino sketch folder. If the * libraries folder doesn't exist, create it. Then copy everything inside. (re)launch the Arduino IDE.
* You're done. Time for a mojito - * + * *

Raspberry pi

* install

- * + * * sudo make install
* cd examples_Rpi
* make

- * + * * What to do after changes to the library

* sudo make clean
* sudo make install
@@ -392,7 +393,7 @@ class AES * How to start a sketch

* cd examples_Rpi
* sudo ./\

- * + * * @section AesNews News * * If issues are discovered with the documentation, please report them here @@ -411,6 +412,6 @@ class AES * - Arduino * - Intel Galileo support * - Raspberry Pi Support - * + * * - The library has not been tested to other boards, but it should suppport ATMega 328 based boards,Mega Boards,Arduino Due,ATTiny board */ diff --git a/drivers/AES/AES_config.h b/drivers/AES/AES_config.h index d0ae8282f..ab3848960 100644 --- a/drivers/AES/AES_config.h +++ b/drivers/AES/AES_config.h @@ -7,34 +7,34 @@ #if (defined(__linux) || defined(linux)) && !defined(__ARDUINO_X86__) - #define AES_LINUX - - #include - #include - #include - #include - #include - #include +#define AES_LINUX + +#include +#include +#include +#include +#include +#include #else - #include +#include #endif #include #include #if defined(__ARDUINO_X86__) || (defined (__linux) || defined (linux)) - #undef PROGMEM - #define PROGMEM __attribute__(( section(".progmem.data") )) - #define pgm_read_byte(p) (*(p)) - typedef unsigned char byte; - #define printf_P printf - #define PSTR(x) (x) +#undef PROGMEM +#define PROGMEM __attribute__(( section(".progmem.data") )) +#define pgm_read_byte(p) (*(p)) +typedef unsigned char byte; +#define printf_P printf +#define PSTR(x) (x) #elif defined(ARDUINO_ARCH_ESP8266) - #include +#include #elif defined(ARDUINO_ARCH_SAMD) - #define printf_P printf +#define printf_P printf #else - #include +#include #endif #define N_ROW 4 diff --git a/drivers/AES/examples_Rpi/aes.cpp b/drivers/AES/examples_Rpi/aes.cpp index 7b6d8fef0..c7d45ae6c 100644 --- a/drivers/AES/examples_Rpi/aes.cpp +++ b/drivers/AES/examples_Rpi/aes.cpp @@ -15,33 +15,33 @@ unsigned long long int my_iv = 01234567; int main(int argc, char** argv) { - printf("\n===testng mode\n") ; + printf("\n===testng mode\n") ; - for (int i=0;i<1;i++){ - prekey_test () ; - } + for (int i=0; i<1; i++) { + prekey_test () ; + } } void prekey (int bits) { - byte iv [N_BLOCK] ; - byte plain_p[sizeof(plain) + (N_BLOCK - (sizeof(plain) % 16)) - 1]; - byte cipher[sizeof(plain_p)]; - aes.do_aes_encrypt(plain,sizeof(plain),cipher,key,bits); - aes.get_IV(iv); - aes.do_aes_dencrypt(cipher,aes.get_size(),plain_p,key,bits,iv); - //normally u have sizeof(cipher) but if its in the same sketch you cannot determin it dynamically - - printf("\n\nPLAIN :"); - aes.printArray(plain); - printf("\nCIPHER:"); - aes.printArray(cipher); - printf("\nPlain2:"); - aes.printArray(plain_p); - printf("\n============================================================\n"); + byte iv [N_BLOCK] ; + byte plain_p[sizeof(plain) + (N_BLOCK - (sizeof(plain) % 16)) - 1]; + byte cipher[sizeof(plain_p)]; + aes.do_aes_encrypt(plain,sizeof(plain),cipher,key,bits); + aes.get_IV(iv); + aes.do_aes_dencrypt(cipher,aes.get_size(),plain_p,key,bits,iv); + //normally u have sizeof(cipher) but if its in the same sketch you cannot determin it dynamically + + printf("\n\nPLAIN :"); + aes.printArray(plain); + printf("\nCIPHER:"); + aes.printArray(cipher); + printf("\nPlain2:"); + aes.printArray(plain_p); + printf("\n============================================================\n"); } void prekey_test () { - prekey (128) ; + prekey (128) ; } diff --git a/drivers/AES/examples_Rpi/test_vectors.cpp b/drivers/AES/examples_Rpi/test_vectors.cpp index 334713d47..d50b497de 100644 --- a/drivers/AES/examples_Rpi/test_vectors.cpp +++ b/drivers/AES/examples_Rpi/test_vectors.cpp @@ -18,108 +18,113 @@ void monte_carlo (int bits); int main(int argc, char** argv) { - printf ("AES library test vectors") ; + printf ("AES library test vectors") ; - monte_carlo (128) ; + monte_carlo (128) ; - for (int keysize = 128 ; keysize <= 256 ; keysize += 64) - { - prekey_test_var_plaintext (keysize) ; - prekey_test_var_key (keysize) ; - } + for (int keysize = 128 ; keysize <= 256 ; keysize += 64) { + prekey_test_var_plaintext (keysize) ; + prekey_test_var_key (keysize) ; + } } void prekey_test_var_plaintext (int bits) { - printf ("\nECB Varying Plaintext %i bits\n",bits) ; - - byte succ ; - set_bits (bits, key, 0) ; // all zero key - succ = aes.set_key (key, bits) ; - if (succ != SUCCESS) - printf("Failure set_key\n") ; - - - for (int bitcount = 1 ; bitcount <= 128 ; bitcount++) - { - printf ("COUNT = %i \n",bitcount-1); - print_value ("KEY = ", key, bits) ; - set_bits (128, plain, bitcount) ; - - print_value ("PLAINTEXT = ", plain, 128) ; - - succ = aes.encrypt (plain, cipher) ; - if (succ != SUCCESS) - printf ("Failure encrypt\n") ; - - print_value ("CIPHERTEXT = ", cipher, 128) ; - - succ = aes.decrypt (cipher, check) ; - if (succ != SUCCESS) - printf ("Failure decrypt\n") ; - - //print_value ("CHECK = ", check, 128) ; - check_same (plain, check, 128) ; - printf ("\n") ; - } + printf ("\nECB Varying Plaintext %i bits\n",bits) ; + + byte succ ; + set_bits (bits, key, 0) ; // all zero key + succ = aes.set_key (key, bits) ; + if (succ != SUCCESS) { + printf("Failure set_key\n") ; + } + + + for (int bitcount = 1 ; bitcount <= 128 ; bitcount++) { + printf ("COUNT = %i \n",bitcount-1); + print_value ("KEY = ", key, bits) ; + set_bits (128, plain, bitcount) ; + + print_value ("PLAINTEXT = ", plain, 128) ; + + succ = aes.encrypt (plain, cipher) ; + if (succ != SUCCESS) { + printf ("Failure encrypt\n") ; + } + + print_value ("CIPHERTEXT = ", cipher, 128) ; + + succ = aes.decrypt (cipher, check) ; + if (succ != SUCCESS) { + printf ("Failure decrypt\n") ; + } + + //print_value ("CHECK = ", check, 128) ; + check_same (plain, check, 128) ; + printf ("\n") ; + } } void prekey_test_var_key (int bits) { - printf ("\nECB Varying key %i bits\n",bits); - - byte succ ; - set_bits (128, plain, 0) ; - - for (int bitcount = 1 ; bitcount <= bits ; bitcount++) - { - set_bits (bits, key, bitcount) ; // all zero key - succ = aes.set_key (key, bits) ; - if (succ != SUCCESS) - printf ("Failure set_key\n") ; - printf ("COUNT = %i\n",bitcount-1); - print_value ("KEY = ", key, bits) ; - - print_value ("PLAINTEXT = ", plain, 128) ; - - succ = aes.encrypt (plain, cipher) ; - if (succ != SUCCESS) - printf ("Failure encrypt\n") ; - - print_value ("CIPHERTEXT = ", cipher, 128) ; - - succ = aes.decrypt (cipher, check) ; - if (succ != SUCCESS) - printf ("Failure decrypt\n") ; - - check_same (plain, check, 128) ; - printf("\n"); - } + printf ("\nECB Varying key %i bits\n",bits); + + byte succ ; + set_bits (128, plain, 0) ; + + for (int bitcount = 1 ; bitcount <= bits ; bitcount++) { + set_bits (bits, key, bitcount) ; // all zero key + succ = aes.set_key (key, bits) ; + if (succ != SUCCESS) { + printf ("Failure set_key\n") ; + } + printf ("COUNT = %i\n",bitcount-1); + print_value ("KEY = ", key, bits) ; + + print_value ("PLAINTEXT = ", plain, 128) ; + + succ = aes.encrypt (plain, cipher) ; + if (succ != SUCCESS) { + printf ("Failure encrypt\n") ; + } + + print_value ("CIPHERTEXT = ", cipher, 128) ; + + succ = aes.decrypt (cipher, check) ; + if (succ != SUCCESS) { + printf ("Failure decrypt\n") ; + } + + check_same (plain, check, 128) ; + printf("\n"); + } } void set_bits (int bits, byte * a, int count) { - bits >>= 3 ; - byte bcount = count >> 3 ; - for (byte i = 0 ; i < bcount ; i++) - a [i] = 0xFF ; - if ((count & 7) != 0) - a [bcount++] = 0xFF & (0xFF00 >> (count & 7)) ; - for (byte i = bcount ; i < bits ; i++) - a [i] = 0x00 ; + bits >>= 3 ; + byte bcount = count >> 3 ; + for (byte i = 0 ; i < bcount ; i++) { + a [i] = 0xFF ; + } + if ((count & 7) != 0) { + a [bcount++] = 0xFF & (0xFF00 >> (count & 7)) ; + } + for (byte i = bcount ; i < bits ; i++) { + a [i] = 0x00 ; + } } void check_same (byte * a, byte * b, int bits) { - bits >>= 3 ; - for (byte i = 0 ; i < bits ; i++) - if (a[i] != b[i]) - { - printf ("Failure plain != check\n") ; - return ; - } + bits >>= 3 ; + for (byte i = 0 ; i < bits ; i++) + if (a[i] != b[i]) { + printf ("Failure plain != check\n") ; + return ; + } } char hex[] = "0123456789abcdef" ; @@ -127,57 +132,51 @@ char hex[] = "0123456789abcdef" ; void print_value (const char * str, byte * a, int bits) { - printf ("%s",str) ; - bits >>= 3 ; - for (int i = 0 ; i < bits ; i++) - { - byte b = a[i] ; - printf("%c%c",hex[b >> 4],hex [b & 15]); - //Serial.print (hex [b >> 4]) ; - //Serial.print (hex [b & 15]) ; - } - printf("\n") ; + printf ("%s",str) ; + bits >>= 3 ; + for (int i = 0 ; i < bits ; i++) { + byte b = a[i] ; + printf("%c%c",hex[b >> 4],hex [b & 15]); + //Serial.print (hex [b >> 4]) ; + //Serial.print (hex [b & 15]) ; + } + printf("\n") ; } -byte monteplain [] = - { 0xb9, 0x14, 0x5a, 0x76, 0x8b, 0x7d, 0xc4, 0x89, - 0xa0, 0x96, 0xb5, 0x46, 0xf4, 0x3b, 0x23, 0x1f } ; -byte montekey [] = - { 0x13, 0x9a, 0x35, 0x42, 0x2f, 0x1d, 0x61, 0xde, - 0x3c, 0x91, 0x78, 0x7f, 0xe0, 0x50, 0x7a, 0xfd } ; +byte monteplain [] = { + 0xb9, 0x14, 0x5a, 0x76, 0x8b, 0x7d, 0xc4, 0x89, + 0xa0, 0x96, 0xb5, 0x46, 0xf4, 0x3b, 0x23, 0x1f +} ; +byte montekey [] = { + 0x13, 0x9a, 0x35, 0x42, 0x2f, 0x1d, 0x61, 0xde, + 0x3c, 0x91, 0x78, 0x7f, 0xe0, 0x50, 0x7a, 0xfd +} ; void monte_carlo (int bits) { - printf ("\nMonte Carlo %i bits\n",bits); - byte succ; - for (int i = 0 ; i < 16 ; i++) - { - plain [i] = monteplain [i] ; - key [i] = montekey [i] ; - } - for (int i = 0 ; i < 100 ; i++) - { - printf ("COUNT = %i\n",i); - print_value ("KEY = ", key, bits) ; - print_value ("PLAINTEXT = ", plain, 128) ; - succ = aes.set_key (key, bits) ; - for (int j = 0 ; j < 1000 ; j++) - { - succ = aes.encrypt (plain, cipher) ; - aes.copy_n_bytes (plain, cipher, 16) ; - } - print_value ("CIPHERTEXT = ", cipher, 128) ; - printf("\n"); - if (bits == 128) - { - for (byte k = 0 ; k < 16 ; k++) - key [k] ^= cipher [k] ; - } - else if (bits == 192) - { - } - else - { - } - } + printf ("\nMonte Carlo %i bits\n",bits); + byte succ; + for (int i = 0 ; i < 16 ; i++) { + plain [i] = monteplain [i] ; + key [i] = montekey [i] ; + } + for (int i = 0 ; i < 100 ; i++) { + printf ("COUNT = %i\n",i); + print_value ("KEY = ", key, bits) ; + print_value ("PLAINTEXT = ", plain, 128) ; + succ = aes.set_key (key, bits) ; + for (int j = 0 ; j < 1000 ; j++) { + succ = aes.encrypt (plain, cipher) ; + aes.copy_n_bytes (plain, cipher, 16) ; + } + print_value ("CIPHERTEXT = ", cipher, 128) ; + printf("\n"); + if (bits == 128) { + for (byte k = 0 ; k < 16 ; k++) { + key [k] ^= cipher [k] ; + } + } else if (bits == 192) { + } else { + } + } } diff --git a/drivers/AES/printf.h b/drivers/AES/printf.h index d54e6619f..5d4935d8b 100644 --- a/drivers/AES/printf.h +++ b/drivers/AES/printf.h @@ -5,7 +5,7 @@ modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. */ - /* Galileo support from spaniakos */ +/* Galileo support from spaniakos */ /** * @file printf.h @@ -21,36 +21,36 @@ int serial_putc( char c, FILE * ) { - Serial.write( c ); + Serial.write( c ); - return c; + return c; } void printf_begin(void) { - fdevopen( &serial_putc, 0 ); + fdevopen( &serial_putc, 0 ); } #elif defined (__arm__) -void printf_begin(void){} +void printf_begin(void) {} #elif defined(__ARDUINO_X86__) int serial_putc( char c, FILE * ) { - Serial.write( c ); + Serial.write( c ); - return c; + return c; } void printf_begin(void) { - //JESUS - For reddirect stdout to /dev/ttyGS0 (Serial Monitor port) - stdout = freopen("/dev/ttyGS0","w",stdout); - delay(500); - printf("redirecting to Serial..."); - - //JESUS ----------------------------------------------------------- + //JESUS - For reddirect stdout to /dev/ttyGS0 (Serial Monitor port) + stdout = freopen("/dev/ttyGS0","w",stdout); + delay(500); + printf("redirecting to Serial..."); + + //JESUS ----------------------------------------------------------- } #else #error This example is only for use on Arduino. diff --git a/drivers/ATSHA204/ATSHA204.cpp b/drivers/ATSHA204/ATSHA204.cpp index ff7d250a7..9c6ad006b 100644 --- a/drivers/ATSHA204/ATSHA204.cpp +++ b/drivers/ATSHA204/ATSHA204.cpp @@ -16,393 +16,361 @@ static uint8_t swi_send_byte(uint8_t value); static uint8_t sha204p_receive_response(uint8_t size, uint8_t *response); static uint8_t sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address); static uint8_t sha204c_resync(uint8_t size, uint8_t *response); -static uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout); +static uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, + uint8_t execution_delay, uint8_t execution_timeout); /* SWI bit bang functions */ static void swi_set_signal_pin(uint8_t is_high) { - SHA204_SET_OUTPUT(); - - if (is_high) { - SHA204_POUT_HIGH(); - } - else { - SHA204_POUT_LOW(); - } + SHA204_SET_OUTPUT(); + + if (is_high) { + SHA204_POUT_HIGH(); + } else { + SHA204_POUT_LOW(); + } } static uint8_t swi_send_bytes(uint8_t count, uint8_t *buffer) { - uint8_t i, bit_mask; - - // Disable interrupts while sending. - noInterrupts(); //swi_disable_interrupts(); - - // Set signal pin as output. - SHA204_POUT_HIGH(); - SHA204_SET_OUTPUT(); - - - // Wait turn around time. - delayMicroseconds(RX_TX_DELAY); //RX_TX_DELAY; - - for (i = 0; i < count; i++) - { - for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1) - { - if (bit_mask & buffer[i]) - { - SHA204_POUT_LOW(); //*device_port_OUT &= ~device_pin; - delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; - SHA204_POUT_HIGH(); //*device_port_OUT |= device_pin; - delayMicroseconds(7*BIT_DELAY); //BIT_DELAY_7; - } - else - { - // Send a zero bit. - SHA204_POUT_LOW(); //*device_port_OUT &= ~device_pin; - delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; - SHA204_POUT_HIGH(); //*device_port_OUT |= device_pin; - delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; - SHA204_POUT_LOW(); //*device_port_OUT &= ~device_pin; - delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; - SHA204_POUT_HIGH(); //*device_port_OUT |= device_pin; - delayMicroseconds(5*BIT_DELAY); //BIT_DELAY_5; - } - } - } - interrupts(); //swi_enable_interrupts(); - return SWI_FUNCTION_RETCODE_SUCCESS; + uint8_t i, bit_mask; + + // Disable interrupts while sending. + noInterrupts(); //swi_disable_interrupts(); + + // Set signal pin as output. + SHA204_POUT_HIGH(); + SHA204_SET_OUTPUT(); + + + // Wait turn around time. + delayMicroseconds(RX_TX_DELAY); //RX_TX_DELAY; + + for (i = 0; i < count; i++) { + for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1) { + if (bit_mask & buffer[i]) { + SHA204_POUT_LOW(); //*device_port_OUT &= ~device_pin; + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + SHA204_POUT_HIGH(); //*device_port_OUT |= device_pin; + delayMicroseconds(7*BIT_DELAY); //BIT_DELAY_7; + } else { + // Send a zero bit. + SHA204_POUT_LOW(); //*device_port_OUT &= ~device_pin; + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + SHA204_POUT_HIGH(); //*device_port_OUT |= device_pin; + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + SHA204_POUT_LOW(); //*device_port_OUT &= ~device_pin; + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + SHA204_POUT_HIGH(); //*device_port_OUT |= device_pin; + delayMicroseconds(5*BIT_DELAY); //BIT_DELAY_5; + } + } + } + interrupts(); //swi_enable_interrupts(); + return SWI_FUNCTION_RETCODE_SUCCESS; } static uint8_t swi_send_byte(uint8_t value) { - return swi_send_bytes(1, &value); + return swi_send_bytes(1, &value); } static uint8_t swi_receive_bytes(uint8_t count, uint8_t *buffer) { - uint8_t status = SWI_FUNCTION_RETCODE_SUCCESS; - uint8_t i; - uint8_t bit_mask; - uint8_t pulse_count; - uint8_t timeout_count; - - // Disable interrupts while receiving. - noInterrupts(); //swi_disable_interrupts(); - - // Configure signal pin as input. - SHA204_SET_INPUT(); - - // Receive bits and store in buffer. - for (i = 0; i < count; i++) - { - for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1) - { - pulse_count = 0; - - // Make sure that the variable below is big enough. - // Change it to uint16_t if 255 is too small, but be aware that - // the loop resolution decreases on an 8-bit controller in that case. - timeout_count = START_PULSE_TIME_OUT; - - // Detect start bit. - while (--timeout_count > 0) - { - // Wait for falling edge. - if (SHA204_PIN_READ() == 0) { - break; - } - } - - if (timeout_count == 0) - { - status = SWI_FUNCTION_RETCODE_TIMEOUT; - break; - } - - do - { - // Wait for rising edge. - if (SHA204_PIN_READ() != 0) - { - // For an Atmel microcontroller this might be faster than "pulse_count++". - pulse_count = 1; - break; - } - } while (--timeout_count > 0); - - if (pulse_count == 0) - { - status = SWI_FUNCTION_RETCODE_TIMEOUT; - break; - } - - // Trying to measure the time of start bit and calculating the timeout - // for zero bit detection is not accurate enough for an 8 MHz 8-bit CPU. - // So let's just wait the maximum time for the falling edge of a zero bit - // to arrive after we have detected the rising edge of the start bit. - timeout_count = ZERO_PULSE_TIME_OUT; - - // Detect possible edge indicating zero bit. - do - { - if (SHA204_PIN_READ() == 0) - { - // For an Atmel microcontroller this might be faster than "pulse_count++". - pulse_count = 2; - break; - } - } while (--timeout_count > 0); - - // Wait for rising edge of zero pulse before returning. Otherwise we might interpret - // its rising edge as the next start pulse. - if (pulse_count == 2) - { - do - { - if (SHA204_PIN_READ() != 0) { - break; - } - } while (timeout_count-- > 0); - } - - // Update byte at current buffer index. - else - buffer[i] |= bit_mask; // received "one" bit - } - - if (status != SWI_FUNCTION_RETCODE_SUCCESS) { - break; - } - } - interrupts(); //swi_enable_interrupts(); - - if (status == SWI_FUNCTION_RETCODE_TIMEOUT) - { - if (i > 0) { - // Indicate that we timed out after having received at least one byte. - status = SWI_FUNCTION_RETCODE_RX_FAIL; - } - } - return status; + uint8_t status = SWI_FUNCTION_RETCODE_SUCCESS; + uint8_t i; + uint8_t bit_mask; + uint8_t pulse_count; + uint8_t timeout_count; + + // Disable interrupts while receiving. + noInterrupts(); //swi_disable_interrupts(); + + // Configure signal pin as input. + SHA204_SET_INPUT(); + + // Receive bits and store in buffer. + for (i = 0; i < count; i++) { + for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1) { + pulse_count = 0; + + // Make sure that the variable below is big enough. + // Change it to uint16_t if 255 is too small, but be aware that + // the loop resolution decreases on an 8-bit controller in that case. + timeout_count = START_PULSE_TIME_OUT; + + // Detect start bit. + while (--timeout_count > 0) { + // Wait for falling edge. + if (SHA204_PIN_READ() == 0) { + break; + } + } + + if (timeout_count == 0) { + status = SWI_FUNCTION_RETCODE_TIMEOUT; + break; + } + + do { + // Wait for rising edge. + if (SHA204_PIN_READ() != 0) { + // For an Atmel microcontroller this might be faster than "pulse_count++". + pulse_count = 1; + break; + } + } while (--timeout_count > 0); + + if (pulse_count == 0) { + status = SWI_FUNCTION_RETCODE_TIMEOUT; + break; + } + + // Trying to measure the time of start bit and calculating the timeout + // for zero bit detection is not accurate enough for an 8 MHz 8-bit CPU. + // So let's just wait the maximum time for the falling edge of a zero bit + // to arrive after we have detected the rising edge of the start bit. + timeout_count = ZERO_PULSE_TIME_OUT; + + // Detect possible edge indicating zero bit. + do { + if (SHA204_PIN_READ() == 0) { + // For an Atmel microcontroller this might be faster than "pulse_count++". + pulse_count = 2; + break; + } + } while (--timeout_count > 0); + + // Wait for rising edge of zero pulse before returning. Otherwise we might interpret + // its rising edge as the next start pulse. + if (pulse_count == 2) { + do { + if (SHA204_PIN_READ() != 0) { + break; + } + } while (timeout_count-- > 0); + } + + // Update byte at current buffer index. + else { + buffer[i] |= bit_mask; // received "one" bit + } + } + + if (status != SWI_FUNCTION_RETCODE_SUCCESS) { + break; + } + } + interrupts(); //swi_enable_interrupts(); + + if (status == SWI_FUNCTION_RETCODE_TIMEOUT) { + if (i > 0) { + // Indicate that we timed out after having received at least one byte. + status = SWI_FUNCTION_RETCODE_RX_FAIL; + } + } + return status; } /* Physical functions */ static uint8_t sha204p_receive_response(uint8_t size, uint8_t *response) { - uint8_t count_byte; - uint8_t i; - uint8_t ret_code; - - for (i = 0; i < size; i++) { - response[i] = 0; - } - - (void) swi_send_byte(SHA204_SWI_FLAG_TX); - - ret_code = swi_receive_bytes(size, response); - if (ret_code == SWI_FUNCTION_RETCODE_SUCCESS || ret_code == SWI_FUNCTION_RETCODE_RX_FAIL) - { - count_byte = response[SHA204_BUFFER_POS_COUNT]; - if ((count_byte < SHA204_RSP_SIZE_MIN) || (count_byte > size)) { - return SHA204_INVALID_SIZE; - } - - return SHA204_SUCCESS; - } - - // Translate error so that the Communication layer - // can distinguish between a real error or the - // device being busy executing a command. - if (ret_code == SWI_FUNCTION_RETCODE_TIMEOUT) { - return SHA204_RX_NO_RESPONSE; - } - else { - return SHA204_RX_FAIL; - } + uint8_t count_byte; + uint8_t i; + uint8_t ret_code; + + for (i = 0; i < size; i++) { + response[i] = 0; + } + + (void) swi_send_byte(SHA204_SWI_FLAG_TX); + + ret_code = swi_receive_bytes(size, response); + if (ret_code == SWI_FUNCTION_RETCODE_SUCCESS || ret_code == SWI_FUNCTION_RETCODE_RX_FAIL) { + count_byte = response[SHA204_BUFFER_POS_COUNT]; + if ((count_byte < SHA204_RSP_SIZE_MIN) || (count_byte > size)) { + return SHA204_INVALID_SIZE; + } + + return SHA204_SUCCESS; + } + + // Translate error so that the Communication layer + // can distinguish between a real error or the + // device being busy executing a command. + if (ret_code == SWI_FUNCTION_RETCODE_TIMEOUT) { + return SHA204_RX_NO_RESPONSE; + } else { + return SHA204_RX_FAIL; + } } /* Communication functions */ static uint8_t sha204c_resync(uint8_t size, uint8_t *response) { - // Try to re-synchronize without sending a Wake token - // (step 1 of the re-synchronization process). - delay(SHA204_SYNC_TIMEOUT); - uint8_t ret_code = sha204p_receive_response(size, response); - if (ret_code == SHA204_SUCCESS) { - return ret_code; - } - - // We lost communication. Send a Wake pulse and try - // to receive a response (steps 2 and 3 of the - // re-synchronization process). - atsha204_sleep(); - ret_code = atsha204_wakeup(response); - - // Translate a return value of success into one - // that indicates that the device had to be woken up - // and might have lost its TempKey. - return (ret_code == SHA204_SUCCESS ? SHA204_RESYNC_WITH_WAKEUP : ret_code); + // Try to re-synchronize without sending a Wake token + // (step 1 of the re-synchronization process). + delay(SHA204_SYNC_TIMEOUT); + uint8_t ret_code = sha204p_receive_response(size, response); + if (ret_code == SHA204_SUCCESS) { + return ret_code; + } + + // We lost communication. Send a Wake pulse and try + // to receive a response (steps 2 and 3 of the + // re-synchronization process). + atsha204_sleep(); + ret_code = atsha204_wakeup(response); + + // Translate a return value of success into one + // that indicates that the device had to be woken up + // and might have lost its TempKey. + return (ret_code == SHA204_SUCCESS ? SHA204_RESYNC_WITH_WAKEUP : ret_code); } -static uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout) +static uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, + uint8_t execution_delay, uint8_t execution_timeout) { - uint8_t ret_code = SHA204_FUNC_FAIL; - uint8_t ret_code_resync; - uint8_t n_retries_send; - uint8_t n_retries_receive; - uint8_t i; - uint8_t status_byte; - uint8_t count = tx_buffer[SHA204_BUFFER_POS_COUNT]; - uint8_t count_minus_crc = count - SHA204_CRC_SIZE; - uint16_t execution_timeout_us = (uint16_t) (execution_timeout * 1000) + SHA204_RESPONSE_TIMEOUT; - volatile uint16_t timeout_countdown; - - // Append CRC. - sha204c_calculate_crc(count_minus_crc, tx_buffer, tx_buffer + count_minus_crc); - - // Retry loop for sending a command and receiving a response. - n_retries_send = SHA204_RETRY_COUNT + 1; - - while ((n_retries_send-- > 0) && (ret_code != SHA204_SUCCESS)) - { - // Send command. - ret_code = swi_send_byte(SHA204_SWI_FLAG_CMD); - if (ret_code != SWI_FUNCTION_RETCODE_SUCCESS) { - ret_code = SHA204_COMM_FAIL; - } - else { - ret_code = swi_send_bytes(count, tx_buffer); - } - - if (ret_code != SHA204_SUCCESS) - { - if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE) { - return ret_code; // The device seems to be dead in the water. - } - else { - continue; - } - } - - // Wait minimum command execution time and then start polling for a response. - delay(execution_delay); - - // Retry loop for receiving a response. - n_retries_receive = SHA204_RETRY_COUNT + 1; - while (n_retries_receive-- > 0) - { - // Reset response buffer. - for (i = 0; i < rx_size; i++) { - rx_buffer[i] = 0; - } - - // Poll for response. - timeout_countdown = execution_timeout_us; - do - { - ret_code = sha204p_receive_response(rx_size, rx_buffer); - timeout_countdown -= SHA204_RESPONSE_TIMEOUT; - } - while ((timeout_countdown > SHA204_RESPONSE_TIMEOUT) && (ret_code == SHA204_RX_NO_RESPONSE)); - - if (ret_code == SHA204_RX_NO_RESPONSE) - { - // We did not receive a response. Re-synchronize and send command again. - if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE) { - // The device seems to be dead in the water. - return ret_code; - } - else { - break; - } - } - - // Check whether we received a valid response. - if (ret_code == SHA204_INVALID_SIZE) - { - // We see 0xFF for the count when communication got out of sync. - ret_code_resync = sha204c_resync(rx_size, rx_buffer); - if (ret_code_resync == SHA204_SUCCESS) { - // We did not have to wake up the device. Try receiving response again. - continue; - } - if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP) { - // We could re-synchronize, but only after waking up the device. - // Re-send command. - break; - } - else { - // We failed to re-synchronize. - return ret_code; - } - } - - // We received a response of valid size. - // Check the consistency of the response. - ret_code = sha204c_check_crc(rx_buffer); - if (ret_code == SHA204_SUCCESS) - { - // Received valid response. - if (rx_buffer[SHA204_BUFFER_POS_COUNT] > SHA204_RSP_SIZE_MIN) { - // Received non-status response. We are done. - return ret_code; - } - - // Received status response. - status_byte = rx_buffer[SHA204_BUFFER_POS_STATUS]; - - // Translate the three possible device status error codes - // into library return codes. - if (status_byte == SHA204_STATUS_BYTE_PARSE) { - return SHA204_PARSE_ERROR; - } - if (status_byte == SHA204_STATUS_BYTE_EXEC) { - return SHA204_CMD_FAIL; - } - if (status_byte == SHA204_STATUS_BYTE_COMM) - { - // In case of the device status byte indicating a communication - // error this function exits the retry loop for receiving a response - // and enters the overall retry loop - // (send command / receive response). - ret_code = SHA204_STATUS_CRC; - break; - } - - // Received status response from CheckMAC, DeriveKey, GenDig, - // Lock, Nonce, Pause, UpdateExtra, or Write command. - return ret_code; - } - - else - { - // Received response with incorrect CRC. - ret_code_resync = sha204c_resync(rx_size, rx_buffer); - if (ret_code_resync == SHA204_SUCCESS) { - // We did not have to wake up the device. Try receiving response again. - continue; - } - if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP) { - // We could re-synchronize, but only after waking up the device. - // Re-send command. - break; - } - else { - // We failed to re-synchronize. - return ret_code; - } - } // block end of check response consistency - - } // block end of receive retry loop - - } // block end of send and receive retry loop - - return ret_code; + uint8_t ret_code = SHA204_FUNC_FAIL; + uint8_t ret_code_resync; + uint8_t n_retries_send; + uint8_t n_retries_receive; + uint8_t i; + uint8_t status_byte; + uint8_t count = tx_buffer[SHA204_BUFFER_POS_COUNT]; + uint8_t count_minus_crc = count - SHA204_CRC_SIZE; + uint16_t execution_timeout_us = (uint16_t) (execution_timeout * 1000) + SHA204_RESPONSE_TIMEOUT; + volatile uint16_t timeout_countdown; + + // Append CRC. + sha204c_calculate_crc(count_minus_crc, tx_buffer, tx_buffer + count_minus_crc); + + // Retry loop for sending a command and receiving a response. + n_retries_send = SHA204_RETRY_COUNT + 1; + + while ((n_retries_send-- > 0) && (ret_code != SHA204_SUCCESS)) { + // Send command. + ret_code = swi_send_byte(SHA204_SWI_FLAG_CMD); + if (ret_code != SWI_FUNCTION_RETCODE_SUCCESS) { + ret_code = SHA204_COMM_FAIL; + } else { + ret_code = swi_send_bytes(count, tx_buffer); + } + + if (ret_code != SHA204_SUCCESS) { + if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE) { + return ret_code; // The device seems to be dead in the water. + } else { + continue; + } + } + + // Wait minimum command execution time and then start polling for a response. + delay(execution_delay); + + // Retry loop for receiving a response. + n_retries_receive = SHA204_RETRY_COUNT + 1; + while (n_retries_receive-- > 0) { + // Reset response buffer. + for (i = 0; i < rx_size; i++) { + rx_buffer[i] = 0; + } + + // Poll for response. + timeout_countdown = execution_timeout_us; + do { + ret_code = sha204p_receive_response(rx_size, rx_buffer); + timeout_countdown -= SHA204_RESPONSE_TIMEOUT; + } while ((timeout_countdown > SHA204_RESPONSE_TIMEOUT) && (ret_code == SHA204_RX_NO_RESPONSE)); + + if (ret_code == SHA204_RX_NO_RESPONSE) { + // We did not receive a response. Re-synchronize and send command again. + if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE) { + // The device seems to be dead in the water. + return ret_code; + } else { + break; + } + } + + // Check whether we received a valid response. + if (ret_code == SHA204_INVALID_SIZE) { + // We see 0xFF for the count when communication got out of sync. + ret_code_resync = sha204c_resync(rx_size, rx_buffer); + if (ret_code_resync == SHA204_SUCCESS) { + // We did not have to wake up the device. Try receiving response again. + continue; + } + if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP) { + // We could re-synchronize, but only after waking up the device. + // Re-send command. + break; + } else { + // We failed to re-synchronize. + return ret_code; + } + } + + // We received a response of valid size. + // Check the consistency of the response. + ret_code = sha204c_check_crc(rx_buffer); + if (ret_code == SHA204_SUCCESS) { + // Received valid response. + if (rx_buffer[SHA204_BUFFER_POS_COUNT] > SHA204_RSP_SIZE_MIN) { + // Received non-status response. We are done. + return ret_code; + } + + // Received status response. + status_byte = rx_buffer[SHA204_BUFFER_POS_STATUS]; + + // Translate the three possible device status error codes + // into library return codes. + if (status_byte == SHA204_STATUS_BYTE_PARSE) { + return SHA204_PARSE_ERROR; + } + if (status_byte == SHA204_STATUS_BYTE_EXEC) { + return SHA204_CMD_FAIL; + } + if (status_byte == SHA204_STATUS_BYTE_COMM) { + // In case of the device status byte indicating a communication + // error this function exits the retry loop for receiving a response + // and enters the overall retry loop + // (send command / receive response). + ret_code = SHA204_STATUS_CRC; + break; + } + + // Received status response from CheckMAC, DeriveKey, GenDig, + // Lock, Nonce, Pause, UpdateExtra, or Write command. + return ret_code; + } + + else { + // Received response with incorrect CRC. + ret_code_resync = sha204c_resync(rx_size, rx_buffer); + if (ret_code_resync == SHA204_SUCCESS) { + // We did not have to wake up the device. Try receiving response again. + continue; + } + if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP) { + // We could re-synchronize, but only after waking up the device. + // Re-send command. + break; + } else { + // We failed to re-synchronize. + return ret_code; + } + } // block end of check response consistency + + } // block end of receive retry loop + + } // block end of send and receive retry loop + + return ret_code; } @@ -410,60 +378,59 @@ static uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uin static uint8_t sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address) { - uint8_t rx_size; + uint8_t rx_size; - address >>= 2; + address >>= 2; - tx_buffer[SHA204_COUNT_IDX] = READ_COUNT; - tx_buffer[SHA204_OPCODE_IDX] = SHA204_READ; - tx_buffer[READ_ZONE_IDX] = zone; - tx_buffer[READ_ADDR_IDX] = (uint8_t) (address & SHA204_ADDRESS_MASK); - tx_buffer[READ_ADDR_IDX + 1] = 0; + tx_buffer[SHA204_COUNT_IDX] = READ_COUNT; + tx_buffer[SHA204_OPCODE_IDX] = SHA204_READ; + tx_buffer[READ_ZONE_IDX] = zone; + tx_buffer[READ_ADDR_IDX] = (uint8_t) (address & SHA204_ADDRESS_MASK); + tx_buffer[READ_ADDR_IDX + 1] = 0; - rx_size = (zone & SHA204_ZONE_COUNT_FLAG) ? READ_32_RSP_SIZE : READ_4_RSP_SIZE; + rx_size = (zone & SHA204_ZONE_COUNT_FLAG) ? READ_32_RSP_SIZE : READ_4_RSP_SIZE; - return sha204c_send_and_receive(&tx_buffer[0], rx_size, &rx_buffer[0], READ_DELAY, READ_EXEC_MAX - READ_DELAY); + return sha204c_send_and_receive(&tx_buffer[0], rx_size, &rx_buffer[0], READ_DELAY, + READ_EXEC_MAX - READ_DELAY); } /* CRC Calculator and Checker */ static void sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc) { - uint8_t counter; - uint16_t crc_register = 0; - uint16_t polynom = 0x8005; - uint8_t shift_register; - uint8_t data_bit, crc_bit; - - for (counter = 0; counter < length; counter++) - { - for (shift_register = 0x01; shift_register > 0x00; shift_register <<= 1) - { - data_bit = (data[counter] & shift_register) ? 1 : 0; - crc_bit = crc_register >> 15; - - // Shift CRC to the left by 1. - crc_register <<= 1; - - if ((data_bit ^ crc_bit) != 0) { - crc_register ^= polynom; - } - } - } - crc[0] = (uint8_t) (crc_register & 0x00FF); - crc[1] = (uint8_t) (crc_register >> 8); + uint8_t counter; + uint16_t crc_register = 0; + uint16_t polynom = 0x8005; + uint8_t shift_register; + uint8_t data_bit, crc_bit; + + for (counter = 0; counter < length; counter++) { + for (shift_register = 0x01; shift_register > 0x00; shift_register <<= 1) { + data_bit = (data[counter] & shift_register) ? 1 : 0; + crc_bit = crc_register >> 15; + + // Shift CRC to the left by 1. + crc_register <<= 1; + + if ((data_bit ^ crc_bit) != 0) { + crc_register ^= polynom; + } + } + } + crc[0] = (uint8_t) (crc_register & 0x00FF); + crc[1] = (uint8_t) (crc_register >> 8); } static uint8_t sha204c_check_crc(uint8_t *response) { - uint8_t crc[SHA204_CRC_SIZE]; - uint8_t count = response[SHA204_BUFFER_POS_COUNT]; + uint8_t crc[SHA204_CRC_SIZE]; + uint8_t count = response[SHA204_BUFFER_POS_COUNT]; - count -= SHA204_CRC_SIZE; - sha204c_calculate_crc(count, response, crc); + count -= SHA204_CRC_SIZE; + sha204c_calculate_crc(count, response, crc); - return (crc[0] == response[count] && crc[1] == response[count + 1]) - ? SHA204_SUCCESS : SHA204_BAD_CRC; + return (crc[0] == response[count] && crc[1] == response[count + 1]) + ? SHA204_SUCCESS : SHA204_BAD_CRC; } /* Public functions */ @@ -471,116 +438,113 @@ static uint8_t sha204c_check_crc(uint8_t *response) void atsha204_init(uint8_t pin) { #if defined(ARDUINO_ARCH_AVR) - device_pin = digitalPinToBitMask(pin); // Find the bit value of the pin - uint8_t port = digitalPinToPort(pin); // temoporarily used to get the next three registers - - // Point to data direction register port of pin - device_port_DDR = portModeRegister(port); - // Point to output register of pin - device_port_OUT = portOutputRegister(port); - // Point to input register of pin - device_port_IN = portInputRegister(port); + device_pin = digitalPinToBitMask(pin); // Find the bit value of the pin + uint8_t port = digitalPinToPort(pin); // temoporarily used to get the next three registers + + // Point to data direction register port of pin + device_port_DDR = portModeRegister(port); + // Point to output register of pin + device_port_OUT = portOutputRegister(port); + // Point to input register of pin + device_port_IN = portInputRegister(port); #else - device_pin = pin; + device_pin = pin; #endif } void atsha204_idle(void) { - swi_send_byte(SHA204_SWI_FLAG_IDLE); + swi_send_byte(SHA204_SWI_FLAG_IDLE); } void atsha204_sleep(void) { - swi_send_byte(SHA204_SWI_FLAG_SLEEP); + swi_send_byte(SHA204_SWI_FLAG_SLEEP); } uint8_t atsha204_wakeup(uint8_t *response) { - swi_set_signal_pin(0); - delayMicroseconds(10*SHA204_WAKEUP_PULSE_WIDTH); - swi_set_signal_pin(1); - delay(SHA204_WAKEUP_DELAY); - - uint8_t ret_code = sha204p_receive_response(SHA204_RSP_SIZE_MIN, response); - if (ret_code != SHA204_SUCCESS) { - return ret_code; - } - - // Verify status response. - if (response[SHA204_BUFFER_POS_COUNT] != SHA204_RSP_SIZE_MIN) { - ret_code = SHA204_INVALID_SIZE; - } - else if (response[SHA204_BUFFER_POS_STATUS] != SHA204_STATUS_BYTE_WAKEUP) { - ret_code = SHA204_COMM_FAIL; - } - else - { - if ((response[SHA204_RSP_SIZE_MIN - SHA204_CRC_SIZE] != 0x33) - || (response[SHA204_RSP_SIZE_MIN + 1 - SHA204_CRC_SIZE] != 0x43)) { - ret_code = SHA204_BAD_CRC; - } - } - if (ret_code != SHA204_SUCCESS) { - delay(SHA204_COMMAND_EXEC_MAX); - } - - return ret_code; + swi_set_signal_pin(0); + delayMicroseconds(10*SHA204_WAKEUP_PULSE_WIDTH); + swi_set_signal_pin(1); + delay(SHA204_WAKEUP_DELAY); + + uint8_t ret_code = sha204p_receive_response(SHA204_RSP_SIZE_MIN, response); + if (ret_code != SHA204_SUCCESS) { + return ret_code; + } + + // Verify status response. + if (response[SHA204_BUFFER_POS_COUNT] != SHA204_RSP_SIZE_MIN) { + ret_code = SHA204_INVALID_SIZE; + } else if (response[SHA204_BUFFER_POS_STATUS] != SHA204_STATUS_BYTE_WAKEUP) { + ret_code = SHA204_COMM_FAIL; + } else { + if ((response[SHA204_RSP_SIZE_MIN - SHA204_CRC_SIZE] != 0x33) + || (response[SHA204_RSP_SIZE_MIN + 1 - SHA204_CRC_SIZE] != 0x43)) { + ret_code = SHA204_BAD_CRC; + } + } + if (ret_code != SHA204_SUCCESS) { + delay(SHA204_COMMAND_EXEC_MAX); + } + + return ret_code; } uint8_t atsha204_execute(uint8_t op_code, uint8_t param1, uint16_t param2, - uint8_t datalen1, uint8_t *data1, uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer) + uint8_t datalen1, uint8_t *data1, uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, + uint8_t *rx_buffer) { uint8_t poll_delay, poll_timeout, response_size; uint8_t *p_buffer; uint8_t len; - (void)tx_size; + (void)tx_size; // Supply delays and response size. - switch (op_code) - { - case SHA204_GENDIG: - poll_delay = GENDIG_DELAY; - poll_timeout = GENDIG_EXEC_MAX - GENDIG_DELAY; - response_size = GENDIG_RSP_SIZE; - break; - - case SHA204_HMAC: - poll_delay = HMAC_DELAY; - poll_timeout = HMAC_EXEC_MAX - HMAC_DELAY; - response_size = HMAC_RSP_SIZE; - break; - - case SHA204_NONCE: - poll_delay = NONCE_DELAY; - poll_timeout = NONCE_EXEC_MAX - NONCE_DELAY; - response_size = param1 == NONCE_MODE_PASSTHROUGH - ? NONCE_RSP_SIZE_SHORT : NONCE_RSP_SIZE_LONG; - break; - - case SHA204_RANDOM: - poll_delay = RANDOM_DELAY; - poll_timeout = RANDOM_EXEC_MAX - RANDOM_DELAY; - response_size = RANDOM_RSP_SIZE; - break; - - case SHA204_SHA: - poll_delay = SHA_DELAY; - poll_timeout = SHA_EXEC_MAX - SHA_DELAY; - response_size = param1 == SHA_INIT - ? SHA_RSP_SIZE_SHORT : SHA_RSP_SIZE_LONG; - break; - - case SHA204_WRITE: - poll_delay = WRITE_DELAY; - poll_timeout = WRITE_EXEC_MAX - WRITE_DELAY; - response_size = WRITE_RSP_SIZE; - break; - - default: - poll_delay = 0; - poll_timeout = SHA204_COMMAND_EXEC_MAX; - response_size = rx_size; + switch (op_code) { + case SHA204_GENDIG: + poll_delay = GENDIG_DELAY; + poll_timeout = GENDIG_EXEC_MAX - GENDIG_DELAY; + response_size = GENDIG_RSP_SIZE; + break; + + case SHA204_HMAC: + poll_delay = HMAC_DELAY; + poll_timeout = HMAC_EXEC_MAX - HMAC_DELAY; + response_size = HMAC_RSP_SIZE; + break; + + case SHA204_NONCE: + poll_delay = NONCE_DELAY; + poll_timeout = NONCE_EXEC_MAX - NONCE_DELAY; + response_size = param1 == NONCE_MODE_PASSTHROUGH + ? NONCE_RSP_SIZE_SHORT : NONCE_RSP_SIZE_LONG; + break; + + case SHA204_RANDOM: + poll_delay = RANDOM_DELAY; + poll_timeout = RANDOM_EXEC_MAX - RANDOM_DELAY; + response_size = RANDOM_RSP_SIZE; + break; + + case SHA204_SHA: + poll_delay = SHA_DELAY; + poll_timeout = SHA_EXEC_MAX - SHA_DELAY; + response_size = param1 == SHA_INIT + ? SHA_RSP_SIZE_SHORT : SHA_RSP_SIZE_LONG; + break; + + case SHA204_WRITE: + poll_delay = WRITE_DELAY; + poll_timeout = WRITE_EXEC_MAX - WRITE_DELAY; + response_size = WRITE_RSP_SIZE; + break; + + default: + poll_delay = 0; + poll_timeout = SHA204_COMMAND_EXEC_MAX; + response_size = rx_size; } // Assemble command. @@ -601,35 +565,34 @@ uint8_t atsha204_execute(uint8_t op_code, uint8_t param1, uint16_t param2, // Send command and receive response. return sha204c_send_and_receive(&tx_buffer[0], response_size, - &rx_buffer[0], poll_delay, poll_timeout); + &rx_buffer[0], poll_delay, poll_timeout); } uint8_t atsha204_getSerialNumber(uint8_t * response) { - uint8_t readCommand[READ_COUNT]; - uint8_t readResponse[READ_4_RSP_SIZE]; - - /* read from bytes 0->3 of config zone */ - uint8_t returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN03); - if (!returnCode) - { - for (int i=0; i<4; i++) {// store bytes 0-3 into respones array - response[i] = readResponse[SHA204_BUFFER_POS_DATA+i]; - } - - /* read from bytes 8->11 of config zone */ - returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN47); - - for (int i=4; i<8; i++) {// store bytes 4-7 of SN into response array - response[i] = readResponse[SHA204_BUFFER_POS_DATA+(i-4)]; - } - - if (!returnCode) - { /* Finally if last two reads were successful, read byte 8 of the SN */ - returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN8); - response[8] = readResponse[SHA204_BUFFER_POS_DATA]; // Byte 8 of SN should always be 0xEE - } - } - - return returnCode; + uint8_t readCommand[READ_COUNT]; + uint8_t readResponse[READ_4_RSP_SIZE]; + + /* read from bytes 0->3 of config zone */ + uint8_t returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN03); + if (!returnCode) { + for (int i=0; i<4; i++) {// store bytes 0-3 into respones array + response[i] = readResponse[SHA204_BUFFER_POS_DATA+i]; + } + + /* read from bytes 8->11 of config zone */ + returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN47); + + for (int i=4; i<8; i++) {// store bytes 4-7 of SN into response array + response[i] = readResponse[SHA204_BUFFER_POS_DATA+(i-4)]; + } + + if (!returnCode) { + /* Finally if last two reads were successful, read byte 8 of the SN */ + returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN8); + response[8] = readResponse[SHA204_BUFFER_POS_DATA]; // Byte 8 of SN should always be 0xEE + } + } + + return returnCode; } diff --git a/drivers/ATSHA204/ATSHA204.h b/drivers/ATSHA204/ATSHA204.h index aefa644e4..94b417160 100644 --- a/drivers/ATSHA204/ATSHA204.h +++ b/drivers/ATSHA204/ATSHA204.h @@ -244,8 +244,8 @@ void atsha204_idle(void); void atsha204_sleep(void); uint8_t atsha204_wakeup(uint8_t *response); uint8_t atsha204_execute(uint8_t op_code, uint8_t param1, uint16_t param2, - uint8_t datalen1, uint8_t *data1, uint8_t tx_size, - uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer); + uint8_t datalen1, uint8_t *data1, uint8_t tx_size, + uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer); uint8_t atsha204_getSerialNumber(uint8_t *response); #endif diff --git a/drivers/ATSHA204/sha256.cpp b/drivers/ATSHA204/sha256.cpp index ac89f8e76..b085e72a6 100644 --- a/drivers/ATSHA204/sha256.cpp +++ b/drivers/ATSHA204/sha256.cpp @@ -1,7 +1,7 @@ #include #if defined(__AVR__) - #include - #define PRIPSTR "%S" +#include +#define PRIPSTR "%S" #elif defined(ESP8266) #include #endif @@ -9,132 +9,146 @@ const uint32_t sha256K[] PROGMEM = { - 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, - 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, - 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, - 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, - 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, - 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, - 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, - 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 + 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5, + 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174, + 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da, + 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967, + 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85, + 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070, + 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3, + 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2 }; #define BUFFER_SIZE 64 const uint8_t sha256InitState[] PROGMEM = { - 0x67,0xe6,0x09,0x6a, // H0 - 0x85,0xae,0x67,0xbb, // H1 - 0x72,0xf3,0x6e,0x3c, // H2 - 0x3a,0xf5,0x4f,0xa5, // H3 - 0x7f,0x52,0x0e,0x51, // H4 - 0x8c,0x68,0x05,0x9b, // H5 - 0xab,0xd9,0x83,0x1f, // H6 - 0x19,0xcd,0xe0,0x5b // H7 + 0x67,0xe6,0x09,0x6a, // H0 + 0x85,0xae,0x67,0xbb, // H1 + 0x72,0xf3,0x6e,0x3c, // H2 + 0x3a,0xf5,0x4f,0xa5, // H3 + 0x7f,0x52,0x0e,0x51, // H4 + 0x8c,0x68,0x05,0x9b, // H5 + 0xab,0xd9,0x83,0x1f, // H6 + 0x19,0xcd,0xe0,0x5b // H7 }; -void Sha256Class::init(void) { - memcpy_P(state.b,sha256InitState,32); - byteCount = 0; - bufferOffset = 0; +void Sha256Class::init(void) +{ + memcpy_P(state.b,sha256InitState,32); + byteCount = 0; + bufferOffset = 0; } -uint32_t Sha256Class::ror32(uint32_t number, uint8_t bits) { - return ((number << (32-bits)) | (number >> bits)); +uint32_t Sha256Class::ror32(uint32_t number, uint8_t bits) +{ + return ((number << (32-bits)) | (number >> bits)); } -void Sha256Class::hashBlock() { - uint8_t i; - uint32_t a,b,c,d,e,f,g,h,t1,t2; - - a=state.w[0]; - b=state.w[1]; - c=state.w[2]; - d=state.w[3]; - e=state.w[4]; - f=state.w[5]; - g=state.w[6]; - h=state.w[7]; - - for (i=0; i<64; i++) { - if (i>=16) { - t1 = buffer.w[i&15] + buffer.w[(i-7)&15]; - t2 = buffer.w[(i-2)&15]; - t1 += ror32(t2,17) ^ ror32(t2,19) ^ (t2>>10); - t2 = buffer.w[(i-15)&15]; - t1 += ror32(t2,7) ^ ror32(t2,18) ^ (t2>>3); - buffer.w[i&15] = t1; - } - t1 = h; - t1 += ror32(e,6) ^ ror32(e,11) ^ ror32(e,25); // ∑1(e) - t1 += g ^ (e & (g ^ f)); // Ch(e,f,g) - t1 += pgm_read_dword(sha256K+i); // Ki - t1 += buffer.w[i&15]; // Wi - t2 = ror32(a,2) ^ ror32(a,13) ^ ror32(a,22); // ∑0(a) - t2 += ((b & c) | (a & (b | c))); // Maj(a,b,c) - h=g; g=f; f=e; e=d+t1; d=c; c=b; b=a; a=t1+t2; - } - state.w[0] += a; - state.w[1] += b; - state.w[2] += c; - state.w[3] += d; - state.w[4] += e; - state.w[5] += f; - state.w[6] += g; - state.w[7] += h; +void Sha256Class::hashBlock() +{ + uint8_t i; + uint32_t a,b,c,d,e,f,g,h,t1,t2; + + a=state.w[0]; + b=state.w[1]; + c=state.w[2]; + d=state.w[3]; + e=state.w[4]; + f=state.w[5]; + g=state.w[6]; + h=state.w[7]; + + for (i=0; i<64; i++) { + if (i>=16) { + t1 = buffer.w[i&15] + buffer.w[(i-7)&15]; + t2 = buffer.w[(i-2)&15]; + t1 += ror32(t2,17) ^ ror32(t2,19) ^ (t2>>10); + t2 = buffer.w[(i-15)&15]; + t1 += ror32(t2,7) ^ ror32(t2,18) ^ (t2>>3); + buffer.w[i&15] = t1; + } + t1 = h; + t1 += ror32(e,6) ^ ror32(e,11) ^ ror32(e,25); // ∑1(e) + t1 += g ^ (e & (g ^ f)); // Ch(e,f,g) + t1 += pgm_read_dword(sha256K+i); // Ki + t1 += buffer.w[i&15]; // Wi + t2 = ror32(a,2) ^ ror32(a,13) ^ ror32(a,22); // ∑0(a) + t2 += ((b & c) | (a & (b | c))); // Maj(a,b,c) + h=g; + g=f; + f=e; + e=d+t1; + d=c; + c=b; + b=a; + a=t1+t2; + } + state.w[0] += a; + state.w[1] += b; + state.w[2] += c; + state.w[3] += d; + state.w[4] += e; + state.w[5] += f; + state.w[6] += g; + state.w[7] += h; } -void Sha256Class::addUncounted(uint8_t data) { - buffer.b[bufferOffset ^ 3] = data; - bufferOffset++; - if (bufferOffset == BUFFER_SIZE) { - hashBlock(); - bufferOffset = 0; - } +void Sha256Class::addUncounted(uint8_t data) +{ + buffer.b[bufferOffset ^ 3] = data; + bufferOffset++; + if (bufferOffset == BUFFER_SIZE) { + hashBlock(); + bufferOffset = 0; + } } -void Sha256Class::write(uint8_t data) { - ++byteCount; - addUncounted(data); +void Sha256Class::write(uint8_t data) +{ + ++byteCount; + addUncounted(data); } -void Sha256Class::pad() { - // Implement SHA-256 padding (fips180-2 §5.1.1) +void Sha256Class::pad() +{ + // Implement SHA-256 padding (fips180-2 §5.1.1) - // Pad with 0x80 followed by 0x00 until the end of the block - addUncounted(0x80); - while (bufferOffset != 56) { + // Pad with 0x80 followed by 0x00 until the end of the block + addUncounted(0x80); + while (bufferOffset != 56) { addUncounted(0x00); } - // Append length in the last 8 bytes - addUncounted(0); // We're only using 32 bit lengths - addUncounted(0); // But SHA-1 supports 64 bit lengths - addUncounted(0); // So zero pad the top bits - addUncounted(byteCount >> 29); // Shifting to multiply by 8 - addUncounted(byteCount >> 21); // as SHA-1 supports bitstreams as well as - addUncounted(byteCount >> 13); // byte. - addUncounted(byteCount >> 5); - addUncounted(byteCount << 3); + // Append length in the last 8 bytes + addUncounted(0); // We're only using 32 bit lengths + addUncounted(0); // But SHA-1 supports 64 bit lengths + addUncounted(0); // So zero pad the top bits + addUncounted(byteCount >> 29); // Shifting to multiply by 8 + addUncounted(byteCount >> 21); // as SHA-1 supports bitstreams as well as + addUncounted(byteCount >> 13); // byte. + addUncounted(byteCount >> 5); + addUncounted(byteCount << 3); } -uint8_t* Sha256Class::result(void) { - // Pad to complete the last block - pad(); - - // Swap byte order back - for (int i=0; i<8; i++) { - uint32_t a,b; - a=state.w[i]; - b=a<<24; - b|=(a<<8) & 0x00ff0000; - b|=(a>>8) & 0x0000ff00; - b|=a>>24; - state.w[i]=b; - } +uint8_t* Sha256Class::result(void) +{ + // Pad to complete the last block + pad(); + + // Swap byte order back + for (int i=0; i<8; i++) { + uint32_t a,b; + a=state.w[i]; + b=a<<24; + b|=(a<<8) & 0x00ff0000; + b|=(a>>8) & 0x0000ff00; + b|=a>>24; + state.w[i]=b; + } - // Return pointer to hash (20 characters) - return state.b; + // Return pointer to hash (20 characters) + return state.b; } #define HMAC_IPAD 0x36 @@ -143,38 +157,40 @@ uint8_t* Sha256Class::result(void) { uint8_t keyBuffer[BLOCK_LENGTH]; // K0 in FIPS-198a uint8_t innerHash[HASH_LENGTH]; -void Sha256Class::initHmac(const uint8_t* key, int keyLength) { - uint8_t i; - memset(keyBuffer,0,BLOCK_LENGTH); - if (keyLength > BLOCK_LENGTH) { - // Hash long keys - init(); - for (;keyLength--;) { +void Sha256Class::initHmac(const uint8_t* key, int keyLength) +{ + uint8_t i; + memset(keyBuffer,0,BLOCK_LENGTH); + if (keyLength > BLOCK_LENGTH) { + // Hash long keys + init(); + for (; keyLength--;) { write(*key++); } - memcpy(keyBuffer,result(),HASH_LENGTH); - } else { - // Block length keys are used as is - memcpy(keyBuffer,key,keyLength); - } - // Start inner hash - init(); - for (i=0; i= digitalPinCount) { - badPinNumber(); - } +static ALWAYS_INLINE void badPinCheck(uint8_t pin) +{ + if (!__builtin_constant_p(pin) || pin >= digitalPinCount) { + badPinNumber(); + } } //------------------------------------------------------------------------------ /** fast write helper @@ -413,29 +414,31 @@ static ALWAYS_INLINE void badPinCheck(uint8_t pin) { * @param[in] bit bit number to write * @param[in] level value for bit */ -static ALWAYS_INLINE void fastBitWriteSafe(volatile uint8_t* address, uint8_t bit, bool level) { - uint8_t oldSREG; - if (address > (uint8_t*)0X5F) { - oldSREG = SREG; - cli(); - } - if (level) { - *address |= 1 << bit; - } else { - *address &= ~(1 << bit); - } - if (address > (uint8_t*)0X5F) { - SREG = oldSREG; - } +static ALWAYS_INLINE void fastBitWriteSafe(volatile uint8_t* address, uint8_t bit, bool level) +{ + uint8_t oldSREG; + if (address > (uint8_t*)0X5F) { + oldSREG = SREG; + cli(); + } + if (level) { + *address |= 1 << bit; + } else { + *address &= ~(1 << bit); + } + if (address > (uint8_t*)0X5F) { + SREG = oldSREG; + } } //------------------------------------------------------------------------------ /** read pin value * @param[in] pin Arduino pin number * @return value read */ -static ALWAYS_INLINE bool fastDigitalRead(uint8_t pin) { - badPinCheck(pin); - return (*pinMap[pin].pin >> pinMap[pin].bit) & 1; +static ALWAYS_INLINE bool fastDigitalRead(uint8_t pin) +{ + badPinCheck(pin); + return (*pinMap[pin].pin >> pinMap[pin].bit) & 1; } //------------------------------------------------------------------------------ /** toggle a pin @@ -444,24 +447,26 @@ static ALWAYS_INLINE bool fastDigitalRead(uint8_t pin) { * If the pin is in output mode toggle the pin level. * If the pin is in input mode toggle the state of the 20K pullup. */ -static ALWAYS_INLINE void fastDigitalToggle(uint8_t pin) { - badPinCheck(pin); - if (pinMap[pin].pin > (uint8_t*)0X5F) { - // must write bit to high address port - *pinMap[pin].pin = 1 << pinMap[pin].bit; - } else { - // will compile to sbi and PIN register will not be read. - *pinMap[pin].pin |= 1 << pinMap[pin].bit; - } +static ALWAYS_INLINE void fastDigitalToggle(uint8_t pin) +{ + badPinCheck(pin); + if (pinMap[pin].pin > (uint8_t*)0X5F) { + // must write bit to high address port + *pinMap[pin].pin = 1 << pinMap[pin].bit; + } else { + // will compile to sbi and PIN register will not be read. + *pinMap[pin].pin |= 1 << pinMap[pin].bit; + } } //------------------------------------------------------------------------------ /** Set pin value * @param[in] pin Arduino pin number * @param[in] level value to write */ -static ALWAYS_INLINE void fastDigitalWrite(uint8_t pin, bool level) { - badPinCheck(pin); - fastBitWriteSafe(pinMap[pin].port, pinMap[pin].bit, level); +static ALWAYS_INLINE void fastDigitalWrite(uint8_t pin, bool level) +{ + badPinCheck(pin); + fastBitWriteSafe(pinMap[pin].port, pinMap[pin].bit, level); } //------------------------------------------------------------------------------ /** set pin mode @@ -470,9 +475,10 @@ static ALWAYS_INLINE void fastDigitalWrite(uint8_t pin, bool level) { * * fastPinMode does not enable or disable the 20K pullup for input mode. */ -static ALWAYS_INLINE void fastPinMode(uint8_t pin, bool mode) { - badPinCheck(pin); - fastBitWriteSafe(pinMap[pin].ddr, pinMap[pin].bit, mode); +static ALWAYS_INLINE void fastPinMode(uint8_t pin, bool mode) +{ + badPinCheck(pin); + fastBitWriteSafe(pinMap[pin].ddr, pinMap[pin].bit, mode); } //------------------------------------------------------------------------------ /** set pin configuration @@ -481,9 +487,10 @@ static ALWAYS_INLINE void fastPinMode(uint8_t pin, bool mode) { * @param[in] level If mode is output, set level high/low. * If mode is input, enable or disable the pin's 20K pullup. */ -static ALWAYS_INLINE void fastPinConfig(uint8_t pin, bool mode, bool level) { - fastPinMode(pin, mode); - fastDigitalWrite(pin, level); +static ALWAYS_INLINE void fastPinConfig(uint8_t pin, bool mode, bool level) +{ + fastPinMode(pin, mode); + fastDigitalWrite(pin, level); } //============================================================================== /** @@ -491,96 +498,112 @@ static ALWAYS_INLINE void fastPinConfig(uint8_t pin, bool mode, bool level) { * @brief Fast AVR digital port I/O */ template -class DigitalPin { - public: - //---------------------------------------------------------------------------- - /** Constructor */ - DigitalPin() {} - //---------------------------------------------------------------------------- - /** Constructor - * @param[in] pinMode if true set output mode else input mode. - */ - explicit DigitalPin(bool pinMode) { - mode(pinMode); - } - //---------------------------------------------------------------------------- - /** Constructor - * @param[in] mode If true set output mode else input mode - * @param[in] level If mode is output, set level high/low. - * If mode is input, enable or disable the pin's 20K pullup. - */ - DigitalPin(bool mode, bool level) { - config(mode, level); - } - //---------------------------------------------------------------------------- - /** Asignment operator - * @param[in] value If true set the pin's level high else set the - * pin's level low. - * - * @return This DigitalPin instance. - */ - inline DigitalPin & operator = (bool value) __attribute__((always_inline)) { - write(value); - return *this; - } - //---------------------------------------------------------------------------- - /** Parenthesis operator - * @return Pin's level - */ - inline operator bool () const __attribute__((always_inline)) { - return read(); - } - //---------------------------------------------------------------------------- - /** set pin configuration - * @param[in] mode If true set output mode else input mode - * @param[in] level If mode is output, set level high/low. - * If mode is input, enable or disable the pin's 20K pullup. - */ - ALWAYS_INLINE void config(bool mode, bool level) { - fastPinConfig(PinNumber, mode, level); - } - //---------------------------------------------------------------------------- - /** - * Set pin level high if output mode or enable 20K pullup if input mode. - */ - ALWAYS_INLINE void high() {write(true);} - //---------------------------------------------------------------------------- - /** - * Set pin level low if output mode or disable 20K pullup if input mode. - */ - ALWAYS_INLINE void low() {write(false);} - //---------------------------------------------------------------------------- - /** - * Set pin mode - * @param[in] pinMode if true set output mode else input mode. - * - * mode() does not enable or disable the 20K pullup for input mode. - */ - ALWAYS_INLINE void mode(bool pinMode) { - fastPinMode(PinNumber, pinMode); - } - //---------------------------------------------------------------------------- - /** @return Pin's level */ - ALWAYS_INLINE bool read() const { - return fastDigitalRead(PinNumber); - } - //---------------------------------------------------------------------------- - /** toggle a pin - * - * If the pin is in output mode toggle the pin's level. - * If the pin is in input mode toggle the state of the 20K pullup. - */ - ALWAYS_INLINE void toggle() { - fastDigitalToggle(PinNumber); - } - //---------------------------------------------------------------------------- - /** Write the pin's level. - * @param[in] value If true set the pin's level high else set the - * pin's level low. - */ - ALWAYS_INLINE void write(bool value) { - fastDigitalWrite(PinNumber, value); - } +class DigitalPin +{ +public: + //---------------------------------------------------------------------------- + /** Constructor */ + DigitalPin() {} + //---------------------------------------------------------------------------- + /** Constructor + * @param[in] pinMode if true set output mode else input mode. + */ + explicit DigitalPin(bool pinMode) + { + mode(pinMode); + } + //---------------------------------------------------------------------------- + /** Constructor + * @param[in] mode If true set output mode else input mode + * @param[in] level If mode is output, set level high/low. + * If mode is input, enable or disable the pin's 20K pullup. + */ + DigitalPin(bool mode, bool level) + { + config(mode, level); + } + //---------------------------------------------------------------------------- + /** Asignment operator + * @param[in] value If true set the pin's level high else set the + * pin's level low. + * + * @return This DigitalPin instance. + */ + inline DigitalPin & operator = (bool value) __attribute__((always_inline)) + { + write(value); + return *this; + } + //---------------------------------------------------------------------------- + /** Parenthesis operator + * @return Pin's level + */ + inline operator bool () const __attribute__((always_inline)) + { + return read(); + } + //---------------------------------------------------------------------------- + /** set pin configuration + * @param[in] mode If true set output mode else input mode + * @param[in] level If mode is output, set level high/low. + * If mode is input, enable or disable the pin's 20K pullup. + */ + ALWAYS_INLINE void config(bool mode, bool level) + { + fastPinConfig(PinNumber, mode, level); + } + //---------------------------------------------------------------------------- + /** + * Set pin level high if output mode or enable 20K pullup if input mode. + */ + ALWAYS_INLINE void high() + { + write(true); + } + //---------------------------------------------------------------------------- + /** + * Set pin level low if output mode or disable 20K pullup if input mode. + */ + ALWAYS_INLINE void low() + { + write(false); + } + //---------------------------------------------------------------------------- + /** + * Set pin mode + * @param[in] pinMode if true set output mode else input mode. + * + * mode() does not enable or disable the 20K pullup for input mode. + */ + ALWAYS_INLINE void mode(bool pinMode) + { + fastPinMode(PinNumber, pinMode); + } + //---------------------------------------------------------------------------- + /** @return Pin's level */ + ALWAYS_INLINE bool read() const + { + return fastDigitalRead(PinNumber); + } + //---------------------------------------------------------------------------- + /** toggle a pin + * + * If the pin is in output mode toggle the pin's level. + * If the pin is in input mode toggle the state of the 20K pullup. + */ + ALWAYS_INLINE void toggle() + { + fastDigitalToggle(PinNumber); + } + //---------------------------------------------------------------------------- + /** Write the pin's level. + * @param[in] value If true set the pin's level high else set the + * pin's level low. + */ + ALWAYS_INLINE void write(bool value) + { + fastDigitalWrite(PinNumber, value); + } }; #endif // DigitalPin_h /** @} */ \ No newline at end of file diff --git a/drivers/AVR/DigitalIO/PinIO.cpp b/drivers/AVR/DigitalIO/PinIO.cpp index 5f1ff52b7..e2b842bec 100644 --- a/drivers/AVR/DigitalIO/PinIO.cpp +++ b/drivers/AVR/DigitalIO/PinIO.cpp @@ -32,22 +32,26 @@ /** Constructor * @param[in] pin Pin assigned to this object. */ -PinIO::PinIO(uint8_t pin) { - begin(pin); +PinIO::PinIO(uint8_t pin) +{ + begin(pin); } //------------------------------------------------------------------------------ /** Initialize pin bit mask and port address. * @param[in] pin Arduino board pin number. * @return true for success or false if invalid pin number. */ -bool PinIO::begin(uint8_t pin) { - if (pin >= NUM_DIGITAL_PINS) return false; - uint8_t port = digitalPinToPort(pin); - pinReg_ = portInputRegister(port); - bit_ = digitalPinToBitMask(pin); - mask_ = ~bit_; - portReg_ = pinReg_ + 2; - return true; +bool PinIO::begin(uint8_t pin) +{ + if (pin >= NUM_DIGITAL_PINS) { + return false; + } + uint8_t port = digitalPinToPort(pin); + pinReg_ = portInputRegister(port); + bit_ = digitalPinToBitMask(pin); + mask_ = ~bit_; + portReg_ = pinReg_ + 2; + return true; } //------------------------------------------------------------------------------ /** Configure the pin @@ -59,10 +63,11 @@ bool PinIO::begin(uint8_t pin) { * This function may be used with interrupts enabled or disabled. * The previous interrupt state will be restored. */ -void PinIO::config(bool mode, bool data) { - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { - modeI(mode); - writeI(data); - } +void PinIO::config(bool mode, bool data) +{ + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + modeI(mode); + writeI(data); + } } /** @} */ diff --git a/drivers/AVR/DigitalIO/PinIO.h b/drivers/AVR/DigitalIO/PinIO.h index c861d139b..cd9e35d46 100644 --- a/drivers/AVR/DigitalIO/PinIO.h +++ b/drivers/AVR/DigitalIO/PinIO.h @@ -37,118 +37,153 @@ * @class PinIO * @brief AVR port I/O with runtime pin numbers. */ -class PinIO { - public: - /** Create a PinIO object with no assigned pin. */ - PinIO() : bit_(0), mask_(0XFF) {} - /** Constructor - * @param[in] pin Pin assigned to this object. - */ - explicit PinIO(uint8_t pin); - /** Initialize pin bit mask and port address. - * @param[in] pin Arduino board pin number. - * @return true for success or false if invalid pin number. - */ - bool begin(uint8_t pin); - /** Configure the pin - * - * @param[in] mode Configure as output mode if true else input mode. - * @param[in] data For output mode set pin high if true else low. - * For input mode enable 20K pullup if true else Hi-Z. - * - * This function may be used with interrupts enabled or disabled. - * The previous interrupt state will be restored. - */ - void config(bool mode, bool data); - //---------------------------------------------------------------------------- - /** @return Pin's level */ - ALWAYS_INLINE bool read() {return *pinReg_ & bit_;} - //---------------------------------------------------------------------------- - /** toggle a pin - * - * If the pin is in output mode toggle the pin's level. - * If the pin is in input mode toggle the state of the 20K pullup. - */ - ALWAYS_INLINE void toggle() {*pinReg_ = bit_;} - //============================================================================ - /** - * Set pin high if output mode or enable 20K pullup if input mode. - * - * This function must be called with interrupts disabled. - * This function will not change the interrupt state. - */ - ALWAYS_INLINE void highI() {writeI(1);} - /** - * Set pin low if output mode or disable 20K pullup if input mode. - * - * This function must be called with interrupts disabled. - * This function will not change the interrupt state. - */ - ALWAYS_INLINE void lowI() {writeI(0);} - /** - * Set pin mode - * @param[in] mode if true set output mode else input mode. - * - * mode() does not enable or disable the 20K pullup for input mode. - * - * This function must be called with interrupts disabled. - * This function will not change the interrupt state. - */ - ALWAYS_INLINE void modeI(bool mode) { - volatile uint8_t* ddrReg = pinReg_ + 1; - *ddrReg = mode ? *ddrReg | bit_ : *ddrReg & mask_; - } - /** Write pin. - * - * @param[in] level If output mode set pin high if true else low. - * If input mode enable 20K pullup if true else disable pullup. - * - * This function must be called with interrupts disabled. - * This function will not change the interrupt state. - */ - ALWAYS_INLINE void writeI(bool level) { - *portReg_ = level ? *portReg_ | bit_ : *portReg_ & mask_; - } - //============================================================================ - /** - * Set pin level high if output mode or enable 20K pullup if input mode. - * - * This function will enable interrupts. This function should not be - * called in an ISR or where interrupts are disabled. - */ - ALWAYS_INLINE void high() {ATOMIC_BLOCK(ATOMIC_FORCEON) {highI();}} - /** - * Set pin level low if output mode or disable 20K pullup if input mode. - * - * This function will enable interrupts. This function should not be - * called in an ISR or where interrupts are disabled. - */ - ALWAYS_INLINE void low() {ATOMIC_BLOCK(ATOMIC_FORCEON) {lowI();}} - /** - * Set pin mode - * @param[in] pinMode if true set output mode else input mode. - * - * mode() does not enable or disable the 20K pullup for input mode. - * - * This function will enable interrupts. This function should not be - * called in an ISR or where interrupts are disabled. - */ - ALWAYS_INLINE void mode(bool pinMode) {ATOMIC_BLOCK(ATOMIC_FORCEON) {modeI(pinMode);}} - /** Write pin. - * - * @param[in] level If output mode set pin high if true else low. - * If input mode enable 20K pullup if true else disable pullup. - * - * This function will enable interrupts. This function should not be - * called in an ISR or where interrupts are disabled. - */ - ALWAYS_INLINE void write(bool level) {ATOMIC_BLOCK(ATOMIC_FORCEON) {writeI(level);}} - //---------------------------------------------------------------------------- - private: - uint8_t bit_; - uint8_t mask_; - volatile uint8_t* pinReg_; - volatile uint8_t* portReg_; +class PinIO +{ +public: + /** Create a PinIO object with no assigned pin. */ + PinIO() : bit_(0), mask_(0XFF) {} + /** Constructor + * @param[in] pin Pin assigned to this object. + */ + explicit PinIO(uint8_t pin); + /** Initialize pin bit mask and port address. + * @param[in] pin Arduino board pin number. + * @return true for success or false if invalid pin number. + */ + bool begin(uint8_t pin); + /** Configure the pin + * + * @param[in] mode Configure as output mode if true else input mode. + * @param[in] data For output mode set pin high if true else low. + * For input mode enable 20K pullup if true else Hi-Z. + * + * This function may be used with interrupts enabled or disabled. + * The previous interrupt state will be restored. + */ + void config(bool mode, bool data); + //---------------------------------------------------------------------------- + /** @return Pin's level */ + ALWAYS_INLINE bool read() + { + return *pinReg_ & bit_; + } + //---------------------------------------------------------------------------- + /** toggle a pin + * + * If the pin is in output mode toggle the pin's level. + * If the pin is in input mode toggle the state of the 20K pullup. + */ + ALWAYS_INLINE void toggle() + { + *pinReg_ = bit_; + } + //============================================================================ + /** + * Set pin high if output mode or enable 20K pullup if input mode. + * + * This function must be called with interrupts disabled. + * This function will not change the interrupt state. + */ + ALWAYS_INLINE void highI() + { + writeI(1); + } + /** + * Set pin low if output mode or disable 20K pullup if input mode. + * + * This function must be called with interrupts disabled. + * This function will not change the interrupt state. + */ + ALWAYS_INLINE void lowI() + { + writeI(0); + } + /** + * Set pin mode + * @param[in] mode if true set output mode else input mode. + * + * mode() does not enable or disable the 20K pullup for input mode. + * + * This function must be called with interrupts disabled. + * This function will not change the interrupt state. + */ + ALWAYS_INLINE void modeI(bool mode) + { + volatile uint8_t* ddrReg = pinReg_ + 1; + *ddrReg = mode ? *ddrReg | bit_ : *ddrReg & mask_; + } + /** Write pin. + * + * @param[in] level If output mode set pin high if true else low. + * If input mode enable 20K pullup if true else disable pullup. + * + * This function must be called with interrupts disabled. + * This function will not change the interrupt state. + */ + ALWAYS_INLINE void writeI(bool level) + { + *portReg_ = level ? *portReg_ | bit_ : *portReg_ & mask_; + } + //============================================================================ + /** + * Set pin level high if output mode or enable 20K pullup if input mode. + * + * This function will enable interrupts. This function should not be + * called in an ISR or where interrupts are disabled. + */ + ALWAYS_INLINE void high() + { + ATOMIC_BLOCK(ATOMIC_FORCEON) { + highI(); + } + } + /** + * Set pin level low if output mode or disable 20K pullup if input mode. + * + * This function will enable interrupts. This function should not be + * called in an ISR or where interrupts are disabled. + */ + ALWAYS_INLINE void low() + { + ATOMIC_BLOCK(ATOMIC_FORCEON) { + lowI(); + } + } + /** + * Set pin mode + * @param[in] pinMode if true set output mode else input mode. + * + * mode() does not enable or disable the 20K pullup for input mode. + * + * This function will enable interrupts. This function should not be + * called in an ISR or where interrupts are disabled. + */ + ALWAYS_INLINE void mode(bool pinMode) + { + ATOMIC_BLOCK(ATOMIC_FORCEON) { + modeI(pinMode); + } + } + /** Write pin. + * + * @param[in] level If output mode set pin high if true else low. + * If input mode enable 20K pullup if true else disable pullup. + * + * This function will enable interrupts. This function should not be + * called in an ISR or where interrupts are disabled. + */ + ALWAYS_INLINE void write(bool level) + { + ATOMIC_BLOCK(ATOMIC_FORCEON) { + writeI(level); + } + } + //---------------------------------------------------------------------------- +private: + uint8_t bit_; + uint8_t mask_; + volatile uint8_t* pinReg_; + volatile uint8_t* portReg_; }; #endif // PinIO_h /** @} */ \ No newline at end of file diff --git a/drivers/AVR/DigitalIO/SoftI2cMaster.cpp b/drivers/AVR/DigitalIO/SoftI2cMaster.cpp index d02b2bb66..e504d3fc2 100644 --- a/drivers/AVR/DigitalIO/SoftI2cMaster.cpp +++ b/drivers/AVR/DigitalIO/SoftI2cMaster.cpp @@ -49,16 +49,17 @@ * @return true for success else false. */ bool I2cMasterBase::transfer(uint8_t addrRW, - void *buf, size_t nbytes, uint8_t option) { - if (_state != STATE_REP_START) { - start(); - } - if (!write(addrRW)) { - _state = addrRW & I2C_READ ? STATE_RX_ADDR_NACK : STATE_TX_ADDR_NACK; - return false; - } - _state = addrRW & I2C_READ ? STATE_RX_DATA : STATE_TX_DATA; - return transferContinue(buf, nbytes, option); + void *buf, size_t nbytes, uint8_t option) +{ + if (_state != STATE_REP_START) { + start(); + } + if (!write(addrRW)) { + _state = addrRW & I2C_READ ? STATE_RX_ADDR_NACK : STATE_TX_ADDR_NACK; + return false; + } + _state = addrRW & I2C_READ ? STATE_RX_DATA : STATE_TX_DATA; + return transferContinue(buf, nbytes, option); } //------------------------------------------------------------------------------ /** @@ -76,30 +77,31 @@ bool I2cMasterBase::transfer(uint8_t addrRW, * . * @return true for success else false. */ -bool I2cMasterBase::transferContinue(void *buf, size_t nbytes, uint8_t option) { - uint8_t* p = reinterpret_cast(buf); - if (_state == STATE_RX_DATA) { - for (size_t i = 0; i < nbytes; i++) { - p[i] = read(i == (nbytes - 1) && option != I2C_CONTINUE); - } - } else if (_state == STATE_TX_DATA) { - for (size_t i = 0; i < nbytes; i++) { - if (!write(p[i])) { - _state = STATE_TX_DATA_NACK; - return false; - } - } - } else { - return false; - } - if (option == I2C_STOP) { - stop(); - _state = STATE_STOP; - } else if (option == I2C_REP_START) { - start(); - _state = STATE_STOP; - } - return true; +bool I2cMasterBase::transferContinue(void *buf, size_t nbytes, uint8_t option) +{ + uint8_t* p = reinterpret_cast(buf); + if (_state == STATE_RX_DATA) { + for (size_t i = 0; i < nbytes; i++) { + p[i] = read(i == (nbytes - 1) && option != I2C_CONTINUE); + } + } else if (_state == STATE_TX_DATA) { + for (size_t i = 0; i < nbytes; i++) { + if (!write(p[i])) { + _state = STATE_TX_DATA_NACK; + return false; + } + } + } else { + return false; + } + if (option == I2C_STOP) { + stop(); + _state = STATE_STOP; + } else if (option == I2C_REP_START) { + start(); + _state = STATE_STOP; + } + return true; } //============================================================================== // WARNING don't change SoftI2cMaster unless you verify the change with a scope @@ -111,8 +113,9 @@ bool I2cMasterBase::transferContinue(void *buf, size_t nbytes, uint8_t option) { * * @param[in] sclPin The software SCL pin number. */ -SoftI2cMaster::SoftI2cMaster(uint8_t sclPin, uint8_t sdaPin) { - begin(sclPin, sdaPin); +SoftI2cMaster::SoftI2cMaster(uint8_t sclPin, uint8_t sdaPin) +{ + begin(sclPin, sdaPin); } //------------------------------------------------------------------------------ /** @@ -122,32 +125,33 @@ SoftI2cMaster::SoftI2cMaster(uint8_t sclPin, uint8_t sdaPin) { * * @param[in] sclPin The software SCL pin number. */ -void SoftI2cMaster::begin(uint8_t sclPin, uint8_t sdaPin) { - uint8_t port; +void SoftI2cMaster::begin(uint8_t sclPin, uint8_t sdaPin) +{ + uint8_t port; - // Get bit mask and address of scl registers. - _sclBit = digitalPinToBitMask(sclPin); - port = digitalPinToPort(sclPin); - _sclDDR = portModeRegister(port); - volatile uint8_t* sclOutReg = portOutputRegister(port); + // Get bit mask and address of scl registers. + _sclBit = digitalPinToBitMask(sclPin); + port = digitalPinToPort(sclPin); + _sclDDR = portModeRegister(port); + volatile uint8_t* sclOutReg = portOutputRegister(port); - // Get bit mask and address of sda registers. - _sdaBit = digitalPinToBitMask(sdaPin); - port = digitalPinToPort(sdaPin); - _sdaDDR = portModeRegister(port); - _sdaInReg = portInputRegister(port); - volatile uint8_t* sdaOutReg = portOutputRegister(port); + // Get bit mask and address of sda registers. + _sdaBit = digitalPinToBitMask(sdaPin); + port = digitalPinToPort(sdaPin); + _sdaDDR = portModeRegister(port); + _sdaInReg = portInputRegister(port); + volatile uint8_t* sdaOutReg = portOutputRegister(port); - // Clear PORT bit for scl and sda. - uint8_t s = SREG; - noInterrupts(); - *sclOutReg &= ~_sclBit; - *sdaOutReg &= ~_sdaBit; - SREG = s; + // Clear PORT bit for scl and sda. + uint8_t s = SREG; + noInterrupts(); + *sclOutReg &= ~_sclBit; + *sdaOutReg &= ~_sdaBit; + SREG = s; - // Set scl and sda high. - writeScl(HIGH); - writeSda(HIGH); + // Set scl and sda high. + writeScl(HIGH); + writeSda(HIGH); } //------------------------------------------------------------------------------ /* Read a byte and send ACK if more reads follow else NACK to terminate read. @@ -156,51 +160,56 @@ void SoftI2cMaster::begin(uint8_t sclPin, uint8_t sdaPin) { * * @return The byte read from the I2C bus. */ -uint8_t SoftI2cMaster::read(uint8_t last) { - uint8_t b = 0; +uint8_t SoftI2cMaster::read(uint8_t last) +{ + uint8_t b = 0; - // Set sda to high Z mode for read. - writeSda(HIGH); - // Read a byte. - for (uint8_t i = 0; i < 8; i++) { - // Don't change this loop unless you verify the change with a scope. - b <<= 1; - sclDelay(16); - writeScl(HIGH); - sclDelay(12); - if (readSda()) b |= 1; - writeScl(LOW); - } - // send ACK or NACK - writeSda(last); - sclDelay(12); - writeScl(HIGH); - sclDelay(18); - writeScl(LOW); - writeSda(LOW); - return b; + // Set sda to high Z mode for read. + writeSda(HIGH); + // Read a byte. + for (uint8_t i = 0; i < 8; i++) { + // Don't change this loop unless you verify the change with a scope. + b <<= 1; + sclDelay(16); + writeScl(HIGH); + sclDelay(12); + if (readSda()) { + b |= 1; + } + writeScl(LOW); + } + // send ACK or NACK + writeSda(last); + sclDelay(12); + writeScl(HIGH); + sclDelay(18); + writeScl(LOW); + writeSda(LOW); + return b; } //------------------------------------------------------------------------------ /* Issue a start condition. */ -void SoftI2cMaster::start() { - if (!readSda()) { - writeSda(HIGH); - writeScl(HIGH); - sclDelay(20); - } - writeSda(LOW); - sclDelay(20); - writeScl(LOW); +void SoftI2cMaster::start() +{ + if (!readSda()) { + writeSda(HIGH); + writeScl(HIGH); + sclDelay(20); + } + writeSda(LOW); + sclDelay(20); + writeScl(LOW); } //------------------------------------------------------------------------------ - /* Issue a stop condition. */ -void SoftI2cMaster::stop(void) { - writeSda(LOW); - sclDelay(20); - writeScl(HIGH); - sclDelay(20); - writeSda(HIGH); - sclDelay(20); +/* Issue a stop condition. */ +void SoftI2cMaster::stop(void) +{ + writeSda(LOW); + sclDelay(20); + writeScl(HIGH); + sclDelay(20); + writeSda(HIGH); + sclDelay(20); } //------------------------------------------------------------------------------ /* @@ -210,30 +219,31 @@ void SoftI2cMaster::stop(void) { * * @return The value true, 1, if the slave returned an ACK or false for NACK. */ -bool SoftI2cMaster::write(uint8_t data) { - // write byte - for (uint8_t m = 0X80; m != 0; m >>= 1) { - // don't change this loop unless you verify the change with a scope - writeSda(m & data); - sclDelay(8); - writeScl(HIGH); - sclDelay(18); - writeScl(LOW); - } - sclDelay(8); - // Go to sda high Z mode for input. - writeSda(HIGH); - writeScl(HIGH); - sclDelay(16); +bool SoftI2cMaster::write(uint8_t data) +{ + // write byte + for (uint8_t m = 0X80; m != 0; m >>= 1) { + // don't change this loop unless you verify the change with a scope + writeSda(m & data); + sclDelay(8); + writeScl(HIGH); + sclDelay(18); + writeScl(LOW); + } + sclDelay(8); + // Go to sda high Z mode for input. + writeSda(HIGH); + writeScl(HIGH); + sclDelay(16); - // Get ACK or NACK. - uint8_t rtn = readSda(); + // Get ACK or NACK. + uint8_t rtn = readSda(); - // pull scl low. - writeScl(LOW); + // pull scl low. + writeScl(LOW); - // Pull sda low. - writeSda(LOW); - return rtn == 0; + // Pull sda low. + writeSda(LOW); + return rtn == 0; } /** @} */ diff --git a/drivers/AVR/DigitalIO/SoftI2cMaster.h b/drivers/AVR/DigitalIO/SoftI2cMaster.h index dd4bbf0c3..dd250eb9b 100644 --- a/drivers/AVR/DigitalIO/SoftI2cMaster.h +++ b/drivers/AVR/DigitalIO/SoftI2cMaster.h @@ -63,151 +63,161 @@ const uint8_t STATE_TX_DATA_NACK = 6; * @class I2cMasterBase * @brief Base class for FastI2cMaster, SoftI2cMaster */ -class I2cMasterBase { - public: - I2cMasterBase() : _state(STATE_STOP) {} - /** Read a byte - * - * @note This function should only be used by experts. Data should be - * accessed by calling transfer() and transferContinue() - * - * @param[in] last send a NACK to terminate read if last is true else - * send an ACK to continue the read. - * - * @return byte read from I2C bus - */ - virtual uint8_t read(uint8_t last) = 0; +class I2cMasterBase +{ +public: + I2cMasterBase() : _state(STATE_STOP) {} + /** Read a byte + * + * @note This function should only be used by experts. Data should be + * accessed by calling transfer() and transferContinue() + * + * @param[in] last send a NACK to terminate read if last is true else + * send an ACK to continue the read. + * + * @return byte read from I2C bus + */ + virtual uint8_t read(uint8_t last) = 0; - /** Issue a start condition - * - * @note This function should only be used by experts. Data should be - * accessed by calling transfer() and transferContinue() - */ - virtual void start() = 0; - /** Issue a stop condition. - * - * @note This function should only be used by experts. Data should be - * accessed by calling transfer() and transferContinue() - */ - virtual void stop() = 0; + /** Issue a start condition + * + * @note This function should only be used by experts. Data should be + * accessed by calling transfer() and transferContinue() + */ + virtual void start() = 0; + /** Issue a stop condition. + * + * @note This function should only be used by experts. Data should be + * accessed by calling transfer() and transferContinue() + */ + virtual void stop() = 0; -/** - * Start an I2C transfer with possible continuation. - * - * @param[in] addressRW I2C slave address plus R/W bit. - * The I2C slave address is in the high seven bits - * and is ORed with on of the following: - * - I2C_READ for a read transfer. - * - I2C_WRITE for a write transfer. - * . - * @param[in,out] buf Source or destination for transfer. - * @param[in] nbyte Number of bytes to transfer (may be zero). - * @param[in] option Option for ending the transfer, one of: - * - I2C_STOP end the transfer with an I2C stop - * condition. - * - I2C_REP_START end the transfer with an I2C - * repeated start condition. - * - I2C_CONTINUE allow additional transferContinue() - * calls. - * . - * @return true for success else false. - */ - bool transfer(uint8_t addressRW, void *buf, - size_t nbyte, uint8_t option = I2C_STOP); + /** + * Start an I2C transfer with possible continuation. + * + * @param[in] addressRW I2C slave address plus R/W bit. + * The I2C slave address is in the high seven bits + * and is ORed with on of the following: + * - I2C_READ for a read transfer. + * - I2C_WRITE for a write transfer. + * . + * @param[in,out] buf Source or destination for transfer. + * @param[in] nbyte Number of bytes to transfer (may be zero). + * @param[in] option Option for ending the transfer, one of: + * - I2C_STOP end the transfer with an I2C stop + * condition. + * - I2C_REP_START end the transfer with an I2C + * repeated start condition. + * - I2C_CONTINUE allow additional transferContinue() + * calls. + * . + * @return true for success else false. + */ + bool transfer(uint8_t addressRW, void *buf, + size_t nbyte, uint8_t option = I2C_STOP); -/** - * Continue an I2C transfer. - * - * @param[in,out] buf Source or destination for transfer. - * @param[in] nbyte Number of bytes to transfer (may be zero). - * @param[in] option Option for ending the transfer, one of: - * - I2C_STOP end the transfer with an I2C stop - * condition. - * - I2C_REP_START end the transfer with an I2C - * repeated start condition. - * - I2C_CONTINUE allow additional transferContinue() - * calls. - * . - * @return true for success else false. - */ - bool transferContinue(void *buf, size_t nbyte, uint8_t option = I2C_STOP); - /** Write a byte - * - * @note This function should only be used by experts. Data should be - * accessed by calling transfer() and transferContinue() - * - * @param[in] data byte to write - * @return true for ACK or false for NACK */ - virtual bool write(uint8_t data) = 0; + /** + * Continue an I2C transfer. + * + * @param[in,out] buf Source or destination for transfer. + * @param[in] nbyte Number of bytes to transfer (may be zero). + * @param[in] option Option for ending the transfer, one of: + * - I2C_STOP end the transfer with an I2C stop + * condition. + * - I2C_REP_START end the transfer with an I2C + * repeated start condition. + * - I2C_CONTINUE allow additional transferContinue() + * calls. + * . + * @return true for success else false. + */ + bool transferContinue(void *buf, size_t nbyte, uint8_t option = I2C_STOP); + /** Write a byte + * + * @note This function should only be used by experts. Data should be + * accessed by calling transfer() and transferContinue() + * + * @param[in] data byte to write + * @return true for ACK or false for NACK */ + virtual bool write(uint8_t data) = 0; - private: - uint8_t _state; +private: + uint8_t _state; }; //============================================================================== /** * @class SoftI2cMaster * @brief Software I2C master class */ -class SoftI2cMaster : public I2cMasterBase { - public: - SoftI2cMaster() {} - /** - * Constructor, initialize SCL/SDA pins and set the bus high. - * - * @param[in] sdaPin The software SDA pin number. - * - * @param[in] sclPin The software SCL pin number. - */ - SoftI2cMaster(uint8_t sclPin, uint8_t sdaPin); - /** - * Initialize SCL/SDA pins and set the bus high. - * - * @param[in] sdaPin The software SDA pin number. - * - * @param[in] sclPin The software SCL pin number. - */ - void begin(uint8_t sclPin, uint8_t sdaPin); - uint8_t read(uint8_t last); - void start(); - void stop(void); - bool write(uint8_t b); +class SoftI2cMaster : public I2cMasterBase +{ +public: + SoftI2cMaster() {} + /** + * Constructor, initialize SCL/SDA pins and set the bus high. + * + * @param[in] sdaPin The software SDA pin number. + * + * @param[in] sclPin The software SCL pin number. + */ + SoftI2cMaster(uint8_t sclPin, uint8_t sdaPin); + /** + * Initialize SCL/SDA pins and set the bus high. + * + * @param[in] sdaPin The software SDA pin number. + * + * @param[in] sclPin The software SCL pin number. + */ + void begin(uint8_t sclPin, uint8_t sdaPin); + uint8_t read(uint8_t last); + void start(); + void stop(void); + bool write(uint8_t b); - private: - uint8_t _sclBit; - uint8_t _sdaBit; - volatile uint8_t* _sclDDR; - volatile uint8_t* _sdaDDR; - volatile uint8_t* _sdaInReg; - //---------------------------------------------------------------------------- - bool readSda() {return *_sdaInReg & _sdaBit;} - //---------------------------------------------------------------------------- - void sclDelay(uint8_t n) {_delay_loop_1(n);} - //---------------------------------------------------------------------------- - void writeScl(bool value) { - uint8_t s = SREG; - noInterrupts(); - if (value == LOW) { - // Pull scl low. - *_sclDDR |= _sclBit; - } else { - // Put scl in high Z input mode. - *_sclDDR &= ~_sclBit; - } - SREG = s; - } - //---------------------------------------------------------------------------- - void writeSda(bool value) { - uint8_t s = SREG; - noInterrupts(); - if (value == LOW) { - // Pull sda low. - *_sdaDDR |= _sdaBit; - } else { - // Put sda in high Z input mode. - *_sdaDDR &= ~_sdaBit; - } - SREG = s; - } +private: + uint8_t _sclBit; + uint8_t _sdaBit; + volatile uint8_t* _sclDDR; + volatile uint8_t* _sdaDDR; + volatile uint8_t* _sdaInReg; + //---------------------------------------------------------------------------- + bool readSda() + { + return *_sdaInReg & _sdaBit; + } + //---------------------------------------------------------------------------- + void sclDelay(uint8_t n) + { + _delay_loop_1(n); + } + //---------------------------------------------------------------------------- + void writeScl(bool value) + { + uint8_t s = SREG; + noInterrupts(); + if (value == LOW) { + // Pull scl low. + *_sclDDR |= _sclBit; + } else { + // Put scl in high Z input mode. + *_sclDDR &= ~_sclBit; + } + SREG = s; + } + //---------------------------------------------------------------------------- + void writeSda(bool value) + { + uint8_t s = SREG; + noInterrupts(); + if (value == LOW) { + // Pull sda low. + *_sdaDDR |= _sdaBit; + } else { + // Put sda in high Z input mode. + *_sdaDDR &= ~_sdaBit; + } + SREG = s; + } }; //============================================================================== // Template based fast software I2C @@ -217,118 +227,140 @@ class SoftI2cMaster : public I2cMasterBase { * @brief Fast software I2C master class. */ template -class FastI2cMaster : public I2cMasterBase { - public: - //---------------------------------------------------------------------------- - FastI2cMaster() { - begin(); - } - //---------------------------------------------------------------------------- - /** Initialize I2C bus pins. */ - void begin() { - fastDigitalWrite(sclPin, LOW); - fastDigitalWrite(sdaPin, LOW); +class FastI2cMaster : public I2cMasterBase +{ +public: + //---------------------------------------------------------------------------- + FastI2cMaster() + { + begin(); + } + //---------------------------------------------------------------------------- + /** Initialize I2C bus pins. */ + void begin() + { + fastDigitalWrite(sclPin, LOW); + fastDigitalWrite(sdaPin, LOW); - sclWrite(HIGH); - sdaWrite(HIGH); - } - //---------------------------------------------------------------------------- - uint8_t read(uint8_t last) { - uint8_t data = 0; - sdaWrite(HIGH); + sclWrite(HIGH); + sdaWrite(HIGH); + } + //---------------------------------------------------------------------------- + uint8_t read(uint8_t last) + { + uint8_t data = 0; + sdaWrite(HIGH); - readBit(7, &data); - readBit(6, &data); - readBit(5, &data); - readBit(4, &data); - readBit(3, &data); - readBit(2, &data); - readBit(1, &data); - readBit(0, &data); + readBit(7, &data); + readBit(6, &data); + readBit(5, &data); + readBit(4, &data); + readBit(3, &data); + readBit(2, &data); + readBit(1, &data); + readBit(0, &data); - // send ACK or NACK - sdaWrite(last); - sclDelay(4); - sclWrite(HIGH); - sclDelay(6); - sclWrite(LOW); - sdaWrite(LOW); - return data; - } - //---------------------------------------------------------------------------- - void start() { - if (!fastDigitalRead(sdaPin)) { - // It's a repeat start. - sdaWrite(HIGH); - sclDelay(8); - sclWrite(HIGH); - sclDelay(8); - } - sdaWrite(LOW); - sclDelay(8); - sclWrite(LOW); - sclDelay(8); - } - //---------------------------------------------------------------------------- - void stop(void) { - sdaWrite(LOW); - sclDelay(8); - sclWrite(HIGH); - sclDelay(8); - sdaWrite(HIGH); - sclDelay(8); - } - //---------------------------------------------------------------------------- - bool write(uint8_t data) { - // write byte - writeBit(7, data); - writeBit(6, data); - writeBit(5, data); - writeBit(4, data); - writeBit(3, data); - writeBit(2, data); - writeBit(1, data); - writeBit(0, data); + // send ACK or NACK + sdaWrite(last); + sclDelay(4); + sclWrite(HIGH); + sclDelay(6); + sclWrite(LOW); + sdaWrite(LOW); + return data; + } + //---------------------------------------------------------------------------- + void start() + { + if (!fastDigitalRead(sdaPin)) { + // It's a repeat start. + sdaWrite(HIGH); + sclDelay(8); + sclWrite(HIGH); + sclDelay(8); + } + sdaWrite(LOW); + sclDelay(8); + sclWrite(LOW); + sclDelay(8); + } + //---------------------------------------------------------------------------- + void stop(void) + { + sdaWrite(LOW); + sclDelay(8); + sclWrite(HIGH); + sclDelay(8); + sdaWrite(HIGH); + sclDelay(8); + } + //---------------------------------------------------------------------------- + bool write(uint8_t data) + { + // write byte + writeBit(7, data); + writeBit(6, data); + writeBit(5, data); + writeBit(4, data); + writeBit(3, data); + writeBit(2, data); + writeBit(1, data); + writeBit(0, data); - // get ACK or NACK - sdaWrite(HIGH); + // get ACK or NACK + sdaWrite(HIGH); - sclWrite(HIGH); - sclDelay(5); - bool rtn = fastDigitalRead(sdaPin); - sclWrite(LOW); - sdaWrite(LOW); - return rtn == 0; - } + sclWrite(HIGH); + sclDelay(5); + bool rtn = fastDigitalRead(sdaPin); + sclWrite(LOW); + sdaWrite(LOW); + return rtn == 0; + } - private: - //---------------------------------------------------------------------------- - inline __attribute__((always_inline)) - void sclWrite(bool value) {fastPinMode(sclPin, !value);} - //---------------------------------------------------------------------------- - inline __attribute__((always_inline)) - void sdaWrite(bool value) {fastPinMode(sdaPin, !value);} - //---------------------------------------------------------------------------- - inline __attribute__((always_inline)) - void readBit(uint8_t bit, uint8_t* data) { - sclWrite(HIGH); - sclDelay(5); - if (fastDigitalRead(sdaPin)) *data |= 1 << bit; - sclWrite(LOW); - if (bit) sclDelay(6); - } - //---------------------------------------------------------------------------- - void sclDelay(uint8_t n) {_delay_loop_1(n);} - //---------------------------------------------------------------------------- - inline __attribute__((always_inline)) - void writeBit(uint8_t bit, uint8_t data) { - uint8_t mask = 1 << bit; - sdaWrite(data & mask); - sclWrite(HIGH); - sclDelay(5); - sclWrite(LOW); - sclDelay(5); - } +private: + //---------------------------------------------------------------------------- + inline __attribute__((always_inline)) + void sclWrite(bool value) + { + fastPinMode(sclPin, !value); + } + //---------------------------------------------------------------------------- + inline __attribute__((always_inline)) + void sdaWrite(bool value) + { + fastPinMode(sdaPin, !value); + } + //---------------------------------------------------------------------------- + inline __attribute__((always_inline)) + void readBit(uint8_t bit, uint8_t* data) + { + sclWrite(HIGH); + sclDelay(5); + if (fastDigitalRead(sdaPin)) { + *data |= 1 << bit; + } + sclWrite(LOW); + if (bit) { + sclDelay(6); + } + } + //---------------------------------------------------------------------------- + void sclDelay(uint8_t n) + { + _delay_loop_1(n); + } + //---------------------------------------------------------------------------- + inline __attribute__((always_inline)) + void writeBit(uint8_t bit, uint8_t data) + { + uint8_t mask = 1 << bit; + sdaWrite(data & mask); + sclWrite(HIGH); + sclDelay(5); + sclWrite(LOW); + sclDelay(5); + } }; #endif // SOFT_I2C_MASTER_H /** @} */ diff --git a/drivers/AVR/DigitalIO/SoftSPI.h b/drivers/AVR/DigitalIO/SoftSPI.h index 86f9d943b..d71405521 100644 --- a/drivers/AVR/DigitalIO/SoftSPI.h +++ b/drivers/AVR/DigitalIO/SoftSPI.h @@ -18,7 +18,7 @@ * . */ /** - * @file + * @file * @brief Software SPI. * * @defgroup softSPI Software SPI @@ -48,108 +48,126 @@ const bool SCK_MODE = true; * @brief Fast software SPI. */ template -class SoftSPI { - public: - //---------------------------------------------------------------------------- - /** Initialize SoftSPI pins. */ - void begin() { - fastPinConfig(MisoPin, MISO_MODE, MISO_LEVEL); - fastPinConfig(MosiPin, MOSI_MODE, !MODE_CPHA(Mode)); - fastPinConfig(SckPin, SCK_MODE, MODE_CPOL(Mode)); - } - //---------------------------------------------------------------------------- - /** Soft SPI receive byte. - * @return Data byte received. - */ - ALWAYS_INLINE uint8_t receive() { - uint8_t data = 0; - receiveBit(7, &data); - receiveBit(6, &data); - receiveBit(5, &data); - receiveBit(4, &data); - receiveBit(3, &data); - receiveBit(2, &data); - receiveBit(1, &data); - receiveBit(0, &data); - return data; - } - //---------------------------------------------------------------------------- - /** Soft SPI send byte. - * @param[in] data Data byte to send. - */ - ALWAYS_INLINE void send(uint8_t data) { - sendBit(7, data); - sendBit(6, data); - sendBit(5, data); - sendBit(4, data); - sendBit(3, data); - sendBit(2, data); - sendBit(1, data); - sendBit(0, data); - } - //---------------------------------------------------------------------------- - /** Soft SPI transfer byte. - * @param[in] txData Data byte to send. - * @return Data byte received. - */ - ALWAYS_INLINE uint8_t transfer(uint8_t txData) { - uint8_t rxData = 0; - transferBit(7, &rxData, txData); - transferBit(6, &rxData, txData); - transferBit(5, &rxData, txData); - transferBit(4, &rxData, txData); - transferBit(3, &rxData, txData); - transferBit(2, &rxData, txData); - transferBit(1, &rxData, txData); - transferBit(0, &rxData, txData); - return rxData; - } +class SoftSPI +{ +public: + //---------------------------------------------------------------------------- + /** Initialize SoftSPI pins. */ + void begin() + { + fastPinConfig(MisoPin, MISO_MODE, MISO_LEVEL); + fastPinConfig(MosiPin, MOSI_MODE, !MODE_CPHA(Mode)); + fastPinConfig(SckPin, SCK_MODE, MODE_CPOL(Mode)); + } + //---------------------------------------------------------------------------- + /** Soft SPI receive byte. + * @return Data byte received. + */ + ALWAYS_INLINE uint8_t receive() + { + uint8_t data = 0; + receiveBit(7, &data); + receiveBit(6, &data); + receiveBit(5, &data); + receiveBit(4, &data); + receiveBit(3, &data); + receiveBit(2, &data); + receiveBit(1, &data); + receiveBit(0, &data); + return data; + } + //---------------------------------------------------------------------------- + /** Soft SPI send byte. + * @param[in] data Data byte to send. + */ + ALWAYS_INLINE void send(uint8_t data) + { + sendBit(7, data); + sendBit(6, data); + sendBit(5, data); + sendBit(4, data); + sendBit(3, data); + sendBit(2, data); + sendBit(1, data); + sendBit(0, data); + } + //---------------------------------------------------------------------------- + /** Soft SPI transfer byte. + * @param[in] txData Data byte to send. + * @return Data byte received. + */ + ALWAYS_INLINE uint8_t transfer(uint8_t txData) + { + uint8_t rxData = 0; + transferBit(7, &rxData, txData); + transferBit(6, &rxData, txData); + transferBit(5, &rxData, txData); + transferBit(4, &rxData, txData); + transferBit(3, &rxData, txData); + transferBit(2, &rxData, txData); + transferBit(1, &rxData, txData); + transferBit(0, &rxData, txData); + return rxData; + } - private: - //---------------------------------------------------------------------------- - ALWAYS_INLINE bool MODE_CPHA(uint8_t mode) {return (mode & 1) != 0;} - ALWAYS_INLINE bool MODE_CPOL(uint8_t mode) {return (mode & 2) != 0;} - ALWAYS_INLINE void receiveBit(uint8_t bit, uint8_t* data) { - if (MODE_CPHA(Mode)) { - fastDigitalWrite(SckPin, !MODE_CPOL(Mode)); - } - nop; - nop; - fastDigitalWrite(SckPin, - MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode)); - if (fastDigitalRead(MisoPin)) *data |= 1 << bit; - if (!MODE_CPHA(Mode)) { - fastDigitalWrite(SckPin, MODE_CPOL(Mode)); - } - } - //---------------------------------------------------------------------------- - ALWAYS_INLINE void sendBit(uint8_t bit, uint8_t data) { - if (MODE_CPHA(Mode)) { - fastDigitalWrite(SckPin, !MODE_CPOL(Mode)); - } - fastDigitalWrite(MosiPin, data & (1 << bit)); - fastDigitalWrite(SckPin, - MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode)); - nop; - nop; - if (!MODE_CPHA(Mode)) { - fastDigitalWrite(SckPin, MODE_CPOL(Mode)); - } - } - //---------------------------------------------------------------------------- - ALWAYS_INLINE void transferBit(uint8_t bit, uint8_t* rxData, uint8_t txData) { - if (MODE_CPHA(Mode)) { - fastDigitalWrite(SckPin, !MODE_CPOL(Mode)); - } - fastDigitalWrite(MosiPin, txData & (1 << bit)); - fastDigitalWrite(SckPin, - MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode)); - if (fastDigitalRead(MisoPin)) *rxData |= 1 << bit; - if (!MODE_CPHA(Mode)) { - fastDigitalWrite(SckPin, MODE_CPOL(Mode)); - } - } - //---------------------------------------------------------------------------- +private: + //---------------------------------------------------------------------------- + ALWAYS_INLINE bool MODE_CPHA(uint8_t mode) + { + return (mode & 1) != 0; + } + ALWAYS_INLINE bool MODE_CPOL(uint8_t mode) + { + return (mode & 2) != 0; + } + ALWAYS_INLINE void receiveBit(uint8_t bit, uint8_t* data) + { + if (MODE_CPHA(Mode)) { + fastDigitalWrite(SckPin, !MODE_CPOL(Mode)); + } + nop; + nop; + fastDigitalWrite(SckPin, + MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode)); + if (fastDigitalRead(MisoPin)) { + *data |= 1 << bit; + } + if (!MODE_CPHA(Mode)) { + fastDigitalWrite(SckPin, MODE_CPOL(Mode)); + } + } + //---------------------------------------------------------------------------- + ALWAYS_INLINE void sendBit(uint8_t bit, uint8_t data) + { + if (MODE_CPHA(Mode)) { + fastDigitalWrite(SckPin, !MODE_CPOL(Mode)); + } + fastDigitalWrite(MosiPin, data & (1 << bit)); + fastDigitalWrite(SckPin, + MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode)); + nop; + nop; + if (!MODE_CPHA(Mode)) { + fastDigitalWrite(SckPin, MODE_CPOL(Mode)); + } + } + //---------------------------------------------------------------------------- + ALWAYS_INLINE void transferBit(uint8_t bit, uint8_t* rxData, uint8_t txData) + { + if (MODE_CPHA(Mode)) { + fastDigitalWrite(SckPin, !MODE_CPOL(Mode)); + } + fastDigitalWrite(MosiPin, txData & (1 << bit)); + fastDigitalWrite(SckPin, + MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode)); + if (fastDigitalRead(MisoPin)) { + *rxData |= 1 << bit; + } + if (!MODE_CPHA(Mode)) { + fastDigitalWrite(SckPin, MODE_CPOL(Mode)); + } + } + //---------------------------------------------------------------------------- }; #endif // SoftSPI_h /** @} */ diff --git a/drivers/AVR/DigitalIO/attic/ADS7818.h b/drivers/AVR/DigitalIO/attic/ADS7818.h index eb64fb5ab..4e6f5d8ba 100644 --- a/drivers/AVR/DigitalIO/attic/ADS7818.h +++ b/drivers/AVR/DigitalIO/attic/ADS7818.h @@ -9,118 +9,132 @@ //------------------------------------------------------------------------------ template /** ADS7818 class */ -class ADS7818 { - public: - //---------------------------------------------------------------------------- - /** Set pin modes and initial levels. */ - void begin() { - fastPinMode(ClkPin, 1); - fastDigitalWrite(ClkPin, 0); - fastPinMode(ConvPin, 1); - fastDigitalWrite(ConvPin, 1); - fastPinMode(DataPin, 0); - } - //---------------------------------------------------------------------------- - /** Read ADS7818 12-bit ADC - * \return 16-bit value read. - */ - inline __attribute__((always_inline)) - uint16_t read() { - uint16_t v = 0; - fastDigitalWrite(ConvPin, 0); - fastDigitalWrite(ClkPin, 1); - fastDigitalWrite(ClkPin, 0); - fastDigitalWrite(ConvPin, 1); - fastDigitalWrite(ClkPin, 1); - fastDigitalWrite(ClkPin, 0); +class ADS7818 +{ +public: + //---------------------------------------------------------------------------- + /** Set pin modes and initial levels. */ + void begin() + { + fastPinMode(ClkPin, 1); + fastDigitalWrite(ClkPin, 0); + fastPinMode(ConvPin, 1); + fastDigitalWrite(ConvPin, 1); + fastPinMode(DataPin, 0); + } + //---------------------------------------------------------------------------- + /** Read ADS7818 12-bit ADC + * \return 16-bit value read. + */ + inline __attribute__((always_inline)) + uint16_t read() + { + uint16_t v = 0; + fastDigitalWrite(ConvPin, 0); + fastDigitalWrite(ClkPin, 1); + fastDigitalWrite(ClkPin, 0); + fastDigitalWrite(ConvPin, 1); + fastDigitalWrite(ClkPin, 1); + fastDigitalWrite(ClkPin, 0); - readBitFast16(v, 11); - readBitFast16(v, 10); - readBitFast16(v, 9); - readBitFast16(v, 8); - readBitFast16(v, 7); - readBitFast16(v, 6); - readBitFast16(v, 5); - readBitFast16(v, 4); - readBitFast16(v, 3); - readBitFast16(v, 2); - readBitFast16(v, 1); - readBitFast16(v, 0); - return v; - } - private: - //---------------------------------------------------------------------------- - inline __attribute__((always_inline)) - void readBitFast16(uint16_t &v, uint8_t b) { - fastDigitalWrite(ClkPin, 1); - if (fastDigitalRead(DataPin)) v |= (1 << b); - fastDigitalWrite(ClkPin, 0); - } + readBitFast16(v, 11); + readBitFast16(v, 10); + readBitFast16(v, 9); + readBitFast16(v, 8); + readBitFast16(v, 7); + readBitFast16(v, 6); + readBitFast16(v, 5); + readBitFast16(v, 4); + readBitFast16(v, 3); + readBitFast16(v, 2); + readBitFast16(v, 1); + readBitFast16(v, 0); + return v; + } +private: + //---------------------------------------------------------------------------- + inline __attribute__((always_inline)) + void readBitFast16(uint16_t &v, uint8_t b) + { + fastDigitalWrite(ClkPin, 1); + if (fastDigitalRead(DataPin)) { + v |= (1 << b); + } + fastDigitalWrite(ClkPin, 0); + } }; #if 0 /** initialize I/O ports */ -STATIC_ALWAYS_INLINE void adcBegin() { - fastPinMode(ADC_CLK_PIN, 1); - fastDigitalWrite(ADC_CLK_PIN, 0); - fastPinMode(ADC_CONV_PIN, 1); - fastDigitalWrite(ADC_CONV_PIN, 1); - fastPinMode(ADC_DATA_PIN, 0); +STATIC_ALWAYS_INLINE void adcBegin() +{ + fastPinMode(ADC_CLK_PIN, 1); + fastDigitalWrite(ADC_CLK_PIN, 0); + fastPinMode(ADC_CONV_PIN, 1); + fastDigitalWrite(ADC_CONV_PIN, 1); + fastPinMode(ADC_DATA_PIN, 0); } //------------------------------------------------------------------------------ /** clock for don't care bits *\param[in] delayBefore if true, delay before raising clock*/ -STATIC_ALWAYS_INLINE void fastDummy(bool first) { - if (!first) nop; - fastDigitalWrite(ADC_CLK_PIN, 1); - nop; - fastDigitalWrite(ADC_CLK_PIN, 0); +STATIC_ALWAYS_INLINE void fastDummy(bool first) +{ + if (!first) { + nop; + } + fastDigitalWrite(ADC_CLK_PIN, 1); + nop; + fastDigitalWrite(ADC_CLK_PIN, 0); } //------------------------------------------------------------------------------ /** read next bit fast as possible * \param[in] v word to receive bit * \param[in] b bit number to be set. v |= (1 << b) if next bit is high. */ -STATIC_ALWAYS_INLINE void readBitFast16(uint16_t &v, uint8_t b) { - fastDigitalWrite(ADC_CLK_PIN, 1); - if (fastDigitalRead(ADC_DATA_PIN)) v |= (1 << b); - fastDigitalWrite(ADC_CLK_PIN, 0); +STATIC_ALWAYS_INLINE void readBitFast16(uint16_t &v, uint8_t b) +{ + fastDigitalWrite(ADC_CLK_PIN, 1); + if (fastDigitalRead(ADC_DATA_PIN)) { + v |= (1 << b); + } + fastDigitalWrite(ADC_CLK_PIN, 0); } //------------------------------------------------------------------------------ /** Read AD7680 16-bit ADC in less than 8 microseconds * cs is chip select pin */ -STATIC_ALWAYS_INLINE uint16_t adcRead(bool centered = false) { - uint16_t v = 0; - fastDigitalWrite(ADC_CONV_PIN, 0); - fastDigitalWrite(ADC_CLK_PIN, 1); - fastDigitalWrite(ADC_CLK_PIN, 0); - fastDigitalWrite(ADC_CONV_PIN, 1); - fastDigitalWrite(ADC_CLK_PIN, 1); - fastDigitalWrite(ADC_CLK_PIN, 0); -// uint16_t v = 0; +STATIC_ALWAYS_INLINE uint16_t adcRead(bool centered = false) +{ + uint16_t v = 0; + fastDigitalWrite(ADC_CONV_PIN, 0); + fastDigitalWrite(ADC_CLK_PIN, 1); + fastDigitalWrite(ADC_CLK_PIN, 0); + fastDigitalWrite(ADC_CONV_PIN, 1); + fastDigitalWrite(ADC_CLK_PIN, 1); + fastDigitalWrite(ADC_CLK_PIN, 0); + // uint16_t v = 0; -// fastDummy(1); -// fastDummy(0); -// fastDummy(0); - // fastDummy(0); - -// readBitFast16(v, 15); -// readBitFast16(v, 14); -// readBitFast16(v, 13); -// readBitFast16(v, 12); - readBitFast16(v, 11); - readBitFast16(v, 10); - readBitFast16(v, 9); - readBitFast16(v, 8); - readBitFast16(v, 7); - readBitFast16(v, 6); - readBitFast16(v, 5); - readBitFast16(v, 4); - readBitFast16(v, 3); - readBitFast16(v, 2); - readBitFast16(v, 1); - readBitFast16(v, 0); - return centered ? v ^ 0X8000 : v; + // fastDummy(1); + // fastDummy(0); + // fastDummy(0); + // fastDummy(0); + + // readBitFast16(v, 15); + // readBitFast16(v, 14); + // readBitFast16(v, 13); + // readBitFast16(v, 12); + readBitFast16(v, 11); + readBitFast16(v, 10); + readBitFast16(v, 9); + readBitFast16(v, 8); + readBitFast16(v, 7); + readBitFast16(v, 6); + readBitFast16(v, 5); + readBitFast16(v, 4); + readBitFast16(v, 3); + readBitFast16(v, 2); + readBitFast16(v, 1); + readBitFast16(v, 0); + return centered ? v ^ 0X8000 : v; } #endif // 0 #endif // ADS7818_h \ No newline at end of file diff --git a/drivers/AVR/DigitalIO/attic/MCP320X.h b/drivers/AVR/DigitalIO/attic/MCP320X.h index 741bbeeac..9da32dc5a 100644 --- a/drivers/AVR/DigitalIO/attic/MCP320X.h +++ b/drivers/AVR/DigitalIO/attic/MCP320X.h @@ -4,259 +4,302 @@ //============================================================================== template /** MCP3201 class */ -class MCP3201 { - public: - //---------------------------------------------------------------------------- - /** Set pin modes and initial levels. */ - void begin() { - fastPinMode(ClkPin, 1); - fastDigitalWrite(ClkPin, 0); - fastPinMode(CsPin, 1); - fastDigitalWrite(CsPin, 1); - fastPinMode(DoutPin, 0); - } - //---------------------------------------------------------------------------- - /** Read MCP3201 12-bit ADC - * \return 16-bit value read. - */ - inline __attribute__((always_inline)) - uint16_t read() { - fastDigitalWrite(CsPin, 0); - // Start sample. - mcpAdcDummy(3); - // Extra sample time. - if (UsecDelay){ - delayMicroseconds(UsecDelay); - } - // End sample. - mcpAdcDummy(3); - // Null bit. - mcpAdcDummy(3); - uint16_t v = 0; - readBit(v, 11); - readBit(v, 10); - readBit(v, 9); - readBit(v, 8); - readBit(v, 7); - readBit(v, 6); - readBit(v, 5); - readBit(v, 4); - readBit(v, 3); - readBit(v, 2); - readBit(v, 1); - readBit(v, 0); - fastDigitalWrite(CsPin, 1); - return v; - } - private: - //---------------------------------------------------------------------------- - /** delay n nops - * \param[in] n nops to delay, must be a constant so compiler optimizes if(). - */ - inline __attribute__((always_inline)) - void delayCycles(uint8_t n) { - if (n & 1) asm volatile("nop\n\t"); - if (n & 2) asm volatile("nop\n\t" "nop\n\t"); - if (n & 4) asm volatile("nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t"); - } - //---------------------------------------------------------------------------- - /** clock for don't care bits - *\param[in] delayBefore if true, delay before raising clock*/ - inline __attribute__((always_inline)) - void mcpAdcDummy(uint8_t delayBefore) { - delayCycles(delayBefore); - fastDigitalWrite(ClkPin, 1); - delayCycles(3); - fastDigitalWrite(ClkPin, 0); - } - //---------------------------------------------------------------------------- - inline __attribute__((always_inline)) - void readBit(uint16_t &v, uint8_t b, uint8_t delayRead = 2) { - delayCycles(3); - fastDigitalWrite(ClkPin, 1); - delayCycles(delayRead); - if (fastDigitalRead(DoutPin)) v |= (1 << b); - fastDigitalWrite(ClkPin, 0); - } +class MCP3201 +{ +public: + //---------------------------------------------------------------------------- + /** Set pin modes and initial levels. */ + void begin() + { + fastPinMode(ClkPin, 1); + fastDigitalWrite(ClkPin, 0); + fastPinMode(CsPin, 1); + fastDigitalWrite(CsPin, 1); + fastPinMode(DoutPin, 0); + } + //---------------------------------------------------------------------------- + /** Read MCP3201 12-bit ADC + * \return 16-bit value read. + */ + inline __attribute__((always_inline)) + uint16_t read() + { + fastDigitalWrite(CsPin, 0); + // Start sample. + mcpAdcDummy(3); + // Extra sample time. + if (UsecDelay) { + delayMicroseconds(UsecDelay); + } + // End sample. + mcpAdcDummy(3); + // Null bit. + mcpAdcDummy(3); + uint16_t v = 0; + readBit(v, 11); + readBit(v, 10); + readBit(v, 9); + readBit(v, 8); + readBit(v, 7); + readBit(v, 6); + readBit(v, 5); + readBit(v, 4); + readBit(v, 3); + readBit(v, 2); + readBit(v, 1); + readBit(v, 0); + fastDigitalWrite(CsPin, 1); + return v; + } +private: + //---------------------------------------------------------------------------- + /** delay n nops + * \param[in] n nops to delay, must be a constant so compiler optimizes if(). + */ + inline __attribute__((always_inline)) + void delayCycles(uint8_t n) + { + if (n & 1) { + asm volatile("nop\n\t"); + } + if (n & 2) { + asm volatile("nop\n\t" "nop\n\t"); + } + if (n & 4) { + asm volatile("nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t"); + } + } + //---------------------------------------------------------------------------- + /** clock for don't care bits + *\param[in] delayBefore if true, delay before raising clock*/ + inline __attribute__((always_inline)) + void mcpAdcDummy(uint8_t delayBefore) + { + delayCycles(delayBefore); + fastDigitalWrite(ClkPin, 1); + delayCycles(3); + fastDigitalWrite(ClkPin, 0); + } + //---------------------------------------------------------------------------- + inline __attribute__((always_inline)) + void readBit(uint16_t &v, uint8_t b, uint8_t delayRead = 2) + { + delayCycles(3); + fastDigitalWrite(ClkPin, 1); + delayCycles(delayRead); + if (fastDigitalRead(DoutPin)) { + v |= (1 << b); + } + fastDigitalWrite(ClkPin, 0); + } }; //============================================================================== template /** MCP3202 class */ -class MCP3202 { - public: - //---------------------------------------------------------------------------- - /** Set pin modes and initial levels. */ - void begin() { - fastPinMode(ClkPin, 1); - fastDigitalWrite(ClkPin, 0); - fastPinMode(CsPin, 1); - fastDigitalWrite(CsPin, 1); - fastPinMode(DoutPin, 0); - fastPinMode(DinPin, 1); - } - //---------------------------------------------------------------------------- - /** Read MCP3202 12-bit ADC - * \return 16-bit value read. - */ - inline __attribute__((always_inline)) - uint16_t read(uint8_t config) { - uint16_t v = 0; - fastDigitalWrite(CsPin, 0); - // Start bit. - writeBit(true); - // Mode bit. - writeBit(config & 2); - // Channel Selection and start sample. - writeBit(config & 1); - // Extra sample time. - if (UsecDelay){ - delayMicroseconds(UsecDelay); - } - // MSB first format and end sample. - writeBit(true); - // Null bit. - writeBit(true); - // Data bits. - readBit(v, 11); - readBit(v, 10); - readBit(v, 9); - readBit(v, 8); - readBit(v, 7); - readBit(v, 6); - readBit(v, 5); - readBit(v, 4); - readBit(v, 3); - readBit(v, 2); - readBit(v, 1); - readBit(v, 0); - fastDigitalWrite(CsPin, 1); - return v; - } - private: - //---------------------------------------------------------------------------- - /** delay n nops - * \param[in] n nops to delay, must be a constant so compiler optimizes if(). - */ - inline __attribute__((always_inline)) - void delayCycles(uint8_t n) { - if (n & 1) asm volatile("nop\n\t"); - if (n & 2) asm volatile("nop\n\t" "nop\n\t"); - if (n & 4) asm volatile("nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t"); - } - //---------------------------------------------------------------------------- - /** clock for don't care bits - *\param[in] delayBefore if true, delay before raising clock*/ - inline __attribute__((always_inline)) - void writeBit(bool value) { - fastDigitalWrite(DinPin, value); - fastDigitalWrite(ClkPin, 1); - delayCycles(2); - fastDigitalWrite(ClkPin, 0); - } - //---------------------------------------------------------------------------- - inline __attribute__((always_inline)) - void readBit(uint16_t &v, uint8_t b, uint8_t delayRead = 1) { - delayCycles(2); - fastDigitalWrite(ClkPin, 1); - delayCycles(delayRead); - if (fastDigitalRead(DoutPin)) v |= (1 << b); - fastDigitalWrite(ClkPin, 0); - } +class MCP3202 +{ +public: + //---------------------------------------------------------------------------- + /** Set pin modes and initial levels. */ + void begin() + { + fastPinMode(ClkPin, 1); + fastDigitalWrite(ClkPin, 0); + fastPinMode(CsPin, 1); + fastDigitalWrite(CsPin, 1); + fastPinMode(DoutPin, 0); + fastPinMode(DinPin, 1); + } + //---------------------------------------------------------------------------- + /** Read MCP3202 12-bit ADC + * \return 16-bit value read. + */ + inline __attribute__((always_inline)) + uint16_t read(uint8_t config) + { + uint16_t v = 0; + fastDigitalWrite(CsPin, 0); + // Start bit. + writeBit(true); + // Mode bit. + writeBit(config & 2); + // Channel Selection and start sample. + writeBit(config & 1); + // Extra sample time. + if (UsecDelay) { + delayMicroseconds(UsecDelay); + } + // MSB first format and end sample. + writeBit(true); + // Null bit. + writeBit(true); + // Data bits. + readBit(v, 11); + readBit(v, 10); + readBit(v, 9); + readBit(v, 8); + readBit(v, 7); + readBit(v, 6); + readBit(v, 5); + readBit(v, 4); + readBit(v, 3); + readBit(v, 2); + readBit(v, 1); + readBit(v, 0); + fastDigitalWrite(CsPin, 1); + return v; + } +private: + //---------------------------------------------------------------------------- + /** delay n nops + * \param[in] n nops to delay, must be a constant so compiler optimizes if(). + */ + inline __attribute__((always_inline)) + void delayCycles(uint8_t n) + { + if (n & 1) { + asm volatile("nop\n\t"); + } + if (n & 2) { + asm volatile("nop\n\t" "nop\n\t"); + } + if (n & 4) { + asm volatile("nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t"); + } + } + //---------------------------------------------------------------------------- + /** clock for don't care bits + *\param[in] delayBefore if true, delay before raising clock*/ + inline __attribute__((always_inline)) + void writeBit(bool value) + { + fastDigitalWrite(DinPin, value); + fastDigitalWrite(ClkPin, 1); + delayCycles(2); + fastDigitalWrite(ClkPin, 0); + } + //---------------------------------------------------------------------------- + inline __attribute__((always_inline)) + void readBit(uint16_t &v, uint8_t b, uint8_t delayRead = 1) + { + delayCycles(2); + fastDigitalWrite(ClkPin, 1); + delayCycles(delayRead); + if (fastDigitalRead(DoutPin)) { + v |= (1 << b); + } + fastDigitalWrite(ClkPin, 0); + } }; //============================================================================== template /** MCP3204 class */ -class MCP3204 { - public: - //---------------------------------------------------------------------------- - /** Set pin modes and initial levels. */ - void begin() { - fastPinMode(ClkPin, 1); - fastDigitalWrite(ClkPin, 0); - fastPinMode(CsPin, 1); - fastDigitalWrite(CsPin, 1); - fastPinMode(DoutPin, 0); - fastPinMode(DinPin, 1); - } - //---------------------------------------------------------------------------- - /** Read MCP3204 12-bit ADC - * \return 16-bit value read. - */ - inline __attribute__((always_inline)) - uint16_t read(uint8_t config) { - uint16_t v = 0; - fastDigitalWrite(CsPin, 0); - // Start bit. - writeBit(true); - // Mode bit. - writeBit(config & 8); - // D2 channel bit. - writeBit(config & 4); - // D1 channel bit. - writeBit(config & 2); - // D0 channel bit and start sample. - writeBit(config & 1); - // Extra sample time. - if (UsecDelay){ - delayMicroseconds(UsecDelay); - } - // End sample cycle. - writeBit(true); - // Null bit. - writeBit(true); - // Data bits. - readBit(v, 11); - readBit(v, 10); - readBit(v, 9); - readBit(v, 8); - readBit(v, 7); - readBit(v, 6); - readBit(v, 5); - readBit(v, 4); - readBit(v, 3); - readBit(v, 2); - readBit(v, 1); - readBit(v, 0); - fastDigitalWrite(CsPin, 1); - return v; - } - private: - //---------------------------------------------------------------------------- - /** delay n nops - * \param[in] n nops to delay, must be a constant so compiler optimizes if(). - */ - inline __attribute__((always_inline)) - void delayCycles(uint8_t n) { - if (n & 1) asm volatile("nop\n\t"); - if (n & 2) asm volatile("nop\n\t" "nop\n\t"); - if (n & 4) asm volatile("nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t"); - } - //---------------------------------------------------------------------------- - /** clock for don't care bits - *\param[in] delayBefore if true, delay before raising clock*/ - inline __attribute__((always_inline)) - void writeBit(bool value) { - fastDigitalWrite(DinPin, value); - fastDigitalWrite(ClkPin, 1); - delayCycles(2); - fastDigitalWrite(ClkPin, 0); - } - //---------------------------------------------------------------------------- - inline __attribute__((always_inline)) - void readBit(uint16_t &v, uint8_t b, uint8_t delayRead = 1) { - delayCycles(2); - fastDigitalWrite(ClkPin, 1); - delayCycles(delayRead); - if (fastDigitalRead(DoutPin)) v |= (1 << b); - fastDigitalWrite(ClkPin, 0); - } +class MCP3204 +{ +public: + //---------------------------------------------------------------------------- + /** Set pin modes and initial levels. */ + void begin() + { + fastPinMode(ClkPin, 1); + fastDigitalWrite(ClkPin, 0); + fastPinMode(CsPin, 1); + fastDigitalWrite(CsPin, 1); + fastPinMode(DoutPin, 0); + fastPinMode(DinPin, 1); + } + //---------------------------------------------------------------------------- + /** Read MCP3204 12-bit ADC + * \return 16-bit value read. + */ + inline __attribute__((always_inline)) + uint16_t read(uint8_t config) + { + uint16_t v = 0; + fastDigitalWrite(CsPin, 0); + // Start bit. + writeBit(true); + // Mode bit. + writeBit(config & 8); + // D2 channel bit. + writeBit(config & 4); + // D1 channel bit. + writeBit(config & 2); + // D0 channel bit and start sample. + writeBit(config & 1); + // Extra sample time. + if (UsecDelay) { + delayMicroseconds(UsecDelay); + } + // End sample cycle. + writeBit(true); + // Null bit. + writeBit(true); + // Data bits. + readBit(v, 11); + readBit(v, 10); + readBit(v, 9); + readBit(v, 8); + readBit(v, 7); + readBit(v, 6); + readBit(v, 5); + readBit(v, 4); + readBit(v, 3); + readBit(v, 2); + readBit(v, 1); + readBit(v, 0); + fastDigitalWrite(CsPin, 1); + return v; + } +private: + //---------------------------------------------------------------------------- + /** delay n nops + * \param[in] n nops to delay, must be a constant so compiler optimizes if(). + */ + inline __attribute__((always_inline)) + void delayCycles(uint8_t n) + { + if (n & 1) { + asm volatile("nop\n\t"); + } + if (n & 2) { + asm volatile("nop\n\t" "nop\n\t"); + } + if (n & 4) { + asm volatile("nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t"); + } + } + //---------------------------------------------------------------------------- + /** clock for don't care bits + *\param[in] delayBefore if true, delay before raising clock*/ + inline __attribute__((always_inline)) + void writeBit(bool value) + { + fastDigitalWrite(DinPin, value); + fastDigitalWrite(ClkPin, 1); + delayCycles(2); + fastDigitalWrite(ClkPin, 0); + } + //---------------------------------------------------------------------------- + inline __attribute__((always_inline)) + void readBit(uint16_t &v, uint8_t b, uint8_t delayRead = 1) + { + delayCycles(2); + fastDigitalWrite(ClkPin, 1); + delayCycles(delayRead); + if (fastDigitalRead(DoutPin)) { + v |= (1 << b); + } + fastDigitalWrite(ClkPin, 0); + } }; //============================================================================== // MCP3204 and MCP3208 use the same code. template -class MCP3208 : public MCP3204 { +class MCP3208 : public MCP3204 +{ }; #endif // MCP320X_h \ No newline at end of file diff --git a/drivers/AVR/DigitalIO/attic/MCP355X.h b/drivers/AVR/DigitalIO/attic/MCP355X.h index daa29118c..fb66d4a47 100644 --- a/drivers/AVR/DigitalIO/attic/MCP355X.h +++ b/drivers/AVR/DigitalIO/attic/MCP355X.h @@ -9,119 +9,145 @@ const uint8_t MCP355X_TO_MS = 100; //============================================================================== template /** MCP355X class */ -class MCP355X { - public: - //---------------------------------------------------------------------------- - /** Set pin modes and initial levels. */ - void begin(bool singleMode = true) { - m_singleMode = singleMode; - fastPinMode(SdoPin, 0); - fastPinMode(SckPin, 1); - fastDigitalWrite(SckPin, 1); - fastPinMode(CsPin, 1); - fastDigitalWrite(CsPin, 1); - if (!m_singleMode) { - // Wait for conversion to complete. - delay(100); - // Start continuous conversion mode. - fastDigitalWrite(CsPin, 0); - } - } - //---------------------------------------------------------------------------- - /** Read MCP355X 22-bit ADC - * \return 22-bit value. - */ - inline __attribute__((always_inline)) - int32_t read() { - uint8_t t = 0; - uint8_t v3 = 0; - if (m_singleMode) { - // Start conversion. - fastDigitalWrite(CsPin, 0); - // Delay at least 10 usec to avoid RDY glitch on exit from Shutdown. - delay(1); - // Toggle CsPin to indicate single conversion mode. - fastDigitalWrite(CsPin, 1); - // Wait for conversion to complete. - while (1) { - delay(1); - fastDigitalWrite(CsPin, 0); - // Delay while RDY settles. - delayCycles(4); - if (!fastDigitalRead(SdoPin)) break; - fastDigitalWrite(CsPin, 1); - if (t++ > MCP355X_TO_MS) return MCP355X_ERR; - } - } else { - while (1) { - if (!fastDigitalRead(SdoPin)) break; - delay(1); - if (t++ > MCP355X_TO_MS) return MCP355X_ERR; - } - } - uint8_t v2 = readByte(); - uint8_t v1 = readByte(); - uint8_t v0 = readByte(); - - // The 25th falling edge of SCK changes SDO/RDY from Data mode to RDY mode. - uint8_t dummy = 0; - readBit(dummy, 0); +class MCP355X +{ +public: + //---------------------------------------------------------------------------- + /** Set pin modes and initial levels. */ + void begin(bool singleMode = true) + { + m_singleMode = singleMode; + fastPinMode(SdoPin, 0); + fastPinMode(SckPin, 1); + fastDigitalWrite(SckPin, 1); + fastPinMode(CsPin, 1); + fastDigitalWrite(CsPin, 1); + if (!m_singleMode) { + // Wait for conversion to complete. + delay(100); + // Start continuous conversion mode. + fastDigitalWrite(CsPin, 0); + } + } + //---------------------------------------------------------------------------- + /** Read MCP355X 22-bit ADC + * \return 22-bit value. + */ + inline __attribute__((always_inline)) + int32_t read() + { + uint8_t t = 0; + uint8_t v3 = 0; + if (m_singleMode) { + // Start conversion. + fastDigitalWrite(CsPin, 0); + // Delay at least 10 usec to avoid RDY glitch on exit from Shutdown. + delay(1); + // Toggle CsPin to indicate single conversion mode. + fastDigitalWrite(CsPin, 1); + // Wait for conversion to complete. + while (1) { + delay(1); + fastDigitalWrite(CsPin, 0); + // Delay while RDY settles. + delayCycles(4); + if (!fastDigitalRead(SdoPin)) { + break; + } + fastDigitalWrite(CsPin, 1); + if (t++ > MCP355X_TO_MS) { + return MCP355X_ERR; + } + } + } else { + while (1) { + if (!fastDigitalRead(SdoPin)) { + break; + } + delay(1); + if (t++ > MCP355X_TO_MS) { + return MCP355X_ERR; + } + } + } + uint8_t v2 = readByte(); + uint8_t v1 = readByte(); + uint8_t v0 = readByte(); - if (m_singleMode) { - fastDigitalWrite(CsPin, 1); - } - if ((v2 & 0XE0) == 0X20) { - // Negative in range so extend sign bit. - v2 |= 0XC0; - v3 = 0XFF; - } else if (v2 & 0X40) { - // Overflow high. Cause value to be >= MCP355X_OVH. - if (v2 & 0X20) v2 &= 0X3F; - } else if (v2 & 0X80) { - // Overflow low. Cause value to be <= MCP355X_OVH. - if ((v2 & 0X20) == 0) v2 |= 0X40; - v3 = 0XFF; - } - uint16_t v_high = (v3 << 8) | v2; - uint16_t v_low = (v1 << 8) | v0; - return ((uint32_t)v_high << 16) | v_low; - } - private: - //---------------------------------------------------------------------------- - /** delay n nops - * \param[in] n nops to delay, must be a constant so compiler optimizes if(). - */ - inline __attribute__((always_inline)) - void delayCycles(uint8_t n) { - if (n & 1) asm volatile("nop\n\t"); - if (n & 2) asm volatile("nop\n\t" "nop\n\t"); - if (n & 4) asm volatile("nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t"); - } - //---------------------------------------------------------------------------- - // Default delay yields about 2 MHz clock. - inline __attribute__((always_inline)) - void readBit(uint8_t &v, uint8_t b, uint8_t delayRead = 0) { - fastDigitalWrite(SckPin, 0); - delayCycles(2 + delayRead); - fastDigitalWrite(SckPin, 1); - if (fastDigitalRead(SdoPin)) v |= (1 << b); - delayCycles(delayRead); - } - //---------------------------------------------------------------------------- - inline __attribute__((always_inline)) - uint8_t readByte() { - uint8_t v = 0; - readBit(v, 7); - readBit(v, 6); - readBit(v, 5); - readBit(v, 4); - readBit(v, 3); - readBit(v, 2); - readBit(v, 1); - readBit(v, 0); - return v; - } - //---------------------------------------------------------------------------- - bool m_singleMode; + // The 25th falling edge of SCK changes SDO/RDY from Data mode to RDY mode. + uint8_t dummy = 0; + readBit(dummy, 0); + + if (m_singleMode) { + fastDigitalWrite(CsPin, 1); + } + if ((v2 & 0XE0) == 0X20) { + // Negative in range so extend sign bit. + v2 |= 0XC0; + v3 = 0XFF; + } else if (v2 & 0X40) { + // Overflow high. Cause value to be >= MCP355X_OVH. + if (v2 & 0X20) { + v2 &= 0X3F; + } + } else if (v2 & 0X80) { + // Overflow low. Cause value to be <= MCP355X_OVH. + if ((v2 & 0X20) == 0) { + v2 |= 0X40; + } + v3 = 0XFF; + } + uint16_t v_high = (v3 << 8) | v2; + uint16_t v_low = (v1 << 8) | v0; + return ((uint32_t)v_high << 16) | v_low; + } +private: + //---------------------------------------------------------------------------- + /** delay n nops + * \param[in] n nops to delay, must be a constant so compiler optimizes if(). + */ + inline __attribute__((always_inline)) + void delayCycles(uint8_t n) + { + if (n & 1) { + asm volatile("nop\n\t"); + } + if (n & 2) { + asm volatile("nop\n\t" "nop\n\t"); + } + if (n & 4) { + asm volatile("nop\n\t" "nop\n\t" "nop\n\t" "nop\n\t"); + } + } + //---------------------------------------------------------------------------- + // Default delay yields about 2 MHz clock. + inline __attribute__((always_inline)) + void readBit(uint8_t &v, uint8_t b, uint8_t delayRead = 0) + { + fastDigitalWrite(SckPin, 0); + delayCycles(2 + delayRead); + fastDigitalWrite(SckPin, 1); + if (fastDigitalRead(SdoPin)) { + v |= (1 << b); + } + delayCycles(delayRead); + } + //---------------------------------------------------------------------------- + inline __attribute__((always_inline)) + uint8_t readByte() + { + uint8_t v = 0; + readBit(v, 7); + readBit(v, 6); + readBit(v, 5); + readBit(v, 4); + readBit(v, 3); + readBit(v, 2); + readBit(v, 1); + readBit(v, 0); + return v; + } + //---------------------------------------------------------------------------- + bool m_singleMode; }; #endif // MCP355X_h \ No newline at end of file diff --git a/drivers/AVR/DigitalIO/examples/DigitalPinBlink/DigitalPinBlink.ino b/drivers/AVR/DigitalIO/examples/DigitalPinBlink/DigitalPinBlink.ino index 4a698baff..d8fd19f30 100644 --- a/drivers/AVR/DigitalIO/examples/DigitalPinBlink/DigitalPinBlink.ino +++ b/drivers/AVR/DigitalIO/examples/DigitalPinBlink/DigitalPinBlink.ino @@ -4,9 +4,10 @@ DigitalPin<13> pin13(OUTPUT); void setup() {} -void loop() { - // toggle is a two byte instruction that executes - // in two cycles or 125 ns on a 16 MHz CPU - pin13.toggle(); - delay(250); +void loop() +{ + // toggle is a two byte instruction that executes + // in two cycles or 125 ns on a 16 MHz CPU + pin13.toggle(); + delay(250); } \ No newline at end of file diff --git a/drivers/AVR/DigitalIO/examples/DigitalPinConfigToggle/DigitalPinConfigToggle.ino b/drivers/AVR/DigitalIO/examples/DigitalPinConfigToggle/DigitalPinConfigToggle.ino index 06ad860da..78a75c989 100644 --- a/drivers/AVR/DigitalIO/examples/DigitalPinConfigToggle/DigitalPinConfigToggle.ino +++ b/drivers/AVR/DigitalIO/examples/DigitalPinConfigToggle/DigitalPinConfigToggle.ino @@ -4,15 +4,17 @@ // Class with compile time pin number. DigitalPin<13> pin13; -void setup() { - // Set mode to OUTPUT and level LOW. - pin13.config(OUTPUT, LOW); +void setup() +{ + // Set mode to OUTPUT and level LOW. + pin13.config(OUTPUT, LOW); } -void loop() { - // toggle is a two byte instruction that executes - // in two cycles or 125 ns on a 16 MHz CPU - pin13.toggle(); - delay(100); - pin13.toggle(); - delay(400); +void loop() +{ + // toggle is a two byte instruction that executes + // in two cycles or 125 ns on a 16 MHz CPU + pin13.toggle(); + delay(100); + pin13.toggle(); + delay(400); } \ No newline at end of file diff --git a/drivers/AVR/DigitalIO/examples/DigitalPinReadWrite/DigitalPinReadWrite.ino b/drivers/AVR/DigitalIO/examples/DigitalPinReadWrite/DigitalPinReadWrite.ino index 57be1fad9..09fb8d2ea 100644 --- a/drivers/AVR/DigitalIO/examples/DigitalPinReadWrite/DigitalPinReadWrite.ino +++ b/drivers/AVR/DigitalIO/examples/DigitalPinReadWrite/DigitalPinReadWrite.ino @@ -6,6 +6,7 @@ DigitalPin<13> pin13(OUTPUT); void setup() {} -void loop() { - pin13 = pin12; +void loop() +{ + pin13 = pin12; } \ No newline at end of file diff --git a/drivers/AVR/DigitalIO/examples/DigitalPinShiftOut/DigitalPinShiftOut.ino b/drivers/AVR/DigitalIO/examples/DigitalPinShiftOut/DigitalPinShiftOut.ino index 98682bb84..6a31ee6eb 100644 --- a/drivers/AVR/DigitalIO/examples/DigitalPinShiftOut/DigitalPinShiftOut.ino +++ b/drivers/AVR/DigitalIO/examples/DigitalPinShiftOut/DigitalPinShiftOut.ino @@ -10,30 +10,34 @@ DigitalPin<13> dataPin(OUTPUT, HIGH); //------------------------------------------------------------------------------ // Time to send one bit is ten cycles or 625 ns for 16 MHz CPU. inline __attribute__((always_inline)) -void sendBit(uint8_t bit, uint8_t data) { - dataPin = data & (1 << bit); - clockPin = 1; - // may want a nop here - clock pulse is 125 ns wide - clockPin = 0; +void sendBit(uint8_t bit, uint8_t data) +{ + dataPin = data & (1 << bit); + clockPin = 1; + // may want a nop here - clock pulse is 125 ns wide + clockPin = 0; } //------------------------------------------------------------------------------ // Time to send one byte is 5 usec. -void shiftOut(uint8_t bits) { - sendBit(7, bits); - sendBit(6, bits); - sendBit(5, bits); - sendBit(4, bits); - sendBit(3, bits); - sendBit(2, bits); - sendBit(1, bits); - sendBit(0, bits); +void shiftOut(uint8_t bits) +{ + sendBit(7, bits); + sendBit(6, bits); + sendBit(5, bits); + sendBit(4, bits); + sendBit(3, bits); + sendBit(2, bits); + sendBit(1, bits); + sendBit(0, bits); } //------------------------------------------------------------------------------ -void setup() { - // Not used. +void setup() +{ + // Not used. } //------------------------------------------------------------------------------ -void loop() { - shiftOut(0X55); - delay(2); +void loop() +{ + shiftOut(0X55); + delay(2); } diff --git a/drivers/AVR/DigitalIO/examples/PinIOBegin/PinIOBegin.ino b/drivers/AVR/DigitalIO/examples/PinIOBegin/PinIOBegin.ino index 5f7e12432..0ddcb1e05 100644 --- a/drivers/AVR/DigitalIO/examples/PinIOBegin/PinIOBegin.ino +++ b/drivers/AVR/DigitalIO/examples/PinIOBegin/PinIOBegin.ino @@ -6,19 +6,21 @@ PinIO readPin; PinIO writePin; //------------------------------------------------------------------------------ -void setup() { - // Assign pin 12 to readPin. - readPin.begin(12); - - // input mode with pull-ups disabled - readPin.config(INPUT, LOW); +void setup() +{ + // Assign pin 12 to readPin. + readPin.begin(12); - // Assign pin 13 to writePin and set mode to output. - writePin.begin(13); - writePin.mode(OUTPUT); + // input mode with pull-ups disabled + readPin.config(INPUT, LOW); + + // Assign pin 13 to writePin and set mode to output. + writePin.begin(13); + writePin.mode(OUTPUT); } //------------------------------------------------------------------------------ -void loop() { - // Copy the value read from readPin to writePin. - writePin.write(readPin.read()); +void loop() +{ + // Copy the value read from readPin to writePin. + writePin.write(readPin.read()); } \ No newline at end of file diff --git a/drivers/AVR/DigitalIO/examples/PinIOConfigToggle/PinIOConfigToggle.ino b/drivers/AVR/DigitalIO/examples/PinIOConfigToggle/PinIOConfigToggle.ino index 3bf3e0096..b9b981845 100644 --- a/drivers/AVR/DigitalIO/examples/PinIOConfigToggle/PinIOConfigToggle.ino +++ b/drivers/AVR/DigitalIO/examples/PinIOConfigToggle/PinIOConfigToggle.ino @@ -4,13 +4,15 @@ // Set runtime pin number. PinIO pin13(13); -void setup() { - // set mode to OUTPUT and level LOW - pin13.config(OUTPUT, LOW); +void setup() +{ + // set mode to OUTPUT and level LOW + pin13.config(OUTPUT, LOW); } -void loop() { - pin13.toggle(); - delay(100); - pin13.toggle(); - delay(400); +void loop() +{ + pin13.toggle(); + delay(100); + pin13.toggle(); + delay(400); } \ No newline at end of file diff --git a/drivers/AVR/DigitalIO/examples/PinIOReadWrite/PinIOReadWrite.ino b/drivers/AVR/DigitalIO/examples/PinIOReadWrite/PinIOReadWrite.ino index 8b225d5e0..3019a05a4 100644 --- a/drivers/AVR/DigitalIO/examples/PinIOReadWrite/PinIOReadWrite.ino +++ b/drivers/AVR/DigitalIO/examples/PinIOReadWrite/PinIOReadWrite.ino @@ -4,13 +4,15 @@ PinIO readPin(12); PinIO writePin(13); -void setup() { - // Set input mode and disable pull-up. - readPin.config(INPUT, LOW); +void setup() +{ + // Set input mode and disable pull-up. + readPin.config(INPUT, LOW); - // set output mode - writePin.mode(OUTPUT); + // set output mode + writePin.mode(OUTPUT); } -void loop() { - writePin.write(readPin.read()); +void loop() +{ + writePin.write(readPin.read()); } \ No newline at end of file diff --git a/drivers/AVR/DigitalIO/examples/ScanI2cBus/ScanI2cBus.ino b/drivers/AVR/DigitalIO/examples/ScanI2cBus/ScanI2cBus.ino index 6132a3f67..18e5b6e11 100644 --- a/drivers/AVR/DigitalIO/examples/ScanI2cBus/ScanI2cBus.ino +++ b/drivers/AVR/DigitalIO/examples/ScanI2cBus/ScanI2cBus.ino @@ -26,52 +26,59 @@ const uint8_t SCL_PIN = A5; SoftI2cMaster i2c(SCL_PIN, SDA_PIN); //FastI2cMaster i2c; //------------------------------------------------------------------------------ -void setup() { +void setup() +{ - Serial.begin(9600); - while (!Serial); - - if (!digitalRead(SDA_PIN) && !digitalRead(SCL_PIN)) { - Serial.println("External pull-up resistors appear to be missing."); - Serial.println("Many false responses may be detected."); - Serial.println("Type any character to continue."); + Serial.begin(9600); + while (!Serial); - while (!Serial.available()); - Serial.println(); + if (!digitalRead(SDA_PIN) && !digitalRead(SCL_PIN)) { + Serial.println("External pull-up resistors appear to be missing."); + Serial.println("Many false responses may be detected."); + Serial.println("Type any character to continue."); - } - uint8_t add = 0; - bool found = false; - do { - bool wr = i2c.transfer(add | I2C_WRITE, 0, 0); - bool rd = i2c.transfer(add | I2C_READ, 0, 0, I2C_CONTINUE); - if (rd) { - uint8_t dummy; - // Must read byte, send NACK, and issue STOP. - i2c.transferContinue(&dummy, 1); - } - if (rd || wr) { - found = true; - Serial.print("Device at address: 0X"); - Serial.print(add, HEX); - Serial.print(" responds to "); - if (rd) Serial.print("Read"); - if (rd && wr) Serial.print(" and "); - if (wr) Serial.print("Write"); - Serial.println('.'); - } - add += 2; - } - while (add); + while (!Serial.available()); + Serial.println(); - if (!found) { - Serial.println("No devices found."); - } - Serial.println("Done"); + } + uint8_t add = 0; + bool found = false; + do { + bool wr = i2c.transfer(add | I2C_WRITE, 0, 0); + bool rd = i2c.transfer(add | I2C_READ, 0, 0, I2C_CONTINUE); + if (rd) { + uint8_t dummy; + // Must read byte, send NACK, and issue STOP. + i2c.transferContinue(&dummy, 1); + } + if (rd || wr) { + found = true; + Serial.print("Device at address: 0X"); + Serial.print(add, HEX); + Serial.print(" responds to "); + if (rd) { + Serial.print("Read"); + } + if (rd && wr) { + Serial.print(" and "); + } + if (wr) { + Serial.print("Write"); + } + Serial.println('.'); + } + add += 2; + } while (add); + + if (!found) { + Serial.println("No devices found."); + } + Serial.println("Done"); } //------------------------------------------------------------------------------ -void loop() { - // Not used. +void loop() +{ + // Not used. } diff --git a/drivers/AVR/DigitalIO/examples/SoftDS1307Utility/SoftDS1307Utility.ino b/drivers/AVR/DigitalIO/examples/SoftDS1307Utility/SoftDS1307Utility.ino index 3747b9675..aecb9e96c 100644 --- a/drivers/AVR/DigitalIO/examples/SoftDS1307Utility/SoftDS1307Utility.ino +++ b/drivers/AVR/DigitalIO/examples/SoftDS1307Utility/SoftDS1307Utility.ino @@ -16,30 +16,35 @@ FastI2cMaster rtc; /* * Read 'count' bytes from the DS1307 starting at 'address'. */ -uint8_t readDS1307(uint8_t address, uint8_t *buf, uint8_t count) { +uint8_t readDS1307(uint8_t address, uint8_t *buf, uint8_t count) +{ - // Send address of data. - if (!rtc.transfer(DS1307ADDR | I2C_WRITE, &address, 1)) return false; + // Send address of data. + if (!rtc.transfer(DS1307ADDR | I2C_WRITE, &address, 1)) { + return false; + } - // Read data. - return rtc.transfer(DS1307ADDR | I2C_READ, buf, count); + // Read data. + return rtc.transfer(DS1307ADDR | I2C_READ, buf, count); } //------------------------------------------------------------------------------ /* * write 'count' bytes to DS1307 starting at 'address'. */ -uint8_t writeDS1307(uint8_t address, uint8_t *buf, uint8_t count) { +uint8_t writeDS1307(uint8_t address, uint8_t *buf, uint8_t count) +{ - // Write address and continue transfer for write of data. - if (!rtc.transfer(DS1307ADDR | I2C_WRITE, &address, 1, I2C_CONTINUE)) { - return false; - } - // Write data. - return rtc.transferContinue(buf, count); + // Write address and continue transfer for write of data. + if (!rtc.transfer(DS1307ADDR | I2C_WRITE, &address, 1, I2C_CONTINUE)) { + return false; + } + // Write data. + return rtc.transferContinue(buf, count); } //------------------------------------------------------------------------------ -void setup(void) { - Serial.begin(9600); +void setup(void) +{ + Serial.begin(9600); } //------------------------------------------------------------------------------ /** Store and print a string in flash memory.*/ @@ -50,134 +55,142 @@ void setup(void) { // Day of week U.S. convention. char *Ddd[] = {"Bad", "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; //------------------------------------------------------------------------------ -void hexPrint(uint8_t v) { - Serial.print(v >> 4, HEX); - Serial.print(v & 0XF, HEX); +void hexPrint(uint8_t v) +{ + Serial.print(v >> 4, HEX); + Serial.print(v & 0XF, HEX); } //------------------------------------------------------------------------------ -void hexPrintln(uint8_t v) { - hexPrint(v); - Serial.println(); +void hexPrintln(uint8_t v) +{ + hexPrint(v); + Serial.println(); } //------------------------------------------------------------------------------ // read hex input -uint8_t hexRead(uint16_t* v) { - bool valid = false; - uint16_t n = 0; - while (!Serial.available()); - while (Serial.available()) { - uint8_t c = Serial.read(); - // Exit if end-of-line. - if (c == '\n' || c == '\r') { - delay(10); - // If CR/LF. - Serial.read(); - break; - } - n <<= 4; - if ('a' <= c && c <= 'f') { - n += c - ('a' - 10); - } - else if ('A' <= c && c <= 'F') { - n += c - ('A' - 10); - } - else if ('0' <= c && c <= '9') { - n += c - '0'; - } - else { - valid = false; - break; - } - delay(10); - valid = true; - } - if (!valid) { - PgmPrintln("Invalid entry"); - return false; - } - *v = n; - return true; +uint8_t hexRead(uint16_t* v) +{ + bool valid = false; + uint16_t n = 0; + while (!Serial.available()); + while (Serial.available()) { + uint8_t c = Serial.read(); + // Exit if end-of-line. + if (c == '\n' || c == '\r') { + delay(10); + // If CR/LF. + Serial.read(); + break; + } + n <<= 4; + if ('a' <= c && c <= 'f') { + n += c - ('a' - 10); + } else if ('A' <= c && c <= 'F') { + n += c - ('A' - 10); + } else if ('0' <= c && c <= '9') { + n += c - '0'; + } else { + valid = false; + break; + } + delay(10); + valid = true; + } + if (!valid) { + PgmPrintln("Invalid entry"); + return false; + } + *v = n; + return true; } //------------------------------------------------------------------------------ -uint8_t bcdRead(uint8_t min, uint8_t max, uint8_t* n) { - uint16_t v; - if (!hexRead(&v)) return false; - uint8_t d = 10 * (v >> 4) + (v & 0XF); - if ((v >> 4) > 9 || (v & 0XF) > 9 || d < min || d > max) { - PgmPrintln("Invalid"); - return false; - } - *n = v; - return true; +uint8_t bcdRead(uint8_t min, uint8_t max, uint8_t* n) +{ + uint16_t v; + if (!hexRead(&v)) { + return false; + } + uint8_t d = 10 * (v >> 4) + (v & 0XF); + if ((v >> 4) > 9 || (v & 0XF) > 9 || d < min || d > max) { + PgmPrintln("Invalid"); + return false; + } + *n = v; + return true; } //------------------------------------------------------------------------------ -void displayTime(void) { - uint8_t r[8]; - if (!readDS1307(0, r, 8)) { - PgmPrintln("Read Failed for display time"); - return; - } - PgmPrint("The current time is 20"); - // year - hexPrint(r[6]); - Serial.write('-'); +void displayTime(void) +{ + uint8_t r[8]; + if (!readDS1307(0, r, 8)) { + PgmPrintln("Read Failed for display time"); + return; + } + PgmPrint("The current time is 20"); + // year + hexPrint(r[6]); + Serial.write('-'); - // month - hexPrint(r[5]); - Serial.write('-'); + // month + hexPrint(r[5]); + Serial.write('-'); - // day - hexPrint(r[4]); - Serial.write(' '); + // day + hexPrint(r[4]); + Serial.write(' '); - Serial.print(Ddd[r[3] < 8 ? r[3] : 0]); - Serial.write(' '); + Serial.print(Ddd[r[3] < 8 ? r[3] : 0]); + Serial.write(' '); - // hour - hexPrint(r[2]); - Serial.write(':'); + // hour + hexPrint(r[2]); + Serial.write(':'); - // minute - hexPrint(r[1]); - Serial.write(':'); + // minute + hexPrint(r[1]); + Serial.write(':'); - // second - hexPrintln(r[0]); + // second + hexPrintln(r[0]); - // Control register. - PgmPrint("Control Register: "); - hexPrintln(r[7]); + // Control register. + PgmPrint("Control Register: "); + hexPrintln(r[7]); } //------------------------------------------------------------------------------ // dump registers and 56 bytes of RAM -void dumpAll(void) { - uint8_t buf[8]; - for (uint8_t a = 0; a < 64; a += 8) { - hexPrint(a); - Serial.write(' '); - if (!readDS1307(a, buf, 8)) { - PgmPrint("read failed for dumpAll"); - return; - } - for (uint8_t i = 0; i < 8; i++) { - Serial.write(' '); - hexPrint(buf[i]); - } - Serial.println(); - } +void dumpAll(void) +{ + uint8_t buf[8]; + for (uint8_t a = 0; a < 64; a += 8) { + hexPrint(a); + Serial.write(' '); + if (!readDS1307(a, buf, 8)) { + PgmPrint("read failed for dumpAll"); + return; + } + for (uint8_t i = 0; i < 8; i++) { + Serial.write(' '); + hexPrint(buf[i]); + } + Serial.println(); + } } //------------------------------------------------------------------------------ -void fillNvRam(void) { - uint8_t buf[8]; - PgmPrint("Enter HEX value for all NV RAM locations (00-FF): "); - uint16_t v; - if (!hexRead(&v)) return; - hexPrint(v); - for (uint8_t a = 8; a < 64; a ++) { - if (!writeDS1307(a, (uint8_t *)&v, 1)) { - PgmPrintln("write failed for fillNvRam"); - } - } +void fillNvRam(void) +{ + uint8_t buf[8]; + PgmPrint("Enter HEX value for all NV RAM locations (00-FF): "); + uint16_t v; + if (!hexRead(&v)) { + return; + } + hexPrint(v); + for (uint8_t a = 8; a < 64; a ++) { + if (!writeDS1307(a, (uint8_t *)&v, 1)) { + PgmPrintln("write failed for fillNvRam"); + } + } } //------------------------------------------------------------------------------ // set control register @@ -205,120 +218,149 @@ RS1 RS0 FREQUENCY 1 0 8.192kHz 1 1 32.768kHz */ -void setControl(void) { - PgmPrintln("SQW/OUT pin: "); - PgmPrintln("(00) Low"); - PgmPrintln("(10) 1Hz"); - PgmPrintln("(11) 4.096kHz"); - PgmPrintln("(12) 8.192kHz"); - PgmPrintln("(13) 32.768kHz"); - PgmPrintln("(80) High"); - PgmPrint("Enter control: "); - uint16_t r; - if (!hexRead(&r)) return; - hexPrintln(r); - if (!writeDS1307(7, (uint8_t *)&r, 1)) { - PgmPrint("Write Failed for setControl"); - } +void setControl(void) +{ + PgmPrintln("SQW/OUT pin: "); + PgmPrintln("(00) Low"); + PgmPrintln("(10) 1Hz"); + PgmPrintln("(11) 4.096kHz"); + PgmPrintln("(12) 8.192kHz"); + PgmPrintln("(13) 32.768kHz"); + PgmPrintln("(80) High"); + PgmPrint("Enter control: "); + uint16_t r; + if (!hexRead(&r)) { + return; + } + hexPrintln(r); + if (!writeDS1307(7, (uint8_t *)&r, 1)) { + PgmPrint("Write Failed for setControl"); + } } //------------------------------------------------------------------------------ -void setDate(void) { - uint8_t r[4]; - PgmPrint("Enter year (00-99): "); - if (!bcdRead(0, 99, &r[3])) return; - hexPrintln(r[3]); - PgmPrint("Enter month (01-12): "); - if (!bcdRead(1, 12, &r[2])) return; - hexPrintln(r[2]); - PgmPrint("Enter day (01-31): "); - if (!bcdRead(1, 31, &r[1])) return; - hexPrintln(r[1]); - PgmPrint("Enter day of week (01-07, Sun-Sat): "); - if (!bcdRead(1, 7, &r[0])) return; - hexPrintln(r[0]); +void setDate(void) +{ + uint8_t r[4]; + PgmPrint("Enter year (00-99): "); + if (!bcdRead(0, 99, &r[3])) { + return; + } + hexPrintln(r[3]); + PgmPrint("Enter month (01-12): "); + if (!bcdRead(1, 12, &r[2])) { + return; + } + hexPrintln(r[2]); + PgmPrint("Enter day (01-31): "); + if (!bcdRead(1, 31, &r[1])) { + return; + } + hexPrintln(r[1]); + PgmPrint("Enter day of week (01-07, Sun-Sat): "); + if (!bcdRead(1, 7, &r[0])) { + return; + } + hexPrintln(r[0]); - if (!writeDS1307(3, r, 4)) { - PgmPrintln("Write failed for setDate"); - } + if (!writeDS1307(3, r, 4)) { + PgmPrintln("Write failed for setDate"); + } } //------------------------------------------------------------------------------ -void setNvRam() { - uint8_t u; - uint16_t a, v; - while (true) { - PgmPrint("Enter zero to quit or Hex address (8-3F):"); - if (!hexRead(&a) || a == 0) return; - if (a < 8 || a > 0X3F) { - PgmPrintln("Invalid address"); - return; - } - hexPrintln(a); - if (!readDS1307(a, &u, 1)) { - PgmPrintln("Read failed"); - return; - } - PgmPrint("Current value: "); - hexPrintln(u); - PgmPrint("Enter new HEX value (00-FF): "); - if (!hexRead(&v)) return; - hexPrintln(v); - if (!writeDS1307(a, (uint8_t *)&v, 1)) { - PgmPrint("Write Failed"); - return; - } - } +void setNvRam() +{ + uint8_t u; + uint16_t a, v; + while (true) { + PgmPrint("Enter zero to quit or Hex address (8-3F):"); + if (!hexRead(&a) || a == 0) { + return; + } + if (a < 8 || a > 0X3F) { + PgmPrintln("Invalid address"); + return; + } + hexPrintln(a); + if (!readDS1307(a, &u, 1)) { + PgmPrintln("Read failed"); + return; + } + PgmPrint("Current value: "); + hexPrintln(u); + PgmPrint("Enter new HEX value (00-FF): "); + if (!hexRead(&v)) { + return; + } + hexPrintln(v); + if (!writeDS1307(a, (uint8_t *)&v, 1)) { + PgmPrint("Write Failed"); + return; + } + } } //------------------------------------------------------------------------------ -void setTime(void) { - uint8_t r[3]; - PgmPrint("Enter hours (00-23): "); - if (!bcdRead(0, 23, &r[2])) return; - hexPrintln(r[2]); - PgmPrint("Enter minutes (00-59): "); - if (!bcdRead(0, 59, &r[1])) return; - hexPrintln(r[1]); - PgmPrint("Enter seconds (00-59): "); - if (!bcdRead(0, 59, &r[0])) return; - hexPrintln(r[0]); +void setTime(void) +{ + uint8_t r[3]; + PgmPrint("Enter hours (00-23): "); + if (!bcdRead(0, 23, &r[2])) { + return; + } + hexPrintln(r[2]); + PgmPrint("Enter minutes (00-59): "); + if (!bcdRead(0, 59, &r[1])) { + return; + } + hexPrintln(r[1]); + PgmPrint("Enter seconds (00-59): "); + if (!bcdRead(0, 59, &r[0])) { + return; + } + hexPrintln(r[0]); - if (!writeDS1307(0, r, 3)) { - PgmPrintln("write failed in setTime"); - return; - } + if (!writeDS1307(0, r, 3)) { + PgmPrintln("write failed in setTime"); + return; + } } //------------------------------------------------------------------------------ -void loop(void) { - Serial.println(); - displayTime(); - while (Serial.read() >= 0) {} - PgmPrintln("\nOptions are:"); - PgmPrintln("(0) Display date and time"); - PgmPrintln("(1) Set time"); - PgmPrintln("(2) Set date"); - PgmPrintln("(3) Set Control"); - PgmPrintln("(4) Dump all"); - PgmPrintln("(5) Fill NV RAM"); - PgmPrintln("(6) Set NV RAM value"); - PgmPrint("Enter option: "); +void loop(void) +{ + Serial.println(); + displayTime(); + while (Serial.read() >= 0) {} + PgmPrintln("\nOptions are:"); + PgmPrintln("(0) Display date and time"); + PgmPrintln("(1) Set time"); + PgmPrintln("(2) Set date"); + PgmPrintln("(3) Set Control"); + PgmPrintln("(4) Dump all"); + PgmPrintln("(5) Fill NV RAM"); + PgmPrintln("(6) Set NV RAM value"); + PgmPrint("Enter option: "); - uint16_t n; - if (!hexRead(&n)) return; - Serial.println(n, DEC); - if (n == 0) return; - Serial.println(); - if (n == 1) { - setTime(); - } else if (n == 2) { - setDate(); - } else if (n == 3) { - setControl(); - } else if (n == 4) { - dumpAll(); - } else if (n == 5) { - fillNvRam(); - } else if (n == 6) { - setNvRam(); - } else { - PgmPrintln("Invalid option"); - } + uint16_t n; + if (!hexRead(&n)) { + return; + } + Serial.println(n, DEC); + if (n == 0) { + return; + } + Serial.println(); + if (n == 1) { + setTime(); + } else if (n == 2) { + setDate(); + } else if (n == 3) { + setControl(); + } else if (n == 4) { + dumpAll(); + } else if (n == 5) { + fillNvRam(); + } else if (n == 6) { + setNvRam(); + } else { + PgmPrintln("Invalid option"); + } } \ No newline at end of file diff --git a/drivers/AVR/DigitalIO/examples/testArduino/testArduino.ino b/drivers/AVR/DigitalIO/examples/testArduino/testArduino.ino index 13afe0440..144c7fb3a 100644 --- a/drivers/AVR/DigitalIO/examples/testArduino/testArduino.ino +++ b/drivers/AVR/DigitalIO/examples/testArduino/testArduino.ino @@ -1,14 +1,16 @@ // Scope test for write timing with Arduino digitaWrite(). const uint8_t PIN13 = 13; -void setup() { - // Set mode to OUTPUT. - pinMode(PIN13, OUTPUT); +void setup() +{ + // Set mode to OUTPUT. + pinMode(PIN13, OUTPUT); } -void loop() { - digitalWrite(PIN13, HIGH); - digitalWrite(PIN13, LOW); - digitalWrite(PIN13, HIGH); - digitalWrite(PIN13, LOW); - delay(1); +void loop() +{ + digitalWrite(PIN13, HIGH); + digitalWrite(PIN13, LOW); + digitalWrite(PIN13, HIGH); + digitalWrite(PIN13, LOW); + delay(1); } \ No newline at end of file diff --git a/drivers/AVR/DigitalIO/examples/testDigitalPin/testDigitalPin.ino b/drivers/AVR/DigitalIO/examples/testDigitalPin/testDigitalPin.ino index 1ac0c0236..5b4f562aa 100644 --- a/drivers/AVR/DigitalIO/examples/testDigitalPin/testDigitalPin.ino +++ b/drivers/AVR/DigitalIO/examples/testDigitalPin/testDigitalPin.ino @@ -4,16 +4,18 @@ // Class with compile time pin number. DigitalPin<13> pin13; -void setup() { - // set mode to OUTPUT - pin13.mode(OUTPUT); +void setup() +{ + // set mode to OUTPUT + pin13.mode(OUTPUT); } -void loop() { - pin13.high(); - pin13.low(); - pin13.write(1); - pin13.write(0); - pin13.toggle(); - pin13.toggle(); - delay(1); +void loop() +{ + pin13.high(); + pin13.low(); + pin13.write(1); + pin13.write(0); + pin13.toggle(); + pin13.toggle(); + delay(1); } \ No newline at end of file diff --git a/drivers/AVR/DigitalIO/examples/testFastDigital/testFastDigital.ino b/drivers/AVR/DigitalIO/examples/testFastDigital/testFastDigital.ino index 03f38d581..6fca39ab3 100644 --- a/drivers/AVR/DigitalIO/examples/testFastDigital/testFastDigital.ino +++ b/drivers/AVR/DigitalIO/examples/testFastDigital/testFastDigital.ino @@ -1,13 +1,15 @@ // Test fastDigital function timing with a scope. #include const uint8_t PIN = 13; -void setup() { - fastPinMode(PIN, OUTPUT); +void setup() +{ + fastPinMode(PIN, OUTPUT); } -void loop() { - fastDigitalWrite(PIN, HIGH); - fastDigitalWrite(PIN, LOW); - fastDigitalToggle(PIN); - fastDigitalToggle(PIN); - delay(1); +void loop() +{ + fastDigitalWrite(PIN, HIGH); + fastDigitalWrite(PIN, LOW); + fastDigitalToggle(PIN); + fastDigitalToggle(PIN); + delay(1); } \ No newline at end of file diff --git a/drivers/AVR/DigitalIO/examples/testPinIO/testPinIO.ino b/drivers/AVR/DigitalIO/examples/testPinIO/testPinIO.ino index 4f728237d..3cf8a8516 100644 --- a/drivers/AVR/DigitalIO/examples/testPinIO/testPinIO.ino +++ b/drivers/AVR/DigitalIO/examples/testPinIO/testPinIO.ino @@ -4,16 +4,18 @@ // Class with runtime pin numbers. PinIO pin(13); -void setup() { - // Set mode to OUTPUT. - pin.mode(OUTPUT); +void setup() +{ + // Set mode to OUTPUT. + pin.mode(OUTPUT); } -void loop() { - pin.high(); - pin.low(); - pin.write(1); - pin.write(0); - pin.toggle(); - pin.toggle(); - delay(1); +void loop() +{ + pin.high(); + pin.low(); + pin.write(1); + pin.write(0); + pin.toggle(); + pin.toggle(); + delay(1); } \ No newline at end of file diff --git a/drivers/AVR/DigitalIO/examples/testSoftSPI/testSoftSPI.ino b/drivers/AVR/DigitalIO/examples/testSoftSPI/testSoftSPI.ino index 7b9544f7e..f457a3fcb 100644 --- a/drivers/AVR/DigitalIO/examples/testSoftSPI/testSoftSPI.ino +++ b/drivers/AVR/DigitalIO/examples/testSoftSPI/testSoftSPI.ino @@ -9,29 +9,35 @@ const uint8_t SPI_MODE = 0; SoftSPI spi; int test; -void setup() { - Serial.begin(9600); - spi.begin(); - while(1) { - Serial.println("Enter:"); - Serial.println("R - Receive"); - Serial.println("S - Send"); - Serial.println("T - Transfer"); - while ((test = Serial.read()) <= 0) {} - test = toupper(test); - if (strchr("RST", test)) break; - Serial.println("Invalid entry"); - }; - Serial.print("Starting test "); - Serial.println((char)test); +void setup() +{ + Serial.begin(9600); + spi.begin(); + while(1) { + Serial.println("Enter:"); + Serial.println("R - Receive"); + Serial.println("S - Send"); + Serial.println("T - Transfer"); + while ((test = Serial.read()) <= 0) {} + test = toupper(test); + if (strchr("RST", test)) { + break; + } + Serial.println("Invalid entry"); + }; + Serial.print("Starting test "); + Serial.println((char)test); } -void loop() { - if (test == 'S') spi.send(0X55); - if (test == 'R') { - Serial.println(spi.receive(), HEX); - } - if (test == 'T') { - Serial.println(spi.transfer(0XAA), HEX); - } - delay(10); +void loop() +{ + if (test == 'S') { + spi.send(0X55); + } + if (test == 'R') { + Serial.println(spi.receive(), HEX); + } + if (test == 'T') { + Serial.println(spi.transfer(0XAA), HEX); + } + delay(10); } \ No newline at end of file diff --git a/drivers/AVR/DigitalWriteFast/digitalWriteFast.h b/drivers/AVR/DigitalWriteFast/digitalWriteFast.h index f90b4f683..54ee961dc 100644 --- a/drivers/AVR/DigitalWriteFast/digitalWriteFast.h +++ b/drivers/AVR/DigitalWriteFast/digitalWriteFast.h @@ -7,92 +7,92 @@ #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))))))))))))))) +#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))) +#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 ))))))))))))))))))) +#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(__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))) - #define __digitalPinToPINReg(__pin) (((__pin) <= 7) ? &PIND : (((__pin) >= 8 && (__pin) <= 13) ? &PINB : (((__pin) >= 14 && (__pin) <= 19) ? &PINC : &PINE))) - #define __digitalPinToBit(__pin) (((__pin) <= 7) ? (__pin) : (((__pin) >= 8 && (__pin) <= 13) ? (__pin) - 8 : (((__pin) >= 14 && (__pin) <= 19) ? (__pin) - 14 : (((__pin) >= 20 && (__pin) <= 21) ? (__pin) - 18 : (__pin) - 22)))) - #else - #define __digitalPinToPortReg(__pin) (((__pin) <= 7) ? &PORTD : (((__pin) >= 8 && (__pin) <= 13) ? &PORTB : &PORTC)) - #define __digitalPinToDDRReg(__pin) (((__pin) <= 7) ? &DDRD : (((__pin) >= 8 && (__pin) <= 13) ? &DDRB : &DDRC)) - #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 +#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))) +#define __digitalPinToPINReg(__pin) (((__pin) <= 7) ? &PIND : (((__pin) >= 8 && (__pin) <= 13) ? &PINB : (((__pin) >= 14 && (__pin) <= 19) ? &PINC : &PINE))) +#define __digitalPinToBit(__pin) (((__pin) <= 7) ? (__pin) : (((__pin) >= 8 && (__pin) <= 13) ? (__pin) - 8 : (((__pin) >= 14 && (__pin) <= 19) ? (__pin) - 14 : (((__pin) >= 20 && (__pin) <= 21) ? (__pin) - 18 : (__pin) - 22)))) +#else +#define __digitalPinToPortReg(__pin) (((__pin) <= 7) ? &PORTD : (((__pin) >= 8 && (__pin) <= 13) ? &PORTB : &PORTC)) +#define __digitalPinToDDRReg(__pin) (((__pin) <= 7) ? &DDRD : (((__pin) >= 8 && (__pin) <= 13) ? &DDRB : &DDRC)) +#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), __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), __digitalPinToBit(__pin), (__mode)); } else { pinMode((__pin), (__mode)); } } while (0) - #endif - #if !defined(digitalReadFast) - #define digitalReadFast(__pin) ( (bool) (__builtin_constant_p(__pin) ) ? (( bitRead(*__digitalPinToPINReg(__pin), __digitalPinToBit(__pin))) ) : digitalRead((__pin)) ) - #endif +#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), __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), __digitalPinToBit(__pin), (__mode)); } else { pinMode((__pin), (__mode)); } } while (0) +#endif +#if !defined(digitalReadFast) +#define digitalReadFast(__pin) ( (bool) (__builtin_constant_p(__pin) ) ? (( bitRead(*__digitalPinToPINReg(__pin), __digitalPinToBit(__pin))) ) : digitalRead((__pin)) ) +#endif #endif #endif \ No newline at end of file diff --git a/drivers/AltSoftSerial/AltSoftSerial.h b/drivers/AltSoftSerial/AltSoftSerial.h index 533390359..4bb1fdae1 100644 --- a/drivers/AltSoftSerial/AltSoftSerial.h +++ b/drivers/AltSoftSerial/AltSoftSerial.h @@ -1,17 +1,17 @@ /* An Alternative Software Serial Library * http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html * Copyright (c) 2014 PJRC.COM, LLC, Paul Stoffregen, paul@pjrc.com - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -44,28 +44,61 @@ class AltSoftSerial : public Stream { public: AltSoftSerial() { } //!< Constructor - ~AltSoftSerial() { end(); } //!< Destructor - static void begin(uint32_t baud) { init((ALTSS_BASE_FREQ + baud / 2) / baud); } //!< begin + ~AltSoftSerial() + { + end(); //!< Destructor + } + static void begin(uint32_t baud) + { + init((ALTSS_BASE_FREQ + baud / 2) / baud); //!< begin + } static void end(); //!< end int peek(); //!< peek int read(); //!< read int available(); //!< available #if ARDUINO >= 100 - size_t write(uint8_t byte) { writeByte(byte); return 1; } //!< write - void flush() { flushOutput(); } //!< flush + size_t write(uint8_t byte) + { + writeByte(byte); //!< write + return 1; + } + void flush() + { + flushOutput(); //!< flush + } #else - void write(uint8_t byte) { writeByte(byte); } //!< write - void flush() { flushInput(); } //!< flush + void write(uint8_t byte) + { + writeByte(byte); //!< write + } + void flush() + { + flushInput(); //!< flush + } #endif using Print::write; static void flushInput(); //!< flushInput static void flushOutput(); //!< flushOutput // for drop-in compatibility with NewSoftSerial, rxPin & txPin ignored //AltSoftSerial(uint8_t rxPin, uint8_t txPin, bool inverse = false) { } - bool listen() { return false; } //!< listen - bool isListening() { return true; } //!< isListening - bool overflow() { bool r = timing_error; timing_error = false; return r; } //!< overflow - static int library_version() { return 1; } //!< library_version + bool listen() + { + return false; //!< listen + } + bool isListening() + { + return true; //!< isListening + } + bool overflow() + { + bool r = timing_error; //!< overflow + timing_error = false; + return r; + } + static int library_version() + { + return 1; //!< library_version + } static void enable_timer0(bool) { } //!< enable_timer0 static bool timing_error; //!< timing_error private: diff --git a/drivers/AltSoftSerial/config/AltSoftSerial_Boards.h b/drivers/AltSoftSerial/config/AltSoftSerial_Boards.h index 1ccbf684c..51e1f1876 100644 --- a/drivers/AltSoftSerial/config/AltSoftSerial_Boards.h +++ b/drivers/AltSoftSerial/config/AltSoftSerial_Boards.h @@ -1,17 +1,17 @@ /* An Alternative Software Serial Library * http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html * Copyright (c) 2014 PJRC.COM, LLC, Paul Stoffregen, paul@pjrc.com - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -26,15 +26,15 @@ // #if defined(__AVR_ATmega32U4__) && defined(CORE_TEENSY) - //#define ALTSS_USE_TIMER1 - //#define INPUT_CAPTURE_PIN 22 // receive - //#define OUTPUT_COMPARE_A_PIN 14 // transmit - //#define OUTPUT_COMPARE_B_PIN 15 // unusable PWM - //#define OUTPUT_COMPARE_C_PIN 4 // unusable PWM +//#define ALTSS_USE_TIMER1 +//#define INPUT_CAPTURE_PIN 22 // receive +//#define OUTPUT_COMPARE_A_PIN 14 // transmit +//#define OUTPUT_COMPARE_B_PIN 15 // unusable PWM +//#define OUTPUT_COMPARE_C_PIN 4 // unusable PWM - #define ALTSS_USE_TIMER3 - #define INPUT_CAPTURE_PIN 10 // receive - #define OUTPUT_COMPARE_A_PIN 9 // transmit +#define ALTSS_USE_TIMER3 +#define INPUT_CAPTURE_PIN 10 // receive +#define OUTPUT_COMPARE_A_PIN 9 // transmit @@ -42,41 +42,41 @@ // #elif defined(__AVR_AT90USB1286__) && defined(CORE_TEENSY) - #define ALTSS_USE_TIMER1 - #define INPUT_CAPTURE_PIN 4 // receive - #define OUTPUT_COMPARE_A_PIN 25 // transmit - #define OUTPUT_COMPARE_B_PIN 26 // unusable PWM - #define OUTPUT_COMPARE_C_PIN 27 // unusable PWM +#define ALTSS_USE_TIMER1 +#define INPUT_CAPTURE_PIN 4 // receive +#define OUTPUT_COMPARE_A_PIN 25 // transmit +#define OUTPUT_COMPARE_B_PIN 26 // unusable PWM +#define OUTPUT_COMPARE_C_PIN 27 // unusable PWM - //#define ALTSS_USE_TIMER3 - //#define INPUT_CAPTURE_PIN 17 // receive - //#define OUTPUT_COMPARE_A_PIN 16 // transmit - //#define OUTPUT_COMPARE_B_PIN 15 // unusable PWM - //#define OUTPUT_COMPARE_C_PIN 14 // unusable PWM +//#define ALTSS_USE_TIMER3 +//#define INPUT_CAPTURE_PIN 17 // receive +//#define OUTPUT_COMPARE_A_PIN 16 // transmit +//#define OUTPUT_COMPARE_B_PIN 15 // unusable PWM +//#define OUTPUT_COMPARE_C_PIN 14 // unusable PWM // Teensy 3.0 & 3.1 // #elif defined(__MK20DX128__) || defined(__MK20DX256__) - #define ALTSS_USE_FTM0 - #define INPUT_CAPTURE_PIN 20 // receive (FTM0_CH5) - #define OUTPUT_COMPARE_A_PIN 21 // transmit (FTM0_CH6) - #define OUTPUT_COMPARE_B_PIN 22 // unusable PWM (FTM0_CH0) - #define OUTPUT_COMPARE_C_PIN 23 // PWM usable fixed freq - #define OUTPUT_COMPARE_D_PIN 5 // PWM usable fixed freq - #define OUTPUT_COMPARE_E_PIN 6 // PWM usable fixed freq - #define OUTPUT_COMPARE_F_PIN 9 // PWM usable fixed freq - #define OUTPUT_COMPARE_G_PIN 10 // PWM usable fixed freq +#define ALTSS_USE_FTM0 +#define INPUT_CAPTURE_PIN 20 // receive (FTM0_CH5) +#define OUTPUT_COMPARE_A_PIN 21 // transmit (FTM0_CH6) +#define OUTPUT_COMPARE_B_PIN 22 // unusable PWM (FTM0_CH0) +#define OUTPUT_COMPARE_C_PIN 23 // PWM usable fixed freq +#define OUTPUT_COMPARE_D_PIN 5 // PWM usable fixed freq +#define OUTPUT_COMPARE_E_PIN 6 // PWM usable fixed freq +#define OUTPUT_COMPARE_F_PIN 9 // PWM usable fixed freq +#define OUTPUT_COMPARE_G_PIN 10 // PWM usable fixed freq // Wiring-S // #elif defined(__AVR_ATmega644P__) && defined(WIRING) - #define ALTSS_USE_TIMER1 - #define INPUT_CAPTURE_PIN 6 // receive - #define OUTPUT_COMPARE_A_PIN 5 // transmit - #define OUTPUT_COMPARE_B_PIN 4 // unusable PWM +#define ALTSS_USE_TIMER1 +#define INPUT_CAPTURE_PIN 6 // receive +#define OUTPUT_COMPARE_A_PIN 5 // transmit +#define OUTPUT_COMPARE_B_PIN 4 // unusable PWM @@ -84,51 +84,51 @@ // #elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) - #define ALTSS_USE_TIMER1 - #define INPUT_CAPTURE_PIN 8 // receive - #define OUTPUT_COMPARE_A_PIN 9 // transmit - #define OUTPUT_COMPARE_B_PIN 10 // unusable PWM +#define ALTSS_USE_TIMER1 +#define INPUT_CAPTURE_PIN 8 // receive +#define OUTPUT_COMPARE_A_PIN 9 // transmit +#define OUTPUT_COMPARE_B_PIN 10 // unusable PWM // Arduino Leonardo & Yun (from Cristian Maglie) // #elif defined(ARDUINO_AVR_YUN) || defined(ARDUINO_AVR_LEONARDO) || defined(__AVR_ATmega32U4__) - //#define ALTSS_USE_TIMER1 - //#define INPUT_CAPTURE_PIN 4 // receive - //#define OUTPUT_COMPARE_A_PIN 9 // transmit - //#define OUTPUT_COMPARE_B_PIN 10 // unusable PWM - //#define OUTPUT_COMPARE_C_PIN 11 // unusable PWM +//#define ALTSS_USE_TIMER1 +//#define INPUT_CAPTURE_PIN 4 // receive +//#define OUTPUT_COMPARE_A_PIN 9 // transmit +//#define OUTPUT_COMPARE_B_PIN 10 // unusable PWM +//#define OUTPUT_COMPARE_C_PIN 11 // unusable PWM - #define ALTSS_USE_TIMER3 - #define INPUT_CAPTURE_PIN 13 // receive - #define OUTPUT_COMPARE_A_PIN 5 // transmit +#define ALTSS_USE_TIMER3 +#define INPUT_CAPTURE_PIN 13 // receive +#define OUTPUT_COMPARE_A_PIN 5 // transmit // Arduino Mega // #elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - //#define ALTSS_USE_TIMER4 - //#define INPUT_CAPTURE_PIN 49 // receive - //#define OUTPUT_COMPARE_A_PIN 6 // transmit - //#define OUTPUT_COMPARE_B_PIN 7 // unusable PWM - //#define OUTPUT_COMPARE_C_PIN 8 // unusable PWM +//#define ALTSS_USE_TIMER4 +//#define INPUT_CAPTURE_PIN 49 // receive +//#define OUTPUT_COMPARE_A_PIN 6 // transmit +//#define OUTPUT_COMPARE_B_PIN 7 // unusable PWM +//#define OUTPUT_COMPARE_C_PIN 8 // unusable PWM - #define ALTSS_USE_TIMER5 - #define INPUT_CAPTURE_PIN 48 // receive - #define OUTPUT_COMPARE_A_PIN 46 // transmit - #define OUTPUT_COMPARE_B_PIN 45 // unusable PWM - #define OUTPUT_COMPARE_C_PIN 44 // unusable PWM +#define ALTSS_USE_TIMER5 +#define INPUT_CAPTURE_PIN 48 // receive +#define OUTPUT_COMPARE_A_PIN 46 // transmit +#define OUTPUT_COMPARE_B_PIN 45 // unusable PWM +#define OUTPUT_COMPARE_C_PIN 44 // unusable PWM // Sanguino #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) - #define ALTSS_USE_TIMER1 - #define INPUT_CAPTURE_PIN 14 // receive - #define OUTPUT_COMPARE_A_PIN 13 // transmit - #define OUTPUT_COMPARE_B_PIN 12 // unusable PWM +#define ALTSS_USE_TIMER1 +#define INPUT_CAPTURE_PIN 14 // receive +#define OUTPUT_COMPARE_A_PIN 13 // transmit +#define OUTPUT_COMPARE_B_PIN 12 // unusable PWM // Unknown board diff --git a/drivers/AltSoftSerial/config/AltSoftSerial_Timers.h b/drivers/AltSoftSerial/config/AltSoftSerial_Timers.h index 4270cd860..3f8c96fc4 100644 --- a/drivers/AltSoftSerial/config/AltSoftSerial_Timers.h +++ b/drivers/AltSoftSerial/config/AltSoftSerial_Timers.h @@ -1,17 +1,17 @@ /* An Alternative Software Serial Library * http://www.pjrc.com/teensy/td_libs_AltSoftSerial.html * Copyright (c) 2014 PJRC.COM, LLC, Paul Stoffregen, paul@pjrc.com - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -22,153 +22,153 @@ */ #if defined(ALTSS_USE_TIMER1) - #define CONFIG_TIMER_NOPRESCALE() (TIMSK1 = 0, TCCR1A = 0, TCCR1B = (1< class CircularBuffer { - public: - /** - * Constructor - * @param buffer Preallocated buffer of at least size records. - * @param size Number of records available in the buffer. - */ - CircularBuffer(T* buffer, const uint8_t size ) - : m_size(size), m_buff(buffer) - { - clear(); - } - - /** - * Clear all entries in the circular buffer. - */ - void clear(void) - { - MY_CRITICAL_SECTION - { - m_front = 0; - m_fill = 0; - } - } - - /** - * Test if the circular buffer is empty. - * @return True, when empty. - */ - inline bool empty(void) const - { - bool empty; - MY_CRITICAL_SECTION - { - empty = !m_fill; - } - return empty; - } - - /** - * Test if the circular buffer is full. - * @return True, when full. - */ - inline bool full(void) const - { - bool full; - MY_CRITICAL_SECTION - { - full = m_fill == m_size; - } - return full; - } - - /** - * Return the number of records stored in the buffer. - * @return number of records. - */ - inline uint8_t available(void) const - { - MY_CRITICAL_SECTION - { - return m_fill; - } - } - - /** - * Aquire unused record on front of the buffer, for writing. - * After filling the record, it has to be pushed to actually - * add it to the buffer. - * @return Pointer to record, or NULL when buffer is full. - */ - T* getFront(void) const - { - MY_CRITICAL_SECTION - { - if (!full()) return get(m_front); - } - return static_cast(NULL); - } - - /** - * Push record to front of the buffer. - * @param record Record to push. If record was aquired previously (using getFront) its - * data will not be copied as it is already present in the buffer. - * @return True, when record was pushed successfully. - */ - bool pushFront(T* record) - { - MY_CRITICAL_SECTION - { - if (!full()) - { - T* f = get(m_front); - if (f != record) - *f = *record; - m_front = (m_front+1) % m_size; - m_fill++; - return true; - } - } - return false; - } - - /** - * Aquire record on back of the buffer, for reading. - * After reading the record, it has to be pop'ed to actually - * remove it from the buffer. - * @return Pointer to record, or NULL when buffer is empty. - */ - T* getBack(void) const - { - MY_CRITICAL_SECTION - { - if (!empty()) return get(back()); - } - return static_cast(NULL); - } - - /** - * Remove record from back of the buffer. - * @return True, when record was pop'ed successfully. - */ - bool popBack(void) - { - MY_CRITICAL_SECTION - { - if (!empty()) - { - m_fill--; - return true; - } - } - return false; - } - - protected: - /** - * Internal getter for records. - * @param idx Record index in buffer. - * @return Ptr to record. - */ - inline T * get(const uint8_t idx) const - { - return &(m_buff[idx]); - } - - /** - * Internal getter for index of last used record in buffer. - * @return Index of last record. - */ - inline uint8_t back(void) const - { - return (m_front - m_fill + m_size) % m_size; - } - - const uint8_t m_size; //!< Total number of records that can be stored in the buffer. - T* const m_buff; //!< Ptr to buffer holding all records. - volatile uint8_t m_front; //!< Index of front element (not pushed yet). - volatile uint8_t m_fill; //!< Amount of records currently pushed. +public: + /** + * Constructor + * @param buffer Preallocated buffer of at least size records. + * @param size Number of records available in the buffer. + */ + CircularBuffer(T* buffer, const uint8_t size ) + : m_size(size), m_buff(buffer) + { + clear(); + } + + /** + * Clear all entries in the circular buffer. + */ + void clear(void) + { + MY_CRITICAL_SECTION { + m_front = 0; + m_fill = 0; + } + } + + /** + * Test if the circular buffer is empty. + * @return True, when empty. + */ + inline bool empty(void) const + { + bool empty; + MY_CRITICAL_SECTION { + empty = !m_fill; + } + return empty; + } + + /** + * Test if the circular buffer is full. + * @return True, when full. + */ + inline bool full(void) const + { + bool full; + MY_CRITICAL_SECTION { + full = m_fill == m_size; + } + return full; + } + + /** + * Return the number of records stored in the buffer. + * @return number of records. + */ + inline uint8_t available(void) const + { + MY_CRITICAL_SECTION { + return m_fill; + } + } + + /** + * Aquire unused record on front of the buffer, for writing. + * After filling the record, it has to be pushed to actually + * add it to the buffer. + * @return Pointer to record, or NULL when buffer is full. + */ + T* getFront(void) const + { + MY_CRITICAL_SECTION { + if (!full()) + { + return get(m_front); + } + } + return static_cast(NULL); + } + + /** + * Push record to front of the buffer. + * @param record Record to push. If record was aquired previously (using getFront) its + * data will not be copied as it is already present in the buffer. + * @return True, when record was pushed successfully. + */ + bool pushFront(T* record) + { + MY_CRITICAL_SECTION { + if (!full()) + { + T* f = get(m_front); + if (f != record) { + *f = *record; + } + m_front = (m_front+1) % m_size; + m_fill++; + return true; + } + } + return false; + } + + /** + * Aquire record on back of the buffer, for reading. + * After reading the record, it has to be pop'ed to actually + * remove it from the buffer. + * @return Pointer to record, or NULL when buffer is empty. + */ + T* getBack(void) const + { + MY_CRITICAL_SECTION { + if (!empty()) + { + return get(back()); + } + } + return static_cast(NULL); + } + + /** + * Remove record from back of the buffer. + * @return True, when record was pop'ed successfully. + */ + bool popBack(void) + { + MY_CRITICAL_SECTION { + if (!empty()) + { + m_fill--; + return true; + } + } + return false; + } + +protected: + /** + * Internal getter for records. + * @param idx Record index in buffer. + * @return Ptr to record. + */ + inline T * get(const uint8_t idx) const + { + return &(m_buff[idx]); + } + + /** + * Internal getter for index of last used record in buffer. + * @return Index of last record. + */ + inline uint8_t back(void) const + { + return (m_front - m_fill + m_size) % m_size; + } + + const uint8_t m_size; //!< Total number of records that can be stored in the buffer. + T* const m_buff; //!< Ptr to buffer holding all records. + volatile uint8_t m_front; //!< Index of front element (not pushed yet). + volatile uint8_t m_fill; //!< Amount of records currently pushed. }; #endif // CircularBuffer_h diff --git a/drivers/Linux/Arduino.h b/drivers/Linux/Arduino.h index 71bca2330..1446b98e3 100644 --- a/drivers/Linux/Arduino.h +++ b/drivers/Linux/Arduino.h @@ -14,8 +14,8 @@ #include "stdlib_noniso.h" #ifdef LINUX_ARCH_RASPBERRYPI - #include "rpi_util.h" - using namespace rpi_util; +#include "rpi_util.h" +using namespace rpi_util; #endif #undef PSTR @@ -57,7 +57,7 @@ #define random(...) GET_MACRO(_0, ##__VA_ARGS__, randMinMax, randMax, rand)(__VA_ARGS__) #ifndef delay - #define delay _delay_ms +#define delay _delay_ms #endif using std::string; diff --git a/drivers/Linux/Client.h b/drivers/Linux/Client.h index 4f38ac2a5..6550f3d6a 100644 --- a/drivers/Linux/Client.h +++ b/drivers/Linux/Client.h @@ -26,7 +26,8 @@ #include "IPAddress.h" #if !DOXYGEN -class Client : public Stream { +class Client : public Stream +{ public: virtual int connect(IPAddress ip, uint16_t port) = 0; @@ -43,7 +44,10 @@ class Client : public Stream { virtual operator bool() = 0; protected: - uint8_t* rawIPAddress(IPAddress& addr) { return addr.raw_address(); }; + uint8_t* rawIPAddress(IPAddress& addr) + { + return addr.raw_address(); + }; }; #endif diff --git a/drivers/Linux/EthernetClient.cpp b/drivers/Linux/EthernetClient.cpp index ea69014a8..1b2f0931b 100644 --- a/drivers/Linux/EthernetClient.cpp +++ b/drivers/Linux/EthernetClient.cpp @@ -32,13 +32,16 @@ #include "log.h" #include "EthernetClient.h" -EthernetClient::EthernetClient() : _sock(-1) { +EthernetClient::EthernetClient() : _sock(-1) +{ } -EthernetClient::EthernetClient(int sock) : _sock(sock) { +EthernetClient::EthernetClient(int sock) : _sock(sock) +{ } -int EthernetClient::connect(const char* host, uint16_t port) { +int EthernetClient::connect(const char* host, uint16_t port) +{ int sockfd; struct addrinfo hints, *servinfo, *p; int rv; @@ -51,14 +54,14 @@ int EthernetClient::connect(const char* host, uint16_t port) { sprintf(port_str, "%hu", port); if ((rv = getaddrinfo(host, port_str, &hints, &servinfo)) != 0) { - logError("getaddrinfo: %s\n", gai_strerror(rv)); + logError("getaddrinfo: %s\n", gai_strerror(rv)); return -1; } // loop through all the results and connect to the first we can for (p = servinfo; p != NULL; p = p->ai_next) { if ((sockfd = socket(p->ai_family, p->ai_socktype, - p->ai_protocol)) == -1) { + p->ai_protocol)) == -1) { logError("socket: %s\n", strerror(errno)); continue; } @@ -88,15 +91,18 @@ int EthernetClient::connect(const char* host, uint16_t port) { return 1; } -int EthernetClient::connect(IPAddress ip, uint16_t port) { +int EthernetClient::connect(IPAddress ip, uint16_t port) +{ return connect(ip.toString().c_str(), port); } -size_t EthernetClient::write(uint8_t b) { +size_t EthernetClient::write(uint8_t b) +{ return write(&b, 1); } -size_t EthernetClient::write(const uint8_t *buf, size_t size) { +size_t EthernetClient::write(const uint8_t *buf, size_t size) +{ int rc = 0; int bytes = 0; @@ -119,17 +125,20 @@ size_t EthernetClient::write(const uint8_t *buf, size_t size) { return bytes; } -size_t EthernetClient::write(const char *str) { +size_t EthernetClient::write(const char *str) +{ if (str == NULL) { return 0; } return write((const uint8_t *)str, strlen(str)); } -size_t EthernetClient::write(const char *buffer, size_t size) { +size_t EthernetClient::write(const char *buffer, size_t size) +{ return write((const uint8_t *)buffer, size); } -int EthernetClient::available() { +int EthernetClient::available() +{ int count = 0; if (_sock != -1) { @@ -139,10 +148,10 @@ int EthernetClient::available() { return 0; } -int EthernetClient::read() { +int EthernetClient::read() +{ uint8_t b; - if ( recv(_sock, &b, 1, 0) > 0 ) - { + if ( recv(_sock, &b, 1, 0) > 0 ) { // recv worked return b; } else { @@ -151,22 +160,26 @@ int EthernetClient::read() { } } -int EthernetClient::read(uint8_t *buf, size_t size) { +int EthernetClient::read(uint8_t *buf, size_t size) +{ return recv(_sock, buf, size, 0); } -int EthernetClient::peek() { +int EthernetClient::peek() +{ uint8_t b; return recv(_sock, &b, 1, MSG_PEEK | MSG_DONTWAIT); } -void EthernetClient::flush() { +void EthernetClient::flush() +{ // There isn't much we can do here return; } -void EthernetClient::stop() { +void EthernetClient::stop() +{ if (_sock == -1) { return; } @@ -186,7 +199,8 @@ void EthernetClient::stop() { } usleep(1000); gettimeofday(&curTime, NULL); - } while (((curTime.tv_sec - startTime.tv_sec) * 1000000) + (curTime.tv_usec - startTime.tv_usec) < 1000000); + } while (((curTime.tv_sec - startTime.tv_sec) * 1000000) + (curTime.tv_usec - startTime.tv_usec) < + 1000000); // if it hasn't closed, close it forcefully if (s != ETHERNETCLIENT_W5100_CLOSED) { @@ -195,7 +209,8 @@ void EthernetClient::stop() { _sock = -1; } -uint8_t EthernetClient::status() { +uint8_t EthernetClient::status() +{ if (_sock == -1) { return ETHERNETCLIENT_W5100_CLOSED; } @@ -203,36 +218,38 @@ uint8_t EthernetClient::status() { struct tcp_info tcp_info; int tcp_info_length = sizeof(tcp_info); - if ( getsockopt( _sock, SOL_TCP, TCP_INFO, (void *)&tcp_info, (socklen_t *)&tcp_info_length ) == 0 ) { + if ( getsockopt( _sock, SOL_TCP, TCP_INFO, (void *)&tcp_info, + (socklen_t *)&tcp_info_length ) == 0 ) { switch (tcp_info.tcpi_state) { - case TCP_ESTABLISHED: - return ETHERNETCLIENT_W5100_ESTABLISHED; - case TCP_SYN_SENT: - return ETHERNETCLIENT_W5100_SYNSENT; - case TCP_SYN_RECV: - return ETHERNETCLIENT_W5100_SYNRECV; - case TCP_FIN_WAIT1: - case TCP_FIN_WAIT2: - return ETHERNETCLIENT_W5100_FIN_WAIT; - case TCP_TIME_WAIT: - return TCP_TIME_WAIT; - case TCP_CLOSE: - return ETHERNETCLIENT_W5100_CLOSED; - case TCP_CLOSE_WAIT: - return ETHERNETCLIENT_W5100_CLOSING; - case TCP_LAST_ACK: - return ETHERNETCLIENT_W5100_LAST_ACK; - case TCP_LISTEN: - return ETHERNETCLIENT_W5100_LISTEN; - case TCP_CLOSING: - return ETHERNETCLIENT_W5100_CLOSING; + case TCP_ESTABLISHED: + return ETHERNETCLIENT_W5100_ESTABLISHED; + case TCP_SYN_SENT: + return ETHERNETCLIENT_W5100_SYNSENT; + case TCP_SYN_RECV: + return ETHERNETCLIENT_W5100_SYNRECV; + case TCP_FIN_WAIT1: + case TCP_FIN_WAIT2: + return ETHERNETCLIENT_W5100_FIN_WAIT; + case TCP_TIME_WAIT: + return TCP_TIME_WAIT; + case TCP_CLOSE: + return ETHERNETCLIENT_W5100_CLOSED; + case TCP_CLOSE_WAIT: + return ETHERNETCLIENT_W5100_CLOSING; + case TCP_LAST_ACK: + return ETHERNETCLIENT_W5100_LAST_ACK; + case TCP_LISTEN: + return ETHERNETCLIENT_W5100_LISTEN; + case TCP_CLOSING: + return ETHERNETCLIENT_W5100_CLOSING; } } return ETHERNETCLIENT_W5100_CLOSED; } -uint8_t EthernetClient::connected() { +uint8_t EthernetClient::connected() +{ if (_sock == -1) { return 0; } @@ -246,17 +263,20 @@ uint8_t EthernetClient::connected() { return 1; } -int EthernetClient::getSocketNumber() { +int EthernetClient::getSocketNumber() +{ return _sock; } // the next function allows us to use the client returned by // EthernetServer::available() as the condition in an if-statement. -EthernetClient::operator bool() { +EthernetClient::operator bool() +{ return _sock != -1; } -bool EthernetClient::operator==(const EthernetClient& rhs) { +bool EthernetClient::operator==(const EthernetClient& rhs) +{ return _sock == rhs._sock && _sock != -1 && rhs._sock != -1; } diff --git a/drivers/Linux/EthernetClient.h b/drivers/Linux/EthernetClient.h index 2cbaca9d1..6297ec050 100644 --- a/drivers/Linux/EthernetClient.h +++ b/drivers/Linux/EthernetClient.h @@ -40,7 +40,8 @@ /** * EthernetClient class */ -class EthernetClient : public Client { +class EthernetClient : public Client +{ private: int _sock; //!< @brief Network socket. @@ -168,12 +169,18 @@ class EthernetClient : public Client { * @brief Overloaded cast operators. * */ - virtual bool operator==(const bool value) { return bool() == value; } + virtual bool operator==(const bool value) + { + return bool() == value; + } /** * @brief Overloaded cast operators. * */ - virtual bool operator!=(const bool value) { return bool() != value; } + virtual bool operator!=(const bool value) + { + return bool() != value; + } /** * @brief Overloaded cast operators. * @@ -183,7 +190,10 @@ class EthernetClient : public Client { * @brief Overloaded cast operators. * */ - virtual bool operator!=(const EthernetClient& rhs) { return !this->operator==(rhs); }; + virtual bool operator!=(const EthernetClient& rhs) + { + return !this->operator==(rhs); + }; friend class EthernetServer; }; diff --git a/drivers/Linux/EthernetServer.cpp b/drivers/Linux/EthernetServer.cpp index 311f315f8..e92f0970f 100644 --- a/drivers/Linux/EthernetServer.cpp +++ b/drivers/Linux/EthernetServer.cpp @@ -32,7 +32,8 @@ #include "EthernetClient.h" #include "EthernetServer.h" -EthernetServer::EthernetServer(uint16_t port, uint16_t max_clients) : port(port), max_clients(max_clients) +EthernetServer::EthernetServer(uint16_t port, uint16_t max_clients) : port(port), + max_clients(max_clients) { clients.reserve(max_clients); } diff --git a/drivers/Linux/EthernetServer.h b/drivers/Linux/EthernetServer.h index 4240e9690..376f3d7f1 100644 --- a/drivers/Linux/EthernetServer.h +++ b/drivers/Linux/EthernetServer.h @@ -28,10 +28,10 @@ #include "IPAddress.h" #ifdef ETHERNETSERVER_MAX_CLIENTS - #define ETHERNETSERVER_BACKLOG ETHERNETSERVER_MAX_CLIENTS //!< Maximum length to which the queue of pending connections may grow. +#define ETHERNETSERVER_BACKLOG ETHERNETSERVER_MAX_CLIENTS //!< Maximum length to which the queue of pending connections may grow. #else - #define ETHERNETSERVER_MAX_CLIENTS 10 //!< Default value for max_clients. - #define ETHERNETSERVER_BACKLOG 10 //!< Maximum length to which the queue of pending connections may grow. +#define ETHERNETSERVER_MAX_CLIENTS 10 //!< Default value for max_clients. +#define ETHERNETSERVER_BACKLOG 10 //!< Maximum length to which the queue of pending connections may grow. #endif class EthernetClient; @@ -39,7 +39,8 @@ class EthernetClient; /** * @brief EthernetServer class */ -class EthernetServer : public Server { +class EthernetServer : public Server +{ private: uint16_t port; //!< @brief Port number for the network socket. diff --git a/drivers/Linux/IPAddress.cpp b/drivers/Linux/IPAddress.cpp index dd67b59bc..963f7e292 100644 --- a/drivers/Linux/IPAddress.cpp +++ b/drivers/Linux/IPAddress.cpp @@ -24,53 +24,53 @@ #include #include "IPAddress.h" -IPAddress::IPAddress() { +IPAddress::IPAddress() +{ _address.dword = 0; } -IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) { +IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, + uint8_t fourth_octet) +{ _address.bytes[0] = first_octet; _address.bytes[1] = second_octet; _address.bytes[2] = third_octet; _address.bytes[3] = fourth_octet; } -IPAddress::IPAddress(uint32_t address) { +IPAddress::IPAddress(uint32_t address) +{ _address.dword = address; } -IPAddress::IPAddress(const uint8_t *address) { +IPAddress::IPAddress(const uint8_t *address) +{ memcpy(_address.bytes, address, sizeof(_address.bytes)); } -bool IPAddress::fromString(const char *address) { +bool IPAddress::fromString(const char *address) +{ // TODO: add support for "a", "a.b", "a.b.c" formats uint16_t acc = 0; // Accumulator uint8_t dots = 0; - while (*address) - { + while (*address) { char c = *address++; - if (c >= '0' && c <= '9') - { + if (c >= '0' && c <= '9') { acc = acc * 10 + (c - '0'); if (acc > 255) { // Value out of [0..255] range return false; } - } - else if (c == '.') - { + } else if (c == '.') { if (dots == 3) { // Too much dots (there must be 3 dots) return false; } _address.bytes[dots++] = acc; acc = 0; - } - else - { + } else { // Invalid char return false; } @@ -84,23 +84,27 @@ bool IPAddress::fromString(const char *address) { return true; } -IPAddress& IPAddress::operator=(const uint8_t *address) { +IPAddress& IPAddress::operator=(const uint8_t *address) +{ memcpy(_address.bytes, address, sizeof(_address.bytes)); return *this; } -IPAddress& IPAddress::operator=(uint32_t address) { +IPAddress& IPAddress::operator=(uint32_t address) +{ _address.dword = address; return *this; } -bool IPAddress::operator==(const uint8_t* addr) const { +bool IPAddress::operator==(const uint8_t* addr) const +{ return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0; } std::string IPAddress::toString() { char szRet[16]; - sprintf(szRet,"%u.%u.%u.%u", _address.bytes[0], _address.bytes[1], _address.bytes[2], _address.bytes[3]); + sprintf(szRet,"%u.%u.%u.%u", _address.bytes[0], _address.bytes[1], _address.bytes[2], + _address.bytes[3]); return std::string(szRet); } diff --git a/drivers/Linux/IPAddress.h b/drivers/Linux/IPAddress.h index c8e336c81..68b9fb250 100644 --- a/drivers/Linux/IPAddress.h +++ b/drivers/Linux/IPAddress.h @@ -29,127 +29,137 @@ /** * @brief A class to make it easier to handle and pass around IP addresses */ -class IPAddress { - private: - union { - uint8_t bytes[4]; //!< IPv4 address as an array - uint32_t dword; //!< IPv4 address in 32 bits format - } _address; +class IPAddress +{ +private: + union { + uint8_t bytes[4]; //!< IPv4 address as an array + uint32_t dword; //!< IPv4 address in 32 bits format + } _address; - /** - * @brief Access the raw byte array containing the address. - * - * Because this returns a pointer to the internal structure rather than a copy of the address - * this function should only be used when you know that the usage of the returned uint8_t* will - * be transient and not stored. - * - * @return pointer to the internal structure. - */ - uint8_t* raw_address() { - return _address.bytes; - } + /** + * @brief Access the raw byte array containing the address. + * + * Because this returns a pointer to the internal structure rather than a copy of the address + * this function should only be used when you know that the usage of the returned uint8_t* will + * be transient and not stored. + * + * @return pointer to the internal structure. + */ + uint8_t* raw_address() + { + return _address.bytes; + } - public: - /** - * @brief IPAddress constructor. - */ - IPAddress(); - /** - * @brief IPAddress constructor. - * - * @param first_octet first octet of the IPv4 address. - * @param second_octet second octet of the IPv4 address. - * @param third_octet third octet of the IPv4 address. - * @param fourth_octet fourth octet of the IPv4 address. - */ - IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); - /** - * @brief IPAddress constructor. - * - * @param address to be set from a 32 bits integer. - */ - IPAddress(uint32_t address); - /** - * @brief IPAddress constructor. - * - * @param address to be set from a byte array. - */ - IPAddress(const uint8_t *address); - /** - * @brief Set the IP from a array of characters. - * - * @param address to be set. - */ - bool fromString(const char *address); - /** - * @brief Set the IP from a string class type. - * - * @param address to be set. - */ - bool fromString(const std::string &address) { return fromString(address.c_str()); } - /** - * @brief Overloaded cast operator - * - * Allow IPAddress objects to be used where a pointer to a four-byte uint8_t array is expected - */ - operator uint32_t() const { - return _address.dword; - } - /** - * @brief Overloaded cast operator - * - */ - bool operator==(const IPAddress& addr) const { - return _address.dword == addr._address.dword; - } - /** - * @brief Overloaded cast operator - * - */ - bool operator==(uint32_t addr) const { - return _address.dword == addr; - } - /** - * @brief Overloaded cast operator - * - */ - bool operator==(const uint8_t* addr) const; - /** - * @brief Overloaded index operator. - * - * Allow getting and setting individual octets of the address. - * - */ - uint8_t operator[](int index) const { - return _address.bytes[index]; - } - /** - * @brief Overloaded index operator - * - */ - uint8_t& operator[](int index) { - return _address.bytes[index]; - } - /** - * @brief Overloaded copy operators. - * - * Allow initialisation of IPAddress objects from byte array. - */ - IPAddress& operator=(const uint8_t *address); - /** - * @brief Overloaded copy operator. - * - * Allow initialisation of IPAddress objects from a 32 bits integer. - */ - IPAddress& operator=(uint32_t address); - /** - * @brief Convert the IP address to a string. - * - * @return A stringified IP address - */ - std::string toString(); +public: + /** + * @brief IPAddress constructor. + */ + IPAddress(); + /** + * @brief IPAddress constructor. + * + * @param first_octet first octet of the IPv4 address. + * @param second_octet second octet of the IPv4 address. + * @param third_octet third octet of the IPv4 address. + * @param fourth_octet fourth octet of the IPv4 address. + */ + IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); + /** + * @brief IPAddress constructor. + * + * @param address to be set from a 32 bits integer. + */ + IPAddress(uint32_t address); + /** + * @brief IPAddress constructor. + * + * @param address to be set from a byte array. + */ + IPAddress(const uint8_t *address); + /** + * @brief Set the IP from a array of characters. + * + * @param address to be set. + */ + bool fromString(const char *address); + /** + * @brief Set the IP from a string class type. + * + * @param address to be set. + */ + bool fromString(const std::string &address) + { + return fromString(address.c_str()); + } + /** + * @brief Overloaded cast operator + * + * Allow IPAddress objects to be used where a pointer to a four-byte uint8_t array is expected + */ + operator uint32_t() const + { + return _address.dword; + } + /** + * @brief Overloaded cast operator + * + */ + bool operator==(const IPAddress& addr) const + { + return _address.dword == addr._address.dword; + } + /** + * @brief Overloaded cast operator + * + */ + bool operator==(uint32_t addr) const + { + return _address.dword == addr; + } + /** + * @brief Overloaded cast operator + * + */ + bool operator==(const uint8_t* addr) const; + /** + * @brief Overloaded index operator. + * + * Allow getting and setting individual octets of the address. + * + */ + uint8_t operator[](int index) const + { + return _address.bytes[index]; + } + /** + * @brief Overloaded index operator + * + */ + uint8_t& operator[](int index) + { + return _address.bytes[index]; + } + /** + * @brief Overloaded copy operators. + * + * Allow initialisation of IPAddress objects from byte array. + */ + IPAddress& operator=(const uint8_t *address); + /** + * @brief Overloaded copy operator. + * + * Allow initialisation of IPAddress objects from a 32 bits integer. + */ + IPAddress& operator=(uint32_t address); + /** + * @brief Convert the IP address to a string. + * + * @return A stringified IP address + */ + std::string toString(); - friend class Client; + friend class Client; }; #endif diff --git a/drivers/Linux/Print.cpp b/drivers/Linux/Print.cpp index 4c8d670a3..86c0e20c5 100644 --- a/drivers/Linux/Print.cpp +++ b/drivers/Linux/Print.cpp @@ -30,7 +30,8 @@ // Public Methods ////////////////////////////////////////////////////////////// -size_t Print::write(const uint8_t *buffer, size_t size) { +size_t Print::write(const uint8_t *buffer, size_t size) +{ size_t n = 0; while(size--) { n += write(*buffer++); @@ -42,7 +43,8 @@ size_t #ifdef __GNUC__ __attribute__((format(printf, 2, 3))) #endif -Print::printf(const char *format, ...) { +Print::printf(const char *format, ...) +{ va_list arg; va_start(arg, format); char temp[64]; @@ -65,31 +67,38 @@ Print::printf(const char *format, ...) { return len; } -size_t Print::print(const std::string &s) { +size_t Print::print(const std::string &s) +{ return write(s.c_str(), s.length()); } -size_t Print::print(const char str[]) { +size_t Print::print(const char str[]) +{ return write(str); } -size_t Print::print(char c) { +size_t Print::print(char c) +{ return write(c); } -size_t Print::print(unsigned char b, int base) { +size_t Print::print(unsigned char b, int base) +{ return print((unsigned long) b, base); } -size_t Print::print(int n, int base) { +size_t Print::print(int n, int base) +{ return print((long) n, base); } -size_t Print::print(unsigned int n, int base) { +size_t Print::print(unsigned int n, int base) +{ return print((unsigned long) n, base); } -size_t Print::print(long n, int base) { +size_t Print::print(long n, int base) +{ if(base == 0) { return write(n); } else if(base == 10) { @@ -104,72 +113,83 @@ size_t Print::print(long n, int base) { } } -size_t Print::print(unsigned long n, int base) { +size_t Print::print(unsigned long n, int base) +{ if(base == 0) { return write(n); - } - else { + } else { return printNumber(n, base); } } -size_t Print::print(double n, int digits) { +size_t Print::print(double n, int digits) +{ return printFloat(n, digits); } -size_t Print::println(void) { +size_t Print::println(void) +{ return print("\r\n"); } -size_t Print::println(const std::string &s) { +size_t Print::println(const std::string &s) +{ size_t n = print(s); n += println(); return n; } -size_t Print::println(const char c[]) { +size_t Print::println(const char c[]) +{ size_t n = print(c); n += println(); return n; } -size_t Print::println(char c) { +size_t Print::println(char c) +{ size_t n = print(c); n += println(); return n; } -size_t Print::println(unsigned char b, int base) { +size_t Print::println(unsigned char b, int base) +{ size_t n = print(b, base); n += println(); return n; } -size_t Print::println(int num, int base) { +size_t Print::println(int num, int base) +{ size_t n = print(num, base); n += println(); return n; } -size_t Print::println(unsigned int num, int base) { +size_t Print::println(unsigned int num, int base) +{ size_t n = print(num, base); n += println(); return n; } -size_t Print::println(long num, int base) { +size_t Print::println(long num, int base) +{ size_t n = print(num, base); n += println(); return n; } -size_t Print::println(unsigned long num, int base) { +size_t Print::println(unsigned long num, int base) +{ size_t n = print(num, base); n += println(); return n; } -size_t Print::println(double num, int digits) { +size_t Print::println(double num, int digits) +{ size_t n = print(num, digits); n += println(); return n; @@ -177,7 +197,8 @@ size_t Print::println(double num, int digits) { // Private Methods ///////////////////////////////////////////////////////////// -size_t Print::printNumber(unsigned long n, uint8_t base) { +size_t Print::printNumber(unsigned long n, uint8_t base) +{ char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte. char *str = &buf[sizeof(buf) - 1]; @@ -198,7 +219,8 @@ size_t Print::printNumber(unsigned long n, uint8_t base) { return write(str); } -size_t Print::printFloat(double number, uint8_t digits) { +size_t Print::printFloat(double number, uint8_t digits) +{ size_t n = 0; if(std::isnan(number)) { diff --git a/drivers/Linux/Print.h b/drivers/Linux/Print.h index e59900e20..ff8f69534 100644 --- a/drivers/Linux/Print.h +++ b/drivers/Linux/Print.h @@ -32,54 +32,67 @@ #define OCT 8 #define BIN 2 -class Print { - private: - int write_error; - size_t printNumber(unsigned long n, uint8_t base); - size_t printFloat(double number, uint8_t digits); +class Print +{ +private: + int write_error; + size_t printNumber(unsigned long n, uint8_t base); + size_t printFloat(double number, uint8_t digits); - protected: - void setWriteError(int err = 1) { write_error = err; } +protected: + void setWriteError(int err = 1) + { + write_error = err; + } - public: - Print() : write_error(0) {} +public: + Print() : write_error(0) {} - int getWriteError() { return write_error; } - void clearWriteError() { setWriteError(0); } + int getWriteError() + { + return write_error; + } + void clearWriteError() + { + setWriteError(0); + } - virtual size_t write(uint8_t) = 0; - size_t write(const char *str) { - if (str == NULL) - return 0; - return write((const uint8_t *) str, strlen(str)); - } - virtual size_t write(const uint8_t *buffer, size_t size); - size_t write(const char *buffer, size_t size) { - return write((const uint8_t *) buffer, size); + virtual size_t write(uint8_t) = 0; + size_t write(const char *str) + { + if (str == NULL) { + return 0; } + return write((const uint8_t *) str, strlen(str)); + } + virtual size_t write(const uint8_t *buffer, size_t size); + size_t write(const char *buffer, size_t size) + { + return write((const uint8_t *) buffer, size); + } - size_t printf(const char * format, ...) __attribute__ ((format (printf, 2, 3))); - size_t print(const std::string &); - size_t print(const char[]); - size_t print(char); - size_t print(unsigned char, int = DEC); - size_t print(int, int = DEC); - size_t print(unsigned int, int = DEC); - size_t print(long, int = DEC); - size_t print(unsigned long, int = DEC); - size_t print(double, int = 2); + size_t printf(const char * format, ...) __attribute__ ((format (printf, 2, 3))); + size_t print(const std::string &); + size_t print(const char[]); + size_t print(char); + size_t print(unsigned char, int = DEC); + size_t print(int, int = DEC); + size_t print(unsigned int, int = DEC); + size_t print(long, int = DEC); + size_t print(unsigned long, int = DEC); + size_t print(double, int = 2); - size_t println(const std::string &s); - size_t println(const char[]); - size_t println(char); - size_t println(unsigned char, int = DEC); - size_t println(int, int = DEC); - size_t println(unsigned int, int = DEC); - size_t println(long, int = DEC); - size_t println(unsigned long, int = DEC); - size_t println(double, int = 2); - size_t println(void); - }; + size_t println(const std::string &s); + size_t println(const char[]); + size_t println(char); + size_t println(unsigned char, int = DEC); + size_t println(int, int = DEC); + size_t println(unsigned int, int = DEC); + size_t println(long, int = DEC); + size_t println(unsigned long, int = DEC); + size_t println(double, int = 2); + size_t println(void); +}; #endif #endif diff --git a/drivers/Linux/SerialPort.cpp b/drivers/Linux/SerialPort.cpp index 0c9f1bb1d..5adca054a 100644 --- a/drivers/Linux/SerialPort.cpp +++ b/drivers/Linux/SerialPort.cpp @@ -69,7 +69,8 @@ bool SerialPort::open(int bauds) /* create a symlink with predictable name to the PTY device */ unlink(serialPort.c_str()); // remove the symlink if it already exists if (symlink(ptsname(sd), serialPort.c_str()) != 0) { - logError("Couldn't create a symlink '%s' to PTY! (%d) %s\n", serialPort.c_str(), errno, strerror(errno)); + logError("Couldn't create a symlink '%s' to PTY! (%d) %s\n", serialPort.c_str(), errno, + strerror(errno)); return false; } } else { @@ -83,23 +84,57 @@ bool SerialPort::open(int bauds) } switch (bauds) { - case 50: speed = B50 ; break ; - case 75: speed = B75 ; break ; - case 110: speed = B110 ; break ; - case 134: speed = B134 ; break ; - case 150: speed = B150 ; break ; - case 200: speed = B200 ; break ; - case 300: speed = B300 ; break ; - case 600: speed = B600 ; break ; - case 1200: speed = B1200 ; break ; - case 1800: speed = B1800 ; break ; - case 2400: speed = B2400 ; break ; - case 9600: speed = B9600 ; break ; - case 19200: speed = B19200 ; break ; - case 38400: speed = B38400 ; break ; - case 57600: speed = B57600 ; break ; - case 115200: speed = B115200 ; break ; - default: speed = B115200 ; break ; + case 50: + speed = B50 ; + break ; + case 75: + speed = B75 ; + break ; + case 110: + speed = B110 ; + break ; + case 134: + speed = B134 ; + break ; + case 150: + speed = B150 ; + break ; + case 200: + speed = B200 ; + break ; + case 300: + speed = B300 ; + break ; + case 600: + speed = B600 ; + break ; + case 1200: + speed = B1200 ; + break ; + case 1800: + speed = B1800 ; + break ; + case 2400: + speed = B2400 ; + break ; + case 9600: + speed = B9600 ; + break ; + case 19200: + speed = B19200 ; + break ; + case 38400: + speed = B38400 ; + break ; + case 57600: + speed = B57600 ; + break ; + case 115200: + speed = B115200 ; + break ; + default: + speed = B115200 ; + break ; } // Get the current options of the port diff --git a/drivers/Linux/SerialPort.h b/drivers/Linux/SerialPort.h index e0f77bb8e..4279b3c95 100644 --- a/drivers/Linux/SerialPort.h +++ b/drivers/Linux/SerialPort.h @@ -28,7 +28,8 @@ * SerialPort Class * Class that provides the functionality of arduino Serial library */ -class SerialPort : public Stream { +class SerialPort : public Stream +{ private: int sd; //!< @brief file descriptor number. diff --git a/drivers/Linux/Server.h b/drivers/Linux/Server.h index c637f7abe..61b14a0e5 100644 --- a/drivers/Linux/Server.h +++ b/drivers/Linux/Server.h @@ -23,9 +23,10 @@ #include "Print.h" #if !DOXYGEN -class Server : public Print { - public: - virtual void begin() =0; +class Server : public Print +{ +public: + virtual void begin() =0; }; #endif diff --git a/drivers/Linux/SoftEeprom.cpp b/drivers/Linux/SoftEeprom.cpp index bc1b497a9..46e4b8158 100644 --- a/drivers/Linux/SoftEeprom.cpp +++ b/drivers/Linux/SoftEeprom.cpp @@ -52,7 +52,8 @@ SoftEeprom::SoftEeprom(const char *fileName, size_t length) myFile.write((const char*)_values, _length); myFile.close(); } else if (fileInfo.st_size < 0 || (size_t)fileInfo.st_size != _length) { - logError("Config file %s is not the correct size of %zu. Please remove the file and a new one will be created.\n", _fileName, _length); + logError("Config file %s is not the correct size of %zu. Please remove the file and a new one will be created.\n", + _fileName, _length); exit(1); } else { //Read config into local memory. @@ -98,10 +99,10 @@ void SoftEeprom::readBlock(void* buf, void* addr, size_t length) void SoftEeprom::writeBlock(void* buf, void* addr, size_t length) { unsigned long int offs = reinterpret_cast(addr); - + if (length && offs + length <= _length) { memcpy(_values+offs, buf, length); - + std::ofstream myFile(_fileName, std::ios::out | std::ios::in | std::ios::binary); if (!myFile) { logError("Unable to write config to file %s.\n", _fileName); diff --git a/drivers/Linux/SoftEeprom.h b/drivers/Linux/SoftEeprom.h index e623773ab..70ad72cb1 100644 --- a/drivers/Linux/SoftEeprom.h +++ b/drivers/Linux/SoftEeprom.h @@ -30,7 +30,8 @@ /** * SoftEeprom class */ -class SoftEeprom { +class SoftEeprom +{ private: size_t _length; //!< @brief Eeprom max size. diff --git a/drivers/Linux/Stream.cpp b/drivers/Linux/Stream.cpp index 62f9f6162..b07826ee1 100644 --- a/drivers/Linux/Stream.cpp +++ b/drivers/Linux/Stream.cpp @@ -28,50 +28,53 @@ #define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field // private method to read stream with timeout -int Stream::timedRead() { - int c; - _startMillis = millis(); - do { - c = read(); - if(c >= 0) { - return c; - } - yield(); - } while(millis() - _startMillis < _timeout); - return -1; // -1 indicates timeout +int Stream::timedRead() +{ + int c; + _startMillis = millis(); + do { + c = read(); + if(c >= 0) { + return c; + } + yield(); + } while(millis() - _startMillis < _timeout); + return -1; // -1 indicates timeout } // private method to peek stream with timeout -int Stream::timedPeek() { - int c; - _startMillis = millis(); - do { - c = peek(); - if(c >= 0) { - return c; - } - yield(); - } while(millis() - _startMillis < _timeout); - return -1; // -1 indicates timeout +int Stream::timedPeek() +{ + int c; + _startMillis = millis(); + do { + c = peek(); + if(c >= 0) { + return c; + } + yield(); + } while(millis() - _startMillis < _timeout); + return -1; // -1 indicates timeout } // returns peek of the next digit in the stream or -1 if timeout // discards non-numeric characters -int Stream::peekNextDigit() { - int c; - while(1) { - c = timedPeek(); - if(c < 0) { - return c; // timeout - } - if(c == '-') { - return c; - } - if(c >= '0' && c <= '9') { - return c; - } - read(); // discard non-numeric - } +int Stream::peekNextDigit() +{ + int c; + while(1) { + c = timedPeek(); + if(c < 0) { + return c; // timeout + } + if(c == '-') { + return c; + } + if(c >= '0' && c <= '9') { + return c; + } + read(); // discard non-numeric + } } // Public Methods @@ -79,148 +82,151 @@ int Stream::peekNextDigit() { void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait { - _timeout = timeout; + _timeout = timeout; } // find returns true if the target string is found -bool Stream::find(const char *target) { - return findUntil(target, (char*) ""); +bool Stream::find(const char *target) +{ + return findUntil(target, (char*) ""); } // reads data from the stream until the target string of given length is found // returns true if target string is found, false if timed out -bool Stream::find(const char *target, size_t length) { - return findUntil(target, length, NULL, 0); +bool Stream::find(const char *target, size_t length) +{ + return findUntil(target, length, NULL, 0); } // as find but search ends if the terminator string is found -bool Stream::findUntil(const char *target, const char *terminator) { - return findUntil(target, strlen(target), terminator, strlen(terminator)); +bool Stream::findUntil(const char *target, const char *terminator) +{ + return findUntil(target, strlen(target), terminator, strlen(terminator)); } // reads data from the stream until the target string of the given length is found // search terminated if the terminator string is found // returns true if target string is found, false if terminated or timed out -bool Stream::findUntil(const char *target, size_t targetLen, const char *terminator, size_t termLen) { - size_t index = 0; // maximum target string length is 64k bytes! - size_t termIndex = 0; - int c; - - if(*target == 0) { - return true; // return true if target is a null string - } - while((c = timedRead()) > 0) { - - if(c != target[index]) { - index = 0; // reset index if any char does not match - } - if(c == target[index]) { - //////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1); - if(++index >= targetLen) { // return true if all chars in the target match - return true; - } - } - - if(termLen > 0 && c == terminator[termIndex]) { - if(++termIndex >= termLen) { - return false; // return false if terminate string found before target string - } - } else { - termIndex = 0; - } - } - return false; +bool Stream::findUntil(const char *target, size_t targetLen, const char *terminator, + size_t termLen) +{ + size_t index = 0; // maximum target string length is 64k bytes! + size_t termIndex = 0; + int c; + + if(*target == 0) { + return true; // return true if target is a null string + } + while((c = timedRead()) > 0) { + + if(c != target[index]) { + index = 0; // reset index if any char does not match + } + if(c == target[index]) { + //////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1); + if(++index >= targetLen) { // return true if all chars in the target match + return true; + } + } + + if(termLen > 0 && c == terminator[termIndex]) { + if(++termIndex >= termLen) { + return false; // return false if terminate string found before target string + } + } else { + termIndex = 0; + } + } + return false; } // returns the first valid (long) integer value from the current position. // initial characters that are not digits (or the minus sign) are skipped // function is terminated by the first character that is not a digit. -long Stream::parseInt() { - return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout) +long Stream::parseInt() +{ + return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout) } // as above but a given skipChar is ignored // this allows format characters (typically commas) in values to be ignored -long Stream::parseInt(char skipChar) { - boolean isNegative = false; - long value = 0; - int c; - - c = peekNextDigit(); - // ignore non numeric leading characters - if(c < 0) { - return 0; // zero returned if timeout - } - - do { - if(c == skipChar) { - // ignore this charactor - } - else if(c == '-') { - isNegative = true; - } - else if(c >= '0' && c <= '9') { // is c a digit? - value = value * 10 + c - '0'; - } - read(); // consume the character we got with peek - c = timedPeek(); - } while((c >= '0' && c <= '9') || c == skipChar); - - if(isNegative) { - value = -value; - } - return value; +long Stream::parseInt(char skipChar) +{ + boolean isNegative = false; + long value = 0; + int c; + + c = peekNextDigit(); + // ignore non numeric leading characters + if(c < 0) { + return 0; // zero returned if timeout + } + + do { + if(c == skipChar) { + // ignore this charactor + } else if(c == '-') { + isNegative = true; + } else if(c >= '0' && c <= '9') { // is c a digit? + value = value * 10 + c - '0'; + } + read(); // consume the character we got with peek + c = timedPeek(); + } while((c >= '0' && c <= '9') || c == skipChar); + + if(isNegative) { + value = -value; + } + return value; } // as parseInt but returns a floating point value -float Stream::parseFloat() { - return parseFloat(NO_SKIP_CHAR); +float Stream::parseFloat() +{ + return parseFloat(NO_SKIP_CHAR); } // as above but the given skipChar is ignored // this allows format characters (typically commas) in values to be ignored -float Stream::parseFloat(char skipChar) { - boolean isNegative = false; - boolean isFraction = false; - long value = 0; - int c; - float fraction = 1.0; - - c = peekNextDigit(); - // ignore non numeric leading characters - if(c < 0) { - return 0; // zero returned if timeout - } - - do { - if(c == skipChar) { - // ignore - } - else if(c == '-') { - isNegative = true; - } - else if(c == '.') { - isFraction = true; - } - else if(c >= '0' && c <= '9') { // is c a digit? - value = value * 10 + c - '0'; - if(isFraction) { - fraction *= 0.1; - } - } - read(); // consume the character we got with peek - c = timedPeek(); - } while((c >= '0' && c <= '9') || c == '.' || c == skipChar); - - if(isNegative) { - value = -value; - } - if(isFraction) { - return value * fraction; - } - else { - return value; - } +float Stream::parseFloat(char skipChar) +{ + boolean isNegative = false; + boolean isFraction = false; + long value = 0; + int c; + float fraction = 1.0; + + c = peekNextDigit(); + // ignore non numeric leading characters + if(c < 0) { + return 0; // zero returned if timeout + } + + do { + if(c == skipChar) { + // ignore + } else if(c == '-') { + isNegative = true; + } else if(c == '.') { + isFraction = true; + } else if(c >= '0' && c <= '9') { // is c a digit? + value = value * 10 + c - '0'; + if(isFraction) { + fraction *= 0.1; + } + } + read(); // consume the character we got with peek + c = timedPeek(); + } while((c >= '0' && c <= '9') || c == '.' || c == skipChar); + + if(isNegative) { + value = -value; + } + if(isFraction) { + return value * fraction; + } else { + return value; + } } // read characters from stream into buffer @@ -228,55 +234,59 @@ float Stream::parseFloat(char skipChar) { // returns the number of characters placed in the buffer // the buffer is NOT null terminated. // -size_t Stream::readBytes(char *buffer, size_t length) { - size_t count = 0; - while(count < length) { - int c = timedRead(); - if(c < 0) { - break; - } - *buffer++ = (char) c; - count++; - } - return count; +size_t Stream::readBytes(char *buffer, size_t length) +{ + size_t count = 0; + while(count < length) { + int c = timedRead(); + if(c < 0) { + break; + } + *buffer++ = (char) c; + count++; + } + return count; } // as readBytes with terminator character // terminates if length characters have been read, timeout, or if the terminator character detected // returns the number of characters placed in the buffer (0 means no valid data found) -size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) { - if(length < 1) { - return 0; - } - size_t index = 0; - while(index < length) { - int c = timedRead(); - if(c < 0 || c == terminator) { - break; - } - *buffer++ = (char) c; - index++; - } - return index; // return number of characters, not including null terminator +size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length) +{ + if(length < 1) { + return 0; + } + size_t index = 0; + while(index < length) { + int c = timedRead(); + if(c < 0 || c == terminator) { + break; + } + *buffer++ = (char) c; + index++; + } + return index; // return number of characters, not including null terminator } -std::string Stream::readString() { - std::string ret; - int c = timedRead(); - while(c >= 0) { - ret += (char) c; - c = timedRead(); - } - return ret; +std::string Stream::readString() +{ + std::string ret; + int c = timedRead(); + while(c >= 0) { + ret += (char) c; + c = timedRead(); + } + return ret; } -std::string Stream::readStringUntil(char terminator) { - std::string ret; - int c = timedRead(); - while(c >= 0 && c != terminator) { - ret += (char) c; - c = timedRead(); - } - return ret; +std::string Stream::readStringUntil(char terminator) +{ + std::string ret; + int c = timedRead(); + while(c >= 0 && c != terminator) { + ret += (char) c; + c = timedRead(); + } + return ret; } diff --git a/drivers/Linux/Stream.h b/drivers/Linux/Stream.h index dff2074e5..8bacd5040 100644 --- a/drivers/Linux/Stream.h +++ b/drivers/Linux/Stream.h @@ -38,82 +38,99 @@ */ #if !DOXYGEN -class Stream: public Print { - protected: - unsigned long _timeout; // number of milliseconds to wait for the next char before aborting timed read - unsigned long _startMillis; // used for timeout measurement - int timedRead(); // private method to read stream with timeout - int timedPeek(); // private method to peek stream with timeout - int peekNextDigit(); // returns the next numeric digit in the stream or -1 if timeout - - public: - virtual int available() = 0; - virtual int read() = 0; - virtual int peek() = 0; - virtual void flush() = 0; - - Stream() { - _timeout = 1000; - } - -// parsing methods - - void setTimeout(unsigned long timeout); // sets maximum milliseconds to wait for stream data, default is 1 second - - bool find(const char *target); // reads data from the stream until the target string is found - bool find(uint8_t *target) { - return find((char *) target); - } - // returns true if target string is found, false if timed out (see setTimeout) - - bool find(const char *target, size_t length); // reads data from the stream until the target string of given length is found - bool find(const uint8_t *target, size_t length) { - return find((char *) target, length); - } - // returns true if target string is found, false if timed out - - bool find(char target) { return find (&target, 1); } - - bool findUntil(const char *target, const char *terminator); // as find but search ends if the terminator string is found - bool findUntil(const uint8_t *target, const char *terminator) { - return findUntil((char *) target, terminator); - } - - bool findUntil(const char *target, size_t targetLen, const char *terminate, size_t termLen); // as above but search ends if the terminate string is found - bool findUntil(const uint8_t *target, size_t targetLen, const char *terminate, size_t termLen) { - return findUntil((char *) target, targetLen, terminate, termLen); - } - - long parseInt(); // returns the first valid (long) integer value from the current position. - // initial characters that are not digits (or the minus sign) are skipped - // integer is terminated by the first character that is not a digit. - - float parseFloat(); // float version of parseInt - - virtual size_t readBytes(char *buffer, size_t length); // read chars from stream into buffer - virtual size_t readBytes(uint8_t *buffer, size_t length) { - return readBytes((char *) buffer, length); - } - // terminates if length characters have been read or timeout (see setTimeout) - // returns the number of characters placed in the buffer (0 means no valid data found) - - size_t readBytesUntil(char terminator, char *buffer, size_t length); // as readBytes with terminator character - size_t readBytesUntil(char terminator, uint8_t *buffer, size_t length) { - return readBytesUntil(terminator, (char *) buffer, length); - } - // terminates if length characters have been read, timeout, or if the terminator character detected - // returns the number of characters placed in the buffer (0 means no valid data found) - - // Arduino String functions to be added here - std::string readString(); - std::string readStringUntil(char terminator); - - protected: - long parseInt(char skipChar); // as above but the given skipChar is ignored - // as above but the given skipChar is ignored - // this allows format characters (typically commas) in values to be ignored - - float parseFloat(char skipChar); // as above but the given skipChar is ignored +class Stream: public Print +{ +protected: + unsigned long + _timeout; // number of milliseconds to wait for the next char before aborting timed read + unsigned long _startMillis; // used for timeout measurement + int timedRead(); // private method to read stream with timeout + int timedPeek(); // private method to peek stream with timeout + int peekNextDigit(); // returns the next numeric digit in the stream or -1 if timeout + +public: + virtual int available() = 0; + virtual int read() = 0; + virtual int peek() = 0; + virtual void flush() = 0; + + Stream() + { + _timeout = 1000; + } + + // parsing methods + + void setTimeout(unsigned long + timeout); // sets maximum milliseconds to wait for stream data, default is 1 second + + bool find(const char *target); // reads data from the stream until the target string is found + bool find(uint8_t *target) + { + return find((char *) target); + } + // returns true if target string is found, false if timed out (see setTimeout) + + bool find(const char *target, size_t + length); // reads data from the stream until the target string of given length is found + bool find(const uint8_t *target, size_t length) + { + return find((char *) target, length); + } + // returns true if target string is found, false if timed out + + bool find(char target) + { + return find (&target, 1); + } + + bool findUntil(const char *target, + const char *terminator); // as find but search ends if the terminator string is found + bool findUntil(const uint8_t *target, const char *terminator) + { + return findUntil((char *) target, terminator); + } + + bool findUntil(const char *target, size_t targetLen, const char *terminate, + size_t termLen); // as above but search ends if the terminate string is found + bool findUntil(const uint8_t *target, size_t targetLen, const char *terminate, size_t termLen) + { + return findUntil((char *) target, targetLen, terminate, termLen); + } + + long parseInt(); // returns the first valid (long) integer value from the current position. + // initial characters that are not digits (or the minus sign) are skipped + // integer is terminated by the first character that is not a digit. + + float parseFloat(); // float version of parseInt + + virtual size_t readBytes(char *buffer, size_t length); // read chars from stream into buffer + virtual size_t readBytes(uint8_t *buffer, size_t length) + { + return readBytes((char *) buffer, length); + } + // terminates if length characters have been read or timeout (see setTimeout) + // returns the number of characters placed in the buffer (0 means no valid data found) + + size_t readBytesUntil(char terminator, char *buffer, + size_t length); // as readBytes with terminator character + size_t readBytesUntil(char terminator, uint8_t *buffer, size_t length) + { + return readBytesUntil(terminator, (char *) buffer, length); + } + // terminates if length characters have been read, timeout, or if the terminator character detected + // returns the number of characters placed in the buffer (0 means no valid data found) + + // Arduino String functions to be added here + std::string readString(); + std::string readStringUntil(char terminator); + +protected: + long parseInt(char skipChar); // as above but the given skipChar is ignored + // as above but the given skipChar is ignored + // this allows format characters (typically commas) in values to be ignored + + float parseFloat(char skipChar); // as above but the given skipChar is ignored }; #endif diff --git a/drivers/Linux/compatibility.cpp b/drivers/Linux/compatibility.cpp index a19ce54a6..1f8f74837 100644 --- a/drivers/Linux/compatibility.cpp +++ b/drivers/Linux/compatibility.cpp @@ -23,46 +23,46 @@ unsigned long millis(void) unsigned long micros() { - timeval curTime; + timeval curTime; - if (millis_at_start == 0) { - gettimeofday(&curTime, NULL); - millis_at_start = curTime.tv_sec; - } + if (millis_at_start == 0) { + gettimeofday(&curTime, NULL); + millis_at_start = curTime.tv_sec; + } - gettimeofday(&curTime, NULL); - return ((curTime.tv_sec - millis_at_start) * 1000000) + (curTime.tv_usec); + gettimeofday(&curTime, NULL); + return ((curTime.tv_sec - millis_at_start) * 1000000) + (curTime.tv_usec); } void _delay_ms(unsigned int millis) { - struct timespec sleeper; - - sleeper.tv_sec = (time_t)(millis / 1000); - sleeper.tv_nsec = (long)(millis % 1000) * 1000000; - nanosleep(&sleeper, NULL); + struct timespec sleeper; + + sleeper.tv_sec = (time_t)(millis / 1000); + sleeper.tv_nsec = (long)(millis % 1000) * 1000000; + nanosleep(&sleeper, NULL); } void randomSeed(unsigned long seed) { - if (seed != 0) { - srand(seed); - } + if (seed != 0) { + srand(seed); + } } long randMax(long howbig) { - if (howbig == 0) { - return 0; - } - return rand() % howbig; + if (howbig == 0) { + return 0; + } + return rand() % howbig; } long randMinMax(long howsmall, long howbig) { - if (howsmall >= howbig) { - return howsmall; - } - long diff = howbig - howsmall; - return randMax(diff) + howsmall; + if (howsmall >= howbig) { + return howsmall; + } + long diff = howbig - howsmall; + return randMax(diff) + howsmall; } diff --git a/drivers/Linux/noniso.cpp b/drivers/Linux/noniso.cpp index 04ee6f3ed..f751bb319 100644 --- a/drivers/Linux/noniso.cpp +++ b/drivers/Linux/noniso.cpp @@ -23,127 +23,136 @@ #include #include "stdlib_noniso.h" -char* utoa(unsigned value, char* result, int base) { - if(base < 2 || base > 16) { - *result = 0; - return result; - } - - char* out = result; - unsigned quotient = value; - - do { - const unsigned tmp = quotient / base; - *out = "0123456789abcdef"[quotient - (tmp * base)]; - ++out; - quotient = tmp; - } while(quotient); - - reverse(result, out); - *out = 0; - return result; +char* utoa(unsigned value, char* result, int base) +{ + if(base < 2 || base > 16) { + *result = 0; + return result; + } + + char* out = result; + unsigned quotient = value; + + do { + const unsigned tmp = quotient / base; + *out = "0123456789abcdef"[quotient - (tmp * base)]; + ++out; + quotient = tmp; + } while(quotient); + + reverse(result, out); + *out = 0; + return result; } -char* itoa(int value, char* result, int base) { - if(base < 2 || base > 16) { - *result = 0; - return result; - } - - char* out = result; - int quotient = abs(value); - - do { - const int tmp = quotient / base; - *out = "0123456789abcdef"[quotient - (tmp * base)]; - ++out; - quotient = tmp; - } while(quotient); - - // Apply negative sign - if(value < 0) { - *out++ = '-'; - } - - reverse(result, out); - *out = 0; - return result; +char* itoa(int value, char* result, int base) +{ + if(base < 2 || base > 16) { + *result = 0; + return result; + } + + char* out = result; + int quotient = abs(value); + + do { + const int tmp = quotient / base; + *out = "0123456789abcdef"[quotient - (tmp * base)]; + ++out; + quotient = tmp; + } while(quotient); + + // Apply negative sign + if(value < 0) { + *out++ = '-'; + } + + reverse(result, out); + *out = 0; + return result; } -int atoi(const char* s) { - return (int) atol(s); +int atoi(const char* s) +{ + return (int) atol(s); } -long atol(const char* s) { - char * tmp; - return strtol(s, &tmp, 10); +long atol(const char* s) +{ + char * tmp; + return strtol(s, &tmp, 10); } -double atof(const char* s) { - char * tmp; - return strtod(s, &tmp); +double atof(const char* s) +{ + char * tmp; + return strtod(s, &tmp); } -void reverse(char* begin, char* end) { - char *is = begin; - char *ie = end - 1; - while(is < ie) { - char tmp = *ie; - *ie = *is; - *is = tmp; - ++is; - --ie; - } +void reverse(char* begin, char* end) +{ + char *is = begin; + char *ie = end - 1; + while(is < ie) { + char tmp = *ie; + *ie = *is; + *is = tmp; + ++is; + --ie; + } } -char* ltoa(long value, char* result, int base) { - if(base < 2 || base > 16) { - *result = 0; - return result; - } - - char* out = result; - long quotient = abs(value); - - do { - const long tmp = quotient / base; - *out = "0123456789abcdef"[quotient - (tmp * base)]; - ++out; - quotient = tmp; - } while(quotient); - - // Apply negative sign - if(value < 0) { - *out++ = '-'; - } - - reverse(result, out); - *out = 0; - return result; +char* ltoa(long value, char* result, int base) +{ + if(base < 2 || base > 16) { + *result = 0; + return result; + } + + char* out = result; + long quotient = abs(value); + + do { + const long tmp = quotient / base; + *out = "0123456789abcdef"[quotient - (tmp * base)]; + ++out; + quotient = tmp; + } while(quotient); + + // Apply negative sign + if(value < 0) { + *out++ = '-'; + } + + reverse(result, out); + *out = 0; + return result; } -char* ultoa(unsigned long value, char* result, int base) { - if(base < 2 || base > 16) { - *result = 0; - return result; - } - - char* out = result; - unsigned long quotient = value; - - do { - const unsigned long tmp = quotient / base; - *out = "0123456789abcdef"[quotient - (tmp * base)]; - ++out; - quotient = tmp; - } while(quotient); - - reverse(result, out); - *out = 0; - return result; +char* ultoa(unsigned long value, char* result, int base) +{ + if(base < 2 || base > 16) { + *result = 0; + return result; + } + + char* out = result; + unsigned long quotient = value; + + do { + const unsigned long tmp = quotient / base; + *out = "0123456789abcdef"[quotient - (tmp * base)]; + ++out; + quotient = tmp; + } while(quotient); + + reverse(result, out); + *out = 0; + return result; } -char* dtostrf (double val, signed char width, unsigned char prec, char *s) { - sprintf(s,"%*.*f", width, prec, val); - return s; +char* dtostrf (double val, signed char width, unsigned char prec, char *s) +{ + sprintf(s,"%*.*f", width, prec, val); + return s; } diff --git a/drivers/Linux/stdlib_noniso.h b/drivers/Linux/stdlib_noniso.h index 636cbf437..ddbb920e8 100644 --- a/drivers/Linux/stdlib_noniso.h +++ b/drivers/Linux/stdlib_noniso.h @@ -1,9 +1,9 @@ -/* +/* stdlib_noniso.h - nonstandard (but usefull) conversion functions Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. This file is part of the esp8266 core for Arduino environment. - + This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either @@ -23,7 +23,7 @@ #define STDLIB_NONISO_H #ifdef __cplusplus -extern "C"{ +extern "C" { #endif int atoi(const char *s); @@ -39,7 +39,7 @@ char* ltoa (long val, char *s, int radix); char* utoa (unsigned int val, char *s, int radix); char* ultoa (unsigned long val, char *s, int radix); - + char* dtostrf (double val, signed char width, unsigned char prec, char *s); void reverse(char* begin, char* end); diff --git a/drivers/PubSubClient/PubSubClient.cpp b/drivers/PubSubClient/PubSubClient.cpp index d4a86c54f..989b73f7c 100644 --- a/drivers/PubSubClient/PubSubClient.cpp +++ b/drivers/PubSubClient/PubSubClient.cpp @@ -7,595 +7,644 @@ #include "PubSubClient.h" #include "Arduino.h" -PubSubClient::PubSubClient() { - this->_state = MQTT_DISCONNECTED; - this->_client = NULL; - this->stream = NULL; - setCallback(NULL); -} - -PubSubClient::PubSubClient(Client& client) { - this->_state = MQTT_DISCONNECTED; - setClient(client); - this->stream = NULL; -} - -PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client) { - this->_state = MQTT_DISCONNECTED; - setServer(addr, port); - setClient(client); - this->stream = NULL; -} -PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client, Stream& stream) { - this->_state = MQTT_DISCONNECTED; - setServer(addr,port); - setClient(client); - setStream(stream); -} -PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { - this->_state = MQTT_DISCONNECTED; - setServer(addr, port); - setCallback(callback); - setClient(client); - this->stream = NULL; -} -PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { - this->_state = MQTT_DISCONNECTED; - setServer(addr,port); - setCallback(callback); - setClient(client); - setStream(stream); -} - -PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client) { - this->_state = MQTT_DISCONNECTED; - setServer(ip, port); - setClient(client); - this->stream = NULL; -} -PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client, Stream& stream) { - this->_state = MQTT_DISCONNECTED; - setServer(ip,port); - setClient(client); - setStream(stream); -} -PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { - this->_state = MQTT_DISCONNECTED; - setServer(ip, port); - setCallback(callback); - setClient(client); - this->stream = NULL; -} -PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { - this->_state = MQTT_DISCONNECTED; - setServer(ip,port); - setCallback(callback); - setClient(client); - setStream(stream); -} - -PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client) { - this->_state = MQTT_DISCONNECTED; - setServer(domain,port); - setClient(client); - this->stream = NULL; -} -PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client, Stream& stream) { - this->_state = MQTT_DISCONNECTED; - setServer(domain,port); - setClient(client); - setStream(stream); -} -PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { - this->_state = MQTT_DISCONNECTED; - setServer(domain,port); - setCallback(callback); - setClient(client); - this->stream = NULL; -} -PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { - this->_state = MQTT_DISCONNECTED; - setServer(domain,port); - setCallback(callback); - setClient(client); - setStream(stream); -} - -boolean PubSubClient::connect(const char *id) { - return connect(id,NULL,NULL,0,0,0,0); -} - -boolean PubSubClient::connect(const char *id, const char *user, const char *pass) { - return connect(id,user,pass,0,0,0,0); -} - -boolean PubSubClient::connect(const char *id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) { - return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage); -} - -boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) { - if (!connected()) { - int result = 0; - - if (domain != NULL) { - result = _client->connect(this->domain, this->port); - } else { - result = _client->connect(this->ip, this->port); - } - if (result == 1) { - nextMsgId = 1; - // Leave room in the buffer for header and variable length field - uint16_t length = 5; - unsigned int j; +PubSubClient::PubSubClient() +{ + this->_state = MQTT_DISCONNECTED; + this->_client = NULL; + this->stream = NULL; + setCallback(NULL); +} + +PubSubClient::PubSubClient(Client& client) +{ + this->_state = MQTT_DISCONNECTED; + setClient(client); + this->stream = NULL; +} + +PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client) +{ + this->_state = MQTT_DISCONNECTED; + setServer(addr, port); + setClient(client); + this->stream = NULL; +} +PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client, Stream& stream) +{ + this->_state = MQTT_DISCONNECTED; + setServer(addr,port); + setClient(client); + setStream(stream); +} +PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) +{ + this->_state = MQTT_DISCONNECTED; + setServer(addr, port); + setCallback(callback); + setClient(client); + this->stream = NULL; +} +PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, + Stream& stream) +{ + this->_state = MQTT_DISCONNECTED; + setServer(addr,port); + setCallback(callback); + setClient(client); + setStream(stream); +} + +PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client) +{ + this->_state = MQTT_DISCONNECTED; + setServer(ip, port); + setClient(client); + this->stream = NULL; +} +PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client, Stream& stream) +{ + this->_state = MQTT_DISCONNECTED; + setServer(ip,port); + setClient(client); + setStream(stream); +} +PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) +{ + this->_state = MQTT_DISCONNECTED; + setServer(ip, port); + setCallback(callback); + setClient(client); + this->stream = NULL; +} +PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, + Stream& stream) +{ + this->_state = MQTT_DISCONNECTED; + setServer(ip,port); + setCallback(callback); + setClient(client); + setStream(stream); +} + +PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client) +{ + this->_state = MQTT_DISCONNECTED; + setServer(domain,port); + setClient(client); + this->stream = NULL; +} +PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client, Stream& stream) +{ + this->_state = MQTT_DISCONNECTED; + setServer(domain,port); + setClient(client); + setStream(stream); +} +PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, + Client& client) +{ + this->_state = MQTT_DISCONNECTED; + setServer(domain,port); + setCallback(callback); + setClient(client); + this->stream = NULL; +} +PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, + Client& client, Stream& stream) +{ + this->_state = MQTT_DISCONNECTED; + setServer(domain,port); + setCallback(callback); + setClient(client); + setStream(stream); +} + +boolean PubSubClient::connect(const char *id) +{ + return connect(id,NULL,NULL,0,0,0,0); +} + +boolean PubSubClient::connect(const char *id, const char *user, const char *pass) +{ + return connect(id,user,pass,0,0,0,0); +} + +boolean PubSubClient::connect(const char *id, const char* willTopic, uint8_t willQos, + boolean willRetain, const char* willMessage) +{ + return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage); +} + +boolean PubSubClient::connect(const char *id, const char *user, const char *pass, + const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) +{ + if (!connected()) { + int result = 0; + + if (domain != NULL) { + result = _client->connect(this->domain, this->port); + } else { + result = _client->connect(this->ip, this->port); + } + if (result == 1) { + nextMsgId = 1; + // Leave room in the buffer for header and variable length field + uint16_t length = 5; + unsigned int j; #if MQTT_VERSION == MQTT_VERSION_3_1 - uint8_t d[9] = {0x00,0x06,'M','Q','I','s','d','p', MQTT_VERSION}; + uint8_t d[9] = {0x00,0x06,'M','Q','I','s','d','p', MQTT_VERSION}; #define MQTT_HEADER_VERSION_LENGTH 9 #elif MQTT_VERSION == MQTT_VERSION_3_1_1 - uint8_t d[7] = {0x00,0x04,'M','Q','T','T',MQTT_VERSION}; + uint8_t d[7] = {0x00,0x04,'M','Q','T','T',MQTT_VERSION}; #define MQTT_HEADER_VERSION_LENGTH 7 #endif - for (j = 0;j>1); - } - } - - buffer[length++] = v; - - buffer[length++] = ((MQTT_KEEPALIVE) >> 8); - buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF); - length = writeString(id,buffer,length); - if (willTopic) { - length = writeString(willTopic,buffer,length); - length = writeString(willMessage,buffer,length); - } - - if(user != NULL) { - length = writeString(user,buffer,length); - if(pass != NULL) { - length = writeString(pass,buffer,length); - } - } - - write(MQTTCONNECT,buffer,length-5); - - lastInActivity = lastOutActivity = millis(); - - while (!_client->available()) { - unsigned long t = millis(); - if (t-lastInActivity >= ((int32_t) MQTT_SOCKET_TIMEOUT*1000UL)) { - _state = MQTT_CONNECTION_TIMEOUT; - _client->stop(); - return false; - } - } - uint8_t llen; - uint16_t len = readPacket(&llen); - - if (len == 4) { - if (buffer[3] == 0) { - lastInActivity = millis(); - pingOutstanding = false; - _state = MQTT_CONNECTED; - return true; - } else { - _state = buffer[3]; - } - } - _client->stop(); - } else { - _state = MQTT_CONNECT_FAILED; - } - return false; - } - return true; + for (j = 0; j>1); + } + } + + buffer[length++] = v; + + buffer[length++] = ((MQTT_KEEPALIVE) >> 8); + buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF); + length = writeString(id,buffer,length); + if (willTopic) { + length = writeString(willTopic,buffer,length); + length = writeString(willMessage,buffer,length); + } + + if(user != NULL) { + length = writeString(user,buffer,length); + if(pass != NULL) { + length = writeString(pass,buffer,length); + } + } + + write(MQTTCONNECT,buffer,length-5); + + lastInActivity = lastOutActivity = millis(); + + while (!_client->available()) { + unsigned long t = millis(); + if (t-lastInActivity >= ((int32_t) MQTT_SOCKET_TIMEOUT*1000UL)) { + _state = MQTT_CONNECTION_TIMEOUT; + _client->stop(); + return false; + } + } + uint8_t llen; + uint16_t len = readPacket(&llen); + + if (len == 4) { + if (buffer[3] == 0) { + lastInActivity = millis(); + pingOutstanding = false; + _state = MQTT_CONNECTED; + return true; + } else { + _state = buffer[3]; + } + } + _client->stop(); + } else { + _state = MQTT_CONNECT_FAILED; + } + return false; + } + return true; } // reads a byte into result -boolean PubSubClient::readByte(uint8_t * result) { - uint32_t previousMillis = millis(); - while(!_client->available()) { - uint32_t currentMillis = millis(); - if(currentMillis - previousMillis >= ((int32_t) MQTT_SOCKET_TIMEOUT * 1000)){ - return false; - } - } - *result = _client->read(); - return true; +boolean PubSubClient::readByte(uint8_t * result) +{ + uint32_t previousMillis = millis(); + while(!_client->available()) { + uint32_t currentMillis = millis(); + if(currentMillis - previousMillis >= ((int32_t) MQTT_SOCKET_TIMEOUT * 1000)) { + return false; + } + } + *result = _client->read(); + return true; } // reads a byte into result[*index] and increments index -boolean PubSubClient::readByte(uint8_t * result, uint16_t * index){ - uint16_t current_index = *index; - uint8_t * write_address = &(result[current_index]); - if(readByte(write_address)){ - *index = current_index + 1; - return true; - } - return false; -} - -uint16_t PubSubClient::readPacket(uint8_t* lengthLength) { - uint16_t len = 0; - if(!readByte(buffer, &len)) { - return 0; - } - bool isPublish = (buffer[0]&0xF0) == MQTTPUBLISH; - uint32_t multiplier = 1; - uint16_t length = 0; - uint8_t digit = 0; - uint16_t skip = 0; - uint8_t start = 0; - - do { - if(!readByte(&digit)) { - return 0; - } - buffer[len++] = digit; - length += (digit & 127) * multiplier; - multiplier *= 128; - } while ((digit & 128) != 0); - *lengthLength = len-1; - - if (isPublish) { - // Read in topic length to calculate bytes to skip over for Stream writing - if(!readByte(buffer, &len)) { - return 0; - } - if(!readByte(buffer, &len)) { - return 0; - } - skip = (buffer[*lengthLength+1]<<8)+buffer[*lengthLength+2]; - start = 2; - if (buffer[0]&MQTTQOS1) { - // skip message id - skip += 2; - } - } - - for (uint16_t i = start;istream) { - if (isPublish && len-*lengthLength-2>skip) { - this->stream->write(digit); - } - } - if (len < MQTT_MAX_PACKET_SIZE) { - buffer[len] = digit; - } - len++; - } - - if (!this->stream && len > MQTT_MAX_PACKET_SIZE) { - len = 0; // This will cause the packet to be ignored. - } - - return len; -} - -boolean PubSubClient::loop() { - if (connected()) { - unsigned long t = millis(); - if ((t - lastInActivity > MQTT_KEEPALIVE*1000UL) || (t - lastOutActivity > MQTT_KEEPALIVE*1000UL)) { - if (pingOutstanding) { - this->_state = MQTT_CONNECTION_TIMEOUT; - _client->stop(); - return false; - } else { - buffer[0] = MQTTPINGREQ; - buffer[1] = 0; - _client->write(buffer,2); - lastOutActivity = t; - lastInActivity = t; - pingOutstanding = true; - } - } - if (_client->available()) { - uint8_t llen; - uint16_t len = readPacket(&llen); - uint16_t msgId = 0; - uint8_t *payload; - if (len > 0) { - lastInActivity = t; - uint8_t type = buffer[0]&0xF0; - if (type == MQTTPUBLISH) { - if (callback) { - uint16_t tl = (buffer[llen+1]<<8)+buffer[llen+2]; - char topic[tl+1]; - for (uint16_t i=0;i0 - if ((buffer[0]&0x06) == MQTTQOS1) { - msgId = (buffer[llen+3+tl]<<8)+buffer[llen+3+tl+1]; - payload = buffer+llen+3+tl+2; - callback(topic,payload,len-llen-3-tl-2); - - buffer[0] = MQTTPUBACK; - buffer[1] = 2; - buffer[2] = (msgId >> 8); - buffer[3] = (msgId & 0xFF); - _client->write(buffer,4); - lastOutActivity = t; - - } else { - payload = buffer+llen+3+tl; - callback(topic,payload,len-llen-3-tl); - } - } - } else if (type == MQTTPINGREQ) { - buffer[0] = MQTTPINGRESP; - buffer[1] = 0; - _client->write(buffer,2); - } else if (type == MQTTPINGRESP) { - pingOutstanding = false; - } - } - } - return true; - } - return false; -} - -boolean PubSubClient::publish(const char* topic, const char* payload) { - return publish(topic,(const uint8_t*)payload,strlen(payload),false); -} - -boolean PubSubClient::publish(const char* topic, const char* payload, boolean retained) { - return publish(topic,(const uint8_t*)payload,strlen(payload),retained); -} - -boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength) { - return publish(topic, payload, plength, false); -} - -boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) { - if (connected()) { - if (MQTT_MAX_PACKET_SIZE < 5 + 2+strlen(topic) + plength) { - // Too long - return false; - } - // Leave room in the buffer for header and variable length field - uint16_t length = 5; - length = writeString(topic,buffer,length); - uint16_t i; - for (i=0;i 0) { - digit |= 0x80; - } - buffer[pos++] = digit; - llen++; - } while(len>0); - - pos = writeString(topic,buffer,pos); - - rc += _client->write(buffer,pos); - - for (i=0;iwrite((char)pgm_read_byte_near(payload + i)); - } - - lastOutActivity = millis(); - - return rc == tlen + 4 + plength; -} - -boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) { - uint8_t lenBuf[4]; - uint8_t llen = 0; - uint8_t digit; - uint8_t pos = 0; - uint16_t rc; - uint16_t len = length; - do { - digit = len % 128; - len = len / 128; - if (len > 0) { - digit |= 0x80; - } - lenBuf[pos++] = digit; - llen++; - } while(len>0); - - buf[4-llen] = header; - for (int i=0;istream) { + if (isPublish && len-*lengthLength-2>skip) { + this->stream->write(digit); + } + } + if (len < MQTT_MAX_PACKET_SIZE) { + buffer[len] = digit; + } + len++; + } + + if (!this->stream && len > MQTT_MAX_PACKET_SIZE) { + len = 0; // This will cause the packet to be ignored. + } + + return len; +} + +boolean PubSubClient::loop() +{ + if (connected()) { + unsigned long t = millis(); + if ((t - lastInActivity > MQTT_KEEPALIVE*1000UL) || (t - lastOutActivity > MQTT_KEEPALIVE*1000UL)) { + if (pingOutstanding) { + this->_state = MQTT_CONNECTION_TIMEOUT; + _client->stop(); + return false; + } else { + buffer[0] = MQTTPINGREQ; + buffer[1] = 0; + _client->write(buffer,2); + lastOutActivity = t; + lastInActivity = t; + pingOutstanding = true; + } + } + if (_client->available()) { + uint8_t llen; + uint16_t len = readPacket(&llen); + uint16_t msgId = 0; + uint8_t *payload; + if (len > 0) { + lastInActivity = t; + uint8_t type = buffer[0]&0xF0; + if (type == MQTTPUBLISH) { + if (callback) { + uint16_t tl = (buffer[llen+1]<<8)+buffer[llen+2]; + char topic[tl+1]; + for (uint16_t i=0; i0 + if ((buffer[0]&0x06) == MQTTQOS1) { + msgId = (buffer[llen+3+tl]<<8)+buffer[llen+3+tl+1]; + payload = buffer+llen+3+tl+2; + callback(topic,payload,len-llen-3-tl-2); + + buffer[0] = MQTTPUBACK; + buffer[1] = 2; + buffer[2] = (msgId >> 8); + buffer[3] = (msgId & 0xFF); + _client->write(buffer,4); + lastOutActivity = t; + + } else { + payload = buffer+llen+3+tl; + callback(topic,payload,len-llen-3-tl); + } + } + } else if (type == MQTTPINGREQ) { + buffer[0] = MQTTPINGRESP; + buffer[1] = 0; + _client->write(buffer,2); + } else if (type == MQTTPINGRESP) { + pingOutstanding = false; + } + } + } + return true; + } + return false; +} + +boolean PubSubClient::publish(const char* topic, const char* payload) +{ + return publish(topic,(const uint8_t*)payload,strlen(payload),false); +} + +boolean PubSubClient::publish(const char* topic, const char* payload, boolean retained) +{ + return publish(topic,(const uint8_t*)payload,strlen(payload),retained); +} + +boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength) +{ + return publish(topic, payload, plength, false); +} + +boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength, + boolean retained) +{ + if (connected()) { + if (MQTT_MAX_PACKET_SIZE < 5 + 2+strlen(topic) + plength) { + // Too long + return false; + } + // Leave room in the buffer for header and variable length field + uint16_t length = 5; + length = writeString(topic,buffer,length); + uint16_t i; + for (i=0; i 0) { + digit |= 0x80; + } + buffer[pos++] = digit; + llen++; + } while(len>0); + + pos = writeString(topic,buffer,pos); + + rc += _client->write(buffer,pos); + + for (i=0; iwrite((char)pgm_read_byte_near(payload + i)); + } + + lastOutActivity = millis(); + + return rc == tlen + 4 + plength; +} + +boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) +{ + uint8_t lenBuf[4]; + uint8_t llen = 0; + uint8_t digit; + uint8_t pos = 0; + uint16_t rc; + uint16_t len = length; + do { + digit = len % 128; + len = len / 128; + if (len > 0) { + digit |= 0x80; + } + lenBuf[pos++] = digit; + llen++; + } while(len>0); + + buf[4-llen] = header; + for (int i=0; i 0) && result) { - bytesToWrite = (bytesRemaining > MQTT_MAX_TRANSFER_SIZE)?MQTT_MAX_TRANSFER_SIZE:bytesRemaining; - rc = _client->write(writeBuf,bytesToWrite); - result = (rc == bytesToWrite); - bytesRemaining -= rc; - writeBuf += rc; - } - return result; + uint8_t* writeBuf = buf+(4-llen); + uint16_t bytesRemaining = length+1+llen; //Match the length type + uint8_t bytesToWrite; + boolean result = true; + while((bytesRemaining > 0) && result) { + bytesToWrite = (bytesRemaining > MQTT_MAX_TRANSFER_SIZE)?MQTT_MAX_TRANSFER_SIZE:bytesRemaining; + rc = _client->write(writeBuf,bytesToWrite); + result = (rc == bytesToWrite); + bytesRemaining -= rc; + writeBuf += rc; + } + return result; #else - rc = _client->write(buf+(4-llen),length+1+llen); - lastOutActivity = millis(); - return (rc == 1+llen+length); + rc = _client->write(buf+(4-llen),length+1+llen); + lastOutActivity = millis(); + return (rc == 1+llen+length); #endif } -boolean PubSubClient::subscribe(const char* topic) { - return subscribe(topic, 0); +boolean PubSubClient::subscribe(const char* topic) +{ + return subscribe(topic, 0); } -boolean PubSubClient::subscribe(const char* topic, uint8_t qos) { - // original: if (qos < 0 || qos > 1) { (qos is uint8_t, hence qos < 0 impossible, tekka) +boolean PubSubClient::subscribe(const char* topic, uint8_t qos) +{ + // original: if (qos < 0 || qos > 1) { (qos is uint8_t, hence qos < 0 impossible, tekka) if (qos > 1) { - return false; - } - if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { - // Too long - return false; - } - if (connected()) { - // Leave room in the buffer for header and variable length field - uint16_t length = 5; - nextMsgId++; - if (nextMsgId == 0) { - nextMsgId = 1; - } - buffer[length++] = (nextMsgId >> 8); - buffer[length++] = (nextMsgId & 0xFF); - length = writeString((char*)topic, buffer,length); - buffer[length++] = qos; - return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-5); - } - return false; -} - -boolean PubSubClient::unsubscribe(const char* topic) { - if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { - // Too long - return false; - } - if (connected()) { - uint16_t length = 5; - nextMsgId++; - if (nextMsgId == 0) { - nextMsgId = 1; - } - buffer[length++] = (nextMsgId >> 8); - buffer[length++] = (nextMsgId & 0xFF); - length = writeString(topic, buffer,length); - return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-5); - } - return false; -} - -void PubSubClient::disconnect() { - buffer[0] = MQTTDISCONNECT; - buffer[1] = 0; - _client->write(buffer,2); - _state = MQTT_DISCONNECTED; - _client->stop(); - lastInActivity = lastOutActivity = millis(); -} - -uint16_t PubSubClient::writeString(const char* string, uint8_t* buf, uint16_t pos) { - const char* idp = string; - uint16_t i = 0; - pos += 2; - while (*idp) { - buf[pos++] = *idp++; - i++; - } - buf[pos-i-2] = (i >> 8); - buf[pos-i-1] = (i & 0xFF); - return pos; -} - - -boolean PubSubClient::connected() { - boolean rc; - if (_client == NULL ) { - rc = false; - } else { - rc = (int)_client->connected(); - if (!rc) { - if (this->_state == MQTT_CONNECTED) { - this->_state = MQTT_CONNECTION_LOST; - _client->flush(); - _client->stop(); - } - } - } - return rc; -} - -PubSubClient& PubSubClient::setServer(uint8_t * ip, uint16_t port) { - IPAddress addr(ip[0],ip[1],ip[2],ip[3]); - return setServer(addr,port); -} - -PubSubClient& PubSubClient::setServer(IPAddress ip, uint16_t port) { - this->ip = ip; - this->port = port; - this->domain = NULL; - return *this; -} - -PubSubClient& PubSubClient::setServer(const char * domain, uint16_t port) { - this->domain = domain; - this->port = port; - return *this; -} - -PubSubClient& PubSubClient::setCallback(MQTT_CALLBACK_SIGNATURE) { - this->callback = callback; - return *this; -} - -PubSubClient& PubSubClient::setClient(Client& client){ - this->_client = &client; - return *this; -} - -PubSubClient& PubSubClient::setStream(Stream& stream){ - this->stream = &stream; - return *this; -} - -int PubSubClient::state() { - return this->_state; + return false; + } + if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { + // Too long + return false; + } + if (connected()) { + // Leave room in the buffer for header and variable length field + uint16_t length = 5; + nextMsgId++; + if (nextMsgId == 0) { + nextMsgId = 1; + } + buffer[length++] = (nextMsgId >> 8); + buffer[length++] = (nextMsgId & 0xFF); + length = writeString((char*)topic, buffer,length); + buffer[length++] = qos; + return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-5); + } + return false; +} + +boolean PubSubClient::unsubscribe(const char* topic) +{ + if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { + // Too long + return false; + } + if (connected()) { + uint16_t length = 5; + nextMsgId++; + if (nextMsgId == 0) { + nextMsgId = 1; + } + buffer[length++] = (nextMsgId >> 8); + buffer[length++] = (nextMsgId & 0xFF); + length = writeString(topic, buffer,length); + return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-5); + } + return false; +} + +void PubSubClient::disconnect() +{ + buffer[0] = MQTTDISCONNECT; + buffer[1] = 0; + _client->write(buffer,2); + _state = MQTT_DISCONNECTED; + _client->stop(); + lastInActivity = lastOutActivity = millis(); +} + +uint16_t PubSubClient::writeString(const char* string, uint8_t* buf, uint16_t pos) +{ + const char* idp = string; + uint16_t i = 0; + pos += 2; + while (*idp) { + buf[pos++] = *idp++; + i++; + } + buf[pos-i-2] = (i >> 8); + buf[pos-i-1] = (i & 0xFF); + return pos; +} + + +boolean PubSubClient::connected() +{ + boolean rc; + if (_client == NULL ) { + rc = false; + } else { + rc = (int)_client->connected(); + if (!rc) { + if (this->_state == MQTT_CONNECTED) { + this->_state = MQTT_CONNECTION_LOST; + _client->flush(); + _client->stop(); + } + } + } + return rc; +} + +PubSubClient& PubSubClient::setServer(uint8_t * ip, uint16_t port) +{ + IPAddress addr(ip[0],ip[1],ip[2],ip[3]); + return setServer(addr,port); +} + +PubSubClient& PubSubClient::setServer(IPAddress ip, uint16_t port) +{ + this->ip = ip; + this->port = port; + this->domain = NULL; + return *this; +} + +PubSubClient& PubSubClient::setServer(const char * domain, uint16_t port) +{ + this->domain = domain; + this->port = port; + return *this; +} + +PubSubClient& PubSubClient::setCallback(MQTT_CALLBACK_SIGNATURE) +{ + this->callback = callback; + return *this; +} + +PubSubClient& PubSubClient::setClient(Client& client) +{ + this->_client = &client; + return *this; +} + +PubSubClient& PubSubClient::setStream(Stream& stream) +{ + this->stream = &stream; + return *this; +} + +int PubSubClient::state() +{ + return this->_state; } diff --git a/drivers/PubSubClient/PubSubClient.h b/drivers/PubSubClient/PubSubClient.h index 90ad8ae6a..a1cf90bd3 100644 --- a/drivers/PubSubClient/PubSubClient.h +++ b/drivers/PubSubClient/PubSubClient.h @@ -81,64 +81,72 @@ #endif /** PubSubClient class */ -class PubSubClient { +class PubSubClient +{ private: - Client* _client; - uint8_t buffer[MQTT_MAX_PACKET_SIZE]; - uint16_t nextMsgId; - unsigned long lastOutActivity; - unsigned long lastInActivity; - bool pingOutstanding; - MQTT_CALLBACK_SIGNATURE; - uint16_t readPacket(uint8_t*); - boolean readByte(uint8_t * result); - boolean readByte(uint8_t * result, uint16_t * index); - boolean write(uint8_t header, uint8_t* buf, uint16_t length); - uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos); - IPAddress ip; - const char* domain; - uint16_t port; - Stream* stream; - int _state; + Client* _client; + uint8_t buffer[MQTT_MAX_PACKET_SIZE]; + uint16_t nextMsgId; + unsigned long lastOutActivity; + unsigned long lastInActivity; + bool pingOutstanding; + MQTT_CALLBACK_SIGNATURE; + uint16_t readPacket(uint8_t*); + boolean readByte(uint8_t * result); + boolean readByte(uint8_t * result, uint16_t * index); + boolean write(uint8_t header, uint8_t* buf, uint16_t length); + uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos); + IPAddress ip; + const char* domain; + uint16_t port; + Stream* stream; + int _state; public: - PubSubClient(); //!< PubSubClient - PubSubClient(Client& client); //!< PubSubClient - PubSubClient(IPAddress, uint16_t, Client& client); //!< PubSubClient - PubSubClient(IPAddress, uint16_t, Client& client, Stream&); //!< PubSubClient - PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); //!< PubSubClient - PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&); //!< PubSubClient - PubSubClient(uint8_t *, uint16_t, Client& client); //!< PubSubClient - PubSubClient(uint8_t *, uint16_t, Client& client, Stream&); //!< PubSubClient - PubSubClient(uint8_t *, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); //!< PubSubClient - PubSubClient(uint8_t *, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&); //!< PubSubClient - PubSubClient(const char*, uint16_t, Client& client); //!< PubSubClient - PubSubClient(const char*, uint16_t, Client& client, Stream&); //!< PubSubClient - PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); //!< PubSubClient - PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&); //!< PubSubClient - - PubSubClient& setServer(IPAddress ip, uint16_t port); //!< setServer - PubSubClient& setServer(uint8_t * ip, uint16_t port); //!< setServer - PubSubClient& setServer(const char * domain, uint16_t port); //!< setServer - PubSubClient& setCallback(MQTT_CALLBACK_SIGNATURE); //!< setCallback - PubSubClient& setClient(Client& client); //!< setClient - PubSubClient& setStream(Stream& stream); //!< setStream - - boolean connect(const char* id); //!< connect - boolean connect(const char* id, const char* user, const char* pass); //!< connect - boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); //!< connect - boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); //!< connect - void disconnect(); //!< disconnect - boolean publish(const char* topic, const char* payload); //!< publish - boolean publish(const char* topic, const char* payload, boolean retained); //!< publish - boolean publish(const char* topic, const uint8_t * payload, unsigned int plength); //!< publish - boolean publish(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained); //!< publish - boolean publish_P(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained); //!< publish_P - boolean subscribe(const char* topic); //!< subscribe - boolean subscribe(const char* topic, uint8_t qos); //!< subscribe - boolean unsubscribe(const char* topic); //!< unsubscribe - boolean loop(); //!< loop - boolean connected(); //!< connected - int state(); //!< state + PubSubClient(); //!< PubSubClient + PubSubClient(Client& client); //!< PubSubClient + PubSubClient(IPAddress, uint16_t, Client& client); //!< PubSubClient + PubSubClient(IPAddress, uint16_t, Client& client, Stream&); //!< PubSubClient + PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); //!< PubSubClient + PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, + Stream&); //!< PubSubClient + PubSubClient(uint8_t *, uint16_t, Client& client); //!< PubSubClient + PubSubClient(uint8_t *, uint16_t, Client& client, Stream&); //!< PubSubClient + PubSubClient(uint8_t *, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); //!< PubSubClient + PubSubClient(uint8_t *, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, + Stream&); //!< PubSubClient + PubSubClient(const char*, uint16_t, Client& client); //!< PubSubClient + PubSubClient(const char*, uint16_t, Client& client, Stream&); //!< PubSubClient + PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); //!< PubSubClient + PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, + Stream&); //!< PubSubClient + + PubSubClient& setServer(IPAddress ip, uint16_t port); //!< setServer + PubSubClient& setServer(uint8_t * ip, uint16_t port); //!< setServer + PubSubClient& setServer(const char * domain, uint16_t port); //!< setServer + PubSubClient& setCallback(MQTT_CALLBACK_SIGNATURE); //!< setCallback + PubSubClient& setClient(Client& client); //!< setClient + PubSubClient& setStream(Stream& stream); //!< setStream + + boolean connect(const char* id); //!< connect + boolean connect(const char* id, const char* user, const char* pass); //!< connect + boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain, + const char* willMessage); //!< connect + boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, + uint8_t willQos, boolean willRetain, const char* willMessage); //!< connect + void disconnect(); //!< disconnect + boolean publish(const char* topic, const char* payload); //!< publish + boolean publish(const char* topic, const char* payload, boolean retained); //!< publish + boolean publish(const char* topic, const uint8_t * payload, unsigned int plength); //!< publish + boolean publish(const char* topic, const uint8_t * payload, unsigned int plength, + boolean retained); //!< publish + boolean publish_P(const char* topic, const uint8_t * payload, unsigned int plength, + boolean retained); //!< publish_P + boolean subscribe(const char* topic); //!< subscribe + boolean subscribe(const char* topic, uint8_t qos); //!< subscribe + boolean unsubscribe(const char* topic); //!< unsubscribe + boolean loop(); //!< loop + boolean connected(); //!< connected + int state(); //!< state }; diff --git a/drivers/RF24/RF24.cpp b/drivers/RF24/RF24.cpp index 34d1193e2..45448475c 100644 --- a/drivers/RF24/RF24.cpp +++ b/drivers/RF24/RF24.cpp @@ -36,405 +36,410 @@ uint8_t spi_txbuff[32+1] ; //SPI transmit buffer (payload max 32 bytes + 1 byte LOCAL void RF24_csn(const bool level) { - hwDigitalWrite(MY_RF24_CS_PIN, level); + hwDigitalWrite(MY_RF24_CS_PIN, level); } LOCAL void RF24_ce(const bool level) { - hwDigitalWrite(MY_RF24_CE_PIN, level); + hwDigitalWrite(MY_RF24_CE_PIN, level); } -LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_t len, const bool aReadMode) +LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_t len, + const bool aReadMode) { - uint8_t status; - uint8_t* current = buf; + uint8_t status; + uint8_t* current = buf; #if !defined(MY_SOFTSPI) - _SPI.beginTransaction(SPISettings(MY_RF24_SPI_MAX_SPEED, MY_RF24_SPI_DATA_ORDER, MY_RF24_SPI_DATA_MODE)); + _SPI.beginTransaction(SPISettings(MY_RF24_SPI_MAX_SPEED, MY_RF24_SPI_DATA_ORDER, + MY_RF24_SPI_DATA_MODE)); #endif - RF24_csn(LOW); - // timing - delayMicroseconds(10); + RF24_csn(LOW); + // timing + delayMicroseconds(10); #ifdef LINUX_ARCH_RASPBERRYPI - uint8_t * prx = spi_rxbuff; - uint8_t * ptx = spi_txbuff; - uint8_t size = len + 1; // Add register value to transmit buffer - - *ptx++ = cmd; - while ( len-- ) { - if (aReadMode) { - *ptx++ = RF24_NOP; - } else { - *ptx++ = *current++; - } - } - _SPI.transfernb( (char *) spi_txbuff, (char *) spi_rxbuff, size); - if (aReadMode) { - if (size == 2) { - status = *++prx; // result is 2nd byte of receive buffer - } else { - status = *prx++; // status is 1st byte of receive buffer - // decrement before to skip status byte - while (--size) { - *buf++ = *prx++; - } - } - } else { - status = *prx; // status is 1st byte of receive buffer - } + uint8_t * prx = spi_rxbuff; + uint8_t * ptx = spi_txbuff; + uint8_t size = len + 1; // Add register value to transmit buffer + + *ptx++ = cmd; + while ( len-- ) { + if (aReadMode) { + *ptx++ = RF24_NOP; + } else { + *ptx++ = *current++; + } + } + _SPI.transfernb( (char *) spi_txbuff, (char *) spi_rxbuff, size); + if (aReadMode) { + if (size == 2) { + status = *++prx; // result is 2nd byte of receive buffer + } else { + status = *prx++; // status is 1st byte of receive buffer + // decrement before to skip status byte + while (--size) { + *buf++ = *prx++; + } + } + } else { + status = *prx; // status is 1st byte of receive buffer + } #else - status = _SPI.transfer(cmd); - while ( len-- ) { - if (aReadMode) { - status = _SPI.transfer(RF24_NOP); - if (buf != NULL) { - *current++ = status; - } - } else { - status = _SPI.transfer(*current++); - } - } + status = _SPI.transfer(cmd); + while ( len-- ) { + if (aReadMode) { + status = _SPI.transfer(RF24_NOP); + if (buf != NULL) { + *current++ = status; + } + } else { + status = _SPI.transfer(*current++); + } + } #endif - RF24_csn(HIGH); + RF24_csn(HIGH); #if !defined(MY_SOFTSPI) - _SPI.endTransaction(); + _SPI.endTransaction(); #endif - // timing - delayMicroseconds(10); - return status; + // timing + delayMicroseconds(10); + return status; } LOCAL uint8_t RF24_spiByteTransfer(const uint8_t cmd) { - return RF24_spiMultiByteTransfer(cmd, NULL, 0, false); + return RF24_spiMultiByteTransfer(cmd, NULL, 0, false); } LOCAL uint8_t RF24_RAW_readByteRegister(const uint8_t cmd) { - const uint8_t value = RF24_spiMultiByteTransfer(cmd, NULL, 1, true); - RF24_DEBUG(PSTR("RF24:read register, reg=%d, value=%d\n"), cmd & RF24_REGISTER_MASK, value); - return value; + const uint8_t value = RF24_spiMultiByteTransfer(cmd, NULL, 1, true); + RF24_DEBUG(PSTR("RF24:read register, reg=%d, value=%d\n"), cmd & RF24_REGISTER_MASK, value); + return value; } LOCAL uint8_t RF24_RAW_writeByteRegister(const uint8_t cmd, uint8_t value) { - RF24_DEBUG(PSTR("RF24:write register, reg=%d, value=%d\n"), cmd & RF24_REGISTER_MASK, value); - return RF24_spiMultiByteTransfer( cmd , &value, 1, false); + RF24_DEBUG(PSTR("RF24:write register, reg=%d, value=%d\n"), cmd & RF24_REGISTER_MASK, value); + return RF24_spiMultiByteTransfer( cmd , &value, 1, false); } LOCAL void RF24_flushRX(void) { - RF24_DEBUG(PSTR("RF24:flushRX\n")); - RF24_spiByteTransfer(RF24_FLUSH_RX); + RF24_DEBUG(PSTR("RF24:flushRX\n")); + RF24_spiByteTransfer(RF24_FLUSH_RX); } LOCAL void RF24_flushTX(void) { - RF24_DEBUG(PSTR("RF24:flushTX\n")); - RF24_spiByteTransfer(RF24_FLUSH_TX); + RF24_DEBUG(PSTR("RF24:flushTX\n")); + RF24_spiByteTransfer(RF24_FLUSH_TX); } LOCAL uint8_t RF24_getStatus(void) { - return RF24_spiByteTransfer(RF24_NOP); + return RF24_spiByteTransfer(RF24_NOP); } LOCAL uint8_t RF24_getFIFOStatus(void) { - return RF24_readByteRegister(RF24_FIFO_STATUS); + return RF24_readByteRegister(RF24_FIFO_STATUS); } LOCAL void RF24_setChannel(const uint8_t channel) { - RF24_writeByteRegister(RF24_RF_CH,channel); + RF24_writeByteRegister(RF24_RF_CH,channel); } LOCAL void RF24_setRetries(const uint8_t retransmitDelay, const uint8_t retransmitCount) { - RF24_writeByteRegister(RF24_SETUP_RETR, retransmitDelay << RF24_ARD | retransmitCount << RF24_ARC); + RF24_writeByteRegister(RF24_SETUP_RETR, retransmitDelay << RF24_ARD | retransmitCount << RF24_ARC); } LOCAL void RF24_setAddressWidth(const uint8_t width) { - RF24_writeByteRegister(RF24_SETUP_AW, width - 2); + RF24_writeByteRegister(RF24_SETUP_AW, width - 2); } LOCAL void RF24_setRFSetup(const uint8_t RFsetup) { - RF24_writeByteRegister(RF24_RF_SETUP, RFsetup); + RF24_writeByteRegister(RF24_RF_SETUP, RFsetup); } LOCAL void RF24_setFeature(const uint8_t feature) { - RF24_writeByteRegister(RF24_FEATURE, feature); + RF24_writeByteRegister(RF24_FEATURE, feature); } LOCAL void RF24_setPipe(const uint8_t pipe) { - RF24_writeByteRegister(RF24_EN_RXADDR, pipe); + RF24_writeByteRegister(RF24_EN_RXADDR, pipe); } LOCAL void RF24_setAutoACK(const uint8_t pipe) { - RF24_writeByteRegister(RF24_EN_AA, pipe); + RF24_writeByteRegister(RF24_EN_AA, pipe); } LOCAL void RF24_setDynamicPayload(const uint8_t pipe) { - RF24_writeByteRegister(RF24_DYNPD, pipe); + RF24_writeByteRegister(RF24_DYNPD, pipe); } LOCAL void RF24_setRFConfiguration(const uint8_t configuration) { - RF24_writeByteRegister(RF24_NRF_CONFIG, configuration); + RF24_writeByteRegister(RF24_NRF_CONFIG, configuration); } LOCAL void RF24_setPipeAddress(const uint8_t pipe, uint8_t* address, const uint8_t width) { - RF24_writeMultiByteRegister(pipe, address, width); + RF24_writeMultiByteRegister(pipe, address, width); } LOCAL void RF24_setPipeLSB(const uint8_t pipe, const uint8_t LSB) { - RF24_writeByteRegister(pipe, LSB); + RF24_writeByteRegister(pipe, LSB); } LOCAL uint8_t RF24_getObserveTX(void) { - return RF24_readByteRegister(RF24_OBSERVE_TX); + return RF24_readByteRegister(RF24_OBSERVE_TX); } LOCAL void RF24_setStatus(const uint8_t status) { - RF24_writeByteRegister(RF24_STATUS, status); + RF24_writeByteRegister(RF24_STATUS, status); } LOCAL void RF24_enableFeatures(void) { - RF24_RAW_writeByteRegister(RF24_ACTIVATE, 0x73); + RF24_RAW_writeByteRegister(RF24_ACTIVATE, 0x73); } LOCAL void RF24_openWritingPipe(const uint8_t recipient) { - RF24_DEBUG(PSTR("RF24:OPEN WPIPE,RCPT=%d\n"), recipient); // open writing pipe - // only write LSB of RX0 and TX pipe - RF24_setPipeLSB(RF24_RX_ADDR_P0, recipient); - RF24_setPipeLSB(RF24_TX_ADDR, recipient); + RF24_DEBUG(PSTR("RF24:OPEN WPIPE,RCPT=%d\n"), recipient); // open writing pipe + // only write LSB of RX0 and TX pipe + RF24_setPipeLSB(RF24_RX_ADDR_P0, recipient); + RF24_setPipeLSB(RF24_TX_ADDR, recipient); } LOCAL void RF24_startListening(void) { - RF24_DEBUG(PSTR("RF24:STRT LIS\n")); // start listening - // toggle PRX - RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(RF24_PWR_UP) | _BV(RF24_PRIM_RX) ); - // all RX pipe addresses must be unique, therefore skip if node ID is AUTO - if(MY_RF24_NODE_ADDRESS!=AUTO) { - RF24_setPipeLSB(RF24_RX_ADDR_P0, MY_RF24_NODE_ADDRESS); - } - // start listening - RF24_ce(HIGH); + RF24_DEBUG(PSTR("RF24:STRT LIS\n")); // start listening + // toggle PRX + RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(RF24_PWR_UP) | _BV(RF24_PRIM_RX) ); + // all RX pipe addresses must be unique, therefore skip if node ID is AUTO + if(MY_RF24_NODE_ADDRESS!=AUTO) { + RF24_setPipeLSB(RF24_RX_ADDR_P0, MY_RF24_NODE_ADDRESS); + } + // start listening + RF24_ce(HIGH); } LOCAL void RF24_stopListening(void) { - RF24_DEBUG(PSTR("RF24:STP LIS\n")); // stop listening - RF24_ce(LOW); - // timing - delayMicroseconds(130); - RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(RF24_PWR_UP) ); - // timing - delayMicroseconds(100); + RF24_DEBUG(PSTR("RF24:STP LIS\n")); // stop listening + RF24_ce(LOW); + // timing + delayMicroseconds(130); + RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(RF24_PWR_UP) ); + // timing + delayMicroseconds(100); } LOCAL void RF24_powerDown(void) { - RF24_ce(LOW); - RF24_setRFConfiguration(MY_RF24_CONFIGURATION); - RF24_DEBUG(PSTR("RF24:PD\n")); // power down + RF24_ce(LOW); + RF24_setRFConfiguration(MY_RF24_CONFIGURATION); + RF24_DEBUG(PSTR("RF24:PD\n")); // power down } LOCAL bool RF24_sendMessage(const uint8_t recipient, const void* buf, const uint8_t len) { - uint8_t RF24_status; - RF24_stopListening(); - RF24_openWritingPipe( recipient ); - RF24_DEBUG(PSTR("RF24:SND:TO=%d,LEN=%d\n"),recipient,len); // send message - // flush TX FIFO - RF24_flushTX(); - // this command is affected in clones (e.g. Si24R1): flipped NoACK bit when using W_TX_PAYLOAD_NO_ACK / W_TX_PAYLOAD - // AutoACK is disabled on the broadcasting pipe - NO_ACK prevents resending - RF24_spiMultiByteTransfer(recipient == BROADCAST_ADDRESS ? RF24_WRITE_TX_PAYLOAD_NO_ACK : RF24_WRITE_TX_PAYLOAD, (uint8_t*)buf, len, false ); - // go, TX starts after ~10us - RF24_ce(HIGH); - // timeout counter to detect HW issues - uint16_t timeout = 0xFFFF; - do { - RF24_status = RF24_getStatus(); - } while (!(RF24_status & ( _BV(RF24_MAX_RT) | _BV(RF24_TX_DS) )) && timeout--); - // timeout value after successful TX on 16Mhz AVR ~ 65500, i.e. msg is transmitted after ~36 loop cycles - RF24_ce(LOW); - // reset interrupts - RF24_setStatus(_BV(RF24_TX_DS) | _BV(RF24_MAX_RT) ); - // Max retries exceeded - if(RF24_status & _BV(RF24_MAX_RT)) { - // flush packet - RF24_DEBUG(PSTR("!RF24:SND:MAX_RT\n")); // max retries, no ACK - RF24_flushTX(); - } - RF24_startListening(); - // true if message sent - return (RF24_status & _BV(RF24_TX_DS)); + uint8_t RF24_status; + RF24_stopListening(); + RF24_openWritingPipe( recipient ); + RF24_DEBUG(PSTR("RF24:SND:TO=%d,LEN=%d\n"),recipient,len); // send message + // flush TX FIFO + RF24_flushTX(); + // this command is affected in clones (e.g. Si24R1): flipped NoACK bit when using W_TX_PAYLOAD_NO_ACK / W_TX_PAYLOAD + // AutoACK is disabled on the broadcasting pipe - NO_ACK prevents resending + RF24_spiMultiByteTransfer(recipient == BROADCAST_ADDRESS ? RF24_WRITE_TX_PAYLOAD_NO_ACK : + RF24_WRITE_TX_PAYLOAD, (uint8_t*)buf, len, false ); + // go, TX starts after ~10us + RF24_ce(HIGH); + // timeout counter to detect HW issues + uint16_t timeout = 0xFFFF; + do { + RF24_status = RF24_getStatus(); + } while (!(RF24_status & ( _BV(RF24_MAX_RT) | _BV(RF24_TX_DS) )) && timeout--); + // timeout value after successful TX on 16Mhz AVR ~ 65500, i.e. msg is transmitted after ~36 loop cycles + RF24_ce(LOW); + // reset interrupts + RF24_setStatus(_BV(RF24_TX_DS) | _BV(RF24_MAX_RT) ); + // Max retries exceeded + if(RF24_status & _BV(RF24_MAX_RT)) { + // flush packet + RF24_DEBUG(PSTR("!RF24:SND:MAX_RT\n")); // max retries, no ACK + RF24_flushTX(); + } + RF24_startListening(); + // true if message sent + return (RF24_status & _BV(RF24_TX_DS)); } LOCAL uint8_t RF24_getDynamicPayloadSize(void) { - uint8_t result = RF24_spiMultiByteTransfer(RF24_READ_RX_PL_WID, NULL, 1, true); - // check if payload size invalid - if(result > 32) { - RF24_DEBUG(PSTR("!RF24:GDP:PAYL LEN INVALID=%d\n"),result); // payload len invalid - RF24_flushRX(); - result = 0; - } - return result; + uint8_t result = RF24_spiMultiByteTransfer(RF24_READ_RX_PL_WID, NULL, 1, true); + // check if payload size invalid + if(result > 32) { + RF24_DEBUG(PSTR("!RF24:GDP:PAYL LEN INVALID=%d\n"),result); // payload len invalid + RF24_flushRX(); + result = 0; + } + return result; } LOCAL bool RF24_isDataAvailable() { - return (!(RF24_getFIFOStatus() & _BV(0)) ); + return (!(RF24_getFIFOStatus() & _BV(0)) ); } LOCAL uint8_t RF24_readMessage(void* buf) { - const uint8_t len = RF24_getDynamicPayloadSize(); - RF24_DEBUG(PSTR("RF24:RDM:MSG LEN=%d\n"), len); // read message - RF24_spiMultiByteTransfer(RF24_READ_RX_PAYLOAD,(uint8_t*)buf,len,true); - // clear RX interrupt - RF24_setStatus(_BV(RF24_RX_DR)); - return len; + const uint8_t len = RF24_getDynamicPayloadSize(); + RF24_DEBUG(PSTR("RF24:RDM:MSG LEN=%d\n"), len); // read message + RF24_spiMultiByteTransfer(RF24_READ_RX_PAYLOAD,(uint8_t*)buf,len,true); + // clear RX interrupt + RF24_setStatus(_BV(RF24_RX_DR)); + return len; } LOCAL void RF24_setNodeAddress(const uint8_t address) { - if(address!=AUTO) { - MY_RF24_NODE_ADDRESS = address; - // enable node pipe - RF24_setPipe(_BV(RF24_ERX_P0 + RF24_BROADCAST_PIPE) | _BV(RF24_ERX_P0)); - // enable autoACK on pipe 0 - RF24_setAutoACK(_BV(RF24_ENAA_P0)); - } + if(address!=AUTO) { + MY_RF24_NODE_ADDRESS = address; + // enable node pipe + RF24_setPipe(_BV(RF24_ERX_P0 + RF24_BROADCAST_PIPE) | _BV(RF24_ERX_P0)); + // enable autoACK on pipe 0 + RF24_setAutoACK(_BV(RF24_ENAA_P0)); + } } LOCAL uint8_t RF24_getNodeID(void) { - return MY_RF24_NODE_ADDRESS; + return MY_RF24_NODE_ADDRESS; } LOCAL bool RF24_sanityCheck(void) { - // detect HW defect, configuration errors or interrupted SPI line, CE disconnect cannot be detected - return (RF24_readByteRegister(RF24_RF_SETUP) == MY_RF24_RF_SETUP) & (RF24_readByteRegister(RF24_RF_CH) == MY_RF24_CHANNEL); + // detect HW defect, configuration errors or interrupted SPI line, CE disconnect cannot be detected + return (RF24_readByteRegister(RF24_RF_SETUP) == MY_RF24_RF_SETUP) & (RF24_readByteRegister( + RF24_RF_CH) == MY_RF24_CHANNEL); } #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) LOCAL void RF24_irqHandler(void) { - if (RF24_receiveCallback) { - // Will stay for a while (several 100us) in this interrupt handler. Any interrupts from serial - // rx coming in during our stay will not be handled and will cause characters to be lost. - // As a workaround we re-enable interrupts to allow nested processing of other interrupts. - // Our own handler is disconnected to prevent recursive calling of this handler. + if (RF24_receiveCallback) { + // Will stay for a while (several 100us) in this interrupt handler. Any interrupts from serial + // rx coming in during our stay will not be handled and will cause characters to be lost. + // As a workaround we re-enable interrupts to allow nested processing of other interrupts. + // Our own handler is disconnected to prevent recursive calling of this handler. #if defined(MY_GATEWAY_SERIAL) && !defined(__linux__) - detachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN)); - interrupts(); + detachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN)); + interrupts(); #endif - // Read FIFO until empty. - // Procedure acc. to datasheet (pg. 63): - // 1.Read payload, 2.Clear RX_DR IRQ, 3.Read FIFO_status, 4.Repeat when more data available. - // Datasheet (ch. 8.5) states, that the nRF de-asserts IRQ after reading STATUS. - - // Start checking if RX-FIFO is not empty, as we might end up here from an interrupt - // for a message we've already read. - while (RF24_isDataAvailable()) { - RF24_receiveCallback(); // Must call RF24_readMessage(), which will clear RX_DR IRQ ! - } - // Restore our interrupt handler. + // Read FIFO until empty. + // Procedure acc. to datasheet (pg. 63): + // 1.Read payload, 2.Clear RX_DR IRQ, 3.Read FIFO_status, 4.Repeat when more data available. + // Datasheet (ch. 8.5) states, that the nRF de-asserts IRQ after reading STATUS. + + // Start checking if RX-FIFO is not empty, as we might end up here from an interrupt + // for a message we've already read. + while (RF24_isDataAvailable()) { + RF24_receiveCallback(); // Must call RF24_readMessage(), which will clear RX_DR IRQ ! + } + // Restore our interrupt handler. #if defined(MY_GATEWAY_SERIAL) && !defined(__linux__) - noInterrupts(); - attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING); + noInterrupts(); + attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING); #endif - } else { - // clear RX interrupt - RF24_setStatus(_BV(RF24_RX_DR)); - } + } else { + // clear RX interrupt + RF24_setStatus(_BV(RF24_RX_DR)); + } } LOCAL void RF24_registerReceiveCallback(RF24_receiveCallbackType cb) { - MY_CRITICAL_SECTION { - RF24_receiveCallback = cb; - } + MY_CRITICAL_SECTION { + RF24_receiveCallback = cb; + } } #endif LOCAL bool RF24_initialize(void) { - // prevent warning - (void)RF24_getObserveTX; + // prevent warning + (void)RF24_getObserveTX; - // Initialize pins - hwPinMode(MY_RF24_CE_PIN,OUTPUT); - hwPinMode(MY_RF24_CS_PIN,OUTPUT); + // Initialize pins + hwPinMode(MY_RF24_CE_PIN,OUTPUT); + hwPinMode(MY_RF24_CS_PIN,OUTPUT); #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) - hwPinMode(MY_RF24_IRQ_PIN,INPUT); + hwPinMode(MY_RF24_IRQ_PIN,INPUT); #endif - // Initialize SPI - _SPI.begin(); - RF24_ce(LOW); - RF24_csn(HIGH); + // Initialize SPI + _SPI.begin(); + RF24_ce(LOW); + RF24_csn(HIGH); #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) - // assure SPI can be used from interrupt context - // Note: ESP8266 & SoftSPI currently do not support interrupt usage for SPI, - // therefore it is unsafe to use MY_RF24_IRQ_PIN with ESP8266/SoftSPI! - _SPI.usingInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN)); - // attach interrupt - attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING); + // assure SPI can be used from interrupt context + // Note: ESP8266 & SoftSPI currently do not support interrupt usage for SPI, + // therefore it is unsafe to use MY_RF24_IRQ_PIN with ESP8266/SoftSPI! + _SPI.usingInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN)); + // attach interrupt + attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING); #endif - // CRC and power up - RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(RF24_PWR_UP)) ; - // settle >2ms - delay(5); - // set address width - RF24_setAddressWidth(MY_RF24_ADDR_WIDTH); - // auto retransmit delay 1500us, auto retransmit count 15 - RF24_setRetries(RF24_SET_ARD, RF24_SET_ARC); - // set channel - RF24_setChannel(MY_RF24_CHANNEL); - // set data rate and pa level - RF24_setRFSetup(MY_RF24_RF_SETUP); - // toggle features (necessary on some clones and non-P versions) - RF24_enableFeatures(); - // enable ACK payload and dynamic payload - RF24_setFeature(MY_RF24_FEATURE); - // sanity check (this function is P/non-P independent) - if (!RF24_sanityCheck()) { - RF24_DEBUG(PSTR("!RF24:INIT:SANCHK FAIL\n")); // sanity check failed, check wiring or replace module - return false; - } - // enable broadcasting pipe - RF24_setPipe(_BV(RF24_ERX_P0 + RF24_BROADCAST_PIPE)); - // disable AA on all pipes, activate when node pipe set - RF24_setAutoACK(0x00); - // enable dynamic payloads on used pipes - RF24_setDynamicPayload(_BV(RF24_DPL_P0 + RF24_BROADCAST_PIPE) | _BV(RF24_DPL_P0)); - // listen to broadcast pipe - MY_RF24_BASE_ADDR[0] = BROADCAST_ADDRESS; - RF24_setPipeAddress(RF24_RX_ADDR_P0 + RF24_BROADCAST_PIPE, (uint8_t*)&MY_RF24_BASE_ADDR, RF24_BROADCAST_PIPE > 1 ? 1 : MY_RF24_ADDR_WIDTH); - // pipe 0, set full address, later only LSB is updated - RF24_setPipeAddress(RF24_RX_ADDR_P0, (uint8_t*)&MY_RF24_BASE_ADDR, MY_RF24_ADDR_WIDTH); - RF24_setPipeAddress(RF24_TX_ADDR, (uint8_t*)&MY_RF24_BASE_ADDR, MY_RF24_ADDR_WIDTH); - // reset FIFO - RF24_flushRX(); - RF24_flushTX(); - // reset interrupts - RF24_setStatus(_BV(RF24_TX_DS) | _BV(RF24_MAX_RT) | _BV(RF24_RX_DR)); - return true; + // CRC and power up + RF24_setRFConfiguration(MY_RF24_CONFIGURATION | _BV(RF24_PWR_UP)) ; + // settle >2ms + delay(5); + // set address width + RF24_setAddressWidth(MY_RF24_ADDR_WIDTH); + // auto retransmit delay 1500us, auto retransmit count 15 + RF24_setRetries(RF24_SET_ARD, RF24_SET_ARC); + // set channel + RF24_setChannel(MY_RF24_CHANNEL); + // set data rate and pa level + RF24_setRFSetup(MY_RF24_RF_SETUP); + // toggle features (necessary on some clones and non-P versions) + RF24_enableFeatures(); + // enable ACK payload and dynamic payload + RF24_setFeature(MY_RF24_FEATURE); + // sanity check (this function is P/non-P independent) + if (!RF24_sanityCheck()) { + RF24_DEBUG(PSTR("!RF24:INIT:SANCHK FAIL\n")); // sanity check failed, check wiring or replace module + return false; + } + // enable broadcasting pipe + RF24_setPipe(_BV(RF24_ERX_P0 + RF24_BROADCAST_PIPE)); + // disable AA on all pipes, activate when node pipe set + RF24_setAutoACK(0x00); + // enable dynamic payloads on used pipes + RF24_setDynamicPayload(_BV(RF24_DPL_P0 + RF24_BROADCAST_PIPE) | _BV(RF24_DPL_P0)); + // listen to broadcast pipe + MY_RF24_BASE_ADDR[0] = BROADCAST_ADDRESS; + RF24_setPipeAddress(RF24_RX_ADDR_P0 + RF24_BROADCAST_PIPE, (uint8_t*)&MY_RF24_BASE_ADDR, + RF24_BROADCAST_PIPE > 1 ? 1 : MY_RF24_ADDR_WIDTH); + // pipe 0, set full address, later only LSB is updated + RF24_setPipeAddress(RF24_RX_ADDR_P0, (uint8_t*)&MY_RF24_BASE_ADDR, MY_RF24_ADDR_WIDTH); + RF24_setPipeAddress(RF24_TX_ADDR, (uint8_t*)&MY_RF24_BASE_ADDR, MY_RF24_ADDR_WIDTH); + // reset FIFO + RF24_flushRX(); + RF24_flushTX(); + // reset interrupts + RF24_setStatus(_BV(RF24_TX_DS) | _BV(RF24_MAX_RT) | _BV(RF24_RX_DR)); + return true; } diff --git a/drivers/RF24/RF24.h b/drivers/RF24/RF24.h index ae98d9457..6d228a924 100644 --- a/drivers/RF24/RF24.h +++ b/drivers/RF24/RF24.h @@ -27,65 +27,66 @@ // SPI settings #if !defined(MY_RF24_SPI_MAX_SPEED) - // default 2Mhz - safe for nRF24L01+ clones - #define MY_RF24_SPI_MAX_SPEED 2000000 +// default 2Mhz - safe for nRF24L01+ clones +#define MY_RF24_SPI_MAX_SPEED 2000000 #endif #define MY_RF24_SPI_DATA_ORDER MSBFIRST #define MY_RF24_SPI_DATA_MODE SPI_MODE0 #if defined (ARDUINO) && !defined (__arm__) && !defined (_SPI) - #include - #if defined(MY_SOFTSPI) - SoftSPI _SPI; - #else - #define _SPI SPI - #endif +#include +#if defined(MY_SOFTSPI) +SoftSPI +_SPI; #else - #include - #include - #include - - #define _BV(x) (1<<(x)) - - #if defined(__arm__) - #include - #else - extern HardwareSPI SPI; - #endif - - #if !defined(_SPI) - #define _SPI SPI - #endif +#define _SPI SPI +#endif +#else +#include +#include +#include + +#define _BV(x) (1<<(x)) + +#if defined(__arm__) +#include +#else +extern HardwareSPI SPI; +#endif + +#if !defined(_SPI) +#define _SPI SPI +#endif #endif // verify RF24 IRQ defs #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) - #if !defined(MY_RF24_IRQ_PIN) - #error Message buffering feature requires MY_RF24_IRQ_PIN to be defined! - #endif - // SoftSPI does not support usingInterrupt() - #ifdef MY_SOFTSPI - #error RF24 IRQ usage cannot be used with Soft SPI - #endif - // ESP8266 does not support usingInterrupt() - #ifdef ARDUINO_ARCH_ESP8266 - #error RF24 IRQ usage cannot be used with ESP8266 - #endif - #ifndef SPI_HAS_TRANSACTION - #error RF24 IRQ usage requires transactional SPI support - #endif +#if !defined(MY_RF24_IRQ_PIN) +#error Message buffering feature requires MY_RF24_IRQ_PIN to be defined! +#endif +// SoftSPI does not support usingInterrupt() +#ifdef MY_SOFTSPI +#error RF24 IRQ usage cannot be used with Soft SPI +#endif +// ESP8266 does not support usingInterrupt() +#ifdef ARDUINO_ARCH_ESP8266 +#error RF24 IRQ usage cannot be used with ESP8266 +#endif +#ifndef SPI_HAS_TRANSACTION +#error RF24 IRQ usage requires transactional SPI support +#endif #else - #ifdef MY_RX_MESSAGE_BUFFER_SIZE - #error Receive message buffering requires RF24 IRQ usage - #endif +#ifdef MY_RX_MESSAGE_BUFFER_SIZE +#error Receive message buffering requires RF24 IRQ usage +#endif #endif // RF24 settings #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) - #define MY_RF24_CONFIGURATION (uint8_t) ((RF24_CRC_16 << 2) | (1 << RF24_MASK_TX_DS) | (1 << RF24_MASK_MAX_RT)) +#define MY_RF24_CONFIGURATION (uint8_t) ((RF24_CRC_16 << 2) | (1 << RF24_MASK_TX_DS) | (1 << RF24_MASK_MAX_RT)) #else - #define MY_RF24_CONFIGURATION (uint8_t) (RF24_CRC_16 << 2) +#define MY_RF24_CONFIGURATION (uint8_t) (RF24_CRC_16 << 2) #endif #define MY_RF24_FEATURE (uint8_t)( _BV(RF24_EN_DPL) | _BV(RF24_EN_ACK_PAY) ) #define MY_RF24_RF_SETUP (uint8_t)( ((MY_RF24_DATARATE & 0b10 ) << 4) | ((MY_RF24_DATARATE & 0b01 ) << 3) | (MY_RF24_PA_LEVEL << 1) ) + 1 // +1 for Si24R1 @@ -94,11 +95,11 @@ #define RF24_BROADCAST_PIPE (1) #define RF24_NODE_PIPE (0) -// debug +// debug #if defined(MY_DEBUG_VERBOSE_RF24) - #define RF24_DEBUG(x,...) debug(x, ##__VA_ARGS__) +#define RF24_DEBUG(x,...) debug(x, ##__VA_ARGS__) #else - #define RF24_DEBUG(x,...) +#define RF24_DEBUG(x,...) #endif // PA levels @@ -113,8 +114,8 @@ #define RF24_250KBPS (2) // CRC -#define RF24_CRC_DISABLED (0) -#define RF24_CRC_8 (2) +#define RF24_CRC_DISABLED (0) +#define RF24_CRC_8 (2) #define RF24_CRC_16 (3) // ARD, auto retry delay @@ -232,9 +233,10 @@ // functions -LOCAL void RF24_csn(const bool level); -LOCAL void RF24_ce(const bool level); -LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, const uint8_t len, const bool aReadMode); +LOCAL void RF24_csn(const bool level); +LOCAL void RF24_ce(const bool level); +LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, const uint8_t len, + const bool aReadMode); LOCAL uint8_t RF24_spiByteTransfer(const uint8_t cmd); LOCAL uint8_t RF24_RAW_readByteRegister(const uint8_t cmd); LOCAL uint8_t RF24_RAW_writeByteRegister(const uint8_t cmd, const uint8_t value); @@ -250,11 +252,11 @@ LOCAL uint8_t RF24_getFIFOStatus(void); LOCAL void RF24_openWritingPipe(uint8_t recipient); LOCAL void RF24_startListening(void); LOCAL void RF24_stopListening(void); -LOCAL void RF24_powerDown(void); +LOCAL void RF24_powerDown(void); LOCAL bool RF24_sendMessage(const uint8_t recipient, const void* buf, const uint8_t len); LOCAL uint8_t RF24_getDynamicPayloadSize(void); LOCAL bool RF24_isDataAvailable(); -LOCAL uint8_t RF24_readMessage(void* buf); +LOCAL uint8_t RF24_readMessage(void* buf); LOCAL void RF24_setNodeAddress(const uint8_t address); LOCAL uint8_t RF24_getNodeID(void); LOCAL bool RF24_sanityCheck(void); @@ -275,14 +277,14 @@ LOCAL void RF24_setStatus(const uint8_t status); LOCAL void RF24_enableFeatures(void); #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) - typedef void (*RF24_receiveCallbackType)(void); - /** - * Register a callback, which will be called (from interrupt context) for every message received. - * @note When a callback is registered, it _must_ retrieve the message from the nRF24 - * by calling RF24_readMessage(). Otherwise the interrupt will not get deasserted - * and message reception will stop. - */ - LOCAL void RF24_registerReceiveCallback(RF24_receiveCallbackType cb); +typedef void (*RF24_receiveCallbackType)(void); +/** + * Register a callback, which will be called (from interrupt context) for every message received. + * @note When a callback is registered, it _must_ retrieve the message from the nRF24 + * by calling RF24_readMessage(). Otherwise the interrupt will not get deasserted + * and message reception will stop. + */ +LOCAL void RF24_registerReceiveCallback(RF24_receiveCallbackType cb); #endif #endif // __RF24_H__ \ No newline at end of file diff --git a/drivers/RFM69/RFM69.cpp b/drivers/RFM69/RFM69.cpp index f967c0929..bd3f3aac0 100644 --- a/drivers/RFM69/RFM69.cpp +++ b/drivers/RFM69/RFM69.cpp @@ -39,171 +39,175 @@ volatile uint8_t RFM69::SENDERID; volatile uint8_t RFM69::TARGETID; // should match _address volatile uint8_t RFM69::PAYLOADLEN; volatile uint8_t RFM69::ACK_REQUESTED; -volatile uint8_t RFM69::ACK_RECEIVED; // should be polled immediately after sending a packet with ACK request -volatile int16_t RFM69::RSSI; // most accurate RSSI during reception (closest to the reception) +volatile uint8_t +RFM69::ACK_RECEIVED; // should be polled immediately after sending a packet with ACK request +volatile int16_t +RFM69::RSSI; // most accurate RSSI during reception (closest to the reception) RFM69* RFM69::selfPointer; bool RFM69::initialize(uint8_t freqBand, uint8_t nodeID, uint8_t networkID) { - const uint8_t CONFIG[][2] = - { - /* 0x01 */ { REG_OPMODE, RF_OPMODE_SEQUENCER_ON | RF_OPMODE_LISTEN_OFF | RF_OPMODE_STANDBY }, - /* 0x02 */ { REG_DATAMODUL, RF_DATAMODUL_DATAMODE_PACKET | RF_DATAMODUL_MODULATIONTYPE_FSK | RF_DATAMODUL_MODULATIONSHAPING_00 }, // no shaping - /* 0x03 */ { REG_BITRATEMSB, RF_BITRATEMSB_55555}, // default: 4.8 KBPS - /* 0x04 */ { REG_BITRATELSB, RF_BITRATELSB_55555}, - /* 0x05 */ { REG_FDEVMSB, RF_FDEVMSB_50000}, // default: 5KHz, (FDEV + BitRate / 2 <= 500KHz) - /* 0x06 */ { REG_FDEVLSB, RF_FDEVLSB_50000}, - - /* 0x07 */ { REG_FRFMSB, (uint8_t) (freqBand==RF69_315MHZ ? RF_FRFMSB_315 : (freqBand==RF69_433MHZ ? RF_FRFMSB_433 : (freqBand==RF69_868MHZ ? RF_FRFMSB_868 : RF_FRFMSB_915))) }, - /* 0x08 */ { REG_FRFMID, (uint8_t) (freqBand==RF69_315MHZ ? RF_FRFMID_315 : (freqBand==RF69_433MHZ ? RF_FRFMID_433 : (freqBand==RF69_868MHZ ? RF_FRFMID_868 : RF_FRFMID_915))) }, - /* 0x09 */ { REG_FRFLSB, (uint8_t) (freqBand==RF69_315MHZ ? RF_FRFLSB_315 : (freqBand==RF69_433MHZ ? RF_FRFLSB_433 : (freqBand==RF69_868MHZ ? RF_FRFLSB_868 : RF_FRFLSB_915))) }, - - // looks like PA1 and PA2 are not implemented on RFM69W, hence the max output power is 13dBm - // +17dBm and +20dBm are possible on RFM69HW - // +13dBm formula: Pout = -18 + OutputPower (with PA0 or PA1**) - // +17dBm formula: Pout = -14 + OutputPower (with PA1 and PA2)** - // +20dBm formula: Pout = -11 + OutputPower (with PA1 and PA2)** and high power PA settings (section 3.3.7 in datasheet) - ///* 0x11 */ { REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | RF_PALEVEL_OUTPUTPOWER_11111}, - ///* 0x13 */ { REG_OCP, RF_OCP_ON | RF_OCP_TRIM_95 }, // over current protection (default is 95mA) - - // RXBW defaults are { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_5} (RxBw: 10.4KHz) - /* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_16 | RF_RXBW_EXP_2 }, // (BitRate < 2 * RxBw) - //for BR-19200: /* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_3 }, - /* 0x25 */ { REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01 }, // DIO0 is the only IRQ we're using - /* 0x26 */ { REG_DIOMAPPING2, RF_DIOMAPPING2_CLKOUT_OFF }, // DIO5 ClkOut disable for power saving - /* 0x28 */ { REG_IRQFLAGS2, RF_IRQFLAGS2_FIFOOVERRUN }, // writing to this bit ensures that the FIFO & status flags are reset - /* 0x29 */ { REG_RSSITHRESH, 220 }, // must be set to dBm = (-Sensitivity / 2), default is 0xE4 = 228 so -114dBm - ///* 0x2D */ { REG_PREAMBLELSB, RF_PREAMBLESIZE_LSB_VALUE } // default 3 preamble bytes 0xAAAAAA - /* 0x2E */ { REG_SYNCCONFIG, RF_SYNC_ON | RF_SYNC_FIFOFILL_AUTO | RF_SYNC_SIZE_2 | RF_SYNC_TOL_0 }, - /* 0x2F */ { REG_SYNCVALUE1, 0x2D }, // attempt to make this compatible with sync1 byte of RFM12B lib - /* 0x30 */ { REG_SYNCVALUE2, networkID }, // NETWORK ID - /* 0x37 */ { REG_PACKETCONFIG1, RF_PACKET1_FORMAT_VARIABLE | RF_PACKET1_DCFREE_OFF | RF_PACKET1_CRC_ON | RF_PACKET1_CRCAUTOCLEAR_ON | RF_PACKET1_ADRSFILTERING_OFF }, - /* 0x38 */ { REG_PAYLOADLENGTH, 66 }, // in variable length mode: the max frame size, not used in TX - ///* 0x39 */ { REG_NODEADRS, nodeID }, // turned off because we're not using address filtering - /* 0x3C */ { REG_FIFOTHRESH, RF_FIFOTHRESH_TXSTART_FIFONOTEMPTY | RF_FIFOTHRESH_VALUE }, // TX on FIFO not empty - /* 0x3D */ { REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_2BITS | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF }, // RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent) - //for BR-19200: /* 0x3D */ { REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_NONE | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF }, // RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent) - /* 0x6F */ { REG_TESTDAGC, RF_DAGC_IMPROVED_LOWBETA0 }, // run DAGC continuously in RX mode for Fading Margin Improvement, recommended default for AfcLowBetaOn=0 - {255, 0} - }; - - hwDigitalWrite(_slaveSelectPin, HIGH); - hwPinMode(_slaveSelectPin, OUTPUT); - SPI.begin(); - unsigned long start = millis(); - uint8_t timeout = 50; - do { - writeReg(REG_SYNCVALUE1, 0xAA); - yield(); - } while (readReg(REG_SYNCVALUE1) != 0xaa && millis()-start < timeout); - start = millis(); - do { - writeReg(REG_SYNCVALUE1, 0x55); - yield(); - } while (readReg(REG_SYNCVALUE1) != 0x55 && millis()-start < timeout); - - for (uint8_t i = 0; CONFIG[i][0] != 255; i++) { - writeReg(CONFIG[i][0], CONFIG[i][1]); - } - - // Encryption is persistent between resets and can trip you up during debugging. - // Disable it during initialization so we always start from a known state. - encrypt(0); - - setHighPower(_isRFM69HW); // called regardless if it's a RFM69W or RFM69HW - setMode(RF69_MODE_STANDBY); - start = millis(); - while (((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00) && millis()-start < timeout) { - yield(); - } // wait for ModeReady - if (millis()-start >= timeout) { - return false; - } - attachInterrupt(_interruptNum, RFM69::isr0, RISING); - - selfPointer = this; - _address = nodeID; - return true; + const uint8_t CONFIG[][2] = { + /* 0x01 */ { REG_OPMODE, RF_OPMODE_SEQUENCER_ON | RF_OPMODE_LISTEN_OFF | RF_OPMODE_STANDBY }, + /* 0x02 */ { REG_DATAMODUL, RF_DATAMODUL_DATAMODE_PACKET | RF_DATAMODUL_MODULATIONTYPE_FSK | RF_DATAMODUL_MODULATIONSHAPING_00 }, // no shaping + /* 0x03 */ { REG_BITRATEMSB, RF_BITRATEMSB_55555}, // default: 4.8 KBPS + /* 0x04 */ { REG_BITRATELSB, RF_BITRATELSB_55555}, + /* 0x05 */ { REG_FDEVMSB, RF_FDEVMSB_50000}, // default: 5KHz, (FDEV + BitRate / 2 <= 500KHz) + /* 0x06 */ { REG_FDEVLSB, RF_FDEVLSB_50000}, + + /* 0x07 */ { REG_FRFMSB, (uint8_t) (freqBand==RF69_315MHZ ? RF_FRFMSB_315 : (freqBand==RF69_433MHZ ? RF_FRFMSB_433 : (freqBand==RF69_868MHZ ? RF_FRFMSB_868 : RF_FRFMSB_915))) }, + /* 0x08 */ { REG_FRFMID, (uint8_t) (freqBand==RF69_315MHZ ? RF_FRFMID_315 : (freqBand==RF69_433MHZ ? RF_FRFMID_433 : (freqBand==RF69_868MHZ ? RF_FRFMID_868 : RF_FRFMID_915))) }, + /* 0x09 */ { REG_FRFLSB, (uint8_t) (freqBand==RF69_315MHZ ? RF_FRFLSB_315 : (freqBand==RF69_433MHZ ? RF_FRFLSB_433 : (freqBand==RF69_868MHZ ? RF_FRFLSB_868 : RF_FRFLSB_915))) }, + + // looks like PA1 and PA2 are not implemented on RFM69W, hence the max output power is 13dBm + // +17dBm and +20dBm are possible on RFM69HW + // +13dBm formula: Pout = -18 + OutputPower (with PA0 or PA1**) + // +17dBm formula: Pout = -14 + OutputPower (with PA1 and PA2)** + // +20dBm formula: Pout = -11 + OutputPower (with PA1 and PA2)** and high power PA settings (section 3.3.7 in datasheet) + ///* 0x11 */ { REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | RF_PALEVEL_OUTPUTPOWER_11111}, + ///* 0x13 */ { REG_OCP, RF_OCP_ON | RF_OCP_TRIM_95 }, // over current protection (default is 95mA) + + // RXBW defaults are { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_5} (RxBw: 10.4KHz) + /* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_16 | RF_RXBW_EXP_2 }, // (BitRate < 2 * RxBw) + //for BR-19200: /* 0x19 */ { REG_RXBW, RF_RXBW_DCCFREQ_010 | RF_RXBW_MANT_24 | RF_RXBW_EXP_3 }, + /* 0x25 */ { REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01 }, // DIO0 is the only IRQ we're using + /* 0x26 */ { REG_DIOMAPPING2, RF_DIOMAPPING2_CLKOUT_OFF }, // DIO5 ClkOut disable for power saving + /* 0x28 */ { REG_IRQFLAGS2, RF_IRQFLAGS2_FIFOOVERRUN }, // writing to this bit ensures that the FIFO & status flags are reset + /* 0x29 */ { REG_RSSITHRESH, 220 }, // must be set to dBm = (-Sensitivity / 2), default is 0xE4 = 228 so -114dBm + ///* 0x2D */ { REG_PREAMBLELSB, RF_PREAMBLESIZE_LSB_VALUE } // default 3 preamble bytes 0xAAAAAA + /* 0x2E */ { REG_SYNCCONFIG, RF_SYNC_ON | RF_SYNC_FIFOFILL_AUTO | RF_SYNC_SIZE_2 | RF_SYNC_TOL_0 }, + /* 0x2F */ { REG_SYNCVALUE1, 0x2D }, // attempt to make this compatible with sync1 byte of RFM12B lib + /* 0x30 */ { REG_SYNCVALUE2, networkID }, // NETWORK ID + /* 0x37 */ { REG_PACKETCONFIG1, RF_PACKET1_FORMAT_VARIABLE | RF_PACKET1_DCFREE_OFF | RF_PACKET1_CRC_ON | RF_PACKET1_CRCAUTOCLEAR_ON | RF_PACKET1_ADRSFILTERING_OFF }, + /* 0x38 */ { REG_PAYLOADLENGTH, 66 }, // in variable length mode: the max frame size, not used in TX + ///* 0x39 */ { REG_NODEADRS, nodeID }, // turned off because we're not using address filtering + /* 0x3C */ { REG_FIFOTHRESH, RF_FIFOTHRESH_TXSTART_FIFONOTEMPTY | RF_FIFOTHRESH_VALUE }, // TX on FIFO not empty + /* 0x3D */ { REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_2BITS | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF }, // RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent) + //for BR-19200: /* 0x3D */ { REG_PACKETCONFIG2, RF_PACKET2_RXRESTARTDELAY_NONE | RF_PACKET2_AUTORXRESTART_ON | RF_PACKET2_AES_OFF }, // RXRESTARTDELAY must match transmitter PA ramp-down time (bitrate dependent) + /* 0x6F */ { REG_TESTDAGC, RF_DAGC_IMPROVED_LOWBETA0 }, // run DAGC continuously in RX mode for Fading Margin Improvement, recommended default for AfcLowBetaOn=0 + {255, 0} + }; + + hwDigitalWrite(_slaveSelectPin, HIGH); + hwPinMode(_slaveSelectPin, OUTPUT); + SPI.begin(); + unsigned long start = millis(); + uint8_t timeout = 50; + do { + writeReg(REG_SYNCVALUE1, 0xAA); + yield(); + } while (readReg(REG_SYNCVALUE1) != 0xaa && millis()-start < timeout); + start = millis(); + do { + writeReg(REG_SYNCVALUE1, 0x55); + yield(); + } while (readReg(REG_SYNCVALUE1) != 0x55 && millis()-start < timeout); + + for (uint8_t i = 0; CONFIG[i][0] != 255; i++) { + writeReg(CONFIG[i][0], CONFIG[i][1]); + } + + // Encryption is persistent between resets and can trip you up during debugging. + // Disable it during initialization so we always start from a known state. + encrypt(0); + + setHighPower(_isRFM69HW); // called regardless if it's a RFM69W or RFM69HW + setMode(RF69_MODE_STANDBY); + start = millis(); + while (((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00) && millis()-start < timeout) { + yield(); + } // wait for ModeReady + if (millis()-start >= timeout) { + return false; + } + attachInterrupt(_interruptNum, RFM69::isr0, RISING); + + selfPointer = this; + _address = nodeID; + return true; } // return the frequency (in Hz) uint32_t RFM69::getFrequency() { - return RF69_FSTEP * (((uint32_t) readReg(REG_FRFMSB) << 16) + ((uint16_t) readReg(REG_FRFMID) << 8) + readReg(REG_FRFLSB)); + return RF69_FSTEP * (((uint32_t) readReg(REG_FRFMSB) << 16) + ((uint16_t) readReg( + REG_FRFMID) << 8) + readReg(REG_FRFLSB)); } // set the frequency (in Hz) void RFM69::setFrequency(uint32_t freqHz) { - uint8_t oldMode = _mode; - if (oldMode == RF69_MODE_TX) { - setMode(RF69_MODE_RX); - } - freqHz /= RF69_FSTEP; // divide down by FSTEP to get FRF - writeReg(REG_FRFMSB, freqHz >> 16); - writeReg(REG_FRFMID, freqHz >> 8); - writeReg(REG_FRFLSB, freqHz); - if (oldMode == RF69_MODE_RX) { - setMode(RF69_MODE_SYNTH); - } - setMode(oldMode); + uint8_t oldMode = _mode; + if (oldMode == RF69_MODE_TX) { + setMode(RF69_MODE_RX); + } + freqHz /= RF69_FSTEP; // divide down by FSTEP to get FRF + writeReg(REG_FRFMSB, freqHz >> 16); + writeReg(REG_FRFMID, freqHz >> 8); + writeReg(REG_FRFLSB, freqHz); + if (oldMode == RF69_MODE_RX) { + setMode(RF69_MODE_SYNTH); + } + setMode(oldMode); } void RFM69::setMode(uint8_t newMode) { - if (newMode == _mode) { - return; - } - - switch (newMode) { - case RF69_MODE_TX: - writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_TRANSMITTER); - if (_isRFM69HW) { - setHighPowerRegs(true); - } - break; - case RF69_MODE_RX: - writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_RECEIVER); - if (_isRFM69HW) { - setHighPowerRegs(false); - } - break; - case RF69_MODE_SYNTH: - writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_SYNTHESIZER); - break; - case RF69_MODE_STANDBY: - writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_STANDBY); - break; - case RF69_MODE_SLEEP: - writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_SLEEP); - break; - default: - return; - } - - // we are using packet mode, so this check is not really needed - // but waiting for mode ready is necessary when going from sleep because the FIFO may not be immediately available from previous mode - while (_mode == RF69_MODE_SLEEP && (readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // wait for ModeReady - - _mode = newMode; + if (newMode == _mode) { + return; + } + + switch (newMode) { + case RF69_MODE_TX: + writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_TRANSMITTER); + if (_isRFM69HW) { + setHighPowerRegs(true); + } + break; + case RF69_MODE_RX: + writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_RECEIVER); + if (_isRFM69HW) { + setHighPowerRegs(false); + } + break; + case RF69_MODE_SYNTH: + writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_SYNTHESIZER); + break; + case RF69_MODE_STANDBY: + writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_STANDBY); + break; + case RF69_MODE_SLEEP: + writeReg(REG_OPMODE, (readReg(REG_OPMODE) & 0xE3) | RF_OPMODE_SLEEP); + break; + default: + return; + } + + // we are using packet mode, so this check is not really needed + // but waiting for mode ready is necessary when going from sleep because the FIFO may not be immediately available from previous mode + while (_mode == RF69_MODE_SLEEP && + (readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00); // wait for ModeReady + + _mode = newMode; } //put transceiver in sleep mode to save battery - to wake or resume receiving just call receiveDone() -void RFM69::sleep() { - setMode(RF69_MODE_SLEEP); +void RFM69::sleep() +{ + setMode(RF69_MODE_SLEEP); } //set this node's address void RFM69::setAddress(uint8_t addr) { - _address = addr; - writeReg(REG_NODEADRS, _address); + _address = addr; + writeReg(REG_NODEADRS, _address); } //set this node's network id void RFM69::setNetwork(uint8_t networkID) { - writeReg(REG_SYNCVALUE2, networkID); + writeReg(REG_SYNCVALUE2, networkID); } // set *transmit/TX* output power: 0=min, 31=max @@ -215,31 +219,32 @@ void RFM69::setNetwork(uint8_t networkID) // - for RFM69HW the range is from 0-31 [5dBm to 20dBm] (PA1 & PA2 on PA_BOOST pin & high Power PA settings - see section 3.3.7 in datasheet, p22) void RFM69::setPowerLevel(uint8_t powerLevel) { - _powerLevel = (powerLevel > 31 ? 31 : powerLevel); - if (_isRFM69HW) { - _powerLevel /= 2; - } - writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0xE0) | _powerLevel); + _powerLevel = (powerLevel > 31 ? 31 : powerLevel); + if (_isRFM69HW) { + _powerLevel /= 2; + } + writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0xE0) | _powerLevel); } bool RFM69::canSend() { - if (_mode == RF69_MODE_RX && PAYLOADLEN == 0 && readRSSI() < CSMA_LIMIT) // if signal stronger than -100dBm is detected assume channel activity - { - setMode(RF69_MODE_STANDBY); - return true; - } - return false; + if (_mode == RF69_MODE_RX && PAYLOADLEN == 0 && + readRSSI() < CSMA_LIMIT) { // if signal stronger than -100dBm is detected assume channel activity + setMode(RF69_MODE_STANDBY); + return true; + } + return false; } void RFM69::send(uint8_t toAddress, const void* buffer, uint8_t bufferSize, bool requestACK) { - writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART); // avoid RX deadlocks - uint32_t now = millis(); - while (!canSend() && millis() - now < RF69_CSMA_LIMIT_MS) { - receiveDone(); - } - sendFrame(toAddress, buffer, bufferSize, requestACK, false); + writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFB) | + RF_PACKET2_RXRESTART); // avoid RX deadlocks + uint32_t now = millis(); + while (!canSend() && millis() - now < RF69_CSMA_LIMIT_MS) { + receiveDone(); + } + sendFrame(toAddress, buffer, bufferSize, requestACK, false); } // to increase the chance of getting a packet across, call this function instead of send @@ -248,287 +253,304 @@ void RFM69::send(uint8_t toAddress, const void* buffer, uint8_t bufferSize, bool // The reason for the semi-automaton is that the lib is interrupt driven and // requires user action to read the received data and decide what to do with it // replies usually take only 5..8ms at 50kbps@915MHz -bool RFM69::sendWithRetry(uint8_t toAddress, const void* buffer, uint8_t bufferSize, uint8_t retries, uint8_t retryWaitTime) { - uint32_t sentTime; - for (uint8_t i = 0; i <= retries; i++) - { - send(toAddress, buffer, bufferSize, true); - sentTime = millis(); - while (millis() - sentTime < retryWaitTime) - { - if (ACKReceived(toAddress)) - { - //Serial.print(" ~ms:"); Serial.print(millis() - sentTime); - return true; - } - } - //Serial.print(" RETRY#"); Serial.println(i + 1); - } - return false; +bool RFM69::sendWithRetry(uint8_t toAddress, const void* buffer, uint8_t bufferSize, + uint8_t retries, uint8_t retryWaitTime) +{ + uint32_t sentTime; + for (uint8_t i = 0; i <= retries; i++) { + send(toAddress, buffer, bufferSize, true); + sentTime = millis(); + while (millis() - sentTime < retryWaitTime) { + if (ACKReceived(toAddress)) { + //Serial.print(" ~ms:"); Serial.print(millis() - sentTime); + return true; + } + } + //Serial.print(" RETRY#"); Serial.println(i + 1); + } + return false; } // should be polled immediately after sending a packet with ACK request -bool RFM69::ACKReceived(uint8_t fromNodeID) { - if (receiveDone()) { - return (SENDERID == fromNodeID || fromNodeID == RF69_BROADCAST_ADDR) && ACK_RECEIVED; - } - return false; +bool RFM69::ACKReceived(uint8_t fromNodeID) +{ + if (receiveDone()) { + return (SENDERID == fromNodeID || fromNodeID == RF69_BROADCAST_ADDR) && ACK_RECEIVED; + } + return false; } // check whether an ACK was requested in the last received packet (non-broadcasted packet) -bool RFM69::ACKRequested() { - return ACK_REQUESTED && (TARGETID != RF69_BROADCAST_ADDR); +bool RFM69::ACKRequested() +{ + return ACK_REQUESTED && (TARGETID != RF69_BROADCAST_ADDR); } // should be called immediately after reception in case sender wants ACK -void RFM69::sendACK(const void* buffer, uint8_t bufferSize) { - ACK_REQUESTED = 0; // TWS added to make sure we don't end up in a timing race and infinite loop sending Acks - uint8_t sender = SENDERID; - int16_t _RSSI = RSSI; // save payload received RSSI value - writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART); // avoid RX deadlocks - uint32_t now = millis(); - while (!canSend() && millis() - now < RF69_CSMA_LIMIT_MS) { - receiveDone(); - yield(); - } - SENDERID = sender; // TWS: Restore SenderID after it gets wiped out by receiveDone() - sendFrame(sender, buffer, bufferSize, false, true); - RSSI = _RSSI; // restore payload RSSI -} - -void RFM69::interruptHook(uint8_t CTLbyte) { +void RFM69::sendACK(const void* buffer, uint8_t bufferSize) +{ + ACK_REQUESTED = + 0; // TWS added to make sure we don't end up in a timing race and infinite loop sending Acks + uint8_t sender = SENDERID; + int16_t _RSSI = RSSI; // save payload received RSSI value + writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFB) | + RF_PACKET2_RXRESTART); // avoid RX deadlocks + uint32_t now = millis(); + while (!canSend() && millis() - now < RF69_CSMA_LIMIT_MS) { + receiveDone(); + yield(); + } + SENDERID = sender; // TWS: Restore SenderID after it gets wiped out by receiveDone() + sendFrame(sender, buffer, bufferSize, false, true); + RSSI = _RSSI; // restore payload RSSI +} + +void RFM69::interruptHook(uint8_t CTLbyte) +{ (void)CTLbyte; }; // internal function -void RFM69::sendFrame(uint8_t toAddress, const void* buffer, uint8_t bufferSize, bool requestACK, bool sendACK) -{ - setMode(RF69_MODE_STANDBY); // turn off receiver to prevent reception while filling fifo - while ((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00) {} // wait for ModeReady - writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_00); // DIO0 is "Packet Sent" - if (bufferSize > RF69_MAX_DATA_LEN) { - bufferSize = RF69_MAX_DATA_LEN; - } - - // control byte - uint8_t CTLbyte = 0x00; - if (sendACK) { - CTLbyte = RFM69_CTL_SENDACK; - } - else if (requestACK) { - CTLbyte = RFM69_CTL_REQACK; - } - - // write to FIFO - select(); - SPI.transfer(REG_FIFO | 0x80); - SPI.transfer(bufferSize + 3); - SPI.transfer(toAddress); - SPI.transfer(_address); - SPI.transfer(CTLbyte); - - for (uint8_t i = 0; i < bufferSize; i++) { - SPI.transfer(((uint8_t*) buffer)[i]); - } - unselect(); - - // no need to wait for transmit mode to be ready since its handled by the radio - setMode(RF69_MODE_TX); - uint32_t txStart = millis(); - while (hwDigitalRead(_interruptPin) == 0 && millis() - txStart < RF69_TX_LIMIT_MS) {} // wait for DIO0 to turn HIGH signalling transmission finish - //while (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PACKETSENT == 0x00); // wait for ModeReady - setMode(RF69_MODE_STANDBY); +void RFM69::sendFrame(uint8_t toAddress, const void* buffer, uint8_t bufferSize, bool requestACK, + bool sendACK) +{ + setMode(RF69_MODE_STANDBY); // turn off receiver to prevent reception while filling fifo + while ((readReg(REG_IRQFLAGS1) & RF_IRQFLAGS1_MODEREADY) == 0x00) {} // wait for ModeReady + writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_00); // DIO0 is "Packet Sent" + if (bufferSize > RF69_MAX_DATA_LEN) { + bufferSize = RF69_MAX_DATA_LEN; + } + + // control byte + uint8_t CTLbyte = 0x00; + if (sendACK) { + CTLbyte = RFM69_CTL_SENDACK; + } else if (requestACK) { + CTLbyte = RFM69_CTL_REQACK; + } + + // write to FIFO + select(); + SPI.transfer(REG_FIFO | 0x80); + SPI.transfer(bufferSize + 3); + SPI.transfer(toAddress); + SPI.transfer(_address); + SPI.transfer(CTLbyte); + + for (uint8_t i = 0; i < bufferSize; i++) { + SPI.transfer(((uint8_t*) buffer)[i]); + } + unselect(); + + // no need to wait for transmit mode to be ready since its handled by the radio + setMode(RF69_MODE_TX); + uint32_t txStart = millis(); + while (hwDigitalRead(_interruptPin) == 0 && + millis() - txStart < RF69_TX_LIMIT_MS) {} // wait for DIO0 to turn HIGH signalling transmission finish + //while (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PACKETSENT == 0x00); // wait for ModeReady + setMode(RF69_MODE_STANDBY); } // internal function - interrupt gets called when a packet is received -void RFM69::interruptHandler() { - //hwPinMode(4, OUTPUT); - //hwDigitalWrite(4, 1); - if (_mode == RF69_MODE_RX && (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY)) - { - //RSSI = readRSSI(); - setMode(RF69_MODE_STANDBY); - select(); - SPI.transfer(REG_FIFO & 0x7F); - PAYLOADLEN = SPI.transfer(0); - PAYLOADLEN = PAYLOADLEN > 66 ? 66 : PAYLOADLEN; // precaution - TARGETID = SPI.transfer(0); - if(!(_promiscuousMode || TARGETID == _address || TARGETID == RF69_BROADCAST_ADDR) // match this node's address, or broadcast address or anything in promiscuous mode - || PAYLOADLEN < 3) // address situation could receive packets that are malformed and don't fit this libraries extra fields - { - PAYLOADLEN = 0; - unselect(); - receiveBegin(); - //hwDigitalWrite(4, 0); - return; - } - - DATALEN = PAYLOADLEN - 3; - SENDERID = SPI.transfer(0); - uint8_t CTLbyte = SPI.transfer(0); - - ACK_RECEIVED = CTLbyte & RFM69_CTL_SENDACK; // extract ACK-received flag - ACK_REQUESTED = CTLbyte & RFM69_CTL_REQACK; // extract ACK-requested flag - - interruptHook(CTLbyte); // TWS: hook to derived class interrupt function - - for (uint8_t i = 0; i < DATALEN; i++) - { - DATA[i] = SPI.transfer(0); - } - if (DATALEN < RF69_MAX_DATA_LEN) { - DATA[DATALEN] = 0; // add null at end of string - } - unselect(); - setMode(RF69_MODE_RX); - } - RSSI = readRSSI(); - //hwDigitalWrite(4, 0); +void RFM69::interruptHandler() +{ + //hwPinMode(4, OUTPUT); + //hwDigitalWrite(4, 1); + if (_mode == RF69_MODE_RX && (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY)) { + //RSSI = readRSSI(); + setMode(RF69_MODE_STANDBY); + select(); + SPI.transfer(REG_FIFO & 0x7F); + PAYLOADLEN = SPI.transfer(0); + PAYLOADLEN = PAYLOADLEN > 66 ? 66 : PAYLOADLEN; // precaution + TARGETID = SPI.transfer(0); + if(!(_promiscuousMode || TARGETID == _address || + TARGETID == RF69_BROADCAST_ADDR) // match this node's address, or broadcast address or anything in promiscuous mode + || PAYLOADLEN < + 3) { // address situation could receive packets that are malformed and don't fit this libraries extra fields + PAYLOADLEN = 0; + unselect(); + receiveBegin(); + //hwDigitalWrite(4, 0); + return; + } + + DATALEN = PAYLOADLEN - 3; + SENDERID = SPI.transfer(0); + uint8_t CTLbyte = SPI.transfer(0); + + ACK_RECEIVED = CTLbyte & RFM69_CTL_SENDACK; // extract ACK-received flag + ACK_REQUESTED = CTLbyte & RFM69_CTL_REQACK; // extract ACK-requested flag + + interruptHook(CTLbyte); // TWS: hook to derived class interrupt function + + for (uint8_t i = 0; i < DATALEN; i++) { + DATA[i] = SPI.transfer(0); + } + if (DATALEN < RF69_MAX_DATA_LEN) { + DATA[DATALEN] = 0; // add null at end of string + } + unselect(); + setMode(RF69_MODE_RX); + } + RSSI = readRSSI(); + //hwDigitalWrite(4, 0); } // internal function -void RFM69::isr0() { selfPointer->interruptHandler(); } +void RFM69::isr0() +{ + selfPointer->interruptHandler(); +} // internal function -void RFM69::receiveBegin() { - DATALEN = 0; - SENDERID = 0; - TARGETID = 0; - PAYLOADLEN = 0; - ACK_REQUESTED = 0; - ACK_RECEIVED = 0; - RSSI = 0; - if (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY) { - writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFB) | RF_PACKET2_RXRESTART); // avoid RX deadlocks - } - writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01); // set DIO0 to "PAYLOADREADY" in receive mode - setMode(RF69_MODE_RX); +void RFM69::receiveBegin() +{ + DATALEN = 0; + SENDERID = 0; + TARGETID = 0; + PAYLOADLEN = 0; + ACK_REQUESTED = 0; + ACK_RECEIVED = 0; + RSSI = 0; + if (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PAYLOADREADY) { + writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFB) | + RF_PACKET2_RXRESTART); // avoid RX deadlocks + } + writeReg(REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_01); // set DIO0 to "PAYLOADREADY" in receive mode + setMode(RF69_MODE_RX); } // checks if a packet was received and/or puts transceiver in receive (ie RX or listen) mode -bool RFM69::receiveDone() { -//ATOMIC_BLOCK(ATOMIC_FORCEON) -//{ - noInterrupts(); // re-enabled in unselect() via setMode() or via receiveBegin() - if (_mode == RF69_MODE_RX && PAYLOADLEN > 0) - { - setMode(RF69_MODE_STANDBY); // enables interrupts - return true; - } - else if (_mode == RF69_MODE_RX) // already in RX no payload yet - { - interrupts(); // explicitly re-enable interrupts - return false; - } - receiveBegin(); - return false; -//} +bool RFM69::receiveDone() +{ + //ATOMIC_BLOCK(ATOMIC_FORCEON) + //{ + noInterrupts(); // re-enabled in unselect() via setMode() or via receiveBegin() + if (_mode == RF69_MODE_RX && PAYLOADLEN > 0) { + setMode(RF69_MODE_STANDBY); // enables interrupts + return true; + } else if (_mode == RF69_MODE_RX) { // already in RX no payload yet + interrupts(); // explicitly re-enable interrupts + return false; + } + receiveBegin(); + return false; + //} } // To enable encryption: radio.encrypt("ABCDEFGHIJKLMNOP"); // To disable encryption: radio.encrypt(null) or radio.encrypt(0) // KEY HAS TO BE 16 bytes !!! -void RFM69::encrypt(const char* key) { - setMode(RF69_MODE_STANDBY); - if (key != 0) - { - select(); - SPI.transfer(REG_AESKEY1 | 0x80); - for (uint8_t i = 0; i < 16; i++) { - SPI.transfer(key[i]); - } - unselect(); - } - writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFE) | (key ? 1 : 0)); +void RFM69::encrypt(const char* key) +{ + setMode(RF69_MODE_STANDBY); + if (key != 0) { + select(); + SPI.transfer(REG_AESKEY1 | 0x80); + for (uint8_t i = 0; i < 16; i++) { + SPI.transfer(key[i]); + } + unselect(); + } + writeReg(REG_PACKETCONFIG2, (readReg(REG_PACKETCONFIG2) & 0xFE) | (key ? 1 : 0)); } // get the received signal strength indicator (RSSI) -int16_t RFM69::readRSSI(bool forceTrigger) { - int16_t rssi = 0; - if (forceTrigger) - { - // RSSI trigger not needed if DAGC is in continuous mode - writeReg(REG_RSSICONFIG, RF_RSSI_START); - while ((readReg(REG_RSSICONFIG) & RF_RSSI_DONE) == 0x00) {} // wait for RSSI_Ready - } - rssi = -readReg(REG_RSSIVALUE); - rssi >>= 1; - return rssi; +int16_t RFM69::readRSSI(bool forceTrigger) +{ + int16_t rssi = 0; + if (forceTrigger) { + // RSSI trigger not needed if DAGC is in continuous mode + writeReg(REG_RSSICONFIG, RF_RSSI_START); + while ((readReg(REG_RSSICONFIG) & RF_RSSI_DONE) == 0x00) {} // wait for RSSI_Ready + } + rssi = -readReg(REG_RSSIVALUE); + rssi >>= 1; + return rssi; } uint8_t RFM69::readReg(uint8_t addr) { - select(); - SPI.transfer(addr & 0x7F); - uint8_t regval = SPI.transfer(0); - unselect(); - return regval; + select(); + SPI.transfer(addr & 0x7F); + uint8_t regval = SPI.transfer(0); + unselect(); + return regval; } void RFM69::writeReg(uint8_t addr, uint8_t value) { - select(); - SPI.transfer(addr | 0x80); - SPI.transfer(value); - unselect(); + select(); + SPI.transfer(addr | 0x80); + SPI.transfer(value); + unselect(); } // select the RFM69 transceiver (save SPI settings, set CS low) -void RFM69::select() { - noInterrupts(); +void RFM69::select() +{ + noInterrupts(); #if defined (SPCR) && defined (SPSR) - // save current SPI settings - _SPCR = SPCR; - _SPSR = SPSR; + // save current SPI settings + _SPCR = SPCR; + _SPSR = SPSR; #endif - // set RFM69 SPI settings - SPI.setDataMode(SPI_MODE0); - SPI.setBitOrder(MSBFIRST); - SPI.setClockDivider(SPI_CLOCK_DIV4); // decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present - hwDigitalWrite(_slaveSelectPin, LOW); + // set RFM69 SPI settings + SPI.setDataMode(SPI_MODE0); + SPI.setBitOrder(MSBFIRST); + SPI.setClockDivider( + SPI_CLOCK_DIV4); // decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present + hwDigitalWrite(_slaveSelectPin, LOW); } // unselect the RFM69 transceiver (set CS high, restore SPI settings) -void RFM69::unselect() { - hwDigitalWrite(_slaveSelectPin, HIGH); - // restore SPI settings to what they were before talking to RFM69 +void RFM69::unselect() +{ + hwDigitalWrite(_slaveSelectPin, HIGH); + // restore SPI settings to what they were before talking to RFM69 #if defined (SPCR) && defined (SPSR) - SPCR = _SPCR; - SPSR = _SPSR; + SPCR = _SPCR; + SPSR = _SPSR; #endif - interrupts(); + interrupts(); } // true = disable filtering to capture all frames on network // false = enable node/broadcast filtering to capture only frames sent to this/broadcast address -void RFM69::promiscuous(bool onOff) { - _promiscuousMode = onOff; - //writeReg(REG_PACKETCONFIG1, (readReg(REG_PACKETCONFIG1) & 0xF9) | (onOff ? RF_PACKET1_ADRSFILTERING_OFF : RF_PACKET1_ADRSFILTERING_NODEBROADCAST)); +void RFM69::promiscuous(bool onOff) +{ + _promiscuousMode = onOff; + //writeReg(REG_PACKETCONFIG1, (readReg(REG_PACKETCONFIG1) & 0xF9) | (onOff ? RF_PACKET1_ADRSFILTERING_OFF : RF_PACKET1_ADRSFILTERING_NODEBROADCAST)); } // for RFM69HW only: you must call setHighPower(true) after initialize() or else transmission won't work -void RFM69::setHighPower(bool onOff) { - _isRFM69HW = onOff; - writeReg(REG_OCP, _isRFM69HW ? RF_OCP_OFF : RF_OCP_ON); - if (_isRFM69HW) { // turning ON - writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0x1F) | RF_PALEVEL_PA1_ON | RF_PALEVEL_PA2_ON); // enable P1 & P2 amplifier stages - } - else { - writeReg(REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | _powerLevel); // enable P0 only - } +void RFM69::setHighPower(bool onOff) +{ + _isRFM69HW = onOff; + writeReg(REG_OCP, _isRFM69HW ? RF_OCP_OFF : RF_OCP_ON); + if (_isRFM69HW) { // turning ON + writeReg(REG_PALEVEL, (readReg(REG_PALEVEL) & 0x1F) | RF_PALEVEL_PA1_ON | + RF_PALEVEL_PA2_ON); // enable P1 & P2 amplifier stages + } else { + writeReg(REG_PALEVEL, RF_PALEVEL_PA0_ON | RF_PALEVEL_PA1_OFF | RF_PALEVEL_PA2_OFF | + _powerLevel); // enable P0 only + } } // internal function -void RFM69::setHighPowerRegs(bool onOff) { - writeReg(REG_TESTPA1, onOff ? 0x5D : 0x55); - writeReg(REG_TESTPA2, onOff ? 0x7C : 0x70); +void RFM69::setHighPowerRegs(bool onOff) +{ + writeReg(REG_TESTPA1, onOff ? 0x5D : 0x55); + writeReg(REG_TESTPA2, onOff ? 0x7C : 0x70); } // set the slave select (CS) pin -void RFM69::setCS(uint8_t newSPISlaveSelect) { - _slaveSelectPin = newSPISlaveSelect; - hwDigitalWrite(_slaveSelectPin, HIGH); - hwPinMode(_slaveSelectPin, OUTPUT); +void RFM69::setCS(uint8_t newSPISlaveSelect) +{ + _slaveSelectPin = newSPISlaveSelect; + hwDigitalWrite(_slaveSelectPin, HIGH); + hwPinMode(_slaveSelectPin, OUTPUT); } //for debugging @@ -537,294 +559,295 @@ void RFM69::setCS(uint8_t newSPISlaveSelect) { // SERIAL PRINT // replace Serial.print("string") with SerialPrint("string") #define SerialPrint(x) SerialPrint_P(PSTR(x)) -void SerialWrite ( uint8_t c ) { - Serial.write ( c ); +void SerialWrite ( uint8_t c ) +{ + Serial.write ( c ); } -void SerialPrint_P(PGM_P str, void (*f)(uint8_t) = SerialWrite ) { - for (uint8_t c; (c = pgm_read_byte(str)); str++) { - (*f)(c); - } +void SerialPrint_P(PGM_P str, void (*f)(uint8_t) = SerialWrite ) +{ + for (uint8_t c; (c = pgm_read_byte(str)); str++) { + (*f)(c); + } } #endif void RFM69::readAllRegs() { - uint8_t regVal; + uint8_t regVal; #if REGISTER_DETAIL - int capVal; + int capVal; - //... State Variables for intelligent decoding - uint8_t modeFSK = 0; - int bitRate = 0; - int freqDev = 0; - long freqCenter = 0; + //... State Variables for intelligent decoding + uint8_t modeFSK = 0; + int bitRate = 0; + int freqDev = 0; + long freqCenter = 0; #endif - Serial.println("Address - HEX - BIN"); - for (uint8_t regAddr = 1; regAddr <= 0x4F; regAddr++) - { - select(); - SPI.transfer(regAddr & 0x7F); // send address + r/w bit - regVal = SPI.transfer(0); - unselect(); + Serial.println("Address - HEX - BIN"); + for (uint8_t regAddr = 1; regAddr <= 0x4F; regAddr++) { + select(); + SPI.transfer(regAddr & 0x7F); // send address + r/w bit + regVal = SPI.transfer(0); + unselect(); - Serial.print(regAddr, HEX); - Serial.print(" - "); - Serial.print(regVal,HEX); - Serial.print(" - "); - Serial.println(regVal,BIN); + Serial.print(regAddr, HEX); + Serial.print(" - "); + Serial.print(regVal,HEX); + Serial.print(" - "); + Serial.println(regVal,BIN); #if REGISTER_DETAIL - switch ( regAddr ) - { - case 0x1 : { - SerialPrint ( "Controls the automatic Sequencer ( see section 4.2 )\nSequencerOff : " ); - if ( 0x80 & regVal ) { - SerialPrint ( "1 -> Mode is forced by the user\n" ); - } else { - SerialPrint ( "0 -> Operating mode as selected with Mode bits in RegOpMode is automatically reached with the Sequencer\n" ); - } - - SerialPrint( "\nEnables Listen mode, should be enabled whilst in Standby mode:\nListenOn : " ); - if ( 0x40 & regVal ) { - SerialPrint ( "1 -> On\n" ); - } else { - SerialPrint ( "0 -> Off ( see section 4.3)\n" ); - } - - SerialPrint( "\nAborts Listen mode when set together with ListenOn=0 See section 4.3.4 for details (Always reads 0.)\n" ); - if ( 0x20 & regVal ) { - SerialPrint ( "ERROR - ListenAbort should NEVER return 1 this is a write only register\n" ); - } - - SerialPrint("\nTransceiver's operating modes:\nMode : "); - capVal = (regVal >> 2) & 0x7; - if ( capVal == 0b000 ) { - SerialPrint ( "000 -> Sleep mode (SLEEP)\n" ); - } else if ( capVal = 0b001 ) { - SerialPrint ( "001 -> Standby mode (STDBY)\n" ); - } else if ( capVal = 0b010 ) { - SerialPrint ( "010 -> Frequency Synthesizer mode (FS)\n" ); - } else if ( capVal = 0b011 ) { - SerialPrint ( "011 -> Transmitter mode (TX)\n" ); - } else if ( capVal = 0b100 ) { - SerialPrint ( "100 -> Receiver Mode (RX)\n" ); - } else { - Serial.print( capVal, BIN ); - SerialPrint ( " -> RESERVED\n" ); - } - SerialPrint ( "\n" ); - break; - } - - case 0x2 : { - - SerialPrint("Data Processing mode:\nDataMode : "); - capVal = (regVal >> 5) & 0x3; - if ( capVal == 0b00 ) { - SerialPrint ( "00 -> Packet mode\n" ); - } else if ( capVal == 0b01 ) { - SerialPrint ( "01 -> reserved\n" ); - } else if ( capVal == 0b10 ) { - SerialPrint ( "10 -> Continuous mode with bit synchronizer\n" ); - } else if ( capVal == 0b11 ) { - SerialPrint ( "11 -> Continuous mode without bit synchronizer\n" ); - } - - SerialPrint("\nModulation scheme:\nModulation Type : "); - capVal = (regVal >> 3) & 0x3; - if ( capVal == 0b00 ) { - SerialPrint ( "00 -> FSK\n" ); - modeFSK = 1; - } else if ( capVal == 0b01 ) { - SerialPrint ( "01 -> OOK\n" ); - } else if ( capVal == 0b10 ) { - SerialPrint ( "10 -> reserved\n" ); - } else if ( capVal == 0b11 ) { - SerialPrint ( "11 -> reserved\n" ); - } - - SerialPrint("\nData shaping: "); - if ( modeFSK ) { - SerialPrint( "in FSK:\n" ); - } else { - SerialPrint( "in OOK:\n" ); - } - SerialPrint ("ModulationShaping : "); - capVal = regVal & 0x3; - if ( modeFSK ) { - if ( capVal == 0b00 ) { - SerialPrint ( "00 -> no shaping\n" ); - } else if ( capVal == 0b01 ) { - SerialPrint ( "01 -> Gaussian filter, BT = 1.0\n" ); - } else if ( capVal == 0b10 ) { - SerialPrint ( "10 -> Gaussian filter, BT = 0.5\n" ); - } else if ( capVal == 0b11 ) { - SerialPrint ( "11 -> Gaussian filter, BT = 0.3\n" ); - } - } else { - if ( capVal == 0b00 ) { - SerialPrint ( "00 -> no shaping\n" ); - } else if ( capVal == 0b01 ) { - SerialPrint ( "01 -> filtering with f(cutoff) = BR\n" ); - } else if ( capVal == 0b10 ) { - SerialPrint ( "10 -> filtering with f(cutoff) = 2*BR\n" ); - } else if ( capVal == 0b11 ) { - SerialPrint ( "ERROR - 11 is reserved\n" ); - } - } - - SerialPrint ( "\n" ); - break; - } - - case 0x3 : { - bitRate = (regVal << 8); - break; - } - - case 0x4 : { - bitRate |= regVal; - SerialPrint ( "Bit Rate (Chip Rate when Manchester encoding is enabled)\nBitRate : "); - unsigned long val = 32UL * 1000UL * 1000UL / bitRate; - Serial.println( val ); - SerialPrint( "\n" ); - break; - } - - case 0x5 : { - freqDev = ( (regVal & 0x3f) << 8 ); - break; - } - - case 0x6 : { - freqDev |= regVal; - SerialPrint( "Frequency deviation\nFdev : " ); - unsigned long val = 61UL * freqDev; - Serial.println( val ); - SerialPrint ( "\n" ); - break; - } - - case 0x7 : { - unsigned long tempVal = regVal; - freqCenter = ( tempVal << 16 ); - break; - } - - case 0x8 : { - unsigned long tempVal = regVal; - freqCenter = freqCenter | ( tempVal << 8 ); - break; - } - - case 0x9 : { - freqCenter = freqCenter | regVal; - SerialPrint ( "RF Carrier frequency\nFRF : " ); - unsigned long val = 61UL * freqCenter; - Serial.println( val ); - SerialPrint( "\n" ); - break; - } - - case 0xa : { - SerialPrint ( "RC calibration control & status\nRcCalDone : " ); - if ( 0x40 & regVal ) { - SerialPrint ( "1 -> RC calibration is over\n" ); - } else { - SerialPrint ( "0 -> RC calibration is in progress\n" ); - } - - SerialPrint ( "\n" ); - break; - } - - case 0xb : { - SerialPrint ( "Improved AFC routine for signals with modulation index lower than 2. Refer to section 3.4.16 for details\nAfcLowBetaOn : " ); - if ( 0x20 & regVal ) { - SerialPrint ( "1 -> Improved AFC routine\n" ); - } else { - SerialPrint ( "0 -> Standard AFC routine\n" ); - } - SerialPrint ( "\n" ); - break; - } - - case 0xc : { - SerialPrint ( "Reserved\n\n" ); - break; - } - - case 0xd : { - byte val; - SerialPrint ( "Resolution of Listen mode Idle time (calibrated RC osc):\nListenResolIdle : " ); - val = regVal >> 6; - if ( val == 0b00 ) { - SerialPrint ( "00 -> reserved\n" ); - } else if ( val == 0b01 ) { - SerialPrint ( "01 -> 64 us\n" ); - } else if ( val == 0b10 ) { - SerialPrint ( "10 -> 4.1 ms\n" ); - } else if ( val == 0b11 ) { - SerialPrint ( "11 -> 262 ms\n" ); - } - - SerialPrint ( "\nResolution of Listen mode Rx time (calibrated RC osc):\nListenResolRx : " ); - val = (regVal >> 4) & 0x3; - if ( val == 0b00 ) { - SerialPrint ( "00 -> reserved\n" ); - } else if ( val == 0b01 ) { - SerialPrint ( "01 -> 64 us\n" ); - } else if ( val == 0b10 ) { - SerialPrint ( "10 -> 4.1 ms\n" ); - } else if ( val == 0b11 ) { - SerialPrint ( "11 -> 262 ms\n" ); - } - - SerialPrint ( "\nCriteria for packet acceptance in Listen mode:\nListenCriteria : " ); - if ( 0x8 & regVal ) { - SerialPrint ( "1 -> signal strength is above RssiThreshold and SyncAddress matched\n" ); - } else { - SerialPrint ( "0 -> signal strength is above RssiThreshold\n" ); - } - - SerialPrint ( "\nAction taken after acceptance of a packet in Listen mode:\nListenEnd : " ); - val = (regVal >> 1 ) & 0x3; - if ( val == 0b00 ) { - SerialPrint ( "00 -> chip stays in Rx mode. Listen mode stops and must be disabled (see section 4.3)\n" ); - } else if ( val == 0b01 ) { - SerialPrint ( "01 -> chip stays in Rx mode until PayloadReady or Timeout interrupt occurs. It then goes to the mode defined by Mode. Listen mode stops and must be disabled (see section 4.3)\n" ); - } else if ( val == 0b10 ) { - SerialPrint ( "10 -> chip stays in Rx mode until PayloadReady or Timeout occurs. Listen mode then resumes in Idle state. FIFO content is lost at next Rx wakeup.\n" ); - } else if ( val == 0b11 ) { - SerialPrint ( "11 -> Reserved\n" ); - } - - - SerialPrint ( "\n" ); - break; - } - - default : { - } - } + switch ( regAddr ) { + case 0x1 : { + SerialPrint ( "Controls the automatic Sequencer ( see section 4.2 )\nSequencerOff : " ); + if ( 0x80 & regVal ) { + SerialPrint ( "1 -> Mode is forced by the user\n" ); + } else { + SerialPrint ( "0 -> Operating mode as selected with Mode bits in RegOpMode is automatically reached with the Sequencer\n" ); + } + + SerialPrint( "\nEnables Listen mode, should be enabled whilst in Standby mode:\nListenOn : " ); + if ( 0x40 & regVal ) { + SerialPrint ( "1 -> On\n" ); + } else { + SerialPrint ( "0 -> Off ( see section 4.3)\n" ); + } + + SerialPrint( "\nAborts Listen mode when set together with ListenOn=0 See section 4.3.4 for details (Always reads 0.)\n" ); + if ( 0x20 & regVal ) { + SerialPrint ( "ERROR - ListenAbort should NEVER return 1 this is a write only register\n" ); + } + + SerialPrint("\nTransceiver's operating modes:\nMode : "); + capVal = (regVal >> 2) & 0x7; + if ( capVal == 0b000 ) { + SerialPrint ( "000 -> Sleep mode (SLEEP)\n" ); + } else if ( capVal = 0b001 ) { + SerialPrint ( "001 -> Standby mode (STDBY)\n" ); + } else if ( capVal = 0b010 ) { + SerialPrint ( "010 -> Frequency Synthesizer mode (FS)\n" ); + } else if ( capVal = 0b011 ) { + SerialPrint ( "011 -> Transmitter mode (TX)\n" ); + } else if ( capVal = 0b100 ) { + SerialPrint ( "100 -> Receiver Mode (RX)\n" ); + } else { + Serial.print( capVal, BIN ); + SerialPrint ( " -> RESERVED\n" ); + } + SerialPrint ( "\n" ); + break; + } + + case 0x2 : { + + SerialPrint("Data Processing mode:\nDataMode : "); + capVal = (regVal >> 5) & 0x3; + if ( capVal == 0b00 ) { + SerialPrint ( "00 -> Packet mode\n" ); + } else if ( capVal == 0b01 ) { + SerialPrint ( "01 -> reserved\n" ); + } else if ( capVal == 0b10 ) { + SerialPrint ( "10 -> Continuous mode with bit synchronizer\n" ); + } else if ( capVal == 0b11 ) { + SerialPrint ( "11 -> Continuous mode without bit synchronizer\n" ); + } + + SerialPrint("\nModulation scheme:\nModulation Type : "); + capVal = (regVal >> 3) & 0x3; + if ( capVal == 0b00 ) { + SerialPrint ( "00 -> FSK\n" ); + modeFSK = 1; + } else if ( capVal == 0b01 ) { + SerialPrint ( "01 -> OOK\n" ); + } else if ( capVal == 0b10 ) { + SerialPrint ( "10 -> reserved\n" ); + } else if ( capVal == 0b11 ) { + SerialPrint ( "11 -> reserved\n" ); + } + + SerialPrint("\nData shaping: "); + if ( modeFSK ) { + SerialPrint( "in FSK:\n" ); + } else { + SerialPrint( "in OOK:\n" ); + } + SerialPrint ("ModulationShaping : "); + capVal = regVal & 0x3; + if ( modeFSK ) { + if ( capVal == 0b00 ) { + SerialPrint ( "00 -> no shaping\n" ); + } else if ( capVal == 0b01 ) { + SerialPrint ( "01 -> Gaussian filter, BT = 1.0\n" ); + } else if ( capVal == 0b10 ) { + SerialPrint ( "10 -> Gaussian filter, BT = 0.5\n" ); + } else if ( capVal == 0b11 ) { + SerialPrint ( "11 -> Gaussian filter, BT = 0.3\n" ); + } + } else { + if ( capVal == 0b00 ) { + SerialPrint ( "00 -> no shaping\n" ); + } else if ( capVal == 0b01 ) { + SerialPrint ( "01 -> filtering with f(cutoff) = BR\n" ); + } else if ( capVal == 0b10 ) { + SerialPrint ( "10 -> filtering with f(cutoff) = 2*BR\n" ); + } else if ( capVal == 0b11 ) { + SerialPrint ( "ERROR - 11 is reserved\n" ); + } + } + + SerialPrint ( "\n" ); + break; + } + + case 0x3 : { + bitRate = (regVal << 8); + break; + } + + case 0x4 : { + bitRate |= regVal; + SerialPrint ( "Bit Rate (Chip Rate when Manchester encoding is enabled)\nBitRate : "); + unsigned long val = 32UL * 1000UL * 1000UL / bitRate; + Serial.println( val ); + SerialPrint( "\n" ); + break; + } + + case 0x5 : { + freqDev = ( (regVal & 0x3f) << 8 ); + break; + } + + case 0x6 : { + freqDev |= regVal; + SerialPrint( "Frequency deviation\nFdev : " ); + unsigned long val = 61UL * freqDev; + Serial.println( val ); + SerialPrint ( "\n" ); + break; + } + + case 0x7 : { + unsigned long tempVal = regVal; + freqCenter = ( tempVal << 16 ); + break; + } + + case 0x8 : { + unsigned long tempVal = regVal; + freqCenter = freqCenter | ( tempVal << 8 ); + break; + } + + case 0x9 : { + freqCenter = freqCenter | regVal; + SerialPrint ( "RF Carrier frequency\nFRF : " ); + unsigned long val = 61UL * freqCenter; + Serial.println( val ); + SerialPrint( "\n" ); + break; + } + + case 0xa : { + SerialPrint ( "RC calibration control & status\nRcCalDone : " ); + if ( 0x40 & regVal ) { + SerialPrint ( "1 -> RC calibration is over\n" ); + } else { + SerialPrint ( "0 -> RC calibration is in progress\n" ); + } + + SerialPrint ( "\n" ); + break; + } + + case 0xb : { + SerialPrint ( "Improved AFC routine for signals with modulation index lower than 2. Refer to section 3.4.16 for details\nAfcLowBetaOn : " ); + if ( 0x20 & regVal ) { + SerialPrint ( "1 -> Improved AFC routine\n" ); + } else { + SerialPrint ( "0 -> Standard AFC routine\n" ); + } + SerialPrint ( "\n" ); + break; + } + + case 0xc : { + SerialPrint ( "Reserved\n\n" ); + break; + } + + case 0xd : { + byte val; + SerialPrint ( "Resolution of Listen mode Idle time (calibrated RC osc):\nListenResolIdle : " ); + val = regVal >> 6; + if ( val == 0b00 ) { + SerialPrint ( "00 -> reserved\n" ); + } else if ( val == 0b01 ) { + SerialPrint ( "01 -> 64 us\n" ); + } else if ( val == 0b10 ) { + SerialPrint ( "10 -> 4.1 ms\n" ); + } else if ( val == 0b11 ) { + SerialPrint ( "11 -> 262 ms\n" ); + } + + SerialPrint ( "\nResolution of Listen mode Rx time (calibrated RC osc):\nListenResolRx : " ); + val = (regVal >> 4) & 0x3; + if ( val == 0b00 ) { + SerialPrint ( "00 -> reserved\n" ); + } else if ( val == 0b01 ) { + SerialPrint ( "01 -> 64 us\n" ); + } else if ( val == 0b10 ) { + SerialPrint ( "10 -> 4.1 ms\n" ); + } else if ( val == 0b11 ) { + SerialPrint ( "11 -> 262 ms\n" ); + } + + SerialPrint ( "\nCriteria for packet acceptance in Listen mode:\nListenCriteria : " ); + if ( 0x8 & regVal ) { + SerialPrint ( "1 -> signal strength is above RssiThreshold and SyncAddress matched\n" ); + } else { + SerialPrint ( "0 -> signal strength is above RssiThreshold\n" ); + } + + SerialPrint ( "\nAction taken after acceptance of a packet in Listen mode:\nListenEnd : " ); + val = (regVal >> 1 ) & 0x3; + if ( val == 0b00 ) { + SerialPrint ( "00 -> chip stays in Rx mode. Listen mode stops and must be disabled (see section 4.3)\n" ); + } else if ( val == 0b01 ) { + SerialPrint ( "01 -> chip stays in Rx mode until PayloadReady or Timeout interrupt occurs. It then goes to the mode defined by Mode. Listen mode stops and must be disabled (see section 4.3)\n" ); + } else if ( val == 0b10 ) { + SerialPrint ( "10 -> chip stays in Rx mode until PayloadReady or Timeout occurs. Listen mode then resumes in Idle state. FIFO content is lost at next Rx wakeup.\n" ); + } else if ( val == 0b11 ) { + SerialPrint ( "11 -> Reserved\n" ); + } + + + SerialPrint ( "\n" ); + break; + } + + default : { + } + } #endif - } - unselect(); + } + unselect(); } uint8_t RFM69::readTemperature(uint8_t calFactor) // returns centigrade { - setMode(RF69_MODE_STANDBY); - writeReg(REG_TEMP1, RF_TEMP1_MEAS_START); - while ((readReg(REG_TEMP1) & RF_TEMP1_MEAS_RUNNING)) {} - return ~readReg(REG_TEMP2) + COURSE_TEMP_COEF + calFactor; // 'complement' corrects the slope, rising temp = rising val + setMode(RF69_MODE_STANDBY); + writeReg(REG_TEMP1, RF_TEMP1_MEAS_START); + while ((readReg(REG_TEMP1) & RF_TEMP1_MEAS_RUNNING)) {} + return ~readReg(REG_TEMP2) + COURSE_TEMP_COEF + + calFactor; // 'complement' corrects the slope, rising temp = rising val } // COURSE_TEMP_COEF puts reading in the ballpark, user can add additional correction void RFM69::rcCalibration() { - writeReg(REG_OSC1, RF_OSC1_RCCAL_START); - while ((readReg(REG_OSC1) & RF_OSC1_RCCAL_DONE) == 0x00) {} + writeReg(REG_OSC1, RF_OSC1_RCCAL_START); + while ((readReg(REG_OSC1) & RF_OSC1_RCCAL_DONE) == 0x00) {} } diff --git a/drivers/RFM69/RFM69.h b/drivers/RFM69/RFM69.h index d8eb7aa75..682319b53 100644 --- a/drivers/RFM69/RFM69.h +++ b/drivers/RFM69/RFM69.h @@ -6,23 +6,23 @@ // ********************************************************************************** // License // ********************************************************************************** -// This program is free software; you can redistribute it -// and/or modify it under the terms of the GNU General -// Public License as published by the Free Software -// Foundation; either version 3 of the License, or -// (at your option) any later version. -// -// This program 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 General Public -// License for more details. -// -// You should have received a copy of the GNU General +// This program is free software; you can redistribute it +// and/or modify it under the terms of the GNU General +// Public License as published by the Free Software +// Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public +// License for more details. +// +// You should have received a copy of the GNU General // Public License along with this program. // If not, see . -// -// Licence can be viewed at +// +// Licence can be viewed at // http://www.gnu.org/licenses/gpl-3.0.txt // // Please maintain this license information along with authorship @@ -37,20 +37,20 @@ // INT0 on AVRs should be connected to RFM69's DIO0 (ex on ATmega328 it's D2, on ATmega644/1284 it's D2) #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__) - #define RF69_IRQ_PIN 2 - #define RF69_IRQ_NUM 0 +#define RF69_IRQ_PIN 2 +#define RF69_IRQ_NUM 0 #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) - #define RF69_IRQ_PIN 2 - #define RF69_IRQ_NUM 2 +#define RF69_IRQ_PIN 2 +#define RF69_IRQ_NUM 2 #elif defined(__AVR_ATmega32U4__) - #define RF69_IRQ_PIN 3 - #define RF69_IRQ_NUM 0 +#define RF69_IRQ_PIN 3 +#define RF69_IRQ_NUM 0 #elif defined(__arm__)//Use pin 10 or any pin you want - #define RF69_IRQ_PIN 10 - #define RF69_IRQ_NUM 10 -#else - #define RF69_IRQ_PIN 2 - #define RF69_IRQ_NUM 0 +#define RF69_IRQ_PIN 10 +#define RF69_IRQ_NUM 10 +#else +#define RF69_IRQ_PIN 2 +#define RF69_IRQ_NUM 0 #endif @@ -79,79 +79,96 @@ #define RFM69_CTL_REQACK 0x40 /** RFM69 class */ -class RFM69 { - public: - static volatile uint8_t DATA[RF69_MAX_DATA_LEN]; //!< recv/xmit buf, including hdr & crc bytes - static volatile uint8_t DATALEN; //!< DATALEN - static volatile uint8_t SENDERID; //!< SENDERID - static volatile uint8_t TARGETID; //!< should match _address - static volatile uint8_t PAYLOADLEN; //!< PAYLOADLEN - static volatile uint8_t ACK_REQUESTED; //!< ACK_REQUESTED - static volatile uint8_t ACK_RECEIVED; //!< Should be polled immediately after sending a packet with ACK requestwith ACK request - static volatile int16_t RSSI; //!< most accurate RSSI during reception (closest to the reception) - static volatile uint8_t _mode; //!< should be protected? +class RFM69 +{ +public: + static volatile uint8_t DATA[RF69_MAX_DATA_LEN]; //!< recv/xmit buf, including hdr & crc bytes + static volatile uint8_t DATALEN; //!< DATALEN + static volatile uint8_t SENDERID; //!< SENDERID + static volatile uint8_t TARGETID; //!< should match _address + static volatile uint8_t PAYLOADLEN; //!< PAYLOADLEN + static volatile uint8_t ACK_REQUESTED; //!< ACK_REQUESTED + static volatile uint8_t + ACK_RECEIVED; //!< Should be polled immediately after sending a packet with ACK requestwith ACK request + static volatile int16_t RSSI; //!< most accurate RSSI during reception (closest to the reception) + static volatile uint8_t _mode; //!< should be protected? - RFM69(uint8_t slaveSelectPin=RF69_SPI_CS, uint8_t interruptPin=RF69_IRQ_PIN, bool isRFM69HW=false, uint8_t interruptNum=RF69_IRQ_NUM) { //!< Constructor - _slaveSelectPin = slaveSelectPin; - _interruptPin = interruptPin; - _interruptNum = interruptNum; - _mode = RF69_MODE_STANDBY; - _promiscuousMode = false; - _powerLevel = 31; - _isRFM69HW = isRFM69HW; - } + /** + * @brief Constructor + * + * @param slaveSelectPin ChipSelect pin. + * @param interruptPin Interrupt pin. + * @param isRFM69HW Set to @c true to indicate RFM69HW variant. + * @param interruptNum Interrupt number. + */ + RFM69(uint8_t slaveSelectPin=RF69_SPI_CS, uint8_t interruptPin=RF69_IRQ_PIN, bool isRFM69HW=false, + uint8_t interruptNum=RF69_IRQ_NUM) + { + _slaveSelectPin = slaveSelectPin; + _interruptPin = interruptPin; + _interruptNum = interruptNum; + _mode = RF69_MODE_STANDBY; + _promiscuousMode = false; + _powerLevel = 31; + _isRFM69HW = isRFM69HW; + } - bool initialize(uint8_t freqBand, uint8_t ID, uint8_t networkID=1); //!< initialize - void setAddress(uint8_t addr); //!< setAddress - void setNetwork(uint8_t networkID); //!< setNetwork - bool canSend(); //!< canSend - virtual void send(uint8_t toAddress, const void* buffer, uint8_t bufferSize, bool requestACK=false); //!< send - virtual bool sendWithRetry(uint8_t toAddress, const void* buffer, uint8_t bufferSize, uint8_t retries=2, uint8_t retryWaitTime=40); //!< sendWithRetry (40ms roundtrip req for 61byte packets) - virtual bool receiveDone(); //!< receiveDone - bool ACKReceived(uint8_t fromNodeID); //!< ACKReceived - bool ACKRequested(); //!< ACKRequested - virtual void sendACK(const void* buffer = "", uint8_t bufferSize=0); //!< sendACK - uint32_t getFrequency(); //!< getFrequency - void setFrequency(uint32_t freqHz); //!< setFrequency - void encrypt(const char* key); //!< encrypt - void setCS(uint8_t newSPISlaveSelect); //!< setCS - int16_t readRSSI(bool forceTrigger=false); //!< readRSSI - void promiscuous(bool onOff=true); //!< promiscuous - virtual void setHighPower(bool onOFF=true); //!< setHighPower (have to call it after initialize for RFM69HW) - virtual void setPowerLevel(uint8_t level); //!< setPowerLevel (reduce/increase transmit power level) - void sleep(); //!< sleep - uint8_t readTemperature(uint8_t calFactor=0); //!< readTemperature (get CMOS temperature (8bit)) - void rcCalibration(); //!< rcCalibration (calibrate the internal RC oscillator for use in wide temperature variations - see datasheet section [4.3.5. RC Timer Accuracy]) + bool initialize(uint8_t freqBand, uint8_t ID, uint8_t networkID=1); //!< initialize + void setAddress(uint8_t addr); //!< setAddress + void setNetwork(uint8_t networkID); //!< setNetwork + bool canSend(); //!< canSend + virtual void send(uint8_t toAddress, const void* buffer, uint8_t bufferSize, + bool requestACK=false); //!< send + virtual bool sendWithRetry(uint8_t toAddress, const void* buffer, uint8_t bufferSize, + uint8_t retries=2, uint8_t retryWaitTime= + 40); //!< sendWithRetry (40ms roundtrip req for 61byte packets) + virtual bool receiveDone(); //!< receiveDone + bool ACKReceived(uint8_t fromNodeID); //!< ACKReceived + bool ACKRequested(); //!< ACKRequested + virtual void sendACK(const void* buffer = "", uint8_t bufferSize=0); //!< sendACK + uint32_t getFrequency(); //!< getFrequency + void setFrequency(uint32_t freqHz); //!< setFrequency + void encrypt(const char* key); //!< encrypt + void setCS(uint8_t newSPISlaveSelect); //!< setCS + int16_t readRSSI(bool forceTrigger=false); //!< readRSSI + void promiscuous(bool onOff=true); //!< promiscuous + virtual void setHighPower(bool onOFF= + true); //!< setHighPower (have to call it after initialize for RFM69HW) + virtual void setPowerLevel(uint8_t level); //!< setPowerLevel (reduce/increase transmit power level) + void sleep(); //!< sleep + uint8_t readTemperature(uint8_t calFactor=0); //!< readTemperature (get CMOS temperature (8bit)) + void rcCalibration(); //!< rcCalibration (calibrate the internal RC oscillator for use in wide temperature variations - see datasheet section [4.3.5. RC Timer Accuracy]) - // allow hacking registers by making these public - uint8_t readReg(uint8_t addr); //!< readReg - void writeReg(uint8_t addr, uint8_t val); //!< writeReg - void readAllRegs(); //!< readAllRegs + // allow hacking registers by making these public + uint8_t readReg(uint8_t addr); //!< readReg + void writeReg(uint8_t addr, uint8_t val); //!< writeReg + void readAllRegs(); //!< readAllRegs - protected: - static void isr0(); //!< isr0 - void virtual interruptHandler(); //!< interruptHandler - virtual void interruptHook(uint8_t CTLbyte); //!< interruptHook - virtual void sendFrame(uint8_t toAddress, const void* buffer, uint8_t size, bool requestACK=false, bool sendACK=false); //!< sendFrame +protected: + static void isr0(); //!< isr0 + void virtual interruptHandler(); //!< interruptHandler + virtual void interruptHook(uint8_t CTLbyte); //!< interruptHook + virtual void sendFrame(uint8_t toAddress, const void* buffer, uint8_t size, bool requestACK=false, + bool sendACK=false); //!< sendFrame - static RFM69* selfPointer; //!< selfPointer - uint8_t _slaveSelectPin; //!< _slaveSelectPin - uint8_t _interruptPin; //!< _interruptPin - uint8_t _interruptNum; //!< _interruptNum - uint8_t _address; //!< _address - bool _promiscuousMode; //!< _promiscuousMode - uint8_t _powerLevel; //!< _powerLevel - bool _isRFM69HW; //!< _isRFM69HW + static RFM69* selfPointer; //!< selfPointer + uint8_t _slaveSelectPin; //!< _slaveSelectPin + uint8_t _interruptPin; //!< _interruptPin + uint8_t _interruptNum; //!< _interruptNum + uint8_t _address; //!< _address + bool _promiscuousMode; //!< _promiscuousMode + uint8_t _powerLevel; //!< _powerLevel + bool _isRFM69HW; //!< _isRFM69HW #if defined (SPCR) && defined (SPSR) - uint8_t _SPCR; //!< _SPCR - uint8_t _SPSR; //!< _SPSR + uint8_t _SPCR; //!< _SPCR + uint8_t _SPSR; //!< _SPSR #endif - virtual void receiveBegin(); //!< receiveBegin - virtual void setMode(uint8_t mode); //!< setMode - virtual void setHighPowerRegs(bool onOff); //!< setHighPowerRegs - virtual void select(); //!< select - virtual void unselect(); //!< unselect + virtual void receiveBegin(); //!< receiveBegin + virtual void setMode(uint8_t mode); //!< setMode + virtual void setHighPowerRegs(bool onOff); //!< setHighPowerRegs + virtual void select(); //!< select + virtual void unselect(); //!< unselect }; #endif diff --git a/drivers/RFM69/RFM69registers.h b/drivers/RFM69/RFM69registers.h index 2d815ec90..cb3835925 100644 --- a/drivers/RFM69/RFM69registers.h +++ b/drivers/RFM69/RFM69registers.h @@ -6,25 +6,25 @@ // ********************************************************************************** // License // ********************************************************************************** -// This program is free software; you can redistribute it -// and/or modify it under the terms of the GNU General -// Public License as published by the Free Software -// Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program 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 General Public -// License for more details. -// -// You should have received a copy of the GNU General -// Public License along with this program; if not, write -// to the Free Software Foundation, Inc., +// This program is free software; you can redistribute it +// and/or modify it under the terms of the GNU General +// Public License as published by the Free Software +// Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program 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 General Public +// License for more details. +// +// You should have received a copy of the GNU General +// Public License along with this program; if not, write +// to the Free Software Foundation, Inc., // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// -// Licence can be viewed at -// http://www.fsf.org/licenses/gpl.txt +// +// Licence can be viewed at +// http://www.fsf.org/licenses/gpl.txt // // Please maintain this license information along with authorship // and copyright notices in any redistribution of this code diff --git a/drivers/RFM95/RFM95.cpp b/drivers/RFM95/RFM95.cpp index 37bcf5121..1ce477300 100644 --- a/drivers/RFM95/RFM95.cpp +++ b/drivers/RFM95/RFM95.cpp @@ -26,19 +26,24 @@ #if defined(LINUX_ARCH_RASPBERRYPI) uint8_t spi_rxbuff[32 + 1]; //SPI receive buffer (payload max 32 bytes, MYS protocol limitation) -uint8_t spi_txbuff[32 + 1]; //SPI transmit buffer (payload max 32 bytes + 1 byte for the command, MYS protocol limitation) +uint8_t spi_txbuff[32 + + 1]; //SPI transmit buffer (payload max 32 bytes + 1 byte for the command, MYS protocol limitation) #endif -LOCAL void RFM95_csn(const bool level) { +LOCAL void RFM95_csn(const bool level) +{ hwDigitalWrite(MY_RFM95_SPI_CS, level); } -LOCAL uint8_t RFM95_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_t len, const bool aReadMode) { +LOCAL uint8_t RFM95_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_t len, + const bool aReadMode) +{ uint8_t status; uint8_t* current = buf; - #if !defined(MY_SOFTSPI) - _SPI.beginTransaction(SPISettings(MY_RFM95_SPI_MAX_SPEED, MY_RFM95_SPI_DATA_ORDER, MY_RFM95_SPI_DATA_MODE)); - #endif +#if !defined(MY_SOFTSPI) + _SPI.beginTransaction(SPISettings(MY_RFM95_SPI_MAX_SPEED, MY_RFM95_SPI_DATA_ORDER, + MY_RFM95_SPI_DATA_MODE)); +#endif RFM95_csn(LOW); #if defined(LINUX_ARCH_RASPBERRYPI) uint8_t * prx = spi_rxbuff; @@ -49,8 +54,7 @@ LOCAL uint8_t RFM95_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_ while (len--) { if (aReadMode) { *ptx++ = RF24_NOP; - } - else { + } else { *ptx++ = *current++; } } @@ -58,16 +62,14 @@ LOCAL uint8_t RFM95_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_ if (aReadMode) { if (size == 2) { status = *++prx; // result is 2nd byte of receive buffer - } - else { + } else { status = *prx++; // status is 1st byte of receive buffer - // decrement before to skip status byte + // decrement before to skip status byte while (--size) { *buf++ = *prx++; } } - } - else { + } else { status = *prx; // status is 1st byte of receive buffer } #else @@ -78,24 +80,27 @@ LOCAL uint8_t RFM95_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_ if (buf != NULL) { *current++ = status; } + } else { + status = _SPI.transfer(*current++); } - else status = _SPI.transfer(*current++); } #endif RFM95_csn(HIGH); - #if !defined(MY_SOFTSPI) - _SPI.endTransaction(); - #endif +#if !defined(MY_SOFTSPI) + _SPI.endTransaction(); +#endif return status; } // low level register access -LOCAL uint8_t RFM95_RAW_readByteRegister(const uint8_t address) { +LOCAL uint8_t RFM95_RAW_readByteRegister(const uint8_t address) +{ return RFM95_spiMultiByteTransfer(address, NULL, 1, true); } // low level register access -LOCAL uint8_t RFM95_RAW_writeByteRegister(const uint8_t address, uint8_t value) { +LOCAL uint8_t RFM95_RAW_writeByteRegister(const uint8_t address, uint8_t value) +{ return RFM95_spiMultiByteTransfer(address, &value, 1, false); } @@ -109,24 +114,25 @@ LOCAL uint8_t RFM95_RAW_writeByteRegister(const uint8_t address, uint8_t value) // check RegPktRssiValue (0x1A) vs. RegRssiValue (0x1B) -LOCAL bool RFM95_initialise(const float frequency) { +LOCAL bool RFM95_initialise(const float frequency) +{ RFM95_DEBUG(PSTR("RFM95:INIT\n")); // reset radio module if rst pin defined - #if defined(MY_RFM95_RST_PIN) - hwPinMode(MY_RFM95_RST_PIN, OUTPUT); - hwDigitalWrite(MY_RFM95_RST_PIN, HIGH); - // 100uS - delayMicroseconds(100); - hwDigitalWrite(MY_RFM95_RST_PIN, LOW); - // wait until chip ready - delay(5); - #endif +#if defined(MY_RFM95_RST_PIN) + hwPinMode(MY_RFM95_RST_PIN, OUTPUT); + hwDigitalWrite(MY_RFM95_RST_PIN, HIGH); + // 100uS + delayMicroseconds(100); + hwDigitalWrite(MY_RFM95_RST_PIN, LOW); + // wait until chip ready + delay(5); +#endif // set variables RFM95.address = RFM95_BROADCAST_ADDRESS; RFM95.rxBufferValid = false; RFM95.txSequenceNumber = 0; // initialise TX sequence counter - RFM95.powerLevel = 0; + RFM95.powerLevel = 0; RFM95.ATCenabled = false; RFM95.ATCtargetRSSI = RFM95_TARGET_RSSI + RFM95_RSSI_OFFSET; @@ -158,23 +164,24 @@ LOCAL bool RFM95_initialise(const float frequency) { // IRQ hwPinMode(MY_RFM95_IRQ_PIN, INPUT); - #if defined (SPI_HAS_TRANSACTION) && !defined (ESP8266) - _SPI.usingInterrupt(digitalPinToInterrupt(MY_RFM95_IRQ_PIN)); - #endif +#if defined (SPI_HAS_TRANSACTION) && !defined (ESP8266) + _SPI.usingInterrupt(digitalPinToInterrupt(MY_RFM95_IRQ_PIN)); +#endif attachInterrupt(digitalPinToInterrupt(MY_RFM95_IRQ_PIN), RFM95_interruptHandler, RISING); return true; } // RxDone, TxDone, CADDone is mapped to DI0 -LOCAL void RFM95_interruptHandler(void) { +LOCAL void RFM95_interruptHandler(void) +{ // Read the interrupt register - const uint8_t irqFlags = RFM95_readReg(RFM95_REG_12_IRQ_FLAGS); - if (RFM95.radioMode == RFM95_RADIO_MODE_RX && (irqFlags & (RFM95_RX_TIMEOUT | RFM95_PAYLOAD_CRC_ERROR)) ) { + const uint8_t irqFlags = RFM95_readReg(RFM95_REG_12_IRQ_FLAGS); + if (RFM95.radioMode == RFM95_RADIO_MODE_RX && + (irqFlags & (RFM95_RX_TIMEOUT | RFM95_PAYLOAD_CRC_ERROR)) ) { // CRC error or timeout // RXcontinuous mode: radio stays in RX mode, clearing IRQ needed - } - else if (RFM95.radioMode == RFM95_RADIO_MODE_RX && (irqFlags & RFM95_RX_DONE)) { + } else if (RFM95.radioMode == RFM95_RADIO_MODE_RX && (irqFlags & RFM95_RX_DONE)) { // set radio to STDBY (we are in RXcontinuous mode) (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); // Have received a packet @@ -188,44 +195,46 @@ LOCAL void RFM95_interruptHandler(void) { RFM95.currentPacket.SNR = static_cast(RFM95_readReg(RFM95_REG_19_PKT_SNR_VALUE)); RFM95.currentPacket.payloadLen = bufLen - RFM95_HEADER_LEN; // Message for us - if ((RFM95.currentPacket.header.version >= RFM95_MIN_PACKET_HEADER_VERSION) && - (RFM95_PROMISCUOUS || RFM95.currentPacket.header.recipient == RFM95.address || RFM95.currentPacket.header.recipient == RFM95_BROADCAST_ADDRESS)) { + if ((RFM95.currentPacket.header.version >= RFM95_MIN_PACKET_HEADER_VERSION) && + (RFM95_PROMISCUOUS || RFM95.currentPacket.header.recipient == RFM95.address || + RFM95.currentPacket.header.recipient == RFM95_BROADCAST_ADDRESS)) { RFM95.rxBufferValid = true; } } - - } - else if (RFM95.radioMode == RFM95_RADIO_MODE_TX && (irqFlags & RFM95_TX_DONE) ) { + + } else if (RFM95.radioMode == RFM95_RADIO_MODE_TX && (irqFlags & RFM95_TX_DONE) ) { (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); - } - else if (RFM95.radioMode == RFM95_RADIO_MODE_CAD && (irqFlags & RFM95_CAD_DONE) ) { + } else if (RFM95.radioMode == RFM95_RADIO_MODE_CAD && (irqFlags & RFM95_CAD_DONE) ) { RFM95.cad = irqFlags & RFM95_CAD_DETECTED; (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); - } + } // Clear all IRQ flags RFM95_writeReg(RFM95_REG_12_IRQ_FLAGS, 0xFF); } -LOCAL bool RFM95_available(void) { +LOCAL bool RFM95_available(void) +{ if (RFM95.radioMode == RFM95_RADIO_MODE_TX) { return false; } (void)RFM95_setRadioMode(RFM95_RADIO_MODE_RX); - return RFM95.rxBufferValid; + return RFM95.rxBufferValid; } -LOCAL void RFM95_clearRxBuffer(void) { +LOCAL void RFM95_clearRxBuffer(void) +{ noInterrupts(); RFM95.rxBufferValid = false; interrupts(); } -LOCAL uint8_t RFM95_recv(uint8_t* buf) { +LOCAL uint8_t RFM95_recv(uint8_t* buf) +{ if (!RFM95_available()) { return false; } - + // atomic noInterrupts(); const uint8_t payloadLen = RFM95.currentPacket.payloadLen; @@ -234,10 +243,10 @@ LOCAL uint8_t RFM95_recv(uint8_t* buf) { const uint8_t controlFlags = RFM95.currentPacket.header.controlFlags; const rfm95_RSSI_t RSSI = RFM95.currentPacket.RSSI; // of incoming packet const rfm95_SNR_t SNR = RFM95.currentPacket.SNR; - if (buf != NULL) { + if (buf != NULL) { memcpy((void*)buf, (void*)RFM95.currentPacket.payload, payloadLen); RFM95.rxBufferValid = false; - } + } interrupts(); // ACK handling @@ -249,29 +258,32 @@ LOCAL uint8_t RFM95_recv(uint8_t* buf) { return payloadLen; } -LOCAL bool RFM95_send(rfm95_packet_t &packet) { +LOCAL bool RFM95_send(rfm95_packet_t &packet) +{ const uint8_t finalLen = packet.payloadLen + RFM95_HEADER_LEN; // Make sure we dont interrupt an outgoing message RFM95_waitPacketSent(); (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); - + // Check channel activity if (!RFM95_waitCAD()) { - return false; + return false; } - packet.header.sequenceNumber = RFM95.txSequenceNumber++; - // Position at the beginning of the TX FIFO + packet.header.sequenceNumber = RFM95.txSequenceNumber++; + // Position at the beginning of the TX FIFO RFM95_writeReg(RFM95_REG_0D_FIFO_ADDR_PTR, RFM95_TX_FIFO_ADDR); - // write packet + // write packet RFM95_burstWriteReg(RFM95_REG_00_FIFO, packet.data, finalLen); - // total payload length + // total payload length RFM95_writeReg(RFM95_REG_22_PAYLOAD_LENGTH, finalLen); // send message, if sent, irq fires and radio returns to standby (void)RFM95_setRadioMode(RFM95_RADIO_MODE_TX); return true; } -LOCAL bool RFM95_sendFrame(const uint8_t recipient, uint8_t* data, const uint8_t len, const rfm95_flag_t flags) { +LOCAL bool RFM95_sendFrame(const uint8_t recipient, uint8_t* data, const uint8_t len, + const rfm95_flag_t flags) +{ rfm95_packet_t packet; packet.header.version = RFM95_PACKET_HEADER_VERSION; packet.header.sender = RFM95.address; @@ -283,14 +295,16 @@ LOCAL bool RFM95_sendFrame(const uint8_t recipient, uint8_t* data, const uint8_t return RFM95_send(packet); } -LOCAL void RFM95_setFrequency(const float centre) { - const uint32_t freq = (centre * 1000000.0) / RFM95_FSTEP; +LOCAL void RFM95_setFrequency(const float centre) +{ + const uint32_t freq = (centre * 1000000.0) / RFM95_FSTEP; RFM95_writeReg(RFM95_REG_06_FRF_MSB, (freq >> 16) & 0xff); RFM95_writeReg(RFM95_REG_07_FRF_MID, (freq >> 8) & 0xff); RFM95_writeReg(RFM95_REG_08_FRF_LSB, freq & 0xff); } -LOCAL bool RFM95_setTxPower(uint8_t powerLevel) { +LOCAL bool RFM95_setTxPower(uint8_t powerLevel) +{ // RFM95/96/97/98 does not have RFO pins connected to anything. Only PA_BOOST powerLevel = max((uint8_t)RFM95_MIN_POWER_LEVEL_DBM, powerLevel); powerLevel = min((uint8_t)RFM95_MAX_POWER_LEVEL_DBM, powerLevel); @@ -304,8 +318,7 @@ LOCAL bool RFM95_setTxPower(uint8_t powerLevel) { // My measurements show 20dBm is correct RFM95_writeReg(RFM95_REG_4D_PA_DAC, RFM95_PA_DAC_ENABLE); val = powerLevel - 8; - } - else { + } else { RFM95_writeReg(RFM95_REG_4D_PA_DAC, RFM95_PA_DAC_DISABLE); val = powerLevel - 5; } @@ -318,27 +331,32 @@ LOCAL bool RFM95_setTxPower(uint8_t powerLevel) { } // Sets registers from a canned modem configuration structure -LOCAL void RFM95_setModemRegisters(const rfm95_modemConfig_t config) { +LOCAL void RFM95_setModemRegisters(const rfm95_modemConfig_t config) +{ RFM95_writeReg(RFM95_REG_1D_MODEM_CONFIG1, config.reg_1d); RFM95_writeReg(RFM95_REG_1E_MODEM_CONFIG2, config.reg_1e); RFM95_writeReg(RFM95_REG_26_MODEM_CONFIG3, config.reg_26); } -LOCAL void RFM95_setPreambleLength(const uint16_t preambleLength) { +LOCAL void RFM95_setPreambleLength(const uint16_t preambleLength) +{ RFM95_writeReg(RFM95_REG_20_PREAMBLE_MSB, preambleLength >> 8); RFM95_writeReg(RFM95_REG_21_PREAMBLE_LSB, preambleLength & 0xff); } -LOCAL void RFM95_setAddress(const uint8_t addr) { +LOCAL void RFM95_setAddress(const uint8_t addr) +{ RFM95.address = addr; } -LOCAL uint8_t RFM95_getAddress(void) { +LOCAL uint8_t RFM95_getAddress(void) +{ return RFM95.address; } -LOCAL bool RFM95_isChannelActive(void) { +LOCAL bool RFM95_isChannelActive(void) +{ (void)RFM95_setRadioMode(RFM95_RADIO_MODE_CAD); while (RFM95.radioMode == RFM95_RADIO_MODE_CAD) { doYield(); @@ -347,7 +365,8 @@ LOCAL bool RFM95_isChannelActive(void) { return RFM95.cad; } -LOCAL bool RFM95_setRadioMode(const rfm95_radioMode_t newRadioMode) { +LOCAL bool RFM95_setRadioMode(const rfm95_radioMode_t newRadioMode) +{ if (RFM95.radioMode == newRadioMode) { return false; } @@ -355,35 +374,35 @@ LOCAL bool RFM95_setRadioMode(const rfm95_radioMode_t newRadioMode) { if (newRadioMode == RFM95_RADIO_MODE_STDBY) { regMode = RFM95_MODE_STDBY; - } - else if (newRadioMode == RFM95_RADIO_MODE_SLEEP) { + } else if (newRadioMode == RFM95_RADIO_MODE_SLEEP) { regMode = RFM95_MODE_SLEEP; - } - else if (newRadioMode == RFM95_RADIO_MODE_CAD) { + } else if (newRadioMode == RFM95_RADIO_MODE_CAD) { regMode = RFM95_MODE_CAD; RFM95_writeReg(RFM95_REG_40_DIO_MAPPING1, 0x80); // Interrupt on CadDone, DIO0 - } - else if (newRadioMode == RFM95_RADIO_MODE_RX) { + } else if (newRadioMode == RFM95_RADIO_MODE_RX) { regMode = RFM95_MODE_RXCONTINUOUS; RFM95_writeReg(RFM95_REG_40_DIO_MAPPING1, 0x00); // Interrupt on RxDone, DIO0 - } - else if (newRadioMode == RFM95_RADIO_MODE_TX) { + } else if (newRadioMode == RFM95_RADIO_MODE_TX) { regMode = RFM95_MODE_TX; RFM95_writeReg(RFM95_REG_40_DIO_MAPPING1, 0x40); // Interrupt on TxDone, DIO0 + } else { + return false; } - else return false; RFM95_writeReg(RFM95_REG_01_OP_MODE, regMode); RFM95.radioMode = newRadioMode; return true; } -LOCAL bool RFM95_sleep(void) { +LOCAL bool RFM95_sleep(void) +{ return RFM95_setRadioMode(RFM95_RADIO_MODE_SLEEP); } // should be called immediately after reception in case sender wants ACK -LOCAL void RFM95_sendACK(const uint8_t recipient, const rfm95_sequenceNumber_t sequenceNumber, const rfm95_RSSI_t RSSI, const rfm95_RSSI_t SNR) { +LOCAL void RFM95_sendACK(const uint8_t recipient, const rfm95_sequenceNumber_t sequenceNumber, + const rfm95_RSSI_t RSSI, const rfm95_RSSI_t SNR) +{ RFM95_DEBUG(PSTR("RFM95:SAC:SEND ACK to=%d,RSSI=%d\n"),recipient,RSSI); rfm95_ack_t ACK; ACK.sequenceNumber = sequenceNumber; @@ -395,25 +414,26 @@ LOCAL void RFM95_sendACK(const uint8_t recipient, const rfm95_sequenceNumber_t s (void)RFM95_sendFrame(recipient, (uint8_t*)&ACK, sizeof(rfm95_ack_t), flags); } -LOCAL bool RFM95_executeATC(const rfm95_RSSI_t currentRSSI, const rfm95_RSSI_t targetRSSI) { +LOCAL bool RFM95_executeATC(const rfm95_RSSI_t currentRSSI, const rfm95_RSSI_t targetRSSI) +{ // allow +-5% if (currentRSSI < (targetRSSI*1.05) && RFM95.powerLevel < RFM95_MAX_POWER_LEVEL_DBM) { // increase transmitter power RFM95.powerLevel++; - } - else if (currentRSSI > (targetRSSI*0.95) && RFM95.powerLevel > RFM95_MIN_POWER_LEVEL_DBM) { + } else if (currentRSSI > (targetRSSI*0.95) && RFM95.powerLevel > RFM95_MIN_POWER_LEVEL_DBM) { // decrease transmitter power RFM95.powerLevel--; - } - else { + } else { // nothing to adjust return false; } - RFM95_DEBUG(PSTR("RFM95:ATC:ADJ TXL,cR=%d,tR=%d,TXL=%d\n"), currentRSSI - RFM95_RSSI_OFFSET, targetRSSI - RFM95_RSSI_OFFSET, RFM95.powerLevel); + RFM95_DEBUG(PSTR("RFM95:ATC:ADJ TXL,cR=%d,tR=%d,TXL=%d\n"), currentRSSI - RFM95_RSSI_OFFSET, + targetRSSI - RFM95_RSSI_OFFSET, RFM95.powerLevel); return RFM95_setTxPower(RFM95.powerLevel);; } -LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, const uint8_t bufferSize, const uint8_t retries, const uint32_t retryWaitTime) +LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, + const uint8_t bufferSize, const uint8_t retries, const uint32_t retryWaitTime) { for (uint8_t retry = 0; retry < retries; retry++) { RFM95_DEBUG(PSTR("RFM95:SWR:SEND TO=%d,RETRY=%d\n"), recipient, retry); @@ -431,10 +451,12 @@ LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, cons const uint8_t sender = RFM95.currentPacket.header.sender; const rfm95_sequenceNumber_t ACKsequenceNumber = RFM95.currentPacket.ACK.sequenceNumber; const rfm95_flag_t flag = RFM95.currentPacket.header.controlFlags; - if (sender == recipient && RFM95_getACKReceived(flag) && (ACKsequenceNumber == RFM95.txSequenceNumber - 1)) { - RFM95_DEBUG(PSTR("RFM95:SWR:ACK FROM=%d,SEQ=%d,RSSI=%d,SNR=%d\n"),sender,ACKsequenceNumber, RFM95.currentPacket.ACK.RSSI-RFM95_RSSI_OFFSET, (int8_t)RFM95.currentPacket.ACK.SNR / 4); + if (sender == recipient && RFM95_getACKReceived(flag) && + (ACKsequenceNumber == RFM95.txSequenceNumber - 1)) { + RFM95_DEBUG(PSTR("RFM95:SWR:ACK FROM=%d,SEQ=%d,RSSI=%d,SNR=%d\n"),sender,ACKsequenceNumber, + RFM95.currentPacket.ACK.RSSI-RFM95_RSSI_OFFSET, (int8_t)RFM95.currentPacket.ACK.SNR / 4); RFM95_clearRxBuffer(); - + // ATC if (RFM95.ATCenabled && RFM95_getACKRSSIReport(flag)) { (void)RFM95_executeATC(RFM95.currentPacket.ACK.RSSI, RFM95.ATCtargetRSSI); @@ -455,7 +477,8 @@ LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, cons // Wait until no channel activity detected or timeout -LOCAL bool RFM95_waitCAD(void) { +LOCAL bool RFM95_waitCAD(void) +{ const uint32_t enterMS = hwMillis(); while (RFM95_isChannelActive()) { if (hwMillis() - enterMS > RFM95_CAD_TIMEOUT_MS) { @@ -467,23 +490,27 @@ LOCAL bool RFM95_waitCAD(void) { } // Wait for any previous transmission to finish -LOCAL bool RFM95_waitPacketSent(void) { +LOCAL bool RFM95_waitPacketSent(void) +{ while (RFM95.radioMode == RFM95_RADIO_MODE_TX) { doYield(); } return true; } -LOCAL int16_t RFM95_getRSSI(void) { +LOCAL int16_t RFM95_getRSSI(void) +{ return (int16_t)(RFM95.currentPacket.RSSI - RFM95_RSSI_OFFSET); } -LOCAL void RFM95_ATCmode(const bool OnOff, const int16_t targetRSSI) { +LOCAL void RFM95_ATCmode(const bool OnOff, const int16_t targetRSSI) +{ RFM95.ATCenabled = OnOff; RFM95.ATCtargetRSSI = (uint8_t)(targetRSSI + RFM95_RSSI_OFFSET); } -LOCAL bool RFM95_sanityCheck(void) { +LOCAL bool RFM95_sanityCheck(void) +{ // not implemented yet return true; } diff --git a/drivers/RFM95/RFM95.h b/drivers/RFM95/RFM95.h index 963fcf76a..0a35f293c 100644 --- a/drivers/RFM95/RFM95.h +++ b/drivers/RFM95/RFM95.h @@ -23,73 +23,73 @@ * Changelog: * - ACK with sequenceNumber * - ATC control - * + * * Definitions for HopeRF LoRa radios: * http://www.hoperf.com/upload/rf/RFM95_96_97_98W.pdf * http://www.hoperf.cn/upload/rfchip/RF96_97_98.pdf * */ - /** - * @file RFM95.h - * - * @defgroup RFM95grp RFM95 - * @ingroup internals - * @{ - * - * RFM95 driver-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE - * - [!] Exclamation mark is prepended in case of error - * - * This section is WIP! - * - * |E| SYS | SUB | Message | Comment - * |-|-------|----------|-----------------------------------|--------------------------------------------------------------------- - * | | RFM95 | INIT | | Initialise RFM95 radio - * | | RFM95 | RCV | SEND ACK | ACK request received, sending ACK back - * | | RFM95 | PTC | LEVEL=%d | Set TX power level - * | | RFM95 | SAC | SEND ACK TO=%d,RSSI=%d | Send ACK to node (TO), RSSI of received message (RSSI) - * | | RFM95 | ATC | ADJ TXL,cR=%d,tR=%d,TXL=%d | Adjust TX level, current RSSI (cR), target RSSI (tR), TX level (TXL) - * | | RFM95 | SWR | SEND TO=%d,RETRY=%d | Send message to (TO), NACK retry counter (RETRY) - * | | RFM95 | SWR | ACK FROM=%d,SEQ=%d,RSSI=%d,SNR=%d | ACK received from node (FROM), seq ID (SEQ), (RSSI), (SNR) - * |!| RFM95 | SWR | NACK | No ACK received - - * - * - * RFM95 modem configuration - * - * BW = Bandwidth in kHz - * CR = Error correction code - * SF = Spreading factor, chips / symbol - * - * | CONFIG | REG_1D | REG_1E | REG_26 | BW | CR | SF | Comment - * |------------------|--------|--------|--------|-------|-----|------|----------------------------- - * | BW125CR45SF128 | 0x72 | 0x74 | 0x04 | 125 | 4/5 | 128 | Default, medium range - * | BW500CR45SF128 | 0x92 | 0x74 | 0x04 | 500 | 4/5 | 128 | Fast, short range - * | BW31_25CR48SF512 | 0x48 | 0x94 | 0x04 | 31.25 | 4/8 | 512 | Slow, long range - * | BW125CR48SF4096 | 0x78 | 0xC4 | 0x0C | 125 | 4/8 | 4096 | Slow, long range - * - * @brief API declaration for RFM95 - * - */ +/** +* @file RFM95.h +* +* @defgroup RFM95grp RFM95 +* @ingroup internals +* @{ +* +* RFM95 driver-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE +* - [!] Exclamation mark is prepended in case of error +* +* This section is WIP! +* +* |E| SYS | SUB | Message | Comment +* |-|-------|----------|-----------------------------------|--------------------------------------------------------------------- +* | | RFM95 | INIT | | Initialise RFM95 radio +* | | RFM95 | RCV | SEND ACK | ACK request received, sending ACK back +* | | RFM95 | PTC | LEVEL=%d | Set TX power level +* | | RFM95 | SAC | SEND ACK TO=%d,RSSI=%d | Send ACK to node (TO), RSSI of received message (RSSI) +* | | RFM95 | ATC | ADJ TXL,cR=%d,tR=%d,TXL=%d | Adjust TX level, current RSSI (cR), target RSSI (tR), TX level (TXL) +* | | RFM95 | SWR | SEND TO=%d,RETRY=%d | Send message to (TO), NACK retry counter (RETRY) +* | | RFM95 | SWR | ACK FROM=%d,SEQ=%d,RSSI=%d,SNR=%d | ACK received from node (FROM), seq ID (SEQ), (RSSI), (SNR) +* |!| RFM95 | SWR | NACK | No ACK received + +* +* +* RFM95 modem configuration +* +* BW = Bandwidth in kHz +* CR = Error correction code +* SF = Spreading factor, chips / symbol +* +* | CONFIG | REG_1D | REG_1E | REG_26 | BW | CR | SF | Comment +* |------------------|--------|--------|--------|-------|-----|------|----------------------------- +* | BW125CR45SF128 | 0x72 | 0x74 | 0x04 | 125 | 4/5 | 128 | Default, medium range +* | BW500CR45SF128 | 0x92 | 0x74 | 0x04 | 500 | 4/5 | 128 | Fast, short range +* | BW31_25CR48SF512 | 0x48 | 0x94 | 0x04 | 31.25 | 4/8 | 512 | Slow, long range +* | BW125CR48SF4096 | 0x78 | 0xC4 | 0x0C | 125 | 4/8 | 4096 | Slow, long range +* +* @brief API declaration for RFM95 +* +*/ #ifndef _RFM95_h #define _RFM95_h #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) || defined(__AVR_ATmega88) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega88__) - #define RFM95_IRQ_PIN (2) - #define RFM95_RST_PIN (9) +#define RFM95_IRQ_PIN (2) +#define RFM95_RST_PIN (9) #elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) - #define RFM95_IRQ_PIN (2) - #define RFM95_RST_PIN (9) +#define RFM95_IRQ_PIN (2) +#define RFM95_RST_PIN (9) #elif defined(__AVR_ATmega32U4__) - #define RFM95_IRQ_PIN (3) - #define RFM95_RST_PIN (9) +#define RFM95_IRQ_PIN (3) +#define RFM95_RST_PIN (9) #elif defined(__arm__) - #define RFM95_IRQ_PIN (10) - #define RFM95_RST_PIN (27) -#else - #define RFM95_IRQ_PIN (2) //!< RFM95_IRQ_PIN - #define RFM95_RST_PIN (9) //!< RFM95_IRQ_PIN +#define RFM95_IRQ_PIN (10) +#define RFM95_RST_PIN (27) +#else +#define RFM95_IRQ_PIN (2) //!< RFM95_IRQ_PIN +#define RFM95_RST_PIN (9) //!< RFM95_IRQ_PIN #endif // SPI settings @@ -97,36 +97,37 @@ #if !defined(MY_RFM95_SPI_MAX_SPEED) - #define MY_RFM95_SPI_MAX_SPEED 4000000 //!< SPI speed +#define MY_RFM95_SPI_MAX_SPEED 4000000 //!< SPI speed #endif #define MY_RFM95_SPI_DATA_ORDER MSBFIRST //!< SPI data order #define MY_RFM95_SPI_DATA_MODE SPI_MODE0 //!< SPI mode #if defined (ARDUINO) && !defined (__arm__) && !defined (_SPI) - #include - #if defined(MY_SOFTSPI) - SoftSPI _SPI; - #else - #define _SPI SPI - #endif +#include +#if defined(MY_SOFTSPI) +SoftSPI +_SPI; +#else +#define _SPI SPI +#endif +#else +#if defined(__arm__) +#include #else - #if defined(__arm__) - #include - #else - extern HardwareSPI SPI; //!< SPI - #endif - - #if !defined(_SPI) - #define _SPI SPI //!< SPI - #endif +extern HardwareSPI SPI; //!< SPI +#endif + +#if !defined(_SPI) +#define _SPI SPI //!< SPI +#endif #endif -// debug +// debug #if defined(MY_DEBUG_VERBOSE_RFM95) - #define RFM95_DEBUG(x,...) debug(x, ##__VA_ARGS__) //!< Debug print +#define RFM95_DEBUG(x,...) debug(x, ##__VA_ARGS__) //!< Debug print #else - #define RFM95_DEBUG(x,...) //!< Debug null +#define RFM95_DEBUG(x,...) //!< Debug null #endif #define RFM95_FIFO_SIZE (0xFFu) //!< Max number of bytes the LORA Rx/Tx FIFO can hold @@ -247,7 +248,7 @@ typedef struct { uint8_t payloadLen; //!< Length of payload (excluding header) rfm95_RSSI_t RSSI; //!< RSSI of current packet, RSSI = value - 137 rfm95_SNR_t SNR; //!< SNR of current packet -} __attribute__((packed)) rfm95_packet_t; +} __attribute__((packed)) rfm95_packet_t; /** @@ -316,7 +317,8 @@ LOCAL bool RFM95_send(rfm95_packet_t &packet); * @param flags * @return True if frame sent */ -LOCAL bool RFM95_sendFrame(const uint8_t recipient, uint8_t* data, const uint8_t len, const rfm95_flag_t flags); +LOCAL bool RFM95_sendFrame(const uint8_t recipient, uint8_t* data, const uint8_t len, + const rfm95_flag_t flags); /** * @brief RFM95_setPreambleLength * @param preambleLength @@ -350,7 +352,8 @@ LOCAL bool RFM95_isChannelActive(void); * @param RSSI (rfm95_RSSI_t) * @param SNR (rfm95_RSSI_t) */ -LOCAL void RFM95_sendACK(const uint8_t recipient, const rfm95_sequenceNumber_t sequenceNumber, const rfm95_RSSI_t RSSI, const rfm95_RSSI_t SNR); +LOCAL void RFM95_sendACK(const uint8_t recipient, const rfm95_sequenceNumber_t sequenceNumber, + const rfm95_RSSI_t RSSI, const rfm95_RSSI_t SNR); /** * @brief RFM95_sendWithRetry * @param recipient @@ -360,7 +363,9 @@ LOCAL void RFM95_sendACK(const uint8_t recipient, const rfm95_sequenceNumber_t s * @param retryWaitTime * @return True if packet successfully sent */ -LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, const uint8_t bufferSize, const uint8_t retries = RFM95_RETRIES, const uint32_t retryWaitTime = RFM95_RETRY_TIMEOUT_MS); +LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, + const uint8_t bufferSize, const uint8_t retries = RFM95_RETRIES, + const uint32_t retryWaitTime = RFM95_RETRY_TIMEOUT_MS); /** * @brief RFM95_waitCAD * @return True if no channel activity detected @@ -476,7 +481,7 @@ volatile rfm95_internal_t RFM95; //!< internal variables #define RFM95_MODE_RXSINGLE 0x06 //!< MODE_RXSINGLE #define RFM95_MODE_CAD 0x07 //!< MODE_CAD -// RFM95_REG_09_PA_CONFIG 0x09 +// RFM95_REG_09_PA_CONFIG 0x09 #define RFM95_OUTPUT_POWER 0x0F //!< OUTPUT_POWER #define RFM95_MAX_POWER 0x70 //!< MAX_POWER #define RFM95_PA_SELECT 0x80 //!< PA_SELECT diff --git a/drivers/RPi/SPI.cpp b/drivers/RPi/SPI.cpp index 9ec58572b..1b8684e64 100644 --- a/drivers/RPi/SPI.cpp +++ b/drivers/RPi/SPI.cpp @@ -31,11 +31,13 @@ SPIClass SPI = SPIClass(); uint8_t SPIClass::initialized = 0; -uint8_t SPIClass::is_initialized() { +uint8_t SPIClass::is_initialized() +{ return initialized; } -void SPIClass::begin() { +void SPIClass::begin() +{ if (!initialized) { if (!bcm2835_spi_begin()) { logError("You need root privilege to use SPI.\n"); @@ -46,7 +48,8 @@ void SPIClass::begin() { initialized++; // reference count } -void SPIClass::end() { +void SPIClass::end() +{ if (initialized) { initialized--; } @@ -57,47 +60,53 @@ void SPIClass::end() { } } -void SPIClass::setBitOrder(uint8_t bit_order) { +void SPIClass::setBitOrder(uint8_t bit_order) +{ bcm2835_spi_setBitOrder(bit_order); } -void SPIClass::setDataMode(uint8_t data_mode) { +void SPIClass::setDataMode(uint8_t data_mode) +{ bcm2835_spi_setDataMode(data_mode); } -void SPIClass::setClockDivider(uint16_t divider) { +void SPIClass::setClockDivider(uint16_t divider) +{ bcm2835_spi_setClockDivider(divider); } -void SPIClass::chipSelect(int csn_pin) { +void SPIClass::chipSelect(int csn_pin) +{ if (csn_pin == RPI_GPIO_P1_26) { csn_pin = BCM2835_SPI_CS1; - } - else if (csn_pin == RPI_GPIO_P1_24) { + } else if (csn_pin == RPI_GPIO_P1_24) { csn_pin = BCM2835_SPI_CS0; - } - else { + } else { csn_pin = BCM2835_SPI_CS0; } bcm2835_spi_chipSelect(csn_pin); delayMicroseconds(5); } -void SPIClass::beginTransaction(SPISettings settings) { +void SPIClass::beginTransaction(SPISettings settings) +{ pthread_mutex_lock(&spiMutex); setBitOrder(settings.border); setDataMode(settings.dmode); setClockDivider(settings.cdiv); } -void SPIClass::endTransaction() { +void SPIClass::endTransaction() +{ pthread_mutex_unlock(&spiMutex); } -void SPIClass::usingInterrupt(uint8_t interruptNumber) { +void SPIClass::usingInterrupt(uint8_t interruptNumber) +{ (void)interruptNumber; } -void SPIClass::notUsingInterrupt(uint8_t interruptNumber) { +void SPIClass::notUsingInterrupt(uint8_t interruptNumber) +{ (void)interruptNumber; } diff --git a/drivers/RPi/SPI.h b/drivers/RPi/SPI.h index d83a5405a..7aba9c395 100644 --- a/drivers/RPi/SPI.h +++ b/drivers/RPi/SPI.h @@ -45,7 +45,8 @@ /** * SPISettings class */ -class SPISettings { +class SPISettings +{ public: /** @@ -53,7 +54,8 @@ class SPISettings { * * Default clock speed is 8Mhz. */ - SPISettings() { + SPISettings() + { init(BCM2835_SPI_CLOCK_DIVIDER_32, BCM2835_SPI_BIT_ORDER_MSBFIRST, BCM2835_SPI_MODE0); } /** @@ -63,31 +65,32 @@ class SPISettings { * @param bitOrder SPI bit order. * @param dataMode SPI data mode. */ - SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) { + SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode) + { 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; + 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; } init(divider, bitOrder, dataMode); @@ -105,7 +108,8 @@ class SPISettings { * @param bitOrder SPI bit order. * @param dataMode SPI data mode. */ - void init(uint16_t divider, uint8_t bitOrder, uint8_t dataMode) { + void init(uint16_t divider, uint8_t bitOrder, uint8_t dataMode) + { cdiv = divider; border = bitOrder; dmode = dataMode; @@ -117,7 +121,8 @@ class SPISettings { /** * SPIClass class */ -class SPIClass { +class SPIClass +{ private: static uint8_t initialized; //!< @brief SPI initialized flag. @@ -150,7 +155,7 @@ class SPIClass { * @param buf Buffer to read from and write to. * @param len Buffer length. */ - inline static void transfern(char* buf, uint32_t len); + inline static void transfern(char* buf, uint32_t len); /** * @brief Start SPI operations. */ @@ -207,15 +212,18 @@ class SPIClass { static void notUsingInterrupt(uint8_t interruptNumber); }; -uint8_t SPIClass::transfer(uint8_t data) { +uint8_t SPIClass::transfer(uint8_t data) +{ return bcm2835_spi_transfer(data); } -void SPIClass::transfernb(char* tbuf, char* rbuf, uint32_t len) { +void SPIClass::transfernb(char* tbuf, char* rbuf, uint32_t len) +{ bcm2835_spi_transfernb( tbuf, rbuf, len); } -void SPIClass::transfern(char* buf, uint32_t len) { +void SPIClass::transfern(char* buf, uint32_t len) +{ transfernb(buf, buf, len); } diff --git a/drivers/RPi/Wire.cpp b/drivers/RPi/Wire.cpp index 69ac5a330..eeb487f0b 100644 --- a/drivers/RPi/Wire.cpp +++ b/drivers/RPi/Wire.cpp @@ -150,7 +150,7 @@ size_t TwoWire::write(uint8_t data) // put byte in tx buffer txBuffer[txBufferIndex] = data; ++txBufferIndex; - // update amount in buffer + // update amount in buffer txBufferLength = txBufferIndex; return 1; diff --git a/drivers/RPi/Wire.h b/drivers/RPi/Wire.h index a82625b6c..57c799b37 100644 --- a/drivers/RPi/Wire.h +++ b/drivers/RPi/Wire.h @@ -31,7 +31,8 @@ #define BUFFER_LENGTH 32 -class TwoWire : public Stream { +class TwoWire : public Stream +{ private: static uint8_t rxBuffer[]; @@ -67,10 +68,22 @@ class TwoWire : public Stream { int peek(); void flush(); - inline size_t write(unsigned long n) { return write((uint8_t)n); } - inline size_t write(long n) { return write((uint8_t)n); } - inline size_t write(unsigned int n) { return write((uint8_t)n); } - inline size_t write(int n) { return write((uint8_t)n); } + inline size_t write(unsigned long n) + { + return write((uint8_t)n); + } + inline size_t write(long n) + { + return write((uint8_t)n); + } + inline size_t write(unsigned int n) + { + return write((uint8_t)n); + } + inline size_t write(int n) + { + return write((uint8_t)n); + } using Print::write; }; diff --git a/drivers/RPi/bcm2835.c b/drivers/RPi/bcm2835.c index 26aa8d644..275382609 100644 --- a/drivers/RPi/bcm2835.c +++ b/drivers/RPi/bcm2835.c @@ -44,7 +44,7 @@ uint32_t *bcm2835_peripherals_base = (uint32_t *)BCM2835_PERI_BASE; uint32_t bcm2835_peripherals_size = BCM2835_PERI_SIZE; -/* Virtual memory address of the mapped peripherals block +/* Virtual memory address of the mapped peripherals block */ uint32_t *bcm2835_peripherals = (uint32_t *)MAP_FAILED; @@ -77,36 +77,35 @@ static int i2c_byte_wait_us = 0; /* Function to return the pointers to the hardware register bases */ uint32_t* bcm2835_regbase(uint8_t regbase) { - switch (regbase) - { + switch (regbase) { case BCM2835_REGBASE_ST: - return (uint32_t *)bcm2835_st; + return (uint32_t *)bcm2835_st; case BCM2835_REGBASE_GPIO: - return (uint32_t *)bcm2835_gpio; + return (uint32_t *)bcm2835_gpio; case BCM2835_REGBASE_PWM: - return (uint32_t *)bcm2835_pwm; + return (uint32_t *)bcm2835_pwm; case BCM2835_REGBASE_CLK: - return (uint32_t *)bcm2835_clk; + return (uint32_t *)bcm2835_clk; case BCM2835_REGBASE_PADS: - return (uint32_t *)bcm2835_pads; + return (uint32_t *)bcm2835_pads; case BCM2835_REGBASE_SPI0: - return (uint32_t *)bcm2835_spi0; + return (uint32_t *)bcm2835_spi0; case BCM2835_REGBASE_BSC0: - return (uint32_t *)bcm2835_bsc0; + return (uint32_t *)bcm2835_bsc0; case BCM2835_REGBASE_BSC1: - return (uint32_t *)bcm2835_st; - } - return (uint32_t *)MAP_FAILED; + return (uint32_t *)bcm2835_st; + } + return (uint32_t *)MAP_FAILED; } void bcm2835_set_debug(uint8_t d) { - debug = d; + debug = d; } -unsigned int bcm2835_version(void) +unsigned int bcm2835_version(void) { - return BCM2835_VERSION; + return BCM2835_VERSION; } /* Read with memory barriers from peripheral @@ -114,19 +113,16 @@ unsigned int bcm2835_version(void) */ uint32_t bcm2835_peri_read(volatile uint32_t* paddr) { - uint32_t ret; - if (debug) - { - printf("bcm2835_peri_read paddr %08X\n", (unsigned) paddr); - return 0; - } - else - { - __sync_synchronize(); - ret = *paddr; - __sync_synchronize(); - return ret; - } + uint32_t ret; + if (debug) { + printf("bcm2835_peri_read paddr %08X\n", (unsigned) paddr); + return 0; + } else { + __sync_synchronize(); + ret = *paddr; + __sync_synchronize(); + return ret; + } } /* read from peripheral without the read barrier @@ -137,15 +133,12 @@ uint32_t bcm2835_peri_read(volatile uint32_t* paddr) */ uint32_t bcm2835_peri_read_nb(volatile uint32_t* paddr) { - if (debug) - { - printf("bcm2835_peri_read_nb paddr %08X\n", (unsigned) paddr); - return 0; - } - else - { - return *paddr; - } + if (debug) { + printf("bcm2835_peri_read_nb paddr %08X\n", (unsigned) paddr); + return 0; + } else { + return *paddr; + } } /* Write with memory barriers to peripheral @@ -153,30 +146,24 @@ uint32_t bcm2835_peri_read_nb(volatile uint32_t* paddr) void bcm2835_peri_write(volatile uint32_t* paddr, uint32_t value) { - if (debug) - { - printf("bcm2835_peri_write paddr %08X, value %08X\n", (unsigned) paddr, value); - } - else - { - __sync_synchronize(); - *paddr = value; - __sync_synchronize(); - } + if (debug) { + printf("bcm2835_peri_write paddr %08X, value %08X\n", (unsigned) paddr, value); + } else { + __sync_synchronize(); + *paddr = value; + __sync_synchronize(); + } } /* write to peripheral without the write barrier */ void bcm2835_peri_write_nb(volatile uint32_t* paddr, uint32_t value) { - if (debug) - { - printf("bcm2835_peri_write_nb paddr %08X, value %08X\n", - (unsigned) paddr, value); - } - else - { - *paddr = value; - } + if (debug) { + printf("bcm2835_peri_write_nb paddr %08X, value %08X\n", + (unsigned) paddr, value); + } else { + *paddr = value; + } } /* Set/clear only the bits in value covered by the mask @@ -184,9 +171,9 @@ void bcm2835_peri_write_nb(volatile uint32_t* paddr, uint32_t value) */ void bcm2835_peri_set_bits(volatile uint32_t* paddr, uint32_t value, uint32_t mask) { - uint32_t v = bcm2835_peri_read(paddr); - v = (v & ~mask) | (value & mask); - bcm2835_peri_write(paddr, v); + uint32_t v = bcm2835_peri_read(paddr); + v = (v & ~mask) | (value & mask); + bcm2835_peri_write(paddr, v); } /* @@ -213,51 +200,51 @@ void bcm2835_peri_set_bits(volatile uint32_t* paddr, uint32_t value, uint32_t ma */ void bcm2835_gpio_fsel(uint8_t pin, uint8_t mode) { - /* Function selects are 10 pins per 32 bit word, 3 bits per pin */ - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPFSEL0/4 + (pin/10); - uint8_t shift = (pin % 10) * 3; - uint32_t mask = BCM2835_GPIO_FSEL_MASK << shift; - uint32_t value = mode << shift; - bcm2835_peri_set_bits(paddr, value, mask); + /* Function selects are 10 pins per 32 bit word, 3 bits per pin */ + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPFSEL0/4 + (pin/10); + uint8_t shift = (pin % 10) * 3; + uint32_t mask = BCM2835_GPIO_FSEL_MASK << shift; + uint32_t value = mode << shift; + bcm2835_peri_set_bits(paddr, value, mask); } /* Set output pin */ void bcm2835_gpio_set(uint8_t pin) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPSET0/4 + pin/32; - uint8_t shift = pin % 32; - bcm2835_peri_write(paddr, 1 << shift); + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPSET0/4 + pin/32; + uint8_t shift = pin % 32; + bcm2835_peri_write(paddr, 1 << shift); } /* Clear output pin */ void bcm2835_gpio_clr(uint8_t pin) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPCLR0/4 + pin/32; - uint8_t shift = pin % 32; - bcm2835_peri_write(paddr, 1 << shift); + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPCLR0/4 + pin/32; + uint8_t shift = pin % 32; + bcm2835_peri_write(paddr, 1 << shift); } /* Set all output pins in the mask */ void bcm2835_gpio_set_multi(uint32_t mask) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPSET0/4; - bcm2835_peri_write(paddr, mask); + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPSET0/4; + bcm2835_peri_write(paddr, mask); } /* Clear all output pins in the mask */ void bcm2835_gpio_clr_multi(uint32_t mask) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPCLR0/4; - bcm2835_peri_write(paddr, mask); + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPCLR0/4; + bcm2835_peri_write(paddr, mask); } /* Read input pin */ uint8_t bcm2835_gpio_lev(uint8_t pin) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEV0/4 + pin/32; - uint8_t shift = pin % 32; - uint32_t value = bcm2835_peri_read(paddr); - return (value & (1 << shift)) ? HIGH : LOW; + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEV0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = bcm2835_peri_read(paddr); + return (value & (1 << shift)) ? HIGH : LOW; } /* See if an event detection bit is set @@ -265,135 +252,135 @@ uint8_t bcm2835_gpio_lev(uint8_t pin) */ uint8_t bcm2835_gpio_eds(uint8_t pin) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4 + pin/32; - uint8_t shift = pin % 32; - uint32_t value = bcm2835_peri_read(paddr); - return (value & (1 << shift)) ? HIGH : LOW; + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = bcm2835_peri_read(paddr); + return (value & (1 << shift)) ? HIGH : LOW; } uint32_t bcm2835_gpio_eds_multi(uint32_t mask) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4; - uint32_t value = bcm2835_peri_read(paddr); - return (value & mask); + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4; + uint32_t value = bcm2835_peri_read(paddr); + return (value & mask); } /* Write a 1 to clear the bit in EDS */ void bcm2835_gpio_set_eds(uint8_t pin) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4 + pin/32; - uint8_t shift = pin % 32; - uint32_t value = 1 << shift; - bcm2835_peri_write(paddr, value); + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_write(paddr, value); } void bcm2835_gpio_set_eds_multi(uint32_t mask) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4; - bcm2835_peri_write(paddr, mask); + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPEDS0/4; + bcm2835_peri_write(paddr, mask); } /* Rising edge detect enable */ void bcm2835_gpio_ren(uint8_t pin) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPREN0/4 + pin/32; - uint8_t shift = pin % 32; - uint32_t value = 1 << shift; - bcm2835_peri_set_bits(paddr, value, value); + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPREN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, value, value); } void bcm2835_gpio_clr_ren(uint8_t pin) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPREN0/4 + pin/32; - uint8_t shift = pin % 32; - uint32_t value = 1 << shift; - bcm2835_peri_set_bits(paddr, 0, value); + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPREN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, 0, value); } /* Falling edge detect enable */ void bcm2835_gpio_fen(uint8_t pin) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPFEN0/4 + pin/32; - uint8_t shift = pin % 32; - uint32_t value = 1 << shift; - bcm2835_peri_set_bits(paddr, value, value); + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPFEN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, value, value); } void bcm2835_gpio_clr_fen(uint8_t pin) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPFEN0/4 + pin/32; - uint8_t shift = pin % 32; - uint32_t value = 1 << shift; - bcm2835_peri_set_bits(paddr, 0, value); + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPFEN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, 0, value); } /* High detect enable */ void bcm2835_gpio_hen(uint8_t pin) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPHEN0/4 + pin/32; - uint8_t shift = pin % 32; - uint32_t value = 1 << shift; - bcm2835_peri_set_bits(paddr, value, value); + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPHEN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, value, value); } void bcm2835_gpio_clr_hen(uint8_t pin) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPHEN0/4 + pin/32; - uint8_t shift = pin % 32; - uint32_t value = 1 << shift; - bcm2835_peri_set_bits(paddr, 0, value); + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPHEN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, 0, value); } /* Low detect enable */ void bcm2835_gpio_len(uint8_t pin) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEN0/4 + pin/32; - uint8_t shift = pin % 32; - uint32_t value = 1 << shift; - bcm2835_peri_set_bits(paddr, value, value); + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, value, value); } void bcm2835_gpio_clr_len(uint8_t pin) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEN0/4 + pin/32; - uint8_t shift = pin % 32; - uint32_t value = 1 << shift; - bcm2835_peri_set_bits(paddr, 0, value); + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPLEN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, 0, value); } /* Async rising edge detect enable */ void bcm2835_gpio_aren(uint8_t pin) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAREN0/4 + pin/32; - uint8_t shift = pin % 32; - uint32_t value = 1 << shift; - bcm2835_peri_set_bits(paddr, value, value); + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAREN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, value, value); } void bcm2835_gpio_clr_aren(uint8_t pin) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAREN0/4 + pin/32; - uint8_t shift = pin % 32; - uint32_t value = 1 << shift; - bcm2835_peri_set_bits(paddr, 0, value); + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAREN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, 0, value); } /* Async falling edge detect enable */ void bcm2835_gpio_afen(uint8_t pin) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAFEN0/4 + pin/32; - uint8_t shift = pin % 32; - uint32_t value = 1 << shift; - bcm2835_peri_set_bits(paddr, value, value); + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAFEN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, value, value); } void bcm2835_gpio_clr_afen(uint8_t pin) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAFEN0/4 + pin/32; - uint8_t shift = pin % 32; - uint32_t value = 1 << shift; - bcm2835_peri_set_bits(paddr, 0, value); + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPAFEN0/4 + pin/32; + uint8_t shift = pin % 32; + uint32_t value = 1 << shift; + bcm2835_peri_set_bits(paddr, 0, value); } /* Set pullup/down */ void bcm2835_gpio_pud(uint8_t pud) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUD/4; - bcm2835_peri_write(paddr, pud); + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUD/4; + bcm2835_peri_write(paddr, pud); } /* Pullup/down clock @@ -401,20 +388,20 @@ void bcm2835_gpio_pud(uint8_t pud) */ void bcm2835_gpio_pudclk(uint8_t pin, uint8_t on) { - volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUDCLK0/4 + pin/32; - uint8_t shift = pin % 32; - bcm2835_peri_write(paddr, (on ? 1 : 0) << shift); + volatile uint32_t* paddr = bcm2835_gpio + BCM2835_GPPUDCLK0/4 + pin/32; + uint8_t shift = pin % 32; + bcm2835_peri_write(paddr, (on ? 1 : 0) << shift); } /* Read GPIO pad behaviour for groups of GPIOs */ uint32_t bcm2835_gpio_pad(uint8_t group) { - if (bcm2835_pads == MAP_FAILED) { - return 0; - } - - volatile uint32_t* paddr = bcm2835_pads + BCM2835_PADS_GPIO_0_27/4 + group; - return bcm2835_peri_read(paddr); + if (bcm2835_pads == MAP_FAILED) { + return 0; + } + + volatile uint32_t* paddr = bcm2835_pads + BCM2835_PADS_GPIO_0_27/4 + group; + return bcm2835_peri_read(paddr); } /* Set GPIO pad behaviour for groups of GPIOs @@ -423,12 +410,12 @@ uint32_t bcm2835_gpio_pad(uint8_t group) */ void bcm2835_gpio_set_pad(uint8_t group, uint32_t control) { - if (bcm2835_pads == MAP_FAILED) { - return; - } + if (bcm2835_pads == MAP_FAILED) { + return; + } - volatile uint32_t* paddr = bcm2835_pads + BCM2835_PADS_GPIO_0_27/4 + group; - bcm2835_peri_write(paddr, control | BCM2835_PAD_PASSWRD); + volatile uint32_t* paddr = bcm2835_pads + BCM2835_PADS_GPIO_0_27/4 + group; + bcm2835_peri_write(paddr, control | BCM2835_PAD_PASSWRD); } /* Some convenient arduino-like functions @@ -436,39 +423,37 @@ void bcm2835_gpio_set_pad(uint8_t group, uint32_t control) */ void bcm2835_delay(unsigned int millis) { - struct timespec sleeper; - - sleeper.tv_sec = (time_t)(millis / 1000); - sleeper.tv_nsec = (long)(millis % 1000) * 1000000; - nanosleep(&sleeper, NULL); + struct timespec sleeper; + + sleeper.tv_sec = (time_t)(millis / 1000); + sleeper.tv_nsec = (long)(millis % 1000) * 1000000; + nanosleep(&sleeper, NULL); } /* microseconds */ void bcm2835_delayMicroseconds(uint64_t micros) { - struct timespec t1; - uint64_t start; - - if (debug) - { - /* Cant access sytem timers in debug mode */ - printf("bcm2835_delayMicroseconds %lld\n", micros); - return; - } - - /* Calling nanosleep() takes at least 100-200 us, so use it for - // long waits and use a busy wait on the System Timer for the rest. - */ - start = bcm2835_st_read(); - - if (micros > 450) - { - t1.tv_sec = 0; - t1.tv_nsec = 1000 * (long)(micros - 200); - nanosleep(&t1, NULL); - } - - bcm2835_st_delay(start, micros); + struct timespec t1; + uint64_t start; + + if (debug) { + /* Cant access sytem timers in debug mode */ + printf("bcm2835_delayMicroseconds %lld\n", micros); + return; + } + + /* Calling nanosleep() takes at least 100-200 us, so use it for + // long waits and use a busy wait on the System Timer for the rest. + */ + start = bcm2835_st_read(); + + if (micros > 450) { + t1.tv_sec = 0; + t1.tv_nsec = 1000 * (long)(micros - 200); + nanosleep(&t1, NULL); + } + + bcm2835_st_delay(start, micros); } /* @@ -478,26 +463,28 @@ void bcm2835_delayMicroseconds(uint64_t micros) /* Set the state of an output */ void bcm2835_gpio_write(uint8_t pin, uint8_t on) { - if (on) - bcm2835_gpio_set(pin); - else - bcm2835_gpio_clr(pin); + if (on) { + bcm2835_gpio_set(pin); + } else { + bcm2835_gpio_clr(pin); + } } /* Set the state of a all 32 outputs in the mask to on or off */ void bcm2835_gpio_write_multi(uint32_t mask, uint8_t on) { - if (on) - bcm2835_gpio_set_multi(mask); - else - bcm2835_gpio_clr_multi(mask); + if (on) { + bcm2835_gpio_set_multi(mask); + } else { + bcm2835_gpio_clr_multi(mask); + } } /* Set the state of a all 32 outputs in the mask to the values in value */ void bcm2835_gpio_write_mask(uint32_t value, uint32_t mask) { - bcm2835_gpio_set_multi(value & mask); - bcm2835_gpio_clr_multi((~value) & mask); + bcm2835_gpio_set_multi(value & mask); + bcm2835_gpio_clr_multi((~value) & mask); } /* Set the pullup/down resistor for a pin @@ -520,51 +507,52 @@ void bcm2835_gpio_write_mask(uint32_t value, uint32_t mask) */ void bcm2835_gpio_set_pud(uint8_t pin, uint8_t pud) { - bcm2835_gpio_pud(pud); - delayMicroseconds(10); - bcm2835_gpio_pudclk(pin, 1); - delayMicroseconds(10); - bcm2835_gpio_pud(BCM2835_GPIO_PUD_OFF); - bcm2835_gpio_pudclk(pin, 0); + bcm2835_gpio_pud(pud); + delayMicroseconds(10); + bcm2835_gpio_pudclk(pin, 1); + delayMicroseconds(10); + bcm2835_gpio_pud(BCM2835_GPIO_PUD_OFF); + bcm2835_gpio_pudclk(pin, 0); } int bcm2835_spi_begin(void) { - volatile uint32_t* paddr; + volatile uint32_t* paddr; + + if (bcm2835_spi0 == MAP_FAILED) { + return 0; /* bcm2835_init() failed, or not root */ + } + + /* Set the SPI0 pins to the Alt 0 function to enable SPI0 access on them */ + bcm2835_gpio_fsel(RPI_GPIO_P1_26, BCM2835_GPIO_FSEL_ALT0); /* CE1 */ + bcm2835_gpio_fsel(RPI_GPIO_P1_24, BCM2835_GPIO_FSEL_ALT0); /* CE0 */ + bcm2835_gpio_fsel(RPI_GPIO_P1_21, BCM2835_GPIO_FSEL_ALT0); /* MISO */ + bcm2835_gpio_fsel(RPI_GPIO_P1_19, BCM2835_GPIO_FSEL_ALT0); /* MOSI */ + bcm2835_gpio_fsel(RPI_GPIO_P1_23, BCM2835_GPIO_FSEL_ALT0); /* CLK */ + + /* Set the SPI CS register to the some sensible defaults */ + paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; + bcm2835_peri_write(paddr, 0); /* All 0s */ - if (bcm2835_spi0 == MAP_FAILED) - return 0; /* bcm2835_init() failed, or not root */ - - /* Set the SPI0 pins to the Alt 0 function to enable SPI0 access on them */ - bcm2835_gpio_fsel(RPI_GPIO_P1_26, BCM2835_GPIO_FSEL_ALT0); /* CE1 */ - bcm2835_gpio_fsel(RPI_GPIO_P1_24, BCM2835_GPIO_FSEL_ALT0); /* CE0 */ - bcm2835_gpio_fsel(RPI_GPIO_P1_21, BCM2835_GPIO_FSEL_ALT0); /* MISO */ - bcm2835_gpio_fsel(RPI_GPIO_P1_19, BCM2835_GPIO_FSEL_ALT0); /* MOSI */ - bcm2835_gpio_fsel(RPI_GPIO_P1_23, BCM2835_GPIO_FSEL_ALT0); /* CLK */ - - /* Set the SPI CS register to the some sensible defaults */ - paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; - bcm2835_peri_write(paddr, 0); /* All 0s */ - - /* Clear TX and RX fifos */ - bcm2835_peri_write_nb(paddr, BCM2835_SPI0_CS_CLEAR); + /* Clear TX and RX fifos */ + bcm2835_peri_write_nb(paddr, BCM2835_SPI0_CS_CLEAR); - return 1; // OK + return 1; // OK } void bcm2835_spi_end(void) -{ - /* Set all the SPI0 pins back to input */ - bcm2835_gpio_fsel(RPI_GPIO_P1_26, BCM2835_GPIO_FSEL_INPT); /* CE1 */ - bcm2835_gpio_fsel(RPI_GPIO_P1_24, BCM2835_GPIO_FSEL_INPT); /* CE0 */ - bcm2835_gpio_fsel(RPI_GPIO_P1_21, BCM2835_GPIO_FSEL_INPT); /* MISO */ - bcm2835_gpio_fsel(RPI_GPIO_P1_19, BCM2835_GPIO_FSEL_INPT); /* MOSI */ - bcm2835_gpio_fsel(RPI_GPIO_P1_23, BCM2835_GPIO_FSEL_INPT); /* CLK */ +{ + /* Set all the SPI0 pins back to input */ + bcm2835_gpio_fsel(RPI_GPIO_P1_26, BCM2835_GPIO_FSEL_INPT); /* CE1 */ + bcm2835_gpio_fsel(RPI_GPIO_P1_24, BCM2835_GPIO_FSEL_INPT); /* CE0 */ + bcm2835_gpio_fsel(RPI_GPIO_P1_21, BCM2835_GPIO_FSEL_INPT); /* MISO */ + bcm2835_gpio_fsel(RPI_GPIO_P1_19, BCM2835_GPIO_FSEL_INPT); /* MOSI */ + bcm2835_gpio_fsel(RPI_GPIO_P1_23, BCM2835_GPIO_FSEL_INPT); /* CLK */ } void bcm2835_spi_setBitOrder(uint8_t __attribute__((unused)) order) { - /* BCM2835_SPI_BIT_ORDER_MSBFIRST is the only one supported by SPI0 */ + /* BCM2835_SPI_BIT_ORDER_MSBFIRST is the only one supported by SPI0 */ } /* defaults to 0, which means a divider of 65536. @@ -574,138 +562,136 @@ void bcm2835_spi_setBitOrder(uint8_t __attribute__((unused)) order) */ void bcm2835_spi_setClockDivider(uint16_t divider) { - volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CLK/4; - bcm2835_peri_write(paddr, divider); + volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CLK/4; + bcm2835_peri_write(paddr, divider); } void bcm2835_spi_setDataMode(uint8_t mode) { - volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; - /* Mask in the CPO and CPHA bits of CS */ - bcm2835_peri_set_bits(paddr, mode << 2, BCM2835_SPI0_CS_CPOL | BCM2835_SPI0_CS_CPHA); + volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; + /* Mask in the CPO and CPHA bits of CS */ + bcm2835_peri_set_bits(paddr, mode << 2, BCM2835_SPI0_CS_CPOL | BCM2835_SPI0_CS_CPHA); } /* Writes (and reads) a single byte to SPI */ uint8_t bcm2835_spi_transfer(uint8_t value) { - volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; - volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; - uint32_t ret; + volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; + volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; + uint32_t ret; - /* This is Polled transfer as per section 10.6.1 - // BUG ALERT: what happens if we get interupted in this section, and someone else - // accesses a different peripheral? - // Clear TX and RX fifos - */ - bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); + /* This is Polled transfer as per section 10.6.1 + // BUG ALERT: what happens if we get interupted in this section, and someone else + // accesses a different peripheral? + // Clear TX and RX fifos + */ + bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); - /* Set TA = 1 */ - bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); + /* Set TA = 1 */ + bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); - /* Maybe wait for TXD */ - while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD)) - ; + /* Maybe wait for TXD */ + while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD)) + ; - /* Write to FIFO, no barrier */ - bcm2835_peri_write_nb(fifo, value); + /* Write to FIFO, no barrier */ + bcm2835_peri_write_nb(fifo, value); - /* Wait for DONE to be set */ - while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) - ; + /* Wait for DONE to be set */ + while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) + ; - /* Read any byte that was sent back by the slave while we sere sending to it */ - ret = bcm2835_peri_read_nb(fifo); + /* Read any byte that was sent back by the slave while we sere sending to it */ + ret = bcm2835_peri_read_nb(fifo); - /* Set TA = 0, and also set the barrier */ - bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); + /* Set TA = 0, and also set the barrier */ + bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); - return ret; + return ret; } /* Writes (and reads) an number of bytes to SPI */ void bcm2835_spi_transfernb(char* tbuf, char* rbuf, uint32_t len) { - volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; - volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; - uint32_t TXCnt=0; - uint32_t RXCnt=0; - - /* This is Polled transfer as per section 10.6.1 - // BUG ALERT: what happens if we get interupted in this section, and someone else - // accesses a different peripheral? - */ - - /* Clear TX and RX fifos */ - bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); - - /* Set TA = 1 */ - bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); - - /* Use the FIFO's to reduce the interbyte times */ - while((TXCnt < len)||(RXCnt < len)) - { - /* TX fifo not full, so add some more bytes */ - while(((bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD))&&(TXCnt < len )) - { - bcm2835_peri_write_nb(fifo, tbuf[TXCnt]); - TXCnt++; - } - /* Rx fifo not empty, so get the next received bytes */ - while(((bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD))&&( RXCnt < len )) - { - rbuf[RXCnt] = bcm2835_peri_read_nb(fifo); - RXCnt++; - } - } - /* Wait for DONE to be set */ - while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) - ; - - /* Set TA = 0, and also set the barrier */ - bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); + volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; + volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; + uint32_t TXCnt=0; + uint32_t RXCnt=0; + + /* This is Polled transfer as per section 10.6.1 + // BUG ALERT: what happens if we get interupted in this section, and someone else + // accesses a different peripheral? + */ + + /* Clear TX and RX fifos */ + bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); + + /* Set TA = 1 */ + bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); + + /* Use the FIFO's to reduce the interbyte times */ + while((TXCnt < len)||(RXCnt < len)) { + /* TX fifo not full, so add some more bytes */ + while(((bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD))&&(TXCnt < len )) { + bcm2835_peri_write_nb(fifo, tbuf[TXCnt]); + TXCnt++; + } + /* Rx fifo not empty, so get the next received bytes */ + while(((bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD))&&( RXCnt < len )) { + rbuf[RXCnt] = bcm2835_peri_read_nb(fifo); + RXCnt++; + } + } + /* Wait for DONE to be set */ + while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) + ; + + /* Set TA = 0, and also set the barrier */ + bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); } /* Writes an number of bytes to SPI */ void bcm2835_spi_writenb(char* tbuf, uint32_t len) { - volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; - volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; - uint32_t i; + volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; + volatile uint32_t* fifo = bcm2835_spi0 + BCM2835_SPI0_FIFO/4; + uint32_t i; - /* This is Polled transfer as per section 10.6.1 - // BUG ALERT: what happens if we get interupted in this section, and someone else - // accesses a different peripheral? - // Answer: an ISR is required to issue the required memory barriers. - */ + /* This is Polled transfer as per section 10.6.1 + // BUG ALERT: what happens if we get interupted in this section, and someone else + // accesses a different peripheral? + // Answer: an ISR is required to issue the required memory barriers. + */ - /* Clear TX and RX fifos */ - bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); + /* Clear TX and RX fifos */ + bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_CLEAR, BCM2835_SPI0_CS_CLEAR); - /* Set TA = 1 */ - bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); + /* Set TA = 1 */ + bcm2835_peri_set_bits(paddr, BCM2835_SPI0_CS_TA, BCM2835_SPI0_CS_TA); - for (i = 0; i < len; i++) - { - /* Maybe wait for TXD */ - while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD)) - ; - - /* Write to FIFO, no barrier */ - bcm2835_peri_write_nb(fifo, tbuf[i]); - - /* Read from FIFO to prevent stalling */ - while (bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD) - (void) bcm2835_peri_read_nb(fifo); - } - - /* Wait for DONE to be set */ - while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) { - while (bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD) - (void) bcm2835_peri_read_nb(fifo); - }; - - /* Set TA = 0, and also set the barrier */ - bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); + for (i = 0; i < len; i++) { + /* Maybe wait for TXD */ + while (!(bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_TXD)) + ; + + /* Write to FIFO, no barrier */ + bcm2835_peri_write_nb(fifo, tbuf[i]); + + /* Read from FIFO to prevent stalling */ + while (bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD) { + (void) bcm2835_peri_read_nb(fifo); + } + } + + /* Wait for DONE to be set */ + while (!(bcm2835_peri_read_nb(paddr) & BCM2835_SPI0_CS_DONE)) { + while (bcm2835_peri_read(paddr) & BCM2835_SPI0_CS_RXD) { + (void) bcm2835_peri_read_nb(fifo); + } + }; + + /* Set TA = 0, and also set the barrier */ + bcm2835_peri_set_bits(paddr, 0, BCM2835_SPI0_CS_TA); } /* Writes (and reads) an number of bytes to SPI @@ -713,77 +699,78 @@ void bcm2835_spi_writenb(char* tbuf, uint32_t len) */ void bcm2835_spi_transfern(char* buf, uint32_t len) { - bcm2835_spi_transfernb(buf, buf, len); + bcm2835_spi_transfernb(buf, buf, len); } void bcm2835_spi_chipSelect(uint8_t cs) { - volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; - /* Mask in the CS bits of CS */ - bcm2835_peri_set_bits(paddr, cs, BCM2835_SPI0_CS_CS); + volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; + /* Mask in the CS bits of CS */ + bcm2835_peri_set_bits(paddr, cs, BCM2835_SPI0_CS_CS); } void bcm2835_spi_setChipSelectPolarity(uint8_t cs, uint8_t active) { - volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; - uint8_t shift = 21 + cs; - /* Mask in the appropriate CSPOLn bit */ - bcm2835_peri_set_bits(paddr, active << shift, 1 << shift); + volatile uint32_t* paddr = bcm2835_spi0 + BCM2835_SPI0_CS/4; + uint8_t shift = 21 + cs; + /* Mask in the appropriate CSPOLn bit */ + bcm2835_peri_set_bits(paddr, active << shift, 1 << shift); } int bcm2835_i2c_begin(void) { - uint16_t cdiv; + uint16_t cdiv; - if ( bcm2835_bsc0 == MAP_FAILED - || bcm2835_bsc1 == MAP_FAILED) - return 0; /* bcm2835_init() failed, or not root */ + if ( bcm2835_bsc0 == MAP_FAILED + || bcm2835_bsc1 == MAP_FAILED) { + return 0; /* bcm2835_init() failed, or not root */ + } #ifdef I2C_V1 - volatile uint32_t* paddr = bcm2835_bsc0 + BCM2835_BSC_DIV/4; - /* Set the I2C/BSC0 pins to the Alt 0 function to enable I2C access on them */ - bcm2835_gpio_fsel(RPI_GPIO_P1_03, BCM2835_GPIO_FSEL_ALT0); /* SDA */ - bcm2835_gpio_fsel(RPI_GPIO_P1_05, BCM2835_GPIO_FSEL_ALT0); /* SCL */ + volatile uint32_t* paddr = bcm2835_bsc0 + BCM2835_BSC_DIV/4; + /* Set the I2C/BSC0 pins to the Alt 0 function to enable I2C access on them */ + bcm2835_gpio_fsel(RPI_GPIO_P1_03, BCM2835_GPIO_FSEL_ALT0); /* SDA */ + bcm2835_gpio_fsel(RPI_GPIO_P1_05, BCM2835_GPIO_FSEL_ALT0); /* SCL */ #else - volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_DIV/4; - /* Set the I2C/BSC1 pins to the Alt 0 function to enable I2C access on them */ - bcm2835_gpio_fsel(RPI_V2_GPIO_P1_03, BCM2835_GPIO_FSEL_ALT0); /* SDA */ - bcm2835_gpio_fsel(RPI_V2_GPIO_P1_05, BCM2835_GPIO_FSEL_ALT0); /* SCL */ -#endif + volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_DIV/4; + /* Set the I2C/BSC1 pins to the Alt 0 function to enable I2C access on them */ + bcm2835_gpio_fsel(RPI_V2_GPIO_P1_03, BCM2835_GPIO_FSEL_ALT0); /* SDA */ + bcm2835_gpio_fsel(RPI_V2_GPIO_P1_05, BCM2835_GPIO_FSEL_ALT0); /* SCL */ +#endif - /* Read the clock divider register */ - cdiv = bcm2835_peri_read(paddr); - /* Calculate time for transmitting one byte - // 1000000 = micros seconds in a second - // 9 = Clocks per byte : 8 bits + ACK - */ - i2c_byte_wait_us = ((float)cdiv / BCM2835_CORE_CLK_HZ) * 1000000 * 9; + /* Read the clock divider register */ + cdiv = bcm2835_peri_read(paddr); + /* Calculate time for transmitting one byte + // 1000000 = micros seconds in a second + // 9 = Clocks per byte : 8 bits + ACK + */ + i2c_byte_wait_us = ((float)cdiv / BCM2835_CORE_CLK_HZ) * 1000000 * 9; - return 1; + return 1; } void bcm2835_i2c_end(void) { #ifdef I2C_V1 - /* Set all the I2C/BSC0 pins back to input */ - bcm2835_gpio_fsel(RPI_GPIO_P1_03, BCM2835_GPIO_FSEL_INPT); /* SDA */ - bcm2835_gpio_fsel(RPI_GPIO_P1_05, BCM2835_GPIO_FSEL_INPT); /* SCL */ + /* Set all the I2C/BSC0 pins back to input */ + bcm2835_gpio_fsel(RPI_GPIO_P1_03, BCM2835_GPIO_FSEL_INPT); /* SDA */ + bcm2835_gpio_fsel(RPI_GPIO_P1_05, BCM2835_GPIO_FSEL_INPT); /* SCL */ #else - /* Set all the I2C/BSC1 pins back to input */ - bcm2835_gpio_fsel(RPI_V2_GPIO_P1_03, BCM2835_GPIO_FSEL_INPT); /* SDA */ - bcm2835_gpio_fsel(RPI_V2_GPIO_P1_05, BCM2835_GPIO_FSEL_INPT); /* SCL */ + /* Set all the I2C/BSC1 pins back to input */ + bcm2835_gpio_fsel(RPI_V2_GPIO_P1_03, BCM2835_GPIO_FSEL_INPT); /* SDA */ + bcm2835_gpio_fsel(RPI_V2_GPIO_P1_05, BCM2835_GPIO_FSEL_INPT); /* SCL */ #endif } void bcm2835_i2c_setSlaveAddress(uint8_t addr) { - /* Set I2C Device Address */ + /* Set I2C Device Address */ #ifdef I2C_V1 - volatile uint32_t* paddr = bcm2835_bsc0 + BCM2835_BSC_A/4; -#else - volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_A/4; + volatile uint32_t* paddr = bcm2835_bsc0 + BCM2835_BSC_A/4; +#else + volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_A/4; #endif - bcm2835_peri_write(paddr, addr); + bcm2835_peri_write(paddr, addr); } /* defaults to 0x5dc, should result in a 166.666 kHz I2C clock frequency. @@ -793,16 +780,16 @@ void bcm2835_i2c_setSlaveAddress(uint8_t addr) void bcm2835_i2c_setClockDivider(uint16_t divider) { #ifdef I2C_V1 - volatile uint32_t* paddr = bcm2835_bsc0 + BCM2835_BSC_DIV/4; + volatile uint32_t* paddr = bcm2835_bsc0 + BCM2835_BSC_DIV/4; #else - volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_DIV/4; -#endif - bcm2835_peri_write(paddr, divider); - /* Calculate time for transmitting one byte - // 1000000 = micros seconds in a second - // 9 = Clocks per byte : 8 bits + ACK - */ - i2c_byte_wait_us = ((float)divider / BCM2835_CORE_CLK_HZ) * 1000000 * 9; + volatile uint32_t* paddr = bcm2835_bsc1 + BCM2835_BSC_DIV/4; +#endif + bcm2835_peri_write(paddr, divider); + /* Calculate time for transmitting one byte + // 1000000 = micros seconds in a second + // 9 = Clocks per byte : 8 bits + ACK + */ + i2c_byte_wait_us = ((float)divider / BCM2835_CORE_CLK_HZ) * 1000000 * 9; } /* set I2C clock divider by means of a baudrate number */ @@ -818,468 +805,449 @@ void bcm2835_i2c_set_baudrate(uint32_t baudrate) uint8_t bcm2835_i2c_write(const char * buf, uint32_t len) { #ifdef I2C_V1 - volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; - volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; - volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; - volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; + volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; + volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; + volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; + volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; #else - volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; - volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; - volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; - volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; -#endif - - uint32_t remaining = len; - uint32_t i = 0; - uint8_t reason = BCM2835_I2C_REASON_OK; - - /* Clear FIFO */ - bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); - /* Clear Status */ - bcm2835_peri_write(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); - /* Set Data Length */ - bcm2835_peri_write(dlen, len); - /* pre populate FIFO with max buffer */ - while( remaining && ( i < BCM2835_BSC_FIFO_SIZE ) ) - { - bcm2835_peri_write_nb(fifo, buf[i]); - i++; - remaining--; - } - - /* Enable device and start transfer */ - bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST); - - /* Transfer is over when BCM2835_BSC_S_DONE */ - while(!(bcm2835_peri_read(status) & BCM2835_BSC_S_DONE )) - { - while ( remaining && (bcm2835_peri_read(status) & BCM2835_BSC_S_TXD )) - { - /* Write to FIFO */ - bcm2835_peri_write(fifo, buf[i]); - i++; - remaining--; - } - } - - /* Received a NACK */ - if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) - { - reason = BCM2835_I2C_REASON_ERROR_NACK; - } - - /* Received Clock Stretch Timeout */ - else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) - { - reason = BCM2835_I2C_REASON_ERROR_CLKT; - } - - /* Not all data is sent */ - else if (remaining) - { - reason = BCM2835_I2C_REASON_ERROR_DATA; - } - - bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); - - return reason; + volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; + volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; + volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; + volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; +#endif + + uint32_t remaining = len; + uint32_t i = 0; + uint8_t reason = BCM2835_I2C_REASON_OK; + + /* Clear FIFO */ + bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); + /* Clear Status */ + bcm2835_peri_write(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); + /* Set Data Length */ + bcm2835_peri_write(dlen, len); + /* pre populate FIFO with max buffer */ + while( remaining && ( i < BCM2835_BSC_FIFO_SIZE ) ) { + bcm2835_peri_write_nb(fifo, buf[i]); + i++; + remaining--; + } + + /* Enable device and start transfer */ + bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST); + + /* Transfer is over when BCM2835_BSC_S_DONE */ + while(!(bcm2835_peri_read(status) & BCM2835_BSC_S_DONE )) { + while ( remaining && (bcm2835_peri_read(status) & BCM2835_BSC_S_TXD )) { + /* Write to FIFO */ + bcm2835_peri_write(fifo, buf[i]); + i++; + remaining--; + } + } + + /* Received a NACK */ + if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) { + reason = BCM2835_I2C_REASON_ERROR_NACK; + } + + /* Received Clock Stretch Timeout */ + else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) { + reason = BCM2835_I2C_REASON_ERROR_CLKT; + } + + /* Not all data is sent */ + else if (remaining) { + reason = BCM2835_I2C_REASON_ERROR_DATA; + } + + bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); + + return reason; } /* Read an number of bytes from I2C */ uint8_t bcm2835_i2c_read(char* buf, uint32_t len) { #ifdef I2C_V1 - volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; - volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; - volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; - volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; + volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; + volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; + volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; + volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; #else - volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; - volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; - volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; - volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; -#endif - - uint32_t remaining = len; - uint32_t i = 0; - uint8_t reason = BCM2835_I2C_REASON_OK; - - /* Clear FIFO */ - bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); - /* Clear Status */ - bcm2835_peri_write_nb(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); - /* Set Data Length */ - bcm2835_peri_write_nb(dlen, len); - /* Start read */ - bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ); - - /* wait for transfer to complete */ - while (!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE)) - { - /* we must empty the FIFO as it is populated and not use any delay */ - while (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD) - { - /* Read from FIFO, no barrier */ - buf[i] = bcm2835_peri_read_nb(fifo); - i++; - remaining--; - } - } - - /* transfer has finished - grab any remaining stuff in FIFO */ - while (remaining && (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD)) - { - /* Read from FIFO, no barrier */ - buf[i] = bcm2835_peri_read_nb(fifo); - i++; - remaining--; - } - - /* Received a NACK */ - if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) - { - reason = BCM2835_I2C_REASON_ERROR_NACK; - } - - /* Received Clock Stretch Timeout */ - else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) - { - reason = BCM2835_I2C_REASON_ERROR_CLKT; - } - - /* Not all data is received */ - else if (remaining) - { - reason = BCM2835_I2C_REASON_ERROR_DATA; - } - - bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); - - return reason; + volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; + volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; + volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; + volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; +#endif + + uint32_t remaining = len; + uint32_t i = 0; + uint8_t reason = BCM2835_I2C_REASON_OK; + + /* Clear FIFO */ + bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); + /* Clear Status */ + bcm2835_peri_write_nb(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); + /* Set Data Length */ + bcm2835_peri_write_nb(dlen, len); + /* Start read */ + bcm2835_peri_write_nb(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ); + + /* wait for transfer to complete */ + while (!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE)) { + /* we must empty the FIFO as it is populated and not use any delay */ + while (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD) { + /* Read from FIFO, no barrier */ + buf[i] = bcm2835_peri_read_nb(fifo); + i++; + remaining--; + } + } + + /* transfer has finished - grab any remaining stuff in FIFO */ + while (remaining && (bcm2835_peri_read_nb(status) & BCM2835_BSC_S_RXD)) { + /* Read from FIFO, no barrier */ + buf[i] = bcm2835_peri_read_nb(fifo); + i++; + remaining--; + } + + /* Received a NACK */ + if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) { + reason = BCM2835_I2C_REASON_ERROR_NACK; + } + + /* Received Clock Stretch Timeout */ + else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) { + reason = BCM2835_I2C_REASON_ERROR_CLKT; + } + + /* Not all data is received */ + else if (remaining) { + reason = BCM2835_I2C_REASON_ERROR_DATA; + } + + bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); + + return reason; } /* Read an number of bytes from I2C sending a repeated start after writing // the required register. Only works if your device supports this mode */ uint8_t bcm2835_i2c_read_register_rs(char* regaddr, char* buf, uint32_t len) -{ +{ #ifdef I2C_V1 - volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; - volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; - volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; - volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; + volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; + volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; + volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; + volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; #else - volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; - volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; - volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; - volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; -#endif + volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; + volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; + volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; + volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; +#endif uint32_t remaining = len; - uint32_t i = 0; - uint8_t reason = BCM2835_I2C_REASON_OK; - - /* Clear FIFO */ - bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); - /* Clear Status */ - bcm2835_peri_write(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); - /* Set Data Length */ - bcm2835_peri_write(dlen, 1); - /* Enable device and start transfer */ - bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN); - bcm2835_peri_write(fifo, regaddr[0]); - bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST); - - /* poll for transfer has started */ - while ( !( bcm2835_peri_read(status) & BCM2835_BSC_S_TA ) ) - { - /* Linux may cause us to miss entire transfer stage */ - if(bcm2835_peri_read(status) & BCM2835_BSC_S_DONE) - break; - } - - /* Send a repeated start with read bit set in address */ - bcm2835_peri_write(dlen, len); - bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ ); - - /* Wait for write to complete and first byte back. */ - bcm2835_delayMicroseconds(i2c_byte_wait_us * 3); - - /* wait for transfer to complete */ - while (!(bcm2835_peri_read(status) & BCM2835_BSC_S_DONE)) - { - /* we must empty the FIFO as it is populated and not use any delay */ - while (remaining && bcm2835_peri_read(status) & BCM2835_BSC_S_RXD) - { - /* Read from FIFO */ - buf[i] = bcm2835_peri_read(fifo); - i++; - remaining--; - } - } - - /* transfer has finished - grab any remaining stuff in FIFO */ - while (remaining && (bcm2835_peri_read(status) & BCM2835_BSC_S_RXD)) - { - /* Read from FIFO */ - buf[i] = bcm2835_peri_read(fifo); - i++; - remaining--; - } - - /* Received a NACK */ - if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) - { + uint32_t i = 0; + uint8_t reason = BCM2835_I2C_REASON_OK; + + /* Clear FIFO */ + bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); + /* Clear Status */ + bcm2835_peri_write(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); + /* Set Data Length */ + bcm2835_peri_write(dlen, 1); + /* Enable device and start transfer */ + bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN); + bcm2835_peri_write(fifo, regaddr[0]); + bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST); + + /* poll for transfer has started */ + while ( !( bcm2835_peri_read(status) & BCM2835_BSC_S_TA ) ) { + /* Linux may cause us to miss entire transfer stage */ + if(bcm2835_peri_read(status) & BCM2835_BSC_S_DONE) { + break; + } + } + + /* Send a repeated start with read bit set in address */ + bcm2835_peri_write(dlen, len); + bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ ); + + /* Wait for write to complete and first byte back. */ + bcm2835_delayMicroseconds(i2c_byte_wait_us * 3); + + /* wait for transfer to complete */ + while (!(bcm2835_peri_read(status) & BCM2835_BSC_S_DONE)) { + /* we must empty the FIFO as it is populated and not use any delay */ + while (remaining && bcm2835_peri_read(status) & BCM2835_BSC_S_RXD) { + /* Read from FIFO */ + buf[i] = bcm2835_peri_read(fifo); + i++; + remaining--; + } + } + + /* transfer has finished - grab any remaining stuff in FIFO */ + while (remaining && (bcm2835_peri_read(status) & BCM2835_BSC_S_RXD)) { + /* Read from FIFO */ + buf[i] = bcm2835_peri_read(fifo); + i++; + remaining--; + } + + /* Received a NACK */ + if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) { reason = BCM2835_I2C_REASON_ERROR_NACK; - } + } - /* Received Clock Stretch Timeout */ - else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) - { - reason = BCM2835_I2C_REASON_ERROR_CLKT; - } + /* Received Clock Stretch Timeout */ + else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) { + reason = BCM2835_I2C_REASON_ERROR_CLKT; + } - /* Not all data is sent */ - else if (remaining) - { - reason = BCM2835_I2C_REASON_ERROR_DATA; - } + /* Not all data is sent */ + else if (remaining) { + reason = BCM2835_I2C_REASON_ERROR_DATA; + } - bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); + bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); - return reason; + return reason; } -/* Sending an arbitrary number of bytes before issuing a repeated start +/* Sending an arbitrary number of bytes before issuing a repeated start // (with no prior stop) and reading a response. Some devices require this behavior. */ uint8_t bcm2835_i2c_write_read_rs(char* cmds, uint32_t cmds_len, char* buf, uint32_t buf_len) -{ +{ #ifdef I2C_V1 - volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; - volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; - volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; - volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; + volatile uint32_t* dlen = bcm2835_bsc0 + BCM2835_BSC_DLEN/4; + volatile uint32_t* fifo = bcm2835_bsc0 + BCM2835_BSC_FIFO/4; + volatile uint32_t* status = bcm2835_bsc0 + BCM2835_BSC_S/4; + volatile uint32_t* control = bcm2835_bsc0 + BCM2835_BSC_C/4; #else - volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; - volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; - volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; - volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; -#endif - - uint32_t remaining = cmds_len; - uint32_t i = 0; - uint8_t reason = BCM2835_I2C_REASON_OK; - - /* Clear FIFO */ - bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); - - /* Clear Status */ - bcm2835_peri_write(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); - - /* Set Data Length */ - bcm2835_peri_write(dlen, cmds_len); - - /* pre populate FIFO with max buffer */ - while( remaining && ( i < BCM2835_BSC_FIFO_SIZE ) ) - { - bcm2835_peri_write_nb(fifo, cmds[i]); - i++; - remaining--; - } - - /* Enable device and start transfer */ - bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST); - - /* poll for transfer has started (way to do repeated start, from BCM2835 datasheet) */ - while ( !( bcm2835_peri_read(status) & BCM2835_BSC_S_TA ) ) - { - /* Linux may cause us to miss entire transfer stage */ - if(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE) - break; - } - - remaining = buf_len; - i = 0; - - /* Send a repeated start with read bit set in address */ - bcm2835_peri_write(dlen, buf_len); - bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ ); - - /* Wait for write to complete and first byte back. */ - bcm2835_delayMicroseconds(i2c_byte_wait_us * (cmds_len + 1)); - - /* wait for transfer to complete */ - while (!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE)) - { - /* we must empty the FIFO as it is populated and not use any delay */ - while (remaining && bcm2835_peri_read(status) & BCM2835_BSC_S_RXD) - { - /* Read from FIFO, no barrier */ - buf[i] = bcm2835_peri_read_nb(fifo); - i++; - remaining--; - } - } - - /* transfer has finished - grab any remaining stuff in FIFO */ - while (remaining && (bcm2835_peri_read(status) & BCM2835_BSC_S_RXD)) - { - /* Read from FIFO */ - buf[i] = bcm2835_peri_read(fifo); - i++; - remaining--; - } - - /* Received a NACK */ - if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) - { - reason = BCM2835_I2C_REASON_ERROR_NACK; - } - - /* Received Clock Stretch Timeout */ - else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) - { - reason = BCM2835_I2C_REASON_ERROR_CLKT; - } - - /* Not all data is sent */ - else if (remaining) - { - reason = BCM2835_I2C_REASON_ERROR_DATA; - } - - bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); - - return reason; + volatile uint32_t* dlen = bcm2835_bsc1 + BCM2835_BSC_DLEN/4; + volatile uint32_t* fifo = bcm2835_bsc1 + BCM2835_BSC_FIFO/4; + volatile uint32_t* status = bcm2835_bsc1 + BCM2835_BSC_S/4; + volatile uint32_t* control = bcm2835_bsc1 + BCM2835_BSC_C/4; +#endif + + uint32_t remaining = cmds_len; + uint32_t i = 0; + uint8_t reason = BCM2835_I2C_REASON_OK; + + /* Clear FIFO */ + bcm2835_peri_set_bits(control, BCM2835_BSC_C_CLEAR_1 , BCM2835_BSC_C_CLEAR_1 ); + + /* Clear Status */ + bcm2835_peri_write(status, BCM2835_BSC_S_CLKT | BCM2835_BSC_S_ERR | BCM2835_BSC_S_DONE); + + /* Set Data Length */ + bcm2835_peri_write(dlen, cmds_len); + + /* pre populate FIFO with max buffer */ + while( remaining && ( i < BCM2835_BSC_FIFO_SIZE ) ) { + bcm2835_peri_write_nb(fifo, cmds[i]); + i++; + remaining--; + } + + /* Enable device and start transfer */ + bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST); + + /* poll for transfer has started (way to do repeated start, from BCM2835 datasheet) */ + while ( !( bcm2835_peri_read(status) & BCM2835_BSC_S_TA ) ) { + /* Linux may cause us to miss entire transfer stage */ + if(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE) { + break; + } + } + + remaining = buf_len; + i = 0; + + /* Send a repeated start with read bit set in address */ + bcm2835_peri_write(dlen, buf_len); + bcm2835_peri_write(control, BCM2835_BSC_C_I2CEN | BCM2835_BSC_C_ST | BCM2835_BSC_C_READ ); + + /* Wait for write to complete and first byte back. */ + bcm2835_delayMicroseconds(i2c_byte_wait_us * (cmds_len + 1)); + + /* wait for transfer to complete */ + while (!(bcm2835_peri_read_nb(status) & BCM2835_BSC_S_DONE)) { + /* we must empty the FIFO as it is populated and not use any delay */ + while (remaining && bcm2835_peri_read(status) & BCM2835_BSC_S_RXD) { + /* Read from FIFO, no barrier */ + buf[i] = bcm2835_peri_read_nb(fifo); + i++; + remaining--; + } + } + + /* transfer has finished - grab any remaining stuff in FIFO */ + while (remaining && (bcm2835_peri_read(status) & BCM2835_BSC_S_RXD)) { + /* Read from FIFO */ + buf[i] = bcm2835_peri_read(fifo); + i++; + remaining--; + } + + /* Received a NACK */ + if (bcm2835_peri_read(status) & BCM2835_BSC_S_ERR) { + reason = BCM2835_I2C_REASON_ERROR_NACK; + } + + /* Received Clock Stretch Timeout */ + else if (bcm2835_peri_read(status) & BCM2835_BSC_S_CLKT) { + reason = BCM2835_I2C_REASON_ERROR_CLKT; + } + + /* Not all data is sent */ + else if (remaining) { + reason = BCM2835_I2C_REASON_ERROR_DATA; + } + + bcm2835_peri_set_bits(control, BCM2835_BSC_S_DONE , BCM2835_BSC_S_DONE); + + return reason; } /* Read the System Timer Counter (64-bits) */ uint64_t bcm2835_st_read(void) { - volatile uint32_t* paddr; - uint32_t hi, lo; - uint64_t st; - paddr = bcm2835_st + BCM2835_ST_CHI/4; - hi = bcm2835_peri_read(paddr); - - paddr = bcm2835_st + BCM2835_ST_CLO/4; - lo = bcm2835_peri_read(paddr); - - paddr = bcm2835_st + BCM2835_ST_CHI/4; - st = bcm2835_peri_read(paddr); - - /* Test for overflow */ - if (st == hi) - { - st <<= 32; - st += lo; - } - else - { - st <<= 32; - paddr = bcm2835_st + BCM2835_ST_CLO/4; - st += bcm2835_peri_read(paddr); - } - return st; + volatile uint32_t* paddr; + uint32_t hi, lo; + uint64_t st; + paddr = bcm2835_st + BCM2835_ST_CHI/4; + hi = bcm2835_peri_read(paddr); + + paddr = bcm2835_st + BCM2835_ST_CLO/4; + lo = bcm2835_peri_read(paddr); + + paddr = bcm2835_st + BCM2835_ST_CHI/4; + st = bcm2835_peri_read(paddr); + + /* Test for overflow */ + if (st == hi) { + st <<= 32; + st += lo; + } else { + st <<= 32; + paddr = bcm2835_st + BCM2835_ST_CLO/4; + st += bcm2835_peri_read(paddr); + } + return st; } /* Delays for the specified number of microseconds with offset */ void bcm2835_st_delay(uint64_t offset_micros, uint64_t micros) { - uint64_t compare = offset_micros + micros; + uint64_t compare = offset_micros + micros; - while(bcm2835_st_read() < compare) - ; + while(bcm2835_st_read() < compare) + ; } /* PWM */ void bcm2835_pwm_set_clock(uint32_t divisor) { - if ( bcm2835_clk == MAP_FAILED - || bcm2835_pwm == MAP_FAILED) - return; /* bcm2835_init() failed or not root */ - - /* From Gerts code */ - divisor &= 0xfff; - /* Stop PWM clock */ - bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_CNTL, BCM2835_PWM_PASSWRD | 0x01); - bcm2835_delay(110); /* Prevents clock going slow */ - /* Wait for the clock to be not busy */ - while ((bcm2835_peri_read(bcm2835_clk + BCM2835_PWMCLK_CNTL) & 0x80) != 0) - bcm2835_delay(1); - /* set the clock divider and enable PWM clock */ - bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_DIV, BCM2835_PWM_PASSWRD | (divisor << 12)); - bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_CNTL, BCM2835_PWM_PASSWRD | 0x11); /* Source=osc and enable */ + if ( bcm2835_clk == MAP_FAILED + || bcm2835_pwm == MAP_FAILED) { + return; /* bcm2835_init() failed or not root */ + } + + /* From Gerts code */ + divisor &= 0xfff; + /* Stop PWM clock */ + bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_CNTL, BCM2835_PWM_PASSWRD | 0x01); + bcm2835_delay(110); /* Prevents clock going slow */ + /* Wait for the clock to be not busy */ + while ((bcm2835_peri_read(bcm2835_clk + BCM2835_PWMCLK_CNTL) & 0x80) != 0) { + bcm2835_delay(1); + } + /* set the clock divider and enable PWM clock */ + bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_DIV, BCM2835_PWM_PASSWRD | (divisor << 12)); + bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_CNTL, + BCM2835_PWM_PASSWRD | 0x11); /* Source=osc and enable */ } void bcm2835_pwm_set_mode(uint8_t channel, uint8_t markspace, uint8_t enabled) { - if ( bcm2835_clk == MAP_FAILED - || bcm2835_pwm == MAP_FAILED) - return; /* bcm2835_init() failed or not root */ - - uint32_t control = bcm2835_peri_read(bcm2835_pwm + BCM2835_PWM_CONTROL); - - if (channel == 0) - { - if (markspace) - control |= BCM2835_PWM0_MS_MODE; - else - control &= ~BCM2835_PWM0_MS_MODE; - if (enabled) - control |= BCM2835_PWM0_ENABLE; - else - control &= ~BCM2835_PWM0_ENABLE; - } - else if (channel == 1) - { - if (markspace) - control |= BCM2835_PWM1_MS_MODE; - else - control &= ~BCM2835_PWM1_MS_MODE; - if (enabled) - control |= BCM2835_PWM1_ENABLE; - else - control &= ~BCM2835_PWM1_ENABLE; - } - - /* If you use the barrier here, wierd things happen, and the commands dont work */ - bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM_CONTROL, control); - /* bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM_CONTROL, BCM2835_PWM0_ENABLE | BCM2835_PWM1_ENABLE | BCM2835_PWM0_MS_MODE | BCM2835_PWM1_MS_MODE); */ + if ( bcm2835_clk == MAP_FAILED + || bcm2835_pwm == MAP_FAILED) { + return; /* bcm2835_init() failed or not root */ + } + + uint32_t control = bcm2835_peri_read(bcm2835_pwm + BCM2835_PWM_CONTROL); + + if (channel == 0) { + if (markspace) { + control |= BCM2835_PWM0_MS_MODE; + } else { + control &= ~BCM2835_PWM0_MS_MODE; + } + if (enabled) { + control |= BCM2835_PWM0_ENABLE; + } else { + control &= ~BCM2835_PWM0_ENABLE; + } + } else if (channel == 1) { + if (markspace) { + control |= BCM2835_PWM1_MS_MODE; + } else { + control &= ~BCM2835_PWM1_MS_MODE; + } + if (enabled) { + control |= BCM2835_PWM1_ENABLE; + } else { + control &= ~BCM2835_PWM1_ENABLE; + } + } + + /* If you use the barrier here, wierd things happen, and the commands dont work */ + bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM_CONTROL, control); + /* bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM_CONTROL, BCM2835_PWM0_ENABLE | BCM2835_PWM1_ENABLE | BCM2835_PWM0_MS_MODE | BCM2835_PWM1_MS_MODE); */ } void bcm2835_pwm_set_range(uint8_t channel, uint32_t range) { - if ( bcm2835_clk == MAP_FAILED - || bcm2835_pwm == MAP_FAILED) - return; /* bcm2835_init() failed or not root */ + if ( bcm2835_clk == MAP_FAILED + || bcm2835_pwm == MAP_FAILED) { + return; /* bcm2835_init() failed or not root */ + } - if (channel == 0) - bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM0_RANGE, range); - else if (channel == 1) - bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM1_RANGE, range); + if (channel == 0) { + bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM0_RANGE, range); + } else if (channel == 1) { + bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM1_RANGE, range); + } } void bcm2835_pwm_set_data(uint8_t channel, uint32_t data) { - if ( bcm2835_clk == MAP_FAILED - || bcm2835_pwm == MAP_FAILED) - return; /* bcm2835_init() failed or not root */ + if ( bcm2835_clk == MAP_FAILED + || bcm2835_pwm == MAP_FAILED) { + return; /* bcm2835_init() failed or not root */ + } - if (channel == 0) - bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM0_DATA, data); - else if (channel == 1) - bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM1_DATA, data); + if (channel == 0) { + bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM0_DATA, data); + } else if (channel == 1) { + bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM1_DATA, data); + } } /* Allocate page-aligned memory. */ void *malloc_aligned(size_t size) { - void *mem; - errno = posix_memalign(&mem, BCM2835_PAGE_SIZE, size); - return (errno ? NULL : mem); + void *mem; + errno = posix_memalign(&mem, BCM2835_PAGE_SIZE, size); + return (errno ? NULL : mem); } /* Map 'size' bytes starting at 'off' in file 'fd' to memory. @@ -1288,217 +1256,224 @@ void *malloc_aligned(size_t size) */ static void *mapmem(const char *msg, size_t size, int fd, off_t off) { - void *map = mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, off); - if (map == MAP_FAILED) - logError("bcm2835_init: %s mmap failed: %s\n", msg, strerror(errno)); - return map; + void *map = mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, off); + if (map == MAP_FAILED) { + logError("bcm2835_init: %s mmap failed: %s\n", msg, strerror(errno)); + } + return map; } static void unmapmem(void **pmem, size_t size) { - if (*pmem == MAP_FAILED) return; - munmap(*pmem, size); - *pmem = MAP_FAILED; + if (*pmem == MAP_FAILED) { + return; + } + munmap(*pmem, size); + *pmem = MAP_FAILED; } /* Initialise this library. */ int bcm2835_init(void) { - int memfd; - int ok; - FILE *fp; - - if (debug) - { - bcm2835_peripherals = (uint32_t*)BCM2835_PERI_BASE; - - bcm2835_pads = bcm2835_peripherals + BCM2835_GPIO_PADS/4; - bcm2835_clk = bcm2835_peripherals + BCM2835_CLOCK_BASE/4; - bcm2835_gpio = bcm2835_peripherals + BCM2835_GPIO_BASE/4; - bcm2835_pwm = bcm2835_peripherals + BCM2835_GPIO_PWM/4; - bcm2835_spi0 = bcm2835_peripherals + BCM2835_SPI0_BASE/4; - bcm2835_bsc0 = bcm2835_peripherals + BCM2835_BSC0_BASE/4; - bcm2835_bsc1 = bcm2835_peripherals + BCM2835_BSC1_BASE/4; - bcm2835_st = bcm2835_peripherals + BCM2835_ST_BASE/4; - return 1; /* Success */ - } - - /* Figure out the base and size of the peripheral address block - // using the device-tree. Required for RPi2, optional for RPi 1 - */ - if ((fp = fopen(BMC2835_RPI2_DT_FILENAME , "rb"))) - { - unsigned char buf[4]; - fseek(fp, BMC2835_RPI2_DT_PERI_BASE_ADDRESS_OFFSET, SEEK_SET); - if (fread(buf, 1, sizeof(buf), fp) == sizeof(buf)) - bcm2835_peripherals_base = (uint32_t *)(buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0); - fseek(fp, BMC2835_RPI2_DT_PERI_SIZE_OFFSET, SEEK_SET); - if (fread(buf, 1, sizeof(buf), fp) == sizeof(buf)) - bcm2835_peripherals_size = (buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0); - fclose(fp); - } - /* else we are prob on RPi 1 with BCM2835, and use the hardwired defaults */ - - /* Now get ready to map the peripherals block - * If we are not root, try for the new /dev/gpiomem interface and accept - * the fact that we can only access GPIO - * else try for the /dev/mem interface and get access to everything - */ - memfd = -1; - ok = 0; - if (geteuid() == 0) - { - /* Open the master /dev/mem device */ - if ((memfd = open("/dev/mem", O_RDWR | O_SYNC) ) < 0) - { - logError("bcm2835_init: Unable to open /dev/mem: %s\n", - strerror(errno)) ; - goto exit; + int memfd; + int ok; + FILE *fp; + + if (debug) { + bcm2835_peripherals = (uint32_t*)BCM2835_PERI_BASE; + + bcm2835_pads = bcm2835_peripherals + BCM2835_GPIO_PADS/4; + bcm2835_clk = bcm2835_peripherals + BCM2835_CLOCK_BASE/4; + bcm2835_gpio = bcm2835_peripherals + BCM2835_GPIO_BASE/4; + bcm2835_pwm = bcm2835_peripherals + BCM2835_GPIO_PWM/4; + bcm2835_spi0 = bcm2835_peripherals + BCM2835_SPI0_BASE/4; + bcm2835_bsc0 = bcm2835_peripherals + BCM2835_BSC0_BASE/4; + bcm2835_bsc1 = bcm2835_peripherals + BCM2835_BSC1_BASE/4; + bcm2835_st = bcm2835_peripherals + BCM2835_ST_BASE/4; + return 1; /* Success */ + } + + /* Figure out the base and size of the peripheral address block + // using the device-tree. Required for RPi2, optional for RPi 1 + */ + if ((fp = fopen(BMC2835_RPI2_DT_FILENAME , "rb"))) { + unsigned char buf[4]; + fseek(fp, BMC2835_RPI2_DT_PERI_BASE_ADDRESS_OFFSET, SEEK_SET); + if (fread(buf, 1, sizeof(buf), fp) == sizeof(buf)) { + bcm2835_peripherals_base = (uint32_t *)(buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0); + } + fseek(fp, BMC2835_RPI2_DT_PERI_SIZE_OFFSET, SEEK_SET); + if (fread(buf, 1, sizeof(buf), fp) == sizeof(buf)) { + bcm2835_peripherals_size = (buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0); + } + fclose(fp); } - - /* Base of the peripherals block is mapped to VM */ - bcm2835_peripherals = mapmem("gpio", bcm2835_peripherals_size, memfd, (uint32_t)bcm2835_peripherals_base); - if (bcm2835_peripherals == MAP_FAILED) goto exit; - - /* Now compute the base addresses of various peripherals, - // which are at fixed offsets within the mapped peripherals block - // Caution: bcm2835_peripherals is uint32_t*, so divide offsets by 4 - */ - bcm2835_gpio = bcm2835_peripherals + BCM2835_GPIO_BASE/4; - bcm2835_pwm = bcm2835_peripherals + BCM2835_GPIO_PWM/4; - bcm2835_clk = bcm2835_peripherals + BCM2835_CLOCK_BASE/4; - bcm2835_pads = bcm2835_peripherals + BCM2835_GPIO_PADS/4; - bcm2835_spi0 = bcm2835_peripherals + BCM2835_SPI0_BASE/4; - bcm2835_bsc0 = bcm2835_peripherals + BCM2835_BSC0_BASE/4; /* I2C */ - bcm2835_bsc1 = bcm2835_peripherals + BCM2835_BSC1_BASE/4; /* I2C */ - bcm2835_st = bcm2835_peripherals + BCM2835_ST_BASE/4; - - ok = 1; - } - else - { - /* Not root, try /dev/gpiomem */ - /* Open the master /dev/mem device */ - if ((memfd = open("/dev/gpiomem", O_RDWR | O_SYNC) ) < 0) - { - logError("bcm2835_init: Unable to open /dev/gpiomem: %s\n", - strerror(errno)) ; - goto exit; + /* else we are prob on RPi 1 with BCM2835, and use the hardwired defaults */ + + /* Now get ready to map the peripherals block + * If we are not root, try for the new /dev/gpiomem interface and accept + * the fact that we can only access GPIO + * else try for the /dev/mem interface and get access to everything + */ + memfd = -1; + ok = 0; + if (geteuid() == 0) { + /* Open the master /dev/mem device */ + if ((memfd = open("/dev/mem", O_RDWR | O_SYNC) ) < 0) { + logError("bcm2835_init: Unable to open /dev/mem: %s\n", + strerror(errno)) ; + goto exit; + } + + /* Base of the peripherals block is mapped to VM */ + bcm2835_peripherals = mapmem("gpio", bcm2835_peripherals_size, memfd, + (uint32_t)bcm2835_peripherals_base); + if (bcm2835_peripherals == MAP_FAILED) { + goto exit; + } + + /* Now compute the base addresses of various peripherals, + // which are at fixed offsets within the mapped peripherals block + // Caution: bcm2835_peripherals is uint32_t*, so divide offsets by 4 + */ + bcm2835_gpio = bcm2835_peripherals + BCM2835_GPIO_BASE/4; + bcm2835_pwm = bcm2835_peripherals + BCM2835_GPIO_PWM/4; + bcm2835_clk = bcm2835_peripherals + BCM2835_CLOCK_BASE/4; + bcm2835_pads = bcm2835_peripherals + BCM2835_GPIO_PADS/4; + bcm2835_spi0 = bcm2835_peripherals + BCM2835_SPI0_BASE/4; + bcm2835_bsc0 = bcm2835_peripherals + BCM2835_BSC0_BASE/4; /* I2C */ + bcm2835_bsc1 = bcm2835_peripherals + BCM2835_BSC1_BASE/4; /* I2C */ + bcm2835_st = bcm2835_peripherals + BCM2835_ST_BASE/4; + + ok = 1; + } else { + /* Not root, try /dev/gpiomem */ + /* Open the master /dev/mem device */ + if ((memfd = open("/dev/gpiomem", O_RDWR | O_SYNC) ) < 0) { + logError("bcm2835_init: Unable to open /dev/gpiomem: %s\n", + strerror(errno)) ; + goto exit; + } + + /* Base of the peripherals block is mapped to VM */ + bcm2835_peripherals_base = 0; + bcm2835_peripherals = mapmem("gpio", bcm2835_peripherals_size, memfd, + (uint32_t)bcm2835_peripherals_base); + if (bcm2835_peripherals == MAP_FAILED) { + goto exit; + } + bcm2835_gpio = bcm2835_peripherals; + ok = 1; } - - /* Base of the peripherals block is mapped to VM */ - bcm2835_peripherals_base = 0; - bcm2835_peripherals = mapmem("gpio", bcm2835_peripherals_size, memfd, (uint32_t)bcm2835_peripherals_base); - if (bcm2835_peripherals == MAP_FAILED) goto exit; - bcm2835_gpio = bcm2835_peripherals; - ok = 1; - } exit: - if (memfd >= 0) - close(memfd); + if (memfd >= 0) { + close(memfd); + } - if (!ok) - bcm2835_close(); + if (!ok) { + bcm2835_close(); + } - return ok; + return ok; } /* Close this library and deallocate everything */ int bcm2835_close(void) { - if (debug) return 1; /* Success */ - - unmapmem((void**) &bcm2835_peripherals, bcm2835_peripherals_size); - bcm2835_peripherals = MAP_FAILED; - bcm2835_gpio = MAP_FAILED; - bcm2835_pwm = MAP_FAILED; - bcm2835_clk = MAP_FAILED; - bcm2835_pads = MAP_FAILED; - bcm2835_spi0 = MAP_FAILED; - bcm2835_bsc0 = MAP_FAILED; - bcm2835_bsc1 = MAP_FAILED; - bcm2835_st = MAP_FAILED; - return 1; /* Success */ -} + if (debug) { + return 1; /* Success */ + } + + unmapmem((void**) &bcm2835_peripherals, bcm2835_peripherals_size); + bcm2835_peripherals = MAP_FAILED; + bcm2835_gpio = MAP_FAILED; + bcm2835_pwm = MAP_FAILED; + bcm2835_clk = MAP_FAILED; + bcm2835_pads = MAP_FAILED; + bcm2835_spi0 = MAP_FAILED; + bcm2835_bsc0 = MAP_FAILED; + bcm2835_bsc1 = MAP_FAILED; + bcm2835_st = MAP_FAILED; + return 1; /* Success */ +} #ifdef BCM2835_TEST -/* this is a simple test program that prints out what it will do rather than +/* this is a simple test program that prints out what it will do rather than // actually doing it */ int main(int argc, char **argv) { - /* Be non-destructive */ - bcm2835_set_debug(1); + /* Be non-destructive */ + bcm2835_set_debug(1); - if (!bcm2835_init()) - return 1; + if (!bcm2835_init()) { + return 1; + } - /* Configure some GPIO pins fo some testing - // Set RPI pin P1-11 to be an output - */ - bcm2835_gpio_fsel(RPI_GPIO_P1_11, BCM2835_GPIO_FSEL_OUTP); - /* Set RPI pin P1-15 to be an input */ - bcm2835_gpio_fsel(RPI_GPIO_P1_15, BCM2835_GPIO_FSEL_INPT); - /* with a pullup */ - bcm2835_gpio_set_pud(RPI_GPIO_P1_15, BCM2835_GPIO_PUD_UP); - /* And a low detect enable */ - bcm2835_gpio_len(RPI_GPIO_P1_15); - /* and input hysteresis disabled on GPIOs 0 to 27 */ - bcm2835_gpio_set_pad(BCM2835_PAD_GROUP_GPIO_0_27, BCM2835_PAD_SLEW_RATE_UNLIMITED|BCM2835_PAD_DRIVE_8mA); + /* Configure some GPIO pins fo some testing + // Set RPI pin P1-11 to be an output + */ + bcm2835_gpio_fsel(RPI_GPIO_P1_11, BCM2835_GPIO_FSEL_OUTP); + /* Set RPI pin P1-15 to be an input */ + bcm2835_gpio_fsel(RPI_GPIO_P1_15, BCM2835_GPIO_FSEL_INPT); + /* with a pullup */ + bcm2835_gpio_set_pud(RPI_GPIO_P1_15, BCM2835_GPIO_PUD_UP); + /* And a low detect enable */ + bcm2835_gpio_len(RPI_GPIO_P1_15); + /* and input hysteresis disabled on GPIOs 0 to 27 */ + bcm2835_gpio_set_pad(BCM2835_PAD_GROUP_GPIO_0_27, + BCM2835_PAD_SLEW_RATE_UNLIMITED|BCM2835_PAD_DRIVE_8mA); #if 1 - /* Blink */ - while (1) - { - /* Turn it on */ - bcm2835_gpio_write(RPI_GPIO_P1_11, HIGH); - - /* wait a bit */ - bcm2835_delay(500); - - /* turn it off */ - bcm2835_gpio_write(RPI_GPIO_P1_11, LOW); - - /* wait a bit */ - bcm2835_delay(500); - } + /* Blink */ + while (1) { + /* Turn it on */ + bcm2835_gpio_write(RPI_GPIO_P1_11, HIGH); + + /* wait a bit */ + bcm2835_delay(500); + + /* turn it off */ + bcm2835_gpio_write(RPI_GPIO_P1_11, LOW); + + /* wait a bit */ + bcm2835_delay(500); + } #endif #if 0 - /* Read input */ - while (1) - { - /* Read some data */ - uint8_t value = bcm2835_gpio_lev(RPI_GPIO_P1_15); - printf("read from pin 15: %d\n", value); - - /* wait a bit */ - bcm2835_delay(500); - } + /* Read input */ + while (1) { + /* Read some data */ + uint8_t value = bcm2835_gpio_lev(RPI_GPIO_P1_15); + printf("read from pin 15: %d\n", value); + + /* wait a bit */ + bcm2835_delay(500); + } #endif #if 0 - /* Look for a low event detection - // eds will be set whenever pin 15 goes low - */ - while (1) - { - if (bcm2835_gpio_eds(RPI_GPIO_P1_15)) - { - /* Now clear the eds flag by setting it to 1 */ - bcm2835_gpio_set_eds(RPI_GPIO_P1_15); - printf("low event detect for pin 15\n"); + /* Look for a low event detection + // eds will be set whenever pin 15 goes low + */ + while (1) { + if (bcm2835_gpio_eds(RPI_GPIO_P1_15)) { + /* Now clear the eds flag by setting it to 1 */ + bcm2835_gpio_set_eds(RPI_GPIO_P1_15); + printf("low event detect for pin 15\n"); + } + + /* wait a bit */ + bcm2835_delay(500); } - - /* wait a bit */ - bcm2835_delay(500); - } #endif - if (!bcm2835_close()) - return 1; + if (!bcm2835_close()) { + return 1; + } - return 0; + return 0; } #endif diff --git a/drivers/RPi/bcm2835.h b/drivers/RPi/bcm2835.h index 26acee2ca..4dc081624 100644 --- a/drivers/RPi/bcm2835.h +++ b/drivers/RPi/bcm2835.h @@ -1,7 +1,7 @@ /* bcm2835.h - + C and C++ support for Broadcom BCM 2835 as used in Raspberry Pi - + Author: Mike McCauley Copyright (C) 2011-2013 Mike McCauley $Id: bcm2835.h,v 1.20 2015/03/31 04:55:41 mikem Exp mikem $ @@ -9,46 +9,46 @@ /*! \defgroup BCM2835grp C library for Broadcom BCM 2835 as used in Raspberry Pi \ingroup internals - - This is a C library for Raspberry Pi (RPi). It provides access to + + This is a C library for Raspberry Pi (RPi). It provides access to GPIO and other IO functions on the Broadcom BCM 2835 chip, allowing access to the GPIO pins on the 26 pin IDE plug on the RPi board so you can control and interface with various external devices. - + It provides functions for reading digital inputs and setting digital outputs, using SPI and I2C, and for accessing the system timers. Pin event detection is supported by polling (interrupts are not supported). - - It is C++ compatible, and installs as a header file and non-shared library on - any Linux-based distro (but clearly is no use except on Raspberry Pi or another board with + + It is C++ compatible, and installs as a header file and non-shared library on + any Linux-based distro (but clearly is no use except on Raspberry Pi or another board with BCM 2835). - - The version of the package that this documentation refers to can be downloaded + + The version of the package that this documentation refers to can be downloaded from http://www.airspayce.com/mikem/bcm2835/bcm2835-1.50.tar.gz You can find the latest version at http://www.airspayce.com/mikem/bcm2835 - + Several example programs are provided. - - Based on data in http://elinux.org/RPi_Low-level_peripherals and + + Based on data in http://elinux.org/RPi_Low-level_peripherals and http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf and http://www.scribd.com/doc/101830961/GPIO-Pads-Control2 - + You can also find online help and discussion at http://groups.google.com/group/bcm2835 - Please use that group for all questions and discussions on this topic. + Please use that group for all questions and discussions on this topic. Do not contact the author directly, unless it is to discuss commercial licensing. Before asking a question or reporting a bug, please read http://www.catb.org/esr/faqs/smart-questions.html - + Tested on debian6-19-04-2012, 2012-07-15-wheezy-raspbian, 2013-07-26-wheezy-raspbian and Occidentalisv01, 2016-02-09 Raspbian Jessie. - CAUTION: it has been observed that when detect enables such as bcm2835_gpio_len() + CAUTION: it has been observed that when detect enables such as bcm2835_gpio_len() are used and the pin is pulled LOW it can cause temporary hangs on 2012-07-15-wheezy-raspbian, 2013-07-26-wheezy-raspbian and Occidentalisv01. Reason for this is not yet determined, but we suspect that an interrupt handler is hitting a hard loop on those OSs. - If you must use bcm2835_gpio_len() and friends, make sure you disable the pins with - bcm2835_gpio_clr_len() and friends after use. - + If you must use bcm2835_gpio_len() and friends, make sure you disable the pins with + bcm2835_gpio_clr_len() and friends after use. + \par Running as root Prior to the release of Raspbian Jessie in Feb 2016, access to any @@ -68,10 +68,10 @@ other non-gpio operations may fail silently or crash. \par Installation - + This library consists of a single non-shared library and header file, which will be installed in the usual places by make install - + \code # download the latest version of the library, say bcm2835-1.xx.tar.gz, then: tar zxvf bcm2835-1.xx.tar.gz @@ -81,22 +81,22 @@ sudo make check sudo make install \endcode - + \par Physical Addresses - - The functions bcm2835_peri_read(), bcm2835_peri_write() and bcm2835_peri_set_bits() + + The functions bcm2835_peri_read(), bcm2835_peri_write() and bcm2835_peri_set_bits() are low level peripheral register access functions. They are designed to use physical addresses as described in section 1.2.3 ARM physical addresses - of the BCM2835 ARM Peripherals manual. + of the BCM2835 ARM Peripherals manual. Physical addresses range from 0x20000000 to 0x20FFFFFF for peripherals. The bus addresses for peripherals are set up to map onto the peripheral bus address range starting at 0x7E000000. Thus a peripheral advertised in the manual at bus address 0x7Ennnnnn is available at physical address 0x20nnnnnn. - - On RPI 2, the peripheral addresses are different and the bcm2835 library gets them + + On RPI 2, the peripheral addresses are different and the bcm2835 library gets them from reading /proc/device-tree/soc/ranges. This is only availble with recent versions of the kernel on RPI 2. - - After initialisation, the base address of the various peripheral + + After initialisation, the base address of the various peripheral registers are available with the following externals: bcm2835_gpio @@ -114,8 +114,8 @@ You should also ensure you are using the latest version of Linux. The library has been tested on RPI2 with 2015-02-16-raspbian-wheezy and ArchLinuxARM-rpi-2 as of 2015-03-29. - When device tree suport is enabled, the file /proc/device-tree/soc/ranges will appear in the file system, - and the bcm2835 module relies on its presence to correctly run on RPI2 (it is optional for RPI1). + When device tree suport is enabled, the file /proc/device-tree/soc/ranges will appear in the file system, + and the bcm2835 module relies on its presence to correctly run on RPI2 (it is optional for RPI1). Without device tree support enabled and the presence of this file, it will not work on RPI2. To enable device tree support: @@ -125,59 +125,59 @@ under Advanced Options - enable Device Tree Reboot. \endcode - + \par Pin Numbering - - The GPIO pin numbering as used by RPi is different to and inconsistent with the underlying + + The GPIO pin numbering as used by RPi is different to and inconsistent with the underlying BCM 2835 chip pin numbering. http://elinux.org/RPi_BCM2835_GPIOs - + RPi has a 26 pin IDE header that provides access to some of the GPIO pins on the BCM 2835, - as well as power and ground pins. Not all GPIO pins on the BCM 2835 are available on the + as well as power and ground pins. Not all GPIO pins on the BCM 2835 are available on the IDE header. - + RPi Version 2 also has a P5 connector with 4 GPIO pins, 5V, 3.3V and Gnd. - - The functions in this library are designed to be passed the BCM 2835 GPIO pin number and _not_ + + The functions in this library are designed to be passed the BCM 2835 GPIO pin number and _not_ the RPi pin number. There are symbolic definitions for each of the available pins that you should use for convenience. See \ref RPiGPIOPin. - + \par SPI Pins - - The bcm2835_spi_* functions allow you to control the BCM 2835 SPI0 interface, + + The bcm2835_spi_* functions allow you to control the BCM 2835 SPI0 interface, allowing you to send and received data by SPI (Serial Peripheral Interface). For more information about SPI, see http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus - - When bcm2835_spi_begin() is called it changes the bahaviour of the SPI interface pins from their - default GPIO behaviour in order to support SPI. While SPI is in use, you will not be able + + When bcm2835_spi_begin() is called it changes the bahaviour of the SPI interface pins from their + default GPIO behaviour in order to support SPI. While SPI is in use, you will not be able to control the state of the SPI pins through the usual bcm2835_spi_gpio_write(). When bcm2835_spi_end() is called, the SPI pins will all revert to inputs, and can then be configured and controled with the usual bcm2835_gpio_* calls. - + The Raspberry Pi GPIO pins used for SPI are: - + - P1-19 (MOSI) - - P1-21 (MISO) - - P1-23 (CLK) - - P1-24 (CE0) + - P1-21 (MISO) + - P1-23 (CLK) + - P1-24 (CE0) - P1-26 (CE1) - + \par I2C Pins - + The bcm2835_i2c_* functions allow you to control the BCM 2835 BSC interface, allowing you to send and received data by I2C ("eye-squared cee"; generically referred to as "two-wire interface") . For more information about I?C, see http://en.wikipedia.org/wiki/I%C2%B2C - + The Raspberry Pi V2 GPIO pins used for I2C are: - + - P1-03 (SDA) - P1-05 (SLC) - + \par PWM - - The BCM2835 supports hardware PWM on a limited subset of GPIO pins. This bcm2835 library provides + + The BCM2835 supports hardware PWM on a limited subset of GPIO pins. This bcm2835 library provides functions for configuring and controlling PWM output on these pins. - - The BCM2835 contains 2 independent PWM channels (0 and 1), each of which be connnected to a limited subset of + + The BCM2835 contains 2 independent PWM channels (0 and 1), each of which be connnected to a limited subset of GPIO pins. The following GPIO pins may be connected to the following PWM channels (from section 9.5): \code GPIO PIN RPi pin PWM Channel ALT FUN @@ -195,27 +195,27 @@ Note carefully that current versions of the Raspberry Pi only expose one of these pins (GPIO 18 = RPi Pin 1-12) on the IO headers, and therefore this is the only IO pin on the RPi that can be used for PWM. Further it must be set to ALT FUN 5 to get PWM output. - - Both PWM channels are driven by the same PWM clock, whose clock dvider can be varied using + + Both PWM channels are driven by the same PWM clock, whose clock dvider can be varied using bcm2835_pwm_set_clock(). Each channel can be separately enabled with bcm2835_pwm_set_mode(). The average output of the PWM channel is determined by the ratio of DATA/RANGE for that channel. Use bcm2835_pwm_set_range() to set the range and bcm2835_pwm_set_data() to set the data in that ratio - - Each PWM channel can run in either Balanced or Mark-Space mode. In Balanced mode, the hardware + + Each PWM channel can run in either Balanced or Mark-Space mode. In Balanced mode, the hardware sends a combination of clock pulses that results in an overall DATA pulses per RANGE pulses. - In Mark-Space mode, the hardware sets the output HIGH for DATA clock pulses wide, followed by - LOW for RANGE-DATA clock pulses. - - The PWM clock can be set to control the PWM pulse widths. The PWM clock is derived from + In Mark-Space mode, the hardware sets the output HIGH for DATA clock pulses wide, followed by + LOW for RANGE-DATA clock pulses. + + The PWM clock can be set to control the PWM pulse widths. The PWM clock is derived from a 19.2MHz clock. You can set any divider, but some common ones are provided by the BCM2835_PWM_CLOCK_DIVIDER_* values of \ref bcm2835PWMClockDivider. - - For example, say you wanted to drive a DC motor with PWM at about 1kHz, - and control the speed in 1/1024 increments from - 0/1024 (stopped) through to 1024/1024 (full on). In that case you might set the + + For example, say you wanted to drive a DC motor with PWM at about 1kHz, + and control the speed in 1/1024 increments from + 0/1024 (stopped) through to 1024/1024 (full on). In that case you might set the clock divider to be 16, and the RANGE to 1024. The pulse repetition frequency will be 1.2MHz/1024 = 1171.875Hz. - + \par SPI In order for bcm2835 library SPI to work, you may need to disable the SPI kernel module using: @@ -228,18 +228,18 @@ \endcode \par Real Time performance constraints - - The bcm2835 is a library for user programs (i.e. they run in 'userland'). + + The bcm2835 is a library for user programs (i.e. they run in 'userland'). Such programs are not part of the kernel and are usually - subject to paging and swapping by the kernel while it does other things besides running your program. - This means that you should not expect to get real-time performance or - real-time timing constraints from such programs. In particular, there is no guarantee that the - bcm2835_delay() and bcm2835_delayMicroseconds() will return after exactly the time requested. + subject to paging and swapping by the kernel while it does other things besides running your program. + This means that you should not expect to get real-time performance or + real-time timing constraints from such programs. In particular, there is no guarantee that the + bcm2835_delay() and bcm2835_delayMicroseconds() will return after exactly the time requested. In fact, depending on other activity on the host, IO etc, you might get significantly longer delay times than the one you asked for. So please dont expect to get exactly the time delay you request. - + Arjan reports that you can prevent swapping on Linux with the following code fragment: - + \code struct sched_param sp; memset(&sp, 0, sizeof(sp)); @@ -247,34 +247,34 @@ sched_setscheduler(0, SCHED_FIFO, &sp); mlockall(MCL_CURRENT | MCL_FUTURE); \endcode - + \par Bindings to other languages - + mikem has made Perl bindings available at CPAN: http://search.cpan.org/~mikem/Device-BCM2835-1.9/lib/Device/BCM2835.pm Matthew Baker has kindly made Python bindings available at: https: github.com/mubeta06/py-libbcm2835 - Gary Marks has created a Serial Peripheral Interface (SPI) command-line utility - for Raspberry Pi, based on the bcm2835 library. The - utility, spincl, is licensed under Open Source GNU GPLv3 by iP Solutions (http://ipsolutionscorp.com), as a + Gary Marks has created a Serial Peripheral Interface (SPI) command-line utility + for Raspberry Pi, based on the bcm2835 library. The + utility, spincl, is licensed under Open Source GNU GPLv3 by iP Solutions (http://ipsolutionscorp.com), as a free download with source included: http://ipsolutionscorp.com/raspberry-pi-spi-utility/ - + \par Open Source Licensing GPL V2 - + This is the appropriate option if you want to share the source code of your application with everyone you distribute it to, and you also want to give them the right to share who uses it. If you wish to use this software under Open Source Licensing, you must contribute all your source code to the open source community in accordance with the GPL Version 2 when your application is distributed. See http://www.gnu.org/copyleft/gpl.html and COPYING - + \par Acknowledgements - + Some of this code has been inspired by Dom and Gert. The I2C code has been inspired by Alan Barr. - + \par Revision History - + \version 1.0 Initial release \version 1.1 Minor bug fixes @@ -289,18 +289,18 @@ \version 1.6 Document testing on 2012-07-15-wheezy-raspbian and Occidentalisv01 Functions bcm2835_gpio_ren(), bcm2835_gpio_fen(), bcm2835_gpio_hen() - bcm2835_gpio_len(), bcm2835_gpio_aren() and bcm2835_gpio_afen() now + bcm2835_gpio_len(), bcm2835_gpio_aren() and bcm2835_gpio_afen() now changes only the pin specified. Other pins that were already previously enabled stay enabled. Added bcm2835_gpio_clr_ren(), bcm2835_gpio_clr_fen(), bcm2835_gpio_clr_hen() - bcm2835_gpio_clr_len(), bcm2835_gpio_clr_aren(), bcm2835_gpio_clr_afen() + bcm2835_gpio_clr_len(), bcm2835_gpio_clr_aren(), bcm2835_gpio_clr_afen() to clear the enable for individual pins, suggested by Andreas Sundstrom. \version 1.7 Added bcm2835_spi_transfernb to support different buffers for read and write. \version 1.8 Improvements to read barrier, as suggested by maddin. - \version 1.9 Improvements contributed by mikew: + \version 1.9 Improvements contributed by mikew: I noticed that it was mallocing memory for the mmaps on /dev/mem. It's not necessary to do that, you can just mmap the file directly, so I've removed the mallocs (and frees). @@ -315,7 +315,7 @@ Also added a define for the passwrd value that Gert says is needed to change pad control settings. - \version 1.10 Changed the names of the delay functions to bcm2835_delay() + \version 1.10 Changed the names of the delay functions to bcm2835_delay() and bcm2835_delayMicroseconds() to prevent collisions with wiringPi. Macros to map delay()-> bcm2835_delay() and Macros to map delayMicroseconds()-> bcm2835_delayMicroseconds(), which @@ -323,14 +323,14 @@ \version 1.11 Fixed incorrect link to download file - \version 1.12 New GPIO pin definitions for RPi version 2 (which has a different GPIO mapping) + \version 1.12 New GPIO pin definitions for RPi version 2 (which has a different GPIO mapping) \version 1.13 New GPIO pin definitions for RPi version 2 plug P5 Hardware base pointers are now available (after initialisation) externally as bcm2835_gpio bcm2835_pwm bcm2835_clk bcm2835_pads bcm2835_spi0. \version 1.14 Now compiles even if CLOCK_MONOTONIC_RAW is not available, uses CLOCK_MONOTONIC instead. - Fixed errors in documentation of SPI divider frequencies based on 250MHz clock. + Fixed errors in documentation of SPI divider frequencies based on 250MHz clock. Reported by Ben Simpson. \version 1.15 Added bcm2835_close() to end of examples as suggested by Mark Wolfe. @@ -340,30 +340,30 @@ \version 1.17 Added bcm2835_gpio_write_mask. Requested by Sebastian Loncar. - \version 1.18 Added bcm2835_i2c_* functions. Changes to bcm2835_delayMicroseconds: - now uses the RPi system timer counter, instead of clock_gettime, for improved accuracy. + \version 1.18 Added bcm2835_i2c_* functions. Changes to bcm2835_delayMicroseconds: + now uses the RPi system timer counter, instead of clock_gettime, for improved accuracy. No need to link with -lrt now. Contributed by Arjan van Vught. - \version 1.19 Removed inlines added by previous patch since they don't seem to work everywhere. + \version 1.19 Removed inlines added by previous patch since they don't seem to work everywhere. Reported by olly. \version 1.20 Patch from Mark Dootson to close /dev/mem after access to the peripherals has been granted. - \version 1.21 delayMicroseconds is now not susceptible to 32 bit timer overruns. + \version 1.21 delayMicroseconds is now not susceptible to 32 bit timer overruns. Patch courtesy Jeremy Mortis. - \version 1.22 Fixed incorrect definition of BCM2835_GPFEN0 which broke the ability to set + \version 1.22 Fixed incorrect definition of BCM2835_GPFEN0 which broke the ability to set falling edge events. Reported by Mark Dootson. - \version 1.23 Added bcm2835_i2c_set_baudrate and bcm2835_i2c_read_register_rs. + \version 1.23 Added bcm2835_i2c_set_baudrate and bcm2835_i2c_read_register_rs. Improvements to bcm2835_i2c_read and bcm2835_i2c_write functions to fix ocasional reads not completing. Patched by Mark Dootson. \version 1.24 Mark Dootson p[atched a problem with his previously submitted code - under high load from other processes. + under high load from other processes. \version 1.25 Updated author and distribution location details to airspayce.com - \version 1.26 Added missing unmapmem for pads in bcm2835_close to prevent a memory leak. + \version 1.26 Added missing unmapmem for pads in bcm2835_close to prevent a memory leak. Reported by Hartmut Henkel. \version 1.27 bcm2835_gpio_set_pad() no longer needs BCM2835_PAD_PASSWRD: it is @@ -380,13 +380,13 @@ \version 1.31 Fix a GCC warning about dummy variable, patched by Alan Watson. Thanks. - \version 1.32 Added option I2C_V1 definition to compile for version 1 RPi. + \version 1.32 Added option I2C_V1 definition to compile for version 1 RPi. By default I2C code is generated for the V2 RPi which has SDA1 and SCL1 connected. Contributed by Malcolm Wiles based on work by Arvi Govindaraj. \version 1.33 Added command line utilities i2c and gpio to examples. Contributed by Shahrooz Shahparnia. - \version 1.34 Added bcm2835_i2c_write_read_rs() which writes an arbitrary number of bytes, + \version 1.34 Added bcm2835_i2c_write_read_rs() which writes an arbitrary number of bytes, sends a repeat start, and reads from the device. Contributed by Eduardo Steinhorst. \version 1.35 Fix build errors when compiled under Qt. Also performance improvements with SPI transfers. Contributed b Udo Klaas. @@ -401,7 +401,7 @@ \version 1.38 Added bcm2835_regbase for the benefit of C# wrappers, patch by Frank Hommers
- \version 1.39 Beta version of RPi2 compatibility. Not tested here on RPi2 hardware. + \version 1.39 Beta version of RPi2 compatibility. Not tested here on RPi2 hardware. Testers please confirm correct operation on RPi2.
Unneccessary 'volatile' qualifiers removed from all variables and signatures.
Removed unsupportable PWM dividers, based on a report from Christophe Cecillon.
@@ -413,21 +413,21 @@ Reported by tlhackque.
Fixed a problem where calling bcm2835_delayMicroseconds loops forever when debug is set. Reported by tlhackque.
Reinstated use of volatile in 2 functions where there was a danger of lost reads or writes. Reported by tlhackque.
- + \version 1.41 Added BCM2835_VERSION macro and new function bcm2835_version(); Requested by tlhackque.
Improvements to peripheral memory barriers as suggested by tlhackque.
Reinstated some necessary volatile declarations as requested by tlhackque.
\version 1.42 Further improvements to memory barriers with the patient assistance and patches of tlhackque.
- \version 1.43 Fixed problems with compiling barriers on RPI 2 with Arch Linux and gcc 4.9.2. + \version 1.43 Fixed problems with compiling barriers on RPI 2 with Arch Linux and gcc 4.9.2. Reported and patched by Lars Christensen.
Testing on RPI 2, with ArchLinuxARM-rpi-2-latest and 2015-02-16-raspbian-wheezy.
\version 1.44 Added documention about the need for device tree to be enabled on RPI2.
Improvements to detection of availablity of DMB instruction based on value of __ARM_ARCH macro.
- \version 1.45 Fixed an error in the pad group offsets that would prevent bcm2835_gpio_set_pad() + \version 1.45 Fixed an error in the pad group offsets that would prevent bcm2835_gpio_set_pad() and bcm2835_gpio_pad() working correctly with non-0 pad groups. Reported by Guido. \version 1.46 2015-09-18 @@ -445,8 +445,8 @@ \version 1.50 2016-02-28 Added support for running as non-root, permitting access to GPIO only. Functions - bcm2835_spi_begin() and bcm2835_i2c_begin() will now return 0 if not running as root - (which prevents access to the SPI and I2C peripherals, amongst others). + bcm2835_spi_begin() and bcm2835_i2c_begin() will now return 0 if not running as root + (which prevents access to the SPI and I2C peripherals, amongst others). Testing on Raspbian Jessie. \author Mike McCauley (mikem@airspayce.com) DO NOT CONTACT THE AUTHOR DIRECTLY: USE THE LISTS @@ -577,16 +577,15 @@ extern volatile uint32_t *bcm2835_bsc1; /*! \brief bcm2835RegisterBase Register bases for bcm2835_regbase() */ -typedef enum -{ - BCM2835_REGBASE_ST = 1, /*!< Base of the ST (System Timer) registers. */ - BCM2835_REGBASE_GPIO = 2, /*!< Base of the GPIO registers. */ - BCM2835_REGBASE_PWM = 3, /*!< Base of the PWM registers. */ - BCM2835_REGBASE_CLK = 4, /*!< Base of the CLK registers. */ - BCM2835_REGBASE_PADS = 5, /*!< Base of the PADS registers. */ - BCM2835_REGBASE_SPI0 = 6, /*!< Base of the SPI0 registers. */ - BCM2835_REGBASE_BSC0 = 7, /*!< Base of the BSC0 registers. */ - BCM2835_REGBASE_BSC1 = 8 /*!< Base of the BSC1 registers. */ +typedef enum { + BCM2835_REGBASE_ST = 1, /*!< Base of the ST (System Timer) registers. */ + BCM2835_REGBASE_GPIO = 2, /*!< Base of the GPIO registers. */ + BCM2835_REGBASE_PWM = 3, /*!< Base of the PWM registers. */ + BCM2835_REGBASE_CLK = 4, /*!< Base of the CLK registers. */ + BCM2835_REGBASE_PADS = 5, /*!< Base of the PADS registers. */ + BCM2835_REGBASE_SPI0 = 6, /*!< Base of the SPI0 registers. */ + BCM2835_REGBASE_BSC0 = 7, /*!< Base of the BSC0 registers. */ + BCM2835_REGBASE_BSC1 = 8 /*!< Base of the BSC1 registers. */ } bcm2835RegisterBase; /*! Size of memory page on RPi */ @@ -599,8 +598,8 @@ typedef enum The BCM2835 has 54 GPIO pins. BCM2835 data sheet, Page 90 onwards. */ -/*! GPIO register offsets from BCM2835_GPIO_BASE. - Offsets into the GPIO Peripheral block in bytes per 6.1 Register View +/*! GPIO register offsets from BCM2835_GPIO_BASE. + Offsets into the GPIO Peripheral block in bytes per 6.1 Register View */ #define BCM2835_GPFSEL0 0x0000 /*!< GPIO Function Select 0 */ #define BCM2835_GPFSEL1 0x0004 /*!< GPIO Function Select 1 */ @@ -635,27 +634,25 @@ typedef enum /*! \brief bcm2835PortFunction Port function select modes for bcm2835_gpio_fsel() */ -typedef enum -{ - BCM2835_GPIO_FSEL_INPT = 0x00, /*!< Input 0b000 */ - BCM2835_GPIO_FSEL_OUTP = 0x01, /*!< Output 0b001 */ - BCM2835_GPIO_FSEL_ALT0 = 0x04, /*!< Alternate function 0 0b100 */ - BCM2835_GPIO_FSEL_ALT1 = 0x05, /*!< Alternate function 1 0b101 */ - BCM2835_GPIO_FSEL_ALT2 = 0x06, /*!< Alternate function 2 0b110, */ - BCM2835_GPIO_FSEL_ALT3 = 0x07, /*!< Alternate function 3 0b111 */ - BCM2835_GPIO_FSEL_ALT4 = 0x03, /*!< Alternate function 4 0b011 */ - BCM2835_GPIO_FSEL_ALT5 = 0x02, /*!< Alternate function 5 0b010 */ - BCM2835_GPIO_FSEL_MASK = 0x07 /*!< Function select bits mask 0b111 */ +typedef enum { + BCM2835_GPIO_FSEL_INPT = 0x00, /*!< Input 0b000 */ + BCM2835_GPIO_FSEL_OUTP = 0x01, /*!< Output 0b001 */ + BCM2835_GPIO_FSEL_ALT0 = 0x04, /*!< Alternate function 0 0b100 */ + BCM2835_GPIO_FSEL_ALT1 = 0x05, /*!< Alternate function 1 0b101 */ + BCM2835_GPIO_FSEL_ALT2 = 0x06, /*!< Alternate function 2 0b110, */ + BCM2835_GPIO_FSEL_ALT3 = 0x07, /*!< Alternate function 3 0b111 */ + BCM2835_GPIO_FSEL_ALT4 = 0x03, /*!< Alternate function 4 0b011 */ + BCM2835_GPIO_FSEL_ALT5 = 0x02, /*!< Alternate function 5 0b010 */ + BCM2835_GPIO_FSEL_MASK = 0x07 /*!< Function select bits mask 0b111 */ } bcm2835FunctionSelect; /*! \brief bcm2835PUDControl Pullup/Pulldown defines for bcm2835_gpio_pud() */ -typedef enum -{ - BCM2835_GPIO_PUD_OFF = 0x00, /*!< Off ? disable pull-up/down 0b00 */ - BCM2835_GPIO_PUD_DOWN = 0x01, /*!< Enable Pull Down control 0b01 */ - BCM2835_GPIO_PUD_UP = 0x02 /*!< Enable Pull Up control 0b10 */ +typedef enum { + BCM2835_GPIO_PUD_OFF = 0x00, /*!< Off ? disable pull-up/down 0b00 */ + BCM2835_GPIO_PUD_DOWN = 0x01, /*!< Enable Pull Down control 0b01 */ + BCM2835_GPIO_PUD_UP = 0x02 /*!< Enable Pull Up control 0b10 */ } bcm2835PUDControl; /*! Pad control register offsets from BCM2835_GPIO_PADS */ @@ -679,15 +676,14 @@ typedef enum /*! \brief bcm2835PadGroup Pad group specification for bcm2835_gpio_pad() */ -typedef enum -{ - BCM2835_PAD_GROUP_GPIO_0_27 = 0, /*!< Pad group for GPIO pads 0 to 27 */ - BCM2835_PAD_GROUP_GPIO_28_45 = 1, /*!< Pad group for GPIO pads 28 to 45 */ - BCM2835_PAD_GROUP_GPIO_46_53 = 2 /*!< Pad group for GPIO pads 46 to 53 */ +typedef enum { + BCM2835_PAD_GROUP_GPIO_0_27 = 0, /*!< Pad group for GPIO pads 0 to 27 */ + BCM2835_PAD_GROUP_GPIO_28_45 = 1, /*!< Pad group for GPIO pads 28 to 45 */ + BCM2835_PAD_GROUP_GPIO_46_53 = 2 /*!< Pad group for GPIO pads 46 to 53 */ } bcm2835PadGroup; /*! \brief GPIO Pin Numbers - + Here we define Raspberry Pin GPIO pins on P1 in terms of the underlying BCM GPIO pin numbers. These can be passed as a pin number to any function requiring a pin. Not all pins on the RPi 26 bin IDE plug are connected to GPIO pins @@ -700,91 +696,90 @@ typedef enum If you are using the RPi Compute Module, just use the GPIO number: there is no need to use one of these symbolic names */ -typedef enum -{ - RPI_GPIO_P1_03 = 0, /*!< Version 1, Pin P1-03 */ - RPI_GPIO_P1_05 = 1, /*!< Version 1, Pin P1-05 */ - RPI_GPIO_P1_07 = 4, /*!< Version 1, Pin P1-07 */ - RPI_GPIO_P1_08 = 14, /*!< Version 1, Pin P1-08, defaults to alt function 0 UART0_TXD */ - RPI_GPIO_P1_10 = 15, /*!< Version 1, Pin P1-10, defaults to alt function 0 UART0_RXD */ - RPI_GPIO_P1_11 = 17, /*!< Version 1, Pin P1-11 */ - RPI_GPIO_P1_12 = 18, /*!< Version 1, Pin P1-12, can be PWM channel 0 in ALT FUN 5 */ - RPI_GPIO_P1_13 = 21, /*!< Version 1, Pin P1-13 */ - RPI_GPIO_P1_15 = 22, /*!< Version 1, Pin P1-15 */ - RPI_GPIO_P1_16 = 23, /*!< Version 1, Pin P1-16 */ - RPI_GPIO_P1_18 = 24, /*!< Version 1, Pin P1-18 */ - RPI_GPIO_P1_19 = 10, /*!< Version 1, Pin P1-19, MOSI when SPI0 in use */ - RPI_GPIO_P1_21 = 9, /*!< Version 1, Pin P1-21, MISO when SPI0 in use */ - RPI_GPIO_P1_22 = 25, /*!< Version 1, Pin P1-22 */ - RPI_GPIO_P1_23 = 11, /*!< Version 1, Pin P1-23, CLK when SPI0 in use */ - RPI_GPIO_P1_24 = 8, /*!< Version 1, Pin P1-24, CE0 when SPI0 in use */ - RPI_GPIO_P1_26 = 7, /*!< Version 1, Pin P1-26, CE1 when SPI0 in use */ - - /* RPi Version 2 */ - RPI_V2_GPIO_P1_03 = 2, /*!< Version 2, Pin P1-03 */ - RPI_V2_GPIO_P1_05 = 3, /*!< Version 2, Pin P1-05 */ - RPI_V2_GPIO_P1_07 = 4, /*!< Version 2, Pin P1-07 */ - RPI_V2_GPIO_P1_08 = 14, /*!< Version 2, Pin P1-08, defaults to alt function 0 UART0_TXD */ - RPI_V2_GPIO_P1_10 = 15, /*!< Version 2, Pin P1-10, defaults to alt function 0 UART0_RXD */ - RPI_V2_GPIO_P1_11 = 17, /*!< Version 2, Pin P1-11 */ - RPI_V2_GPIO_P1_12 = 18, /*!< Version 2, Pin P1-12, can be PWM channel 0 in ALT FUN 5 */ - RPI_V2_GPIO_P1_13 = 27, /*!< Version 2, Pin P1-13 */ - RPI_V2_GPIO_P1_15 = 22, /*!< Version 2, Pin P1-15 */ - RPI_V2_GPIO_P1_16 = 23, /*!< Version 2, Pin P1-16 */ - RPI_V2_GPIO_P1_18 = 24, /*!< Version 2, Pin P1-18 */ - RPI_V2_GPIO_P1_19 = 10, /*!< Version 2, Pin P1-19, MOSI when SPI0 in use */ - RPI_V2_GPIO_P1_21 = 9, /*!< Version 2, Pin P1-21, MISO when SPI0 in use */ - RPI_V2_GPIO_P1_22 = 25, /*!< Version 2, Pin P1-22 */ - RPI_V2_GPIO_P1_23 = 11, /*!< Version 2, Pin P1-23, CLK when SPI0 in use */ - RPI_V2_GPIO_P1_24 = 8, /*!< Version 2, Pin P1-24, CE0 when SPI0 in use */ - RPI_V2_GPIO_P1_26 = 7, /*!< Version 2, Pin P1-26, CE1 when SPI0 in use */ - RPI_V2_GPIO_P1_29 = 5, /*!< Version 2, Pin P1-29 */ - RPI_V2_GPIO_P1_31 = 6, /*!< Version 2, Pin P1-31 */ - RPI_V2_GPIO_P1_32 = 12, /*!< Version 2, Pin P1-32 */ - RPI_V2_GPIO_P1_33 = 13, /*!< Version 2, Pin P1-33 */ - RPI_V2_GPIO_P1_35 = 19, /*!< Version 2, Pin P1-35 */ - RPI_V2_GPIO_P1_36 = 16, /*!< Version 2, Pin P1-36 */ - RPI_V2_GPIO_P1_37 = 26, /*!< Version 2, Pin P1-37 */ - RPI_V2_GPIO_P1_38 = 20, /*!< Version 2, Pin P1-38 */ - RPI_V2_GPIO_P1_40 = 21, /*!< Version 2, Pin P1-40 */ - - /* RPi Version 2, new plug P5 */ - RPI_V2_GPIO_P5_03 = 28, /*!< Version 2, Pin P5-03 */ - RPI_V2_GPIO_P5_04 = 29, /*!< Version 2, Pin P5-04 */ - RPI_V2_GPIO_P5_05 = 30, /*!< Version 2, Pin P5-05 */ - RPI_V2_GPIO_P5_06 = 31, /*!< Version 2, Pin P5-06 */ - - /* RPi B+ J8 header, also RPi 2 40 pin GPIO header */ - RPI_BPLUS_GPIO_J8_03 = 2, /*!< B+, Pin J8-03 */ - RPI_BPLUS_GPIO_J8_05 = 3, /*!< B+, Pin J8-05 */ - RPI_BPLUS_GPIO_J8_07 = 4, /*!< B+, Pin J8-07 */ - RPI_BPLUS_GPIO_J8_08 = 14, /*!< B+, Pin J8-08, defaults to alt function 0 UART0_TXD */ - RPI_BPLUS_GPIO_J8_10 = 15, /*!< B+, Pin J8-10, defaults to alt function 0 UART0_RXD */ - RPI_BPLUS_GPIO_J8_11 = 17, /*!< B+, Pin J8-11 */ - RPI_BPLUS_GPIO_J8_12 = 18, /*!< B+, Pin J8-12, can be PWM channel 0 in ALT FUN 5 */ - RPI_BPLUS_GPIO_J8_13 = 27, /*!< B+, Pin J8-13 */ - RPI_BPLUS_GPIO_J8_15 = 22, /*!< B+, Pin J8-15 */ - RPI_BPLUS_GPIO_J8_16 = 23, /*!< B+, Pin J8-16 */ - RPI_BPLUS_GPIO_J8_18 = 24, /*!< B+, Pin J8-18 */ - RPI_BPLUS_GPIO_J8_19 = 10, /*!< B+, Pin J8-19, MOSI when SPI0 in use */ - RPI_BPLUS_GPIO_J8_21 = 9, /*!< B+, Pin J8-21, MISO when SPI0 in use */ - RPI_BPLUS_GPIO_J8_22 = 25, /*!< B+, Pin J8-22 */ - RPI_BPLUS_GPIO_J8_23 = 11, /*!< B+, Pin J8-23, CLK when SPI0 in use */ - RPI_BPLUS_GPIO_J8_24 = 8, /*!< B+, Pin J8-24, CE0 when SPI0 in use */ - RPI_BPLUS_GPIO_J8_26 = 7, /*!< B+, Pin J8-26, CE1 when SPI0 in use */ - RPI_BPLUS_GPIO_J8_29 = 5, /*!< B+, Pin J8-29, */ - RPI_BPLUS_GPIO_J8_31 = 6, /*!< B+, Pin J8-31, */ - RPI_BPLUS_GPIO_J8_32 = 12, /*!< B+, Pin J8-32, */ - RPI_BPLUS_GPIO_J8_33 = 13, /*!< B+, Pin J8-33, */ - RPI_BPLUS_GPIO_J8_35 = 19, /*!< B+, Pin J8-35, */ - RPI_BPLUS_GPIO_J8_36 = 16, /*!< B+, Pin J8-36, */ - RPI_BPLUS_GPIO_J8_37 = 26, /*!< B+, Pin J8-37, */ - RPI_BPLUS_GPIO_J8_38 = 20, /*!< B+, Pin J8-38, */ - RPI_BPLUS_GPIO_J8_40 = 21 /*!< B+, Pin J8-40, */ +typedef enum { + RPI_GPIO_P1_03 = 0, /*!< Version 1, Pin P1-03 */ + RPI_GPIO_P1_05 = 1, /*!< Version 1, Pin P1-05 */ + RPI_GPIO_P1_07 = 4, /*!< Version 1, Pin P1-07 */ + RPI_GPIO_P1_08 = 14, /*!< Version 1, Pin P1-08, defaults to alt function 0 UART0_TXD */ + RPI_GPIO_P1_10 = 15, /*!< Version 1, Pin P1-10, defaults to alt function 0 UART0_RXD */ + RPI_GPIO_P1_11 = 17, /*!< Version 1, Pin P1-11 */ + RPI_GPIO_P1_12 = 18, /*!< Version 1, Pin P1-12, can be PWM channel 0 in ALT FUN 5 */ + RPI_GPIO_P1_13 = 21, /*!< Version 1, Pin P1-13 */ + RPI_GPIO_P1_15 = 22, /*!< Version 1, Pin P1-15 */ + RPI_GPIO_P1_16 = 23, /*!< Version 1, Pin P1-16 */ + RPI_GPIO_P1_18 = 24, /*!< Version 1, Pin P1-18 */ + RPI_GPIO_P1_19 = 10, /*!< Version 1, Pin P1-19, MOSI when SPI0 in use */ + RPI_GPIO_P1_21 = 9, /*!< Version 1, Pin P1-21, MISO when SPI0 in use */ + RPI_GPIO_P1_22 = 25, /*!< Version 1, Pin P1-22 */ + RPI_GPIO_P1_23 = 11, /*!< Version 1, Pin P1-23, CLK when SPI0 in use */ + RPI_GPIO_P1_24 = 8, /*!< Version 1, Pin P1-24, CE0 when SPI0 in use */ + RPI_GPIO_P1_26 = 7, /*!< Version 1, Pin P1-26, CE1 when SPI0 in use */ + + /* RPi Version 2 */ + RPI_V2_GPIO_P1_03 = 2, /*!< Version 2, Pin P1-03 */ + RPI_V2_GPIO_P1_05 = 3, /*!< Version 2, Pin P1-05 */ + RPI_V2_GPIO_P1_07 = 4, /*!< Version 2, Pin P1-07 */ + RPI_V2_GPIO_P1_08 = 14, /*!< Version 2, Pin P1-08, defaults to alt function 0 UART0_TXD */ + RPI_V2_GPIO_P1_10 = 15, /*!< Version 2, Pin P1-10, defaults to alt function 0 UART0_RXD */ + RPI_V2_GPIO_P1_11 = 17, /*!< Version 2, Pin P1-11 */ + RPI_V2_GPIO_P1_12 = 18, /*!< Version 2, Pin P1-12, can be PWM channel 0 in ALT FUN 5 */ + RPI_V2_GPIO_P1_13 = 27, /*!< Version 2, Pin P1-13 */ + RPI_V2_GPIO_P1_15 = 22, /*!< Version 2, Pin P1-15 */ + RPI_V2_GPIO_P1_16 = 23, /*!< Version 2, Pin P1-16 */ + RPI_V2_GPIO_P1_18 = 24, /*!< Version 2, Pin P1-18 */ + RPI_V2_GPIO_P1_19 = 10, /*!< Version 2, Pin P1-19, MOSI when SPI0 in use */ + RPI_V2_GPIO_P1_21 = 9, /*!< Version 2, Pin P1-21, MISO when SPI0 in use */ + RPI_V2_GPIO_P1_22 = 25, /*!< Version 2, Pin P1-22 */ + RPI_V2_GPIO_P1_23 = 11, /*!< Version 2, Pin P1-23, CLK when SPI0 in use */ + RPI_V2_GPIO_P1_24 = 8, /*!< Version 2, Pin P1-24, CE0 when SPI0 in use */ + RPI_V2_GPIO_P1_26 = 7, /*!< Version 2, Pin P1-26, CE1 when SPI0 in use */ + RPI_V2_GPIO_P1_29 = 5, /*!< Version 2, Pin P1-29 */ + RPI_V2_GPIO_P1_31 = 6, /*!< Version 2, Pin P1-31 */ + RPI_V2_GPIO_P1_32 = 12, /*!< Version 2, Pin P1-32 */ + RPI_V2_GPIO_P1_33 = 13, /*!< Version 2, Pin P1-33 */ + RPI_V2_GPIO_P1_35 = 19, /*!< Version 2, Pin P1-35 */ + RPI_V2_GPIO_P1_36 = 16, /*!< Version 2, Pin P1-36 */ + RPI_V2_GPIO_P1_37 = 26, /*!< Version 2, Pin P1-37 */ + RPI_V2_GPIO_P1_38 = 20, /*!< Version 2, Pin P1-38 */ + RPI_V2_GPIO_P1_40 = 21, /*!< Version 2, Pin P1-40 */ + + /* RPi Version 2, new plug P5 */ + RPI_V2_GPIO_P5_03 = 28, /*!< Version 2, Pin P5-03 */ + RPI_V2_GPIO_P5_04 = 29, /*!< Version 2, Pin P5-04 */ + RPI_V2_GPIO_P5_05 = 30, /*!< Version 2, Pin P5-05 */ + RPI_V2_GPIO_P5_06 = 31, /*!< Version 2, Pin P5-06 */ + + /* RPi B+ J8 header, also RPi 2 40 pin GPIO header */ + RPI_BPLUS_GPIO_J8_03 = 2, /*!< B+, Pin J8-03 */ + RPI_BPLUS_GPIO_J8_05 = 3, /*!< B+, Pin J8-05 */ + RPI_BPLUS_GPIO_J8_07 = 4, /*!< B+, Pin J8-07 */ + RPI_BPLUS_GPIO_J8_08 = 14, /*!< B+, Pin J8-08, defaults to alt function 0 UART0_TXD */ + RPI_BPLUS_GPIO_J8_10 = 15, /*!< B+, Pin J8-10, defaults to alt function 0 UART0_RXD */ + RPI_BPLUS_GPIO_J8_11 = 17, /*!< B+, Pin J8-11 */ + RPI_BPLUS_GPIO_J8_12 = 18, /*!< B+, Pin J8-12, can be PWM channel 0 in ALT FUN 5 */ + RPI_BPLUS_GPIO_J8_13 = 27, /*!< B+, Pin J8-13 */ + RPI_BPLUS_GPIO_J8_15 = 22, /*!< B+, Pin J8-15 */ + RPI_BPLUS_GPIO_J8_16 = 23, /*!< B+, Pin J8-16 */ + RPI_BPLUS_GPIO_J8_18 = 24, /*!< B+, Pin J8-18 */ + RPI_BPLUS_GPIO_J8_19 = 10, /*!< B+, Pin J8-19, MOSI when SPI0 in use */ + RPI_BPLUS_GPIO_J8_21 = 9, /*!< B+, Pin J8-21, MISO when SPI0 in use */ + RPI_BPLUS_GPIO_J8_22 = 25, /*!< B+, Pin J8-22 */ + RPI_BPLUS_GPIO_J8_23 = 11, /*!< B+, Pin J8-23, CLK when SPI0 in use */ + RPI_BPLUS_GPIO_J8_24 = 8, /*!< B+, Pin J8-24, CE0 when SPI0 in use */ + RPI_BPLUS_GPIO_J8_26 = 7, /*!< B+, Pin J8-26, CE1 when SPI0 in use */ + RPI_BPLUS_GPIO_J8_29 = 5, /*!< B+, Pin J8-29, */ + RPI_BPLUS_GPIO_J8_31 = 6, /*!< B+, Pin J8-31, */ + RPI_BPLUS_GPIO_J8_32 = 12, /*!< B+, Pin J8-32, */ + RPI_BPLUS_GPIO_J8_33 = 13, /*!< B+, Pin J8-33, */ + RPI_BPLUS_GPIO_J8_35 = 19, /*!< B+, Pin J8-35, */ + RPI_BPLUS_GPIO_J8_36 = 16, /*!< B+, Pin J8-36, */ + RPI_BPLUS_GPIO_J8_37 = 26, /*!< B+, Pin J8-37, */ + RPI_BPLUS_GPIO_J8_38 = 20, /*!< B+, Pin J8-38, */ + RPI_BPLUS_GPIO_J8_40 = 21 /*!< B+, Pin J8-40, */ } RPiGPIOPin; /* Defines for SPI - GPIO register offsets from BCM2835_SPI0_BASE. + GPIO register offsets from BCM2835_SPI0_BASE. Offsets into the SPI Peripheral block in bytes per 10.5 SPI Register Map */ #define BCM2835_SPI0_CS 0x0000 /*!< SPI Master Control and Status */ @@ -825,32 +820,29 @@ typedef enum /*! \brief bcm2835SPIBitOrder SPI Bit order Specifies the SPI data bit ordering for bcm2835_spi_setBitOrder() */ -typedef enum -{ - BCM2835_SPI_BIT_ORDER_LSBFIRST = 0, /*!< LSB First */ - BCM2835_SPI_BIT_ORDER_MSBFIRST = 1 /*!< MSB First */ -}bcm2835SPIBitOrder; +typedef enum { + BCM2835_SPI_BIT_ORDER_LSBFIRST = 0, /*!< LSB First */ + BCM2835_SPI_BIT_ORDER_MSBFIRST = 1 /*!< MSB First */ +} bcm2835SPIBitOrder; /*! \brief SPI Data mode Specify the SPI data mode to be passed to bcm2835_spi_setDataMode() */ -typedef enum -{ - BCM2835_SPI_MODE0 = 0, /*!< CPOL = 0, CPHA = 0 */ - BCM2835_SPI_MODE1 = 1, /*!< CPOL = 0, CPHA = 1 */ - BCM2835_SPI_MODE2 = 2, /*!< CPOL = 1, CPHA = 0 */ - BCM2835_SPI_MODE3 = 3 /*!< CPOL = 1, CPHA = 1 */ -}bcm2835SPIMode; +typedef enum { + BCM2835_SPI_MODE0 = 0, /*!< CPOL = 0, CPHA = 0 */ + BCM2835_SPI_MODE1 = 1, /*!< CPOL = 0, CPHA = 1 */ + BCM2835_SPI_MODE2 = 2, /*!< CPOL = 1, CPHA = 0 */ + BCM2835_SPI_MODE3 = 3 /*!< CPOL = 1, CPHA = 1 */ +} bcm2835SPIMode; /*! \brief bcm2835SPIChipSelect Specify the SPI chip select pin(s) */ -typedef enum -{ - BCM2835_SPI_CS0 = 0, /*!< Chip Select 0 */ - BCM2835_SPI_CS1 = 1, /*!< Chip Select 1 */ - BCM2835_SPI_CS2 = 2, /*!< Chip Select 2 (ie pins CS1 and CS2 are asserted) */ - BCM2835_SPI_CS_NONE = 3 /*!< No CS, control it yourself */ +typedef enum { + BCM2835_SPI_CS0 = 0, /*!< Chip Select 0 */ + BCM2835_SPI_CS1 = 1, /*!< Chip Select 1 */ + BCM2835_SPI_CS2 = 2, /*!< Chip Select 2 (ie pins CS1 and CS2 are asserted) */ + BCM2835_SPI_CS_NONE = 3 /*!< No CS, control it yourself */ } bcm2835SPIChipSelect; /*! \brief bcm2835SPIClockDivider @@ -860,25 +852,24 @@ typedef enum It is reported that (contrary to the documentation) any even divider may used. The frequencies shown for each divider have been confirmed by measurement. */ -typedef enum -{ - BCM2835_SPI_CLOCK_DIVIDER_65536 = 0, /*!< 65536 = 262.144us = 3.814697260kHz */ - BCM2835_SPI_CLOCK_DIVIDER_32768 = 32768, /*!< 32768 = 131.072us = 7.629394531kHz */ - BCM2835_SPI_CLOCK_DIVIDER_16384 = 16384, /*!< 16384 = 65.536us = 15.25878906kHz */ - BCM2835_SPI_CLOCK_DIVIDER_8192 = 8192, /*!< 8192 = 32.768us = 30/51757813kHz */ - BCM2835_SPI_CLOCK_DIVIDER_4096 = 4096, /*!< 4096 = 16.384us = 61.03515625kHz */ - BCM2835_SPI_CLOCK_DIVIDER_2048 = 2048, /*!< 2048 = 8.192us = 122.0703125kHz */ - BCM2835_SPI_CLOCK_DIVIDER_1024 = 1024, /*!< 1024 = 4.096us = 244.140625kHz */ - BCM2835_SPI_CLOCK_DIVIDER_512 = 512, /*!< 512 = 2.048us = 488.28125kHz */ - BCM2835_SPI_CLOCK_DIVIDER_256 = 256, /*!< 256 = 1.024us = 976.5625kHz */ - BCM2835_SPI_CLOCK_DIVIDER_128 = 128, /*!< 128 = 512ns = = 1.953125MHz */ - BCM2835_SPI_CLOCK_DIVIDER_64 = 64, /*!< 64 = 256ns = 3.90625MHz */ - BCM2835_SPI_CLOCK_DIVIDER_32 = 32, /*!< 32 = 128ns = 7.8125MHz */ - BCM2835_SPI_CLOCK_DIVIDER_16 = 16, /*!< 16 = 64ns = 15.625MHz */ - BCM2835_SPI_CLOCK_DIVIDER_8 = 8, /*!< 8 = 32ns = 31.25MHz */ - BCM2835_SPI_CLOCK_DIVIDER_4 = 4, /*!< 4 = 16ns = 62.5MHz */ - BCM2835_SPI_CLOCK_DIVIDER_2 = 2, /*!< 2 = 8ns = 125MHz, fastest you can get */ - BCM2835_SPI_CLOCK_DIVIDER_1 = 1 /*!< 1 = 262.144us = 3.814697260kHz, same as 0/65536 */ +typedef enum { + BCM2835_SPI_CLOCK_DIVIDER_65536 = 0, /*!< 65536 = 262.144us = 3.814697260kHz */ + BCM2835_SPI_CLOCK_DIVIDER_32768 = 32768, /*!< 32768 = 131.072us = 7.629394531kHz */ + BCM2835_SPI_CLOCK_DIVIDER_16384 = 16384, /*!< 16384 = 65.536us = 15.25878906kHz */ + BCM2835_SPI_CLOCK_DIVIDER_8192 = 8192, /*!< 8192 = 32.768us = 30/51757813kHz */ + BCM2835_SPI_CLOCK_DIVIDER_4096 = 4096, /*!< 4096 = 16.384us = 61.03515625kHz */ + BCM2835_SPI_CLOCK_DIVIDER_2048 = 2048, /*!< 2048 = 8.192us = 122.0703125kHz */ + BCM2835_SPI_CLOCK_DIVIDER_1024 = 1024, /*!< 1024 = 4.096us = 244.140625kHz */ + BCM2835_SPI_CLOCK_DIVIDER_512 = 512, /*!< 512 = 2.048us = 488.28125kHz */ + BCM2835_SPI_CLOCK_DIVIDER_256 = 256, /*!< 256 = 1.024us = 976.5625kHz */ + BCM2835_SPI_CLOCK_DIVIDER_128 = 128, /*!< 128 = 512ns = = 1.953125MHz */ + BCM2835_SPI_CLOCK_DIVIDER_64 = 64, /*!< 64 = 256ns = 3.90625MHz */ + BCM2835_SPI_CLOCK_DIVIDER_32 = 32, /*!< 32 = 128ns = 7.8125MHz */ + BCM2835_SPI_CLOCK_DIVIDER_16 = 16, /*!< 16 = 64ns = 15.625MHz */ + BCM2835_SPI_CLOCK_DIVIDER_8 = 8, /*!< 8 = 32ns = 31.25MHz */ + BCM2835_SPI_CLOCK_DIVIDER_4 = 4, /*!< 4 = 16ns = 62.5MHz */ + BCM2835_SPI_CLOCK_DIVIDER_2 = 2, /*!< 2 = 8ns = 125MHz, fastest you can get */ + BCM2835_SPI_CLOCK_DIVIDER_1 = 1 /*!< 1 = 262.144us = 3.814697260kHz, same as 0/65536 */ } bcm2835SPIClockDivider; /* Defines for I2C @@ -922,23 +913,21 @@ typedef enum Specifies the divider used to generate the I2C clock from the system clock. Clock divided is based on nominal base clock rate of 250MHz */ -typedef enum -{ - BCM2835_I2C_CLOCK_DIVIDER_2500 = 2500, /*!< 2500 = 10us = 100 kHz */ - BCM2835_I2C_CLOCK_DIVIDER_626 = 626, /*!< 622 = 2.504us = 399.3610 kHz */ - BCM2835_I2C_CLOCK_DIVIDER_150 = 150, /*!< 150 = 60ns = 1.666 MHz (default at reset) */ - BCM2835_I2C_CLOCK_DIVIDER_148 = 148 /*!< 148 = 59ns = 1.689 MHz */ +typedef enum { + BCM2835_I2C_CLOCK_DIVIDER_2500 = 2500, /*!< 2500 = 10us = 100 kHz */ + BCM2835_I2C_CLOCK_DIVIDER_626 = 626, /*!< 622 = 2.504us = 399.3610 kHz */ + BCM2835_I2C_CLOCK_DIVIDER_150 = 150, /*!< 150 = 60ns = 1.666 MHz (default at reset) */ + BCM2835_I2C_CLOCK_DIVIDER_148 = 148 /*!< 148 = 59ns = 1.689 MHz */ } bcm2835I2CClockDivider; /*! \brief bcm2835I2CReasonCodes Specifies the reason codes for the bcm2835_i2c_write and bcm2835_i2c_read functions. */ -typedef enum -{ - BCM2835_I2C_REASON_OK = 0x00, /*!< Success */ - BCM2835_I2C_REASON_ERROR_NACK = 0x01, /*!< Received a NACK */ - BCM2835_I2C_REASON_ERROR_CLKT = 0x02, /*!< Received Clock Stretch Timeout */ - BCM2835_I2C_REASON_ERROR_DATA = 0x04 /*!< Not all data is sent / received */ +typedef enum { + BCM2835_I2C_REASON_OK = 0x00, /*!< Success */ + BCM2835_I2C_REASON_ERROR_NACK = 0x01, /*!< Received a NACK */ + BCM2835_I2C_REASON_ERROR_CLKT = 0x02, /*!< Received Clock Stretch Timeout */ + BCM2835_I2C_REASON_ERROR_DATA = 0x04 /*!< Not all data is sent / received */ } bcm2835I2CReasonCodes; /* Defines for ST @@ -994,20 +983,19 @@ typedef enum Clock divided is based on nominal PWM base clock rate of 19.2MHz The frequencies shown for each divider have been confirmed by measurement */ -typedef enum -{ - BCM2835_PWM_CLOCK_DIVIDER_2048 = 2048, /*!< 2048 = 9.375kHz */ - BCM2835_PWM_CLOCK_DIVIDER_1024 = 1024, /*!< 1024 = 18.75kHz */ - BCM2835_PWM_CLOCK_DIVIDER_512 = 512, /*!< 512 = 37.5kHz */ - BCM2835_PWM_CLOCK_DIVIDER_256 = 256, /*!< 256 = 75kHz */ - BCM2835_PWM_CLOCK_DIVIDER_128 = 128, /*!< 128 = 150kHz */ - BCM2835_PWM_CLOCK_DIVIDER_64 = 64, /*!< 64 = 300kHz */ - BCM2835_PWM_CLOCK_DIVIDER_32 = 32, /*!< 32 = 600.0kHz */ - BCM2835_PWM_CLOCK_DIVIDER_16 = 16, /*!< 16 = 1.2MHz */ - BCM2835_PWM_CLOCK_DIVIDER_8 = 8, /*!< 8 = 2.4MHz */ - BCM2835_PWM_CLOCK_DIVIDER_4 = 4, /*!< 4 = 4.8MHz */ - BCM2835_PWM_CLOCK_DIVIDER_2 = 2, /*!< 2 = 9.6MHz, fastest you can get */ - BCM2835_PWM_CLOCK_DIVIDER_1 = 1 /*!< 1 = 4.6875kHz, same as divider 4096 */ +typedef enum { + BCM2835_PWM_CLOCK_DIVIDER_2048 = 2048, /*!< 2048 = 9.375kHz */ + BCM2835_PWM_CLOCK_DIVIDER_1024 = 1024, /*!< 1024 = 18.75kHz */ + BCM2835_PWM_CLOCK_DIVIDER_512 = 512, /*!< 512 = 37.5kHz */ + BCM2835_PWM_CLOCK_DIVIDER_256 = 256, /*!< 256 = 75kHz */ + BCM2835_PWM_CLOCK_DIVIDER_128 = 128, /*!< 128 = 150kHz */ + BCM2835_PWM_CLOCK_DIVIDER_64 = 64, /*!< 64 = 300kHz */ + BCM2835_PWM_CLOCK_DIVIDER_32 = 32, /*!< 32 = 600.0kHz */ + BCM2835_PWM_CLOCK_DIVIDER_16 = 16, /*!< 16 = 1.2MHz */ + BCM2835_PWM_CLOCK_DIVIDER_8 = 8, /*!< 8 = 2.4MHz */ + BCM2835_PWM_CLOCK_DIVIDER_4 = 4, /*!< 4 = 4.8MHz */ + BCM2835_PWM_CLOCK_DIVIDER_2 = 2, /*!< 2 = 9.6MHz, fastest you can get */ + BCM2835_PWM_CLOCK_DIVIDER_1 = 1 /*!< 1 = 4.6875kHz, same as divider 4096 */ } bcm2835PWMClockDivider; /*! @} */ @@ -1022,625 +1010,626 @@ typedef enum extern "C" { #endif - /*! \defgroup BCM2835initgrp Library initialisation and management - \ingroup BCM2835grp - These functions allow you to intialise and control the bcm2835 library - @{ - */ - - /*! Initialise the library by opening /dev/mem (if you are root) - or /dev/gpiomem (if you are not) - and getting pointers to the - internal memory for BCM 2835 device registers. You must call this (successfully) - before calling any other - functions in this library (except bcm2835_set_debug). - If bcm2835_init() fails by returning 0, - calling any other function may result in crashes or other failures. - If bcm2835_init() succeeds but you are not running as root, then only gpio operations - are permitted, and calling any other functions may result in crashes or other failures. . - Prints messages to stderr in case of errors. - \return 1 if successful else 0 - */ - extern int bcm2835_init(void); - - /*! Close the library, deallocating any allocated memory and closing /dev/mem - \return 1 if successful else 0 - */ - extern int bcm2835_close(void); - - /*! Sets the debug level of the library. - A value of 1 prevents mapping to /dev/mem, and makes the library print out - what it would do, rather than accessing the GPIO registers. - A value of 0, the default, causes normal operation. - Call this before calling bcm2835_init(); - \param[in] debug The new debug level. 1 means debug - */ - extern void bcm2835_set_debug(uint8_t debug); - - /*! Returns the version number of the library, same as BCM2835_VERSION - \return the current library version number - */ - extern unsigned int bcm2835_version(void); - - /*! @} */ - - /*! \defgroup BCM2835lowlevelgrp Low level register access - \ingroup BCM2835grp - These functions provide low level register access, and should not generally - need to be used - - @{ - */ - - /*! Gets the base of a register - \param[in] regbase You can use one of the common values BCM2835_REGBASE_* - in \ref bcm2835RegisterBase - \return the register base - \sa Physical Addresses - */ - extern uint32_t* bcm2835_regbase(uint8_t regbase); - - /*! Reads 32 bit value from a peripheral address WITH a memory barrier before and after each read. - This is safe, but slow. The MB before protects this read from any in-flight reads that didn't - use a MB. The MB after protects subsequent reads from another peripheral. - - \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc. - \return the value read from the 32 bit register - \sa Physical Addresses - */ - extern uint32_t bcm2835_peri_read(volatile uint32_t* paddr); - - /*! Reads 32 bit value from a peripheral address WITHOUT the read barriers - You should only use this when: - o your code has previously called bcm2835_peri_read() for a register - within the same peripheral, and no read or write to another peripheral has occurred since. - o your code has called bcm2835_memory_barrier() since the last access to ANOTHER peripheral. - - \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc. - \return the value read from the 32 bit register - \sa Physical Addresses - */ - extern uint32_t bcm2835_peri_read_nb(volatile uint32_t* paddr); - - - /*! Writes 32 bit value from a peripheral address WITH a memory barrier before and after each write - This is safe, but slow. The MB before ensures that any in-flight write to another peripheral - completes before this write is issued. The MB after ensures that subsequent reads and writes - to another peripheral will see the effect of this write. - - This is a tricky optimization; if you aren't sure, use the barrier version. - - \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc. - \param[in] value The 32 bit value to write - \sa Physical Addresses - */ - extern void bcm2835_peri_write(volatile uint32_t* paddr, uint32_t value); - - /*! Writes 32 bit value from a peripheral address without the write barrier - You should only use this when: - o your code has previously called bcm2835_peri_write() for a register - within the same peripheral, and no other peripheral access has occurred since. - o your code has called bcm2835_memory_barrier() since the last access to ANOTHER peripheral. - - This is a tricky optimization; if you aren't sure, use the barrier version. - - \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc. - \param[in] value The 32 bit value to write - \sa Physical Addresses - */ - extern void bcm2835_peri_write_nb(volatile uint32_t* paddr, uint32_t value); - - /*! Alters a number of bits in a 32 peripheral regsiter. - It reads the current valu and then alters the bits defines as 1 in mask, - according to the bit value in value. - All other bits that are 0 in the mask are unaffected. - Use this to alter a subset of the bits in a register. - Memory barriers are used. Note that this is not atomic; an interrupt - routine can cause unexpected results. - \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc. - \param[in] value The 32 bit value to write, masked in by mask. - \param[in] mask Bitmask that defines the bits that will be altered in the register. - \sa Physical Addresses - */ - extern void bcm2835_peri_set_bits(volatile uint32_t* paddr, uint32_t value, uint32_t mask); - /*! @} end of lowlevel */ - - /*! \defgroup BCM2835gpiogrp GPIO register access - \ingroup BCM2835grp - These functions allow you to control the GPIO interface. You can set the - function of each GPIO pin, read the input state and set the output state. - @{ - */ - - /*! Sets the Function Select register for the given pin, which configures - the pin as Input, Output or one of the 6 alternate functions. - \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. - \param[in] mode Mode to set the pin to, one of BCM2835_GPIO_FSEL_* from \ref bcm2835FunctionSelect - */ - extern void bcm2835_gpio_fsel(uint8_t pin, uint8_t mode); - - /*! Sets the specified pin output to - HIGH. - \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. - \sa bcm2835_gpio_write() - */ - extern void bcm2835_gpio_set(uint8_t pin); - - /*! Sets the specified pin output to - LOW. - \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. - \sa bcm2835_gpio_write() - */ - extern void bcm2835_gpio_clr(uint8_t pin); - - /*! Sets any of the first 32 GPIO output pins specified in the mask to - HIGH. - \param[in] mask Mask of pins to affect. Use eg: (1 << RPI_GPIO_P1_03) | (1 << RPI_GPIO_P1_05) - \sa bcm2835_gpio_write_multi() - */ - extern void bcm2835_gpio_set_multi(uint32_t mask); - - /*! Sets any of the first 32 GPIO output pins specified in the mask to - LOW. - \param[in] mask Mask of pins to affect. Use eg: (1 << RPI_GPIO_P1_03) | (1 << RPI_GPIO_P1_05) - \sa bcm2835_gpio_write_multi() - */ - extern void bcm2835_gpio_clr_multi(uint32_t mask); - - /*! Reads the current level on the specified - pin and returns either HIGH or LOW. Works whether or not the pin - is an input or an output. - \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. - \return the current level either HIGH or LOW - */ - extern uint8_t bcm2835_gpio_lev(uint8_t pin); - - /*! Event Detect Status. - Tests whether the specified pin has detected a level or edge - as requested by bcm2835_gpio_ren(), bcm2835_gpio_fen(), bcm2835_gpio_hen(), - bcm2835_gpio_len(), bcm2835_gpio_aren(), bcm2835_gpio_afen(). - Clear the flag for a given pin by calling bcm2835_gpio_set_eds(pin); - \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. - \return HIGH if the event detect status for the given pin is true. - */ - extern uint8_t bcm2835_gpio_eds(uint8_t pin); - - /*! Same as bcm2835_gpio_eds() but checks if any of the pins specified in - the mask have detected a level or edge. - \param[in] mask Mask of pins to check. Use eg: (1 << RPI_GPIO_P1_03) | (1 << RPI_GPIO_P1_05) - \return Mask of pins HIGH if the event detect status for the given pin is true. - */ - extern uint32_t bcm2835_gpio_eds_multi(uint32_t mask); - - /*! Sets the Event Detect Status register for a given pin to 1, - which has the effect of clearing the flag. Use this afer seeing - an Event Detect Status on the pin. - \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. - */ - extern void bcm2835_gpio_set_eds(uint8_t pin); - - /*! Same as bcm2835_gpio_set_eds() but clears the flag for any pin which - is set in the mask. - \param[in] mask Mask of pins to clear. Use eg: (1 << RPI_GPIO_P1_03) | (1 << RPI_GPIO_P1_05) - */ - extern void bcm2835_gpio_set_eds_multi(uint32_t mask); - - /*! Enable Rising Edge Detect Enable for the specified pin. - When a rising edge is detected, sets the appropriate pin in Event Detect Status. - The GPRENn registers use - synchronous edge detection. This means the input signal is sampled using the - system clock and then it is looking for a ?011? pattern on the sampled signal. This - has the effect of suppressing glitches. - \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. - */ - extern void bcm2835_gpio_ren(uint8_t pin); - - /*! Disable Rising Edge Detect Enable for the specified pin. - \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. - */ - extern void bcm2835_gpio_clr_ren(uint8_t pin); - - /*! Enable Falling Edge Detect Enable for the specified pin. - When a falling edge is detected, sets the appropriate pin in Event Detect Status. - The GPRENn registers use - synchronous edge detection. This means the input signal is sampled using the - system clock and then it is looking for a ?100? pattern on the sampled signal. This - has the effect of suppressing glitches. - \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. - */ - extern void bcm2835_gpio_fen(uint8_t pin); - - /*! Disable Falling Edge Detect Enable for the specified pin. - \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. - */ - extern void bcm2835_gpio_clr_fen(uint8_t pin); - - /*! Enable High Detect Enable for the specified pin. - When a HIGH level is detected on the pin, sets the appropriate pin in Event Detect Status. - \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. - */ - extern void bcm2835_gpio_hen(uint8_t pin); - - /*! Disable High Detect Enable for the specified pin. - \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. - */ - extern void bcm2835_gpio_clr_hen(uint8_t pin); - - /*! Enable Low Detect Enable for the specified pin. - When a LOW level is detected on the pin, sets the appropriate pin in Event Detect Status. - \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. - */ - extern void bcm2835_gpio_len(uint8_t pin); - - /*! Disable Low Detect Enable for the specified pin. - \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. - */ - extern void bcm2835_gpio_clr_len(uint8_t pin); - - /*! Enable Asynchronous Rising Edge Detect Enable for the specified pin. - When a rising edge is detected, sets the appropriate pin in Event Detect Status. - Asynchronous means the incoming signal is not sampled by the system clock. As such - rising edges of very short duration can be detected. - \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. - */ - extern void bcm2835_gpio_aren(uint8_t pin); - - /*! Disable Asynchronous Rising Edge Detect Enable for the specified pin. - \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. - */ - extern void bcm2835_gpio_clr_aren(uint8_t pin); - - /*! Enable Asynchronous Falling Edge Detect Enable for the specified pin. - When a falling edge is detected, sets the appropriate pin in Event Detect Status. - Asynchronous means the incoming signal is not sampled by the system clock. As such - falling edges of very short duration can be detected. - \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. - */ - extern void bcm2835_gpio_afen(uint8_t pin); - - /*! Disable Asynchronous Falling Edge Detect Enable for the specified pin. - \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. - */ - extern void bcm2835_gpio_clr_afen(uint8_t pin); - - /*! Sets the Pull-up/down register for the given pin. This is - used with bcm2835_gpio_pudclk() to set the Pull-up/down resistor for the given pin. - However, it is usually more convenient to use bcm2835_gpio_set_pud(). - \param[in] pud The desired Pull-up/down mode. One of BCM2835_GPIO_PUD_* from bcm2835PUDControl - \sa bcm2835_gpio_set_pud() - */ - extern void bcm2835_gpio_pud(uint8_t pud); - - /*! Clocks the Pull-up/down value set earlier by bcm2835_gpio_pud() into the pin. - \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. - \param[in] on HIGH to clock the value from bcm2835_gpio_pud() into the pin. - LOW to remove the clock. - \sa bcm2835_gpio_set_pud() - */ - extern void bcm2835_gpio_pudclk(uint8_t pin, uint8_t on); - - /*! Reads and returns the Pad Control for the given GPIO group. - \param[in] group The GPIO pad group number, one of BCM2835_PAD_GROUP_GPIO_* - \return Mask of bits from BCM2835_PAD_* from \ref bcm2835PadGroup - */ - extern uint32_t bcm2835_gpio_pad(uint8_t group); - - /*! Sets the Pad Control for the given GPIO group. - \param[in] group The GPIO pad group number, one of BCM2835_PAD_GROUP_GPIO_* - \param[in] control Mask of bits from BCM2835_PAD_* from \ref bcm2835PadGroup. Note - that it is not necessary to include BCM2835_PAD_PASSWRD in the mask as this - is automatically included. - */ - extern void bcm2835_gpio_set_pad(uint8_t group, uint32_t control); - - /*! Delays for the specified number of milliseconds. - Uses nanosleep(), and therefore does not use CPU until the time is up. - However, you are at the mercy of nanosleep(). From the manual for nanosleep(): - If the interval specified in req is not an exact multiple of the granularity - underlying clock (see time(7)), then the interval will be - rounded up to the next multiple. Furthermore, after the sleep completes, - there may still be a delay before the CPU becomes free to once - again execute the calling thread. - \param[in] millis Delay in milliseconds - */ - extern void bcm2835_delay (unsigned int millis); - - /*! Delays for the specified number of microseconds. - Uses a combination of nanosleep() and a busy wait loop on the BCM2835 system timers, - However, you are at the mercy of nanosleep(). From the manual for nanosleep(): - If the interval specified in req is not an exact multiple of the granularity - underlying clock (see time(7)), then the interval will be - rounded up to the next multiple. Furthermore, after the sleep completes, - there may still be a delay before the CPU becomes free to once - again execute the calling thread. - For times less than about 450 microseconds, uses a busy wait on the System Timer. - It is reported that a delay of 0 microseconds on RaspberryPi will in fact - result in a delay of about 80 microseconds. Your mileage may vary. - \param[in] micros Delay in microseconds - */ - extern void bcm2835_delayMicroseconds (uint64_t micros); - - /*! Sets the output state of the specified pin - \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. - \param[in] on HIGH sets the output to HIGH and LOW to LOW. - */ - extern void bcm2835_gpio_write(uint8_t pin, uint8_t on); - - /*! Sets any of the first 32 GPIO output pins specified in the mask to the state given by on - \param[in] mask Mask of pins to affect. Use eg: (1 << RPI_GPIO_P1_03) | (1 << RPI_GPIO_P1_05) - \param[in] on HIGH sets the output to HIGH and LOW to LOW. - */ - extern void bcm2835_gpio_write_multi(uint32_t mask, uint8_t on); - - /*! Sets the first 32 GPIO output pins specified in the mask to the value given by value - \param[in] value values required for each bit masked in by mask, eg: (1 << RPI_GPIO_P1_03) | (1 << RPI_GPIO_P1_05) - \param[in] mask Mask of pins to affect. Use eg: (1 << RPI_GPIO_P1_03) | (1 << RPI_GPIO_P1_05) - */ - extern void bcm2835_gpio_write_mask(uint32_t value, uint32_t mask); - - /*! Sets the Pull-up/down mode for the specified pin. This is more convenient than - clocking the mode in with bcm2835_gpio_pud() and bcm2835_gpio_pudclk(). - \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. - \param[in] pud The desired Pull-up/down mode. One of BCM2835_GPIO_PUD_* from bcm2835PUDControl - */ - extern void bcm2835_gpio_set_pud(uint8_t pin, uint8_t pud); - - /*! @} */ - - /*! \defgroup BCM2835spigrp SPI access - \ingroup BCM2835grp - These functions let you use SPI0 (Serial Peripheral Interface) to - interface with an external SPI device. - @{ - */ - - /*! Start SPI operations. - Forces RPi SPI0 pins P1-19 (MOSI), P1-21 (MISO), P1-23 (CLK), P1-24 (CE0) and P1-26 (CE1) - to alternate function ALT0, which enables those pins for SPI interface. - You should call bcm2835_spi_end() when all SPI funcitons are complete to return the pins to - their default functions. - \sa bcm2835_spi_end() - \return 1 if successful, 0 otherwise (perhaps because you are not running as root) - */ - extern int bcm2835_spi_begin(void); - - /*! End SPI operations. - SPI0 pins P1-19 (MOSI), P1-21 (MISO), P1-23 (CLK), P1-24 (CE0) and P1-26 (CE1) - are returned to their default INPUT behaviour. - */ - extern void bcm2835_spi_end(void); - - /*! Sets the SPI bit order - NOTE: has no effect. Not supported by SPI0. - Defaults to - \param[in] order The desired bit order, one of BCM2835_SPI_BIT_ORDER_*, - see \ref bcm2835SPIBitOrder - */ - extern void bcm2835_spi_setBitOrder(uint8_t order); - - /*! Sets the SPI clock divider and therefore the - SPI clock speed. - \param[in] divider The desired SPI clock divider, one of BCM2835_SPI_CLOCK_DIVIDER_*, - see \ref bcm2835SPIClockDivider - */ - extern void bcm2835_spi_setClockDivider(uint16_t divider); - - /*! Sets the SPI data mode - Sets the clock polariy and phase - \param[in] mode The desired data mode, one of BCM2835_SPI_MODE*, - see \ref bcm2835SPIMode - */ - extern void bcm2835_spi_setDataMode(uint8_t mode); - - /*! Sets the chip select pin(s) - When an bcm2835_spi_transfer() is made, the selected pin(s) will be asserted during the - transfer. - \param[in] cs Specifies the CS pins(s) that are used to activate the desired slave. - One of BCM2835_SPI_CS*, see \ref bcm2835SPIChipSelect - */ - extern void bcm2835_spi_chipSelect(uint8_t cs); - - /*! Sets the chip select pin polarity for a given pin - When an bcm2835_spi_transfer() occurs, the currently selected chip select pin(s) - will be asserted to the - value given by active. When transfers are not happening, the chip select pin(s) - return to the complement (inactive) value. - \param[in] cs The chip select pin to affect - \param[in] active Whether the chip select pin is to be active HIGH - */ - extern void bcm2835_spi_setChipSelectPolarity(uint8_t cs, uint8_t active); - - /*! Transfers one byte to and from the currently selected SPI slave. - Asserts the currently selected CS pins (as previously set by bcm2835_spi_chipSelect) - during the transfer. - Clocks the 8 bit value out on MOSI, and simultaneously clocks in data from MISO. - Returns the read data byte from the slave. - Uses polled transfer as per section 10.6.1 of the BCM 2835 ARM Peripherls manual - \param[in] value The 8 bit data byte to write to MOSI - \return The 8 bit byte simultaneously read from MISO - \sa bcm2835_spi_transfern() - */ - extern uint8_t bcm2835_spi_transfer(uint8_t value); - - /*! Transfers any number of bytes to and from the currently selected SPI slave. - Asserts the currently selected CS pins (as previously set by bcm2835_spi_chipSelect) - during the transfer. - Clocks the len 8 bit bytes out on MOSI, and simultaneously clocks in data from MISO. - The data read read from the slave is placed into rbuf. rbuf must be at least len bytes long - Uses polled transfer as per section 10.6.1 of the BCM 2835 ARM Peripherls manual - \param[in] tbuf Buffer of bytes to send. - \param[out] rbuf Received bytes will by put in this buffer - \param[in] len Number of bytes in the tbuf buffer, and the number of bytes to send/received - \sa bcm2835_spi_transfer() - */ - extern void bcm2835_spi_transfernb(char* tbuf, char* rbuf, uint32_t len); - - /*! Transfers any number of bytes to and from the currently selected SPI slave - using bcm2835_spi_transfernb. - The returned data from the slave replaces the transmitted data in the buffer. - \param[in,out] buf Buffer of bytes to send. Received bytes will replace the contents - \param[in] len Number of bytes int eh buffer, and the number of bytes to send/received - \sa bcm2835_spi_transfer() - */ - extern void bcm2835_spi_transfern(char* buf, uint32_t len); - - /*! Transfers any number of bytes to the currently selected SPI slave. - Asserts the currently selected CS pins (as previously set by bcm2835_spi_chipSelect) - during the transfer. - \param[in] buf Buffer of bytes to send. - \param[in] len Number of bytes in the tbuf buffer, and the number of bytes to send - */ - extern void bcm2835_spi_writenb(char* buf, uint32_t len); - - /*! @} */ - - /*! \defgroup BCM2835i2cgrp I2C access - \ingroup BCM2835grp - These functions let you use I2C (The Broadcom Serial Control bus with the Philips - I2C bus/interface version 2.1 January 2000.) to interface with an external I2C device. - @{ - */ - - /*! Start I2C operations. - Forces RPi I2C pins P1-03 (SDA) and P1-05 (SCL) - to alternate function ALT0, which enables those pins for I2C interface. - You should call bcm2835_i2c_end() when all I2C functions are complete to return the pins to - their default functions - \return 1 if successful, 0 otherwise (perhaps because you are not running as root) - \sa bcm2835_i2c_end() - */ - extern int bcm2835_i2c_begin(void); - - /*! End I2C operations. - I2C pins P1-03 (SDA) and P1-05 (SCL) - are returned to their default INPUT behaviour. - */ - extern void bcm2835_i2c_end(void); - - /*! Sets the I2C slave address. - \param[in] addr The I2C slave address. - */ - extern void bcm2835_i2c_setSlaveAddress(uint8_t addr); - - /*! Sets the I2C clock divider and therefore the I2C clock speed. - \param[in] divider The desired I2C clock divider, one of BCM2835_I2C_CLOCK_DIVIDER_*, - see \ref bcm2835I2CClockDivider - */ - extern void bcm2835_i2c_setClockDivider(uint16_t divider); - - /*! Sets the I2C clock divider by converting the baudrate parameter to - the equivalent I2C clock divider. ( see \sa bcm2835_i2c_setClockDivider) - For the I2C standard 100khz you would set baudrate to 100000 - The use of baudrate corresponds to its use in the I2C kernel device - driver. (Of course, bcm2835 has nothing to do with the kernel driver) - */ - extern void bcm2835_i2c_set_baudrate(uint32_t baudrate); - - /*! Transfers any number of bytes to the currently selected I2C slave. - (as previously set by \sa bcm2835_i2c_setSlaveAddress) - \param[in] buf Buffer of bytes to send. - \param[in] len Number of bytes in the buf buffer, and the number of bytes to send. - \return reason see \ref bcm2835I2CReasonCodes - */ - extern uint8_t bcm2835_i2c_write(const char * buf, uint32_t len); - - /*! Transfers any number of bytes from the currently selected I2C slave. - (as previously set by \sa bcm2835_i2c_setSlaveAddress) - \param[in] buf Buffer of bytes to receive. - \param[in] len Number of bytes in the buf buffer, and the number of bytes to received. - \return reason see \ref bcm2835I2CReasonCodes - */ - extern uint8_t bcm2835_i2c_read(char* buf, uint32_t len); - - /*! Allows reading from I2C slaves that require a repeated start (without any prior stop) - to read after the required slave register has been set. For example, the popular - MPL3115A2 pressure and temperature sensor. Note that your device must support or - require this mode. If your device does not require this mode then the standard - combined: - \sa bcm2835_i2c_write - \sa bcm2835_i2c_read - are a better choice. - Will read from the slave previously set by \sa bcm2835_i2c_setSlaveAddress - \param[in] regaddr Buffer containing the slave register you wish to read from. - \param[in] buf Buffer of bytes to receive. - \param[in] len Number of bytes in the buf buffer, and the number of bytes to received. - \return reason see \ref bcm2835I2CReasonCodes - */ - extern uint8_t bcm2835_i2c_read_register_rs(char* regaddr, char* buf, uint32_t len); - - /*! Allows sending an arbitrary number of bytes to I2C slaves before issuing a repeated - start (with no prior stop) and reading a response. - Necessary for devices that require such behavior, such as the MLX90620. - Will write to and read from the slave previously set by \sa bcm2835_i2c_setSlaveAddress - \param[in] cmds Buffer containing the bytes to send before the repeated start condition. - \param[in] cmds_len Number of bytes to send from cmds buffer - \param[in] buf Buffer of bytes to receive. - \param[in] buf_len Number of bytes to receive in the buf buffer. - \return reason see \ref bcm2835I2CReasonCodes - */ - extern uint8_t bcm2835_i2c_write_read_rs(char* cmds, uint32_t cmds_len, char* buf, uint32_t buf_len); - - /*! @} */ - - /*! \defgroup BCM2835stgrp System Timer access - \ingroup BCM2835grp - Allows access to and delays using the System Timer Counter. - @{ - */ - - /*! Read the System Timer Counter register. - \return the value read from the System Timer Counter Lower 32 bits register - */ - extern uint64_t bcm2835_st_read(void); - - /*! Delays for the specified number of microseconds with offset. - \param[in] offset_micros Offset in microseconds - \param[in] micros Delay in microseconds - */ - extern void bcm2835_st_delay(uint64_t offset_micros, uint64_t micros); - - /*! @} */ - - /*! \defgroup BCM2835pwmgrp Pulse Width Modulation - \ingroup BCM2835grp - Allows control of 2 independent PWM channels. A limited subset of GPIO pins - can be connected to one of these 2 channels, allowing PWM control of GPIO pins. - You have to set the desired pin into a particular Alt Fun to PWM output. See the PWM - documentation on the Main Page. - @{ - */ - - /*! Sets the PWM clock divisor, - to control the basic PWM pulse widths. - \param[in] divisor Divides the basic 19.2MHz PWM clock. You can use one of the common - values BCM2835_PWM_CLOCK_DIVIDER_* in \ref bcm2835PWMClockDivider - */ - extern void bcm2835_pwm_set_clock(uint32_t divisor); - - /*! Sets the mode of the given PWM channel, - allowing you to control the PWM mode and enable/disable that channel - \param[in] channel The PWM channel. 0 or 1. - \param[in] markspace Set true if you want Mark-Space mode. 0 for Balanced mode. - \param[in] enabled Set true to enable this channel and produce PWM pulses. - */ - extern void bcm2835_pwm_set_mode(uint8_t channel, uint8_t markspace, uint8_t enabled); - - /*! Sets the maximum range of the PWM output. - The data value can vary between 0 and this range to control PWM output - \param[in] channel The PWM channel. 0 or 1. - \param[in] range The maximum value permitted for DATA. - */ - extern void bcm2835_pwm_set_range(uint8_t channel, uint32_t range); - - /*! Sets the PWM pulse ratio to emit to DATA/RANGE, - where RANGE is set by bcm2835_pwm_set_range(). - \param[in] channel The PWM channel. 0 or 1. - \param[in] data Controls the PWM output ratio as a fraction of the range. - Can vary from 0 to RANGE. - */ - extern void bcm2835_pwm_set_data(uint8_t channel, uint32_t data); - - /*! @} */ +/*! \defgroup BCM2835initgrp Library initialisation and management + \ingroup BCM2835grp + These functions allow you to intialise and control the bcm2835 library + @{ +*/ + +/*! Initialise the library by opening /dev/mem (if you are root) + or /dev/gpiomem (if you are not) + and getting pointers to the + internal memory for BCM 2835 device registers. You must call this (successfully) + before calling any other + functions in this library (except bcm2835_set_debug). + If bcm2835_init() fails by returning 0, + calling any other function may result in crashes or other failures. + If bcm2835_init() succeeds but you are not running as root, then only gpio operations + are permitted, and calling any other functions may result in crashes or other failures. . + Prints messages to stderr in case of errors. + \return 1 if successful else 0 +*/ +extern int bcm2835_init(void); + +/*! Close the library, deallocating any allocated memory and closing /dev/mem + \return 1 if successful else 0 +*/ +extern int bcm2835_close(void); + +/*! Sets the debug level of the library. + A value of 1 prevents mapping to /dev/mem, and makes the library print out + what it would do, rather than accessing the GPIO registers. + A value of 0, the default, causes normal operation. + Call this before calling bcm2835_init(); + \param[in] debug The new debug level. 1 means debug +*/ +extern void bcm2835_set_debug(uint8_t debug); + +/*! Returns the version number of the library, same as BCM2835_VERSION + \return the current library version number +*/ +extern unsigned int bcm2835_version(void); + +/*! @} */ + +/*! \defgroup BCM2835lowlevelgrp Low level register access + \ingroup BCM2835grp + These functions provide low level register access, and should not generally + need to be used + + @{ +*/ + +/*! Gets the base of a register + \param[in] regbase You can use one of the common values BCM2835_REGBASE_* + in \ref bcm2835RegisterBase + \return the register base + \sa Physical Addresses +*/ +extern uint32_t* bcm2835_regbase(uint8_t regbase); + +/*! Reads 32 bit value from a peripheral address WITH a memory barrier before and after each read. + This is safe, but slow. The MB before protects this read from any in-flight reads that didn't + use a MB. The MB after protects subsequent reads from another peripheral. + + \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc. + \return the value read from the 32 bit register + \sa Physical Addresses +*/ +extern uint32_t bcm2835_peri_read(volatile uint32_t* paddr); + +/*! Reads 32 bit value from a peripheral address WITHOUT the read barriers + You should only use this when: + o your code has previously called bcm2835_peri_read() for a register + within the same peripheral, and no read or write to another peripheral has occurred since. + o your code has called bcm2835_memory_barrier() since the last access to ANOTHER peripheral. + + \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc. + \return the value read from the 32 bit register + \sa Physical Addresses +*/ +extern uint32_t bcm2835_peri_read_nb(volatile uint32_t* paddr); + + +/*! Writes 32 bit value from a peripheral address WITH a memory barrier before and after each write + This is safe, but slow. The MB before ensures that any in-flight write to another peripheral + completes before this write is issued. The MB after ensures that subsequent reads and writes + to another peripheral will see the effect of this write. + + This is a tricky optimization; if you aren't sure, use the barrier version. + + \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc. + \param[in] value The 32 bit value to write + \sa Physical Addresses +*/ +extern void bcm2835_peri_write(volatile uint32_t* paddr, uint32_t value); + +/*! Writes 32 bit value from a peripheral address without the write barrier + You should only use this when: + o your code has previously called bcm2835_peri_write() for a register + within the same peripheral, and no other peripheral access has occurred since. + o your code has called bcm2835_memory_barrier() since the last access to ANOTHER peripheral. + + This is a tricky optimization; if you aren't sure, use the barrier version. + + \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc. + \param[in] value The 32 bit value to write + \sa Physical Addresses +*/ +extern void bcm2835_peri_write_nb(volatile uint32_t* paddr, uint32_t value); + +/*! Alters a number of bits in a 32 peripheral regsiter. + It reads the current valu and then alters the bits defines as 1 in mask, + according to the bit value in value. + All other bits that are 0 in the mask are unaffected. + Use this to alter a subset of the bits in a register. + Memory barriers are used. Note that this is not atomic; an interrupt + routine can cause unexpected results. + \param[in] paddr Physical address to read from. See BCM2835_GPIO_BASE etc. + \param[in] value The 32 bit value to write, masked in by mask. + \param[in] mask Bitmask that defines the bits that will be altered in the register. + \sa Physical Addresses +*/ +extern void bcm2835_peri_set_bits(volatile uint32_t* paddr, uint32_t value, uint32_t mask); +/*! @} end of lowlevel */ + +/*! \defgroup BCM2835gpiogrp GPIO register access + \ingroup BCM2835grp + These functions allow you to control the GPIO interface. You can set the + function of each GPIO pin, read the input state and set the output state. + @{ +*/ + +/*! Sets the Function Select register for the given pin, which configures + the pin as Input, Output or one of the 6 alternate functions. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + \param[in] mode Mode to set the pin to, one of BCM2835_GPIO_FSEL_* from \ref bcm2835FunctionSelect +*/ +extern void bcm2835_gpio_fsel(uint8_t pin, uint8_t mode); + +/*! Sets the specified pin output to + HIGH. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + \sa bcm2835_gpio_write() +*/ +extern void bcm2835_gpio_set(uint8_t pin); + +/*! Sets the specified pin output to + LOW. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + \sa bcm2835_gpio_write() +*/ +extern void bcm2835_gpio_clr(uint8_t pin); + +/*! Sets any of the first 32 GPIO output pins specified in the mask to + HIGH. + \param[in] mask Mask of pins to affect. Use eg: (1 << RPI_GPIO_P1_03) | (1 << RPI_GPIO_P1_05) + \sa bcm2835_gpio_write_multi() +*/ +extern void bcm2835_gpio_set_multi(uint32_t mask); + +/*! Sets any of the first 32 GPIO output pins specified in the mask to + LOW. + \param[in] mask Mask of pins to affect. Use eg: (1 << RPI_GPIO_P1_03) | (1 << RPI_GPIO_P1_05) + \sa bcm2835_gpio_write_multi() +*/ +extern void bcm2835_gpio_clr_multi(uint32_t mask); + +/*! Reads the current level on the specified + pin and returns either HIGH or LOW. Works whether or not the pin + is an input or an output. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + \return the current level either HIGH or LOW +*/ +extern uint8_t bcm2835_gpio_lev(uint8_t pin); + +/*! Event Detect Status. + Tests whether the specified pin has detected a level or edge + as requested by bcm2835_gpio_ren(), bcm2835_gpio_fen(), bcm2835_gpio_hen(), + bcm2835_gpio_len(), bcm2835_gpio_aren(), bcm2835_gpio_afen(). + Clear the flag for a given pin by calling bcm2835_gpio_set_eds(pin); + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + \return HIGH if the event detect status for the given pin is true. +*/ +extern uint8_t bcm2835_gpio_eds(uint8_t pin); + +/*! Same as bcm2835_gpio_eds() but checks if any of the pins specified in + the mask have detected a level or edge. + \param[in] mask Mask of pins to check. Use eg: (1 << RPI_GPIO_P1_03) | (1 << RPI_GPIO_P1_05) + \return Mask of pins HIGH if the event detect status for the given pin is true. +*/ +extern uint32_t bcm2835_gpio_eds_multi(uint32_t mask); + +/*! Sets the Event Detect Status register for a given pin to 1, + which has the effect of clearing the flag. Use this afer seeing + an Event Detect Status on the pin. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. +*/ +extern void bcm2835_gpio_set_eds(uint8_t pin); + +/*! Same as bcm2835_gpio_set_eds() but clears the flag for any pin which + is set in the mask. + \param[in] mask Mask of pins to clear. Use eg: (1 << RPI_GPIO_P1_03) | (1 << RPI_GPIO_P1_05) +*/ +extern void bcm2835_gpio_set_eds_multi(uint32_t mask); + +/*! Enable Rising Edge Detect Enable for the specified pin. + When a rising edge is detected, sets the appropriate pin in Event Detect Status. + The GPRENn registers use + synchronous edge detection. This means the input signal is sampled using the + system clock and then it is looking for a ?011? pattern on the sampled signal. This + has the effect of suppressing glitches. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. +*/ +extern void bcm2835_gpio_ren(uint8_t pin); + +/*! Disable Rising Edge Detect Enable for the specified pin. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. +*/ +extern void bcm2835_gpio_clr_ren(uint8_t pin); + +/*! Enable Falling Edge Detect Enable for the specified pin. + When a falling edge is detected, sets the appropriate pin in Event Detect Status. + The GPRENn registers use + synchronous edge detection. This means the input signal is sampled using the + system clock and then it is looking for a ?100? pattern on the sampled signal. This + has the effect of suppressing glitches. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. +*/ +extern void bcm2835_gpio_fen(uint8_t pin); + +/*! Disable Falling Edge Detect Enable for the specified pin. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. +*/ +extern void bcm2835_gpio_clr_fen(uint8_t pin); + +/*! Enable High Detect Enable for the specified pin. + When a HIGH level is detected on the pin, sets the appropriate pin in Event Detect Status. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. +*/ +extern void bcm2835_gpio_hen(uint8_t pin); + +/*! Disable High Detect Enable for the specified pin. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. +*/ +extern void bcm2835_gpio_clr_hen(uint8_t pin); + +/*! Enable Low Detect Enable for the specified pin. + When a LOW level is detected on the pin, sets the appropriate pin in Event Detect Status. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. +*/ +extern void bcm2835_gpio_len(uint8_t pin); + +/*! Disable Low Detect Enable for the specified pin. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. +*/ +extern void bcm2835_gpio_clr_len(uint8_t pin); + +/*! Enable Asynchronous Rising Edge Detect Enable for the specified pin. + When a rising edge is detected, sets the appropriate pin in Event Detect Status. + Asynchronous means the incoming signal is not sampled by the system clock. As such + rising edges of very short duration can be detected. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. +*/ +extern void bcm2835_gpio_aren(uint8_t pin); + +/*! Disable Asynchronous Rising Edge Detect Enable for the specified pin. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. +*/ +extern void bcm2835_gpio_clr_aren(uint8_t pin); + +/*! Enable Asynchronous Falling Edge Detect Enable for the specified pin. + When a falling edge is detected, sets the appropriate pin in Event Detect Status. + Asynchronous means the incoming signal is not sampled by the system clock. As such + falling edges of very short duration can be detected. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. +*/ +extern void bcm2835_gpio_afen(uint8_t pin); + +/*! Disable Asynchronous Falling Edge Detect Enable for the specified pin. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. +*/ +extern void bcm2835_gpio_clr_afen(uint8_t pin); + +/*! Sets the Pull-up/down register for the given pin. This is + used with bcm2835_gpio_pudclk() to set the Pull-up/down resistor for the given pin. + However, it is usually more convenient to use bcm2835_gpio_set_pud(). + \param[in] pud The desired Pull-up/down mode. One of BCM2835_GPIO_PUD_* from bcm2835PUDControl + \sa bcm2835_gpio_set_pud() +*/ +extern void bcm2835_gpio_pud(uint8_t pud); + +/*! Clocks the Pull-up/down value set earlier by bcm2835_gpio_pud() into the pin. + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + \param[in] on HIGH to clock the value from bcm2835_gpio_pud() into the pin. + LOW to remove the clock. + \sa bcm2835_gpio_set_pud() +*/ +extern void bcm2835_gpio_pudclk(uint8_t pin, uint8_t on); + +/*! Reads and returns the Pad Control for the given GPIO group. + \param[in] group The GPIO pad group number, one of BCM2835_PAD_GROUP_GPIO_* + \return Mask of bits from BCM2835_PAD_* from \ref bcm2835PadGroup +*/ +extern uint32_t bcm2835_gpio_pad(uint8_t group); + +/*! Sets the Pad Control for the given GPIO group. + \param[in] group The GPIO pad group number, one of BCM2835_PAD_GROUP_GPIO_* + \param[in] control Mask of bits from BCM2835_PAD_* from \ref bcm2835PadGroup. Note + that it is not necessary to include BCM2835_PAD_PASSWRD in the mask as this + is automatically included. +*/ +extern void bcm2835_gpio_set_pad(uint8_t group, uint32_t control); + +/*! Delays for the specified number of milliseconds. + Uses nanosleep(), and therefore does not use CPU until the time is up. + However, you are at the mercy of nanosleep(). From the manual for nanosleep(): + If the interval specified in req is not an exact multiple of the granularity + underlying clock (see time(7)), then the interval will be + rounded up to the next multiple. Furthermore, after the sleep completes, + there may still be a delay before the CPU becomes free to once + again execute the calling thread. + \param[in] millis Delay in milliseconds +*/ +extern void bcm2835_delay (unsigned int millis); + +/*! Delays for the specified number of microseconds. + Uses a combination of nanosleep() and a busy wait loop on the BCM2835 system timers, + However, you are at the mercy of nanosleep(). From the manual for nanosleep(): + If the interval specified in req is not an exact multiple of the granularity + underlying clock (see time(7)), then the interval will be + rounded up to the next multiple. Furthermore, after the sleep completes, + there may still be a delay before the CPU becomes free to once + again execute the calling thread. + For times less than about 450 microseconds, uses a busy wait on the System Timer. + It is reported that a delay of 0 microseconds on RaspberryPi will in fact + result in a delay of about 80 microseconds. Your mileage may vary. + \param[in] micros Delay in microseconds +*/ +extern void bcm2835_delayMicroseconds (uint64_t micros); + +/*! Sets the output state of the specified pin + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + \param[in] on HIGH sets the output to HIGH and LOW to LOW. +*/ +extern void bcm2835_gpio_write(uint8_t pin, uint8_t on); + +/*! Sets any of the first 32 GPIO output pins specified in the mask to the state given by on + \param[in] mask Mask of pins to affect. Use eg: (1 << RPI_GPIO_P1_03) | (1 << RPI_GPIO_P1_05) + \param[in] on HIGH sets the output to HIGH and LOW to LOW. +*/ +extern void bcm2835_gpio_write_multi(uint32_t mask, uint8_t on); + +/*! Sets the first 32 GPIO output pins specified in the mask to the value given by value + \param[in] value values required for each bit masked in by mask, eg: (1 << RPI_GPIO_P1_03) | (1 << RPI_GPIO_P1_05) + \param[in] mask Mask of pins to affect. Use eg: (1 << RPI_GPIO_P1_03) | (1 << RPI_GPIO_P1_05) +*/ +extern void bcm2835_gpio_write_mask(uint32_t value, uint32_t mask); + +/*! Sets the Pull-up/down mode for the specified pin. This is more convenient than + clocking the mode in with bcm2835_gpio_pud() and bcm2835_gpio_pudclk(). + \param[in] pin GPIO number, or one of RPI_GPIO_P1_* from \ref RPiGPIOPin. + \param[in] pud The desired Pull-up/down mode. One of BCM2835_GPIO_PUD_* from bcm2835PUDControl +*/ +extern void bcm2835_gpio_set_pud(uint8_t pin, uint8_t pud); + +/*! @} */ + +/*! \defgroup BCM2835spigrp SPI access + \ingroup BCM2835grp + These functions let you use SPI0 (Serial Peripheral Interface) to + interface with an external SPI device. + @{ +*/ + +/*! Start SPI operations. + Forces RPi SPI0 pins P1-19 (MOSI), P1-21 (MISO), P1-23 (CLK), P1-24 (CE0) and P1-26 (CE1) + to alternate function ALT0, which enables those pins for SPI interface. + You should call bcm2835_spi_end() when all SPI funcitons are complete to return the pins to + their default functions. + \sa bcm2835_spi_end() + \return 1 if successful, 0 otherwise (perhaps because you are not running as root) +*/ +extern int bcm2835_spi_begin(void); + +/*! End SPI operations. + SPI0 pins P1-19 (MOSI), P1-21 (MISO), P1-23 (CLK), P1-24 (CE0) and P1-26 (CE1) + are returned to their default INPUT behaviour. +*/ +extern void bcm2835_spi_end(void); + +/*! Sets the SPI bit order + NOTE: has no effect. Not supported by SPI0. + Defaults to + \param[in] order The desired bit order, one of BCM2835_SPI_BIT_ORDER_*, + see \ref bcm2835SPIBitOrder +*/ +extern void bcm2835_spi_setBitOrder(uint8_t order); + +/*! Sets the SPI clock divider and therefore the + SPI clock speed. + \param[in] divider The desired SPI clock divider, one of BCM2835_SPI_CLOCK_DIVIDER_*, + see \ref bcm2835SPIClockDivider +*/ +extern void bcm2835_spi_setClockDivider(uint16_t divider); + +/*! Sets the SPI data mode + Sets the clock polariy and phase + \param[in] mode The desired data mode, one of BCM2835_SPI_MODE*, + see \ref bcm2835SPIMode +*/ +extern void bcm2835_spi_setDataMode(uint8_t mode); + +/*! Sets the chip select pin(s) + When an bcm2835_spi_transfer() is made, the selected pin(s) will be asserted during the + transfer. + \param[in] cs Specifies the CS pins(s) that are used to activate the desired slave. + One of BCM2835_SPI_CS*, see \ref bcm2835SPIChipSelect +*/ +extern void bcm2835_spi_chipSelect(uint8_t cs); + +/*! Sets the chip select pin polarity for a given pin + When an bcm2835_spi_transfer() occurs, the currently selected chip select pin(s) + will be asserted to the + value given by active. When transfers are not happening, the chip select pin(s) + return to the complement (inactive) value. + \param[in] cs The chip select pin to affect + \param[in] active Whether the chip select pin is to be active HIGH +*/ +extern void bcm2835_spi_setChipSelectPolarity(uint8_t cs, uint8_t active); + +/*! Transfers one byte to and from the currently selected SPI slave. + Asserts the currently selected CS pins (as previously set by bcm2835_spi_chipSelect) + during the transfer. + Clocks the 8 bit value out on MOSI, and simultaneously clocks in data from MISO. + Returns the read data byte from the slave. + Uses polled transfer as per section 10.6.1 of the BCM 2835 ARM Peripherls manual + \param[in] value The 8 bit data byte to write to MOSI + \return The 8 bit byte simultaneously read from MISO + \sa bcm2835_spi_transfern() +*/ +extern uint8_t bcm2835_spi_transfer(uint8_t value); + +/*! Transfers any number of bytes to and from the currently selected SPI slave. + Asserts the currently selected CS pins (as previously set by bcm2835_spi_chipSelect) + during the transfer. + Clocks the len 8 bit bytes out on MOSI, and simultaneously clocks in data from MISO. + The data read read from the slave is placed into rbuf. rbuf must be at least len bytes long + Uses polled transfer as per section 10.6.1 of the BCM 2835 ARM Peripherls manual + \param[in] tbuf Buffer of bytes to send. + \param[out] rbuf Received bytes will by put in this buffer + \param[in] len Number of bytes in the tbuf buffer, and the number of bytes to send/received + \sa bcm2835_spi_transfer() +*/ +extern void bcm2835_spi_transfernb(char* tbuf, char* rbuf, uint32_t len); + +/*! Transfers any number of bytes to and from the currently selected SPI slave + using bcm2835_spi_transfernb. + The returned data from the slave replaces the transmitted data in the buffer. + \param[in,out] buf Buffer of bytes to send. Received bytes will replace the contents + \param[in] len Number of bytes int eh buffer, and the number of bytes to send/received + \sa bcm2835_spi_transfer() +*/ +extern void bcm2835_spi_transfern(char* buf, uint32_t len); + +/*! Transfers any number of bytes to the currently selected SPI slave. + Asserts the currently selected CS pins (as previously set by bcm2835_spi_chipSelect) + during the transfer. + \param[in] buf Buffer of bytes to send. + \param[in] len Number of bytes in the tbuf buffer, and the number of bytes to send +*/ +extern void bcm2835_spi_writenb(char* buf, uint32_t len); + +/*! @} */ + +/*! \defgroup BCM2835i2cgrp I2C access + \ingroup BCM2835grp + These functions let you use I2C (The Broadcom Serial Control bus with the Philips + I2C bus/interface version 2.1 January 2000.) to interface with an external I2C device. + @{ +*/ + +/*! Start I2C operations. + Forces RPi I2C pins P1-03 (SDA) and P1-05 (SCL) + to alternate function ALT0, which enables those pins for I2C interface. + You should call bcm2835_i2c_end() when all I2C functions are complete to return the pins to + their default functions + \return 1 if successful, 0 otherwise (perhaps because you are not running as root) + \sa bcm2835_i2c_end() +*/ +extern int bcm2835_i2c_begin(void); + +/*! End I2C operations. + I2C pins P1-03 (SDA) and P1-05 (SCL) + are returned to their default INPUT behaviour. +*/ +extern void bcm2835_i2c_end(void); + +/*! Sets the I2C slave address. + \param[in] addr The I2C slave address. +*/ +extern void bcm2835_i2c_setSlaveAddress(uint8_t addr); + +/*! Sets the I2C clock divider and therefore the I2C clock speed. + \param[in] divider The desired I2C clock divider, one of BCM2835_I2C_CLOCK_DIVIDER_*, + see \ref bcm2835I2CClockDivider +*/ +extern void bcm2835_i2c_setClockDivider(uint16_t divider); + +/*! Sets the I2C clock divider by converting the baudrate parameter to + the equivalent I2C clock divider. ( see \sa bcm2835_i2c_setClockDivider) + For the I2C standard 100khz you would set baudrate to 100000 + The use of baudrate corresponds to its use in the I2C kernel device + driver. (Of course, bcm2835 has nothing to do with the kernel driver) +*/ +extern void bcm2835_i2c_set_baudrate(uint32_t baudrate); + +/*! Transfers any number of bytes to the currently selected I2C slave. + (as previously set by \sa bcm2835_i2c_setSlaveAddress) + \param[in] buf Buffer of bytes to send. + \param[in] len Number of bytes in the buf buffer, and the number of bytes to send. + \return reason see \ref bcm2835I2CReasonCodes +*/ +extern uint8_t bcm2835_i2c_write(const char * buf, uint32_t len); + +/*! Transfers any number of bytes from the currently selected I2C slave. + (as previously set by \sa bcm2835_i2c_setSlaveAddress) + \param[in] buf Buffer of bytes to receive. + \param[in] len Number of bytes in the buf buffer, and the number of bytes to received. + \return reason see \ref bcm2835I2CReasonCodes +*/ +extern uint8_t bcm2835_i2c_read(char* buf, uint32_t len); + +/*! Allows reading from I2C slaves that require a repeated start (without any prior stop) + to read after the required slave register has been set. For example, the popular + MPL3115A2 pressure and temperature sensor. Note that your device must support or + require this mode. If your device does not require this mode then the standard + combined: + \sa bcm2835_i2c_write + \sa bcm2835_i2c_read + are a better choice. + Will read from the slave previously set by \sa bcm2835_i2c_setSlaveAddress + \param[in] regaddr Buffer containing the slave register you wish to read from. + \param[in] buf Buffer of bytes to receive. + \param[in] len Number of bytes in the buf buffer, and the number of bytes to received. + \return reason see \ref bcm2835I2CReasonCodes +*/ +extern uint8_t bcm2835_i2c_read_register_rs(char* regaddr, char* buf, uint32_t len); + +/*! Allows sending an arbitrary number of bytes to I2C slaves before issuing a repeated + start (with no prior stop) and reading a response. + Necessary for devices that require such behavior, such as the MLX90620. + Will write to and read from the slave previously set by \sa bcm2835_i2c_setSlaveAddress + \param[in] cmds Buffer containing the bytes to send before the repeated start condition. + \param[in] cmds_len Number of bytes to send from cmds buffer + \param[in] buf Buffer of bytes to receive. + \param[in] buf_len Number of bytes to receive in the buf buffer. + \return reason see \ref bcm2835I2CReasonCodes +*/ +extern uint8_t bcm2835_i2c_write_read_rs(char* cmds, uint32_t cmds_len, char* buf, + uint32_t buf_len); + +/*! @} */ + +/*! \defgroup BCM2835stgrp System Timer access + \ingroup BCM2835grp + Allows access to and delays using the System Timer Counter. + @{ +*/ + +/*! Read the System Timer Counter register. + \return the value read from the System Timer Counter Lower 32 bits register +*/ +extern uint64_t bcm2835_st_read(void); + +/*! Delays for the specified number of microseconds with offset. + \param[in] offset_micros Offset in microseconds + \param[in] micros Delay in microseconds +*/ +extern void bcm2835_st_delay(uint64_t offset_micros, uint64_t micros); + +/*! @} */ + +/*! \defgroup BCM2835pwmgrp Pulse Width Modulation + \ingroup BCM2835grp + Allows control of 2 independent PWM channels. A limited subset of GPIO pins + can be connected to one of these 2 channels, allowing PWM control of GPIO pins. + You have to set the desired pin into a particular Alt Fun to PWM output. See the PWM + documentation on the Main Page. + @{ +*/ + +/*! Sets the PWM clock divisor, + to control the basic PWM pulse widths. + \param[in] divisor Divides the basic 19.2MHz PWM clock. You can use one of the common + values BCM2835_PWM_CLOCK_DIVIDER_* in \ref bcm2835PWMClockDivider +*/ +extern void bcm2835_pwm_set_clock(uint32_t divisor); + +/*! Sets the mode of the given PWM channel, + allowing you to control the PWM mode and enable/disable that channel + \param[in] channel The PWM channel. 0 or 1. + \param[in] markspace Set true if you want Mark-Space mode. 0 for Balanced mode. + \param[in] enabled Set true to enable this channel and produce PWM pulses. +*/ +extern void bcm2835_pwm_set_mode(uint8_t channel, uint8_t markspace, uint8_t enabled); + +/*! Sets the maximum range of the PWM output. + The data value can vary between 0 and this range to control PWM output + \param[in] channel The PWM channel. 0 or 1. + \param[in] range The maximum value permitted for DATA. +*/ +extern void bcm2835_pwm_set_range(uint8_t channel, uint32_t range); + +/*! Sets the PWM pulse ratio to emit to DATA/RANGE, + where RANGE is set by bcm2835_pwm_set_range(). + \param[in] channel The PWM channel. 0 or 1. + \param[in] data Controls the PWM output ratio as a fraction of the range. + Can vary from 0 to RANGE. +*/ +extern void bcm2835_pwm_set_data(uint8_t channel, uint32_t data); + +/*! @} */ #ifdef __cplusplus } #endif diff --git a/drivers/RPi/cpuinfo.c b/drivers/RPi/cpuinfo.c index 5fa48dcd3..8c16a0dd1 100644 --- a/drivers/RPi/cpuinfo.c +++ b/drivers/RPi/cpuinfo.c @@ -27,167 +27,232 @@ SOFTWARE. int get_rpi_info(rpi_info *info) { - FILE *fp; - char buffer[1024]; - char hardware[1024]; - char revision[1024]; - char *rev; - int found = 0; - int len; - - if ((fp = fopen("/proc/cpuinfo", "r")) == NULL) - return -1; - while(!feof(fp)) { - fgets(buffer, sizeof(buffer), fp); - sscanf(buffer, "Hardware : %s", hardware); - if (strcmp(hardware, "BCM2708") == 0 || - strcmp(hardware, "BCM2709") == 0 || - strcmp(hardware, "BCM2835") == 0 || - strcmp(hardware, "BCM2836") == 0 || - strcmp(hardware, "BCM2837") == 0 ) { - found = 1; - } - sscanf(buffer, "Revision : %s", revision); - } - fclose(fp); - - if (!found) - return -1; - - if ((len = strlen(revision)) == 0) - return -1; - - if (len >= 6 && strtol((char[]){revision[len-6],0}, NULL, 16) & 8) { - // new scheme - //info->rev = revision[len-1]-'0'; - strcpy(info->revision, revision); - switch (revision[len-2]) { - case '0': info->type = "Model A"; info->p1_revision = 2; break; - case '1': info->type = "Model B"; info->p1_revision = 2; break; - case '2': info->type = "Model A+"; info->p1_revision = 3; break; - case '3': info->type = "Model B+"; info->p1_revision = 3; break; - case '4': info->type = "Pi 2 Model B"; info->p1_revision = 3; break; - case '5': info->type = "Alpha"; info->p1_revision = 3; break; - case '6': info->type = "Compute"; info->p1_revision = 0; break; - case '8': info->type = "Pi 3 Model B"; info->p1_revision = 3; break; - case '9': info->type = "Zero"; info->p1_revision = 3; break; - default : info->type = "Unknown"; info->p1_revision = 3; break; - } - switch (revision[len-4]) { - case '0': info->processor = "BCM2835"; break; - case '1': info->processor = "BCM2836"; break; - case '2': info->processor = "BCM2837"; break; - default : info->processor = "Unknown"; break; - } - switch (revision[len-5]) { - case '0': info->manufacturer = "Sony"; break; - case '1': info->manufacturer = "Egoman"; break; - case '2': info->manufacturer = "Embest"; break; - case '4': info->manufacturer = "Embest"; break; - default : info->manufacturer = "Unknown"; break; - } - switch (strtol((char[]){revision[len-6],0}, NULL, 16) & 7) { - case 0: info->ram = "256M"; break; - case 1: info->ram = "512M"; break; - case 2: info->ram = "1024M"; break; - default: info->ram = "Unknown"; break; - } - } else { - // old scheme - info->ram = "Unknown"; - info->manufacturer = "Unknown"; - info->processor = "Unknown"; - info->type = "Unknown"; - strcpy(info->revision, revision); - - // get last four characters (ignore preceeding 1000 for overvolt) - if (len > 4) - rev = (char *)&revision+len-4; - else - rev = revision; - - if ((strcmp(rev, "0002") == 0) || - (strcmp(rev, "0003") == 0)) { - info->type = "Model B"; - info->p1_revision = 1; - info->ram = "256M"; - info->processor = "BCM2835"; - } else if (strcmp(rev, "0004") == 0) { - info->type = "Model B"; - info->p1_revision = 2; - info->ram = "256M"; - info->manufacturer = "Sony"; - info->processor = "BCM2835"; - } else if (strcmp(rev, "0005") == 0) { - info->type = "Model B"; - info->p1_revision = 2; - info->ram = "256M"; - info->manufacturer = "Qisda"; - info->processor = "BCM2835"; - } else if (strcmp(rev, "0006") == 0) { - info->type = "Model B"; - info->p1_revision = 2; - info->ram = "256M"; - info->manufacturer = "Egoman"; - info->processor = "BCM2835"; - } else if (strcmp(rev, "0007") == 0) { - info->type = "Model A"; - info->p1_revision = 2; - info->ram = "256M"; - info->manufacturer = "Egoman"; - info->processor = "BCM2835"; - } else if (strcmp(rev, "0008") == 0) { - info->type = "Model A"; - info->p1_revision = 2; - info->ram = "256M"; - info->manufacturer = "Sony"; - info->processor = "BCM2835"; - } else if (strcmp(rev, "0009") == 0) { - info->type = "Model A"; - info->p1_revision = 2; - info->ram = "256M"; - info->manufacturer = "Qisda"; - info->processor = "BCM2835"; - } else if (strcmp(rev, "000d") == 0) { - info->type = "Model B"; - info->p1_revision = 2; - info->ram = "512M"; - info->manufacturer = "Egoman"; - info->processor = "BCM2835"; - } else if (strcmp(rev, "000e") == 0) { - info->type = "Model B"; - info->p1_revision = 2; - info->ram = "512M"; - info->manufacturer = "Sony"; - info->processor = "BCM2835"; - } else if (strcmp(rev, "000f") == 0) { - info->type = "Model B"; - info->p1_revision = 2; - info->ram = "512M"; - info->manufacturer = "Qisda"; - info->processor = "BCM2835"; - } else if ((strcmp(rev, "0011") == 0) || - (strcmp(rev, "0014") == 0)) { - info->type = "Compute Module"; - info->p1_revision = 0; - info->ram = "512M"; - info->processor = "BCM2835"; - } else if (strcmp(rev, "0012") == 0) { - info->type = "Model A+"; - info->p1_revision = 3; - info->ram = "256M"; - info->processor = "BCM2835"; - } else if ((strcmp(rev, "0010") == 0) || - (strcmp(rev, "0013") == 0)) { - info->type = "Model B+"; - info->p1_revision = 3; - info->ram = "512M"; - info->processor = "BCM2835"; - } else { // don't know - assume revision 3 p1 connector - info->p1_revision = 3; - } - } - return 0; + FILE *fp; + char buffer[1024]; + char hardware[1024]; + char revision[1024]; + char *rev; + int found = 0; + int len; + + if ((fp = fopen("/proc/cpuinfo", "r")) == NULL) { + return -1; + } + while(!feof(fp)) { + fgets(buffer, sizeof(buffer), fp); + sscanf(buffer, "Hardware : %s", hardware); + if (strcmp(hardware, "BCM2708") == 0 || + strcmp(hardware, "BCM2709") == 0 || + strcmp(hardware, "BCM2835") == 0 || + strcmp(hardware, "BCM2836") == 0 || + strcmp(hardware, "BCM2837") == 0 ) { + found = 1; + } + sscanf(buffer, "Revision : %s", revision); + } + fclose(fp); + + if (!found) { + return -1; + } + + if ((len = strlen(revision)) == 0) { + return -1; + } + + if (len >= 6 && strtol((char[]) { + revision[len-6],0 + }, NULL, 16) & 8) { + // new scheme + //info->rev = revision[len-1]-'0'; + strcpy(info->revision, revision); + switch (revision[len-2]) { + case '0': + info->type = "Model A"; + info->p1_revision = 2; + break; + case '1': + info->type = "Model B"; + info->p1_revision = 2; + break; + case '2': + info->type = "Model A+"; + info->p1_revision = 3; + break; + case '3': + info->type = "Model B+"; + info->p1_revision = 3; + break; + case '4': + info->type = "Pi 2 Model B"; + info->p1_revision = 3; + break; + case '5': + info->type = "Alpha"; + info->p1_revision = 3; + break; + case '6': + info->type = "Compute"; + info->p1_revision = 0; + break; + case '8': + info->type = "Pi 3 Model B"; + info->p1_revision = 3; + break; + case '9': + info->type = "Zero"; + info->p1_revision = 3; + break; + default : + info->type = "Unknown"; + info->p1_revision = 3; + break; + } + switch (revision[len-4]) { + case '0': + info->processor = "BCM2835"; + break; + case '1': + info->processor = "BCM2836"; + break; + case '2': + info->processor = "BCM2837"; + break; + default : + info->processor = "Unknown"; + break; + } + switch (revision[len-5]) { + case '0': + info->manufacturer = "Sony"; + break; + case '1': + info->manufacturer = "Egoman"; + break; + case '2': + info->manufacturer = "Embest"; + break; + case '4': + info->manufacturer = "Embest"; + break; + default : + info->manufacturer = "Unknown"; + break; + } + switch (strtol((char[]) { + revision[len-6],0 + }, NULL, 16) & 7) { + case 0: + info->ram = "256M"; + break; + case 1: + info->ram = "512M"; + break; + case 2: + info->ram = "1024M"; + break; + default: + info->ram = "Unknown"; + break; + } + } + else { + // old scheme + info->ram = "Unknown"; + info->manufacturer = "Unknown"; + info->processor = "Unknown"; + info->type = "Unknown"; + strcpy(info->revision, revision); + + // get last four characters (ignore preceeding 1000 for overvolt) + if (len > 4) { + rev = (char *)&revision+len-4; + } else { + rev = revision; + } + + if ((strcmp(rev, "0002") == 0) || + (strcmp(rev, "0003") == 0)) { + info->type = "Model B"; + info->p1_revision = 1; + info->ram = "256M"; + info->processor = "BCM2835"; + } else if (strcmp(rev, "0004") == 0) { + info->type = "Model B"; + info->p1_revision = 2; + info->ram = "256M"; + info->manufacturer = "Sony"; + info->processor = "BCM2835"; + } else if (strcmp(rev, "0005") == 0) { + info->type = "Model B"; + info->p1_revision = 2; + info->ram = "256M"; + info->manufacturer = "Qisda"; + info->processor = "BCM2835"; + } else if (strcmp(rev, "0006") == 0) { + info->type = "Model B"; + info->p1_revision = 2; + info->ram = "256M"; + info->manufacturer = "Egoman"; + info->processor = "BCM2835"; + } else if (strcmp(rev, "0007") == 0) { + info->type = "Model A"; + info->p1_revision = 2; + info->ram = "256M"; + info->manufacturer = "Egoman"; + info->processor = "BCM2835"; + } else if (strcmp(rev, "0008") == 0) { + info->type = "Model A"; + info->p1_revision = 2; + info->ram = "256M"; + info->manufacturer = "Sony"; + info->processor = "BCM2835"; + } else if (strcmp(rev, "0009") == 0) { + info->type = "Model A"; + info->p1_revision = 2; + info->ram = "256M"; + info->manufacturer = "Qisda"; + info->processor = "BCM2835"; + } else if (strcmp(rev, "000d") == 0) { + info->type = "Model B"; + info->p1_revision = 2; + info->ram = "512M"; + info->manufacturer = "Egoman"; + info->processor = "BCM2835"; + } else if (strcmp(rev, "000e") == 0) { + info->type = "Model B"; + info->p1_revision = 2; + info->ram = "512M"; + info->manufacturer = "Sony"; + info->processor = "BCM2835"; + } else if (strcmp(rev, "000f") == 0) { + info->type = "Model B"; + info->p1_revision = 2; + info->ram = "512M"; + info->manufacturer = "Qisda"; + info->processor = "BCM2835"; + } else if ((strcmp(rev, "0011") == 0) || + (strcmp(rev, "0014") == 0)) { + info->type = "Compute Module"; + info->p1_revision = 0; + info->ram = "512M"; + info->processor = "BCM2835"; + } else if (strcmp(rev, "0012") == 0) { + info->type = "Model A+"; + info->p1_revision = 3; + info->ram = "256M"; + info->processor = "BCM2835"; + } else if ((strcmp(rev, "0010") == 0) || + (strcmp(rev, "0013") == 0)) { + info->type = "Model B+"; + info->p1_revision = 3; + info->ram = "512M"; + info->processor = "BCM2835"; + } else { // don't know - assume revision 3 p1 connector + info->p1_revision = 3; + } + } + return 0; } /* diff --git a/drivers/RPi/cpuinfo.h b/drivers/RPi/cpuinfo.h index b3c43fe33..dc32f44e0 100644 --- a/drivers/RPi/cpuinfo.h +++ b/drivers/RPi/cpuinfo.h @@ -28,14 +28,13 @@ SOFTWARE. extern "C" { #endif -typedef struct -{ - int p1_revision; - char *ram; - char *manufacturer; - char *processor; - char *type; - char revision[1024]; +typedef struct { + int p1_revision; + char *ram; + char *manufacturer; + char *processor; + char *type; + char revision[1024]; } rpi_info; int get_rpi_info(rpi_info *info); diff --git a/drivers/RPi/piHiPri.c b/drivers/RPi/piHiPri.c index 63c021662..2300298c0 100644 --- a/drivers/RPi/piHiPri.c +++ b/drivers/RPi/piHiPri.c @@ -35,14 +35,15 @@ int piHiPri (const int pri) { - struct sched_param sched ; + struct sched_param sched ; - memset (&sched, 0, sizeof(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 ; + 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) ; + return sched_setscheduler (0, SCHED_RR, &sched) ; } diff --git a/drivers/RPi/rpi_util.cpp b/drivers/RPi/rpi_util.cpp index f3ea8fe3d..39815753d 100644 --- a/drivers/RPi/rpi_util.cpp +++ b/drivers/RPi/rpi_util.cpp @@ -55,8 +55,7 @@ static pthread_t *threadIds[64] = {NULL}; // sysFds: // Map a file descriptor from the /sys/class/gpio/gpioX/value -static int sysFds[64] = -{ +static int sysFds[64] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -82,7 +81,7 @@ int get_gpio_number(uint8_t physPin, uint8_t *gpio) } if ((rpiinfo.p1_revision != 3 && physPin > 26) - || (rpiinfo.p1_revision == 3 && physPin > 40)) { + || (rpiinfo.p1_revision == 3 && physPin > 40)) { return -1; } @@ -95,7 +94,8 @@ int get_gpio_number(uint8_t physPin, uint8_t *gpio) return 0; } -void *interruptHandler(void *args) { +void *interruptHandler(void *args) +{ int fd, ret; struct pollfd polls; char c; @@ -126,7 +126,7 @@ void *interruptHandler(void *args) { // 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) ; + lseek (fd, 0, SEEK_SET) ; // Call user function. pthread_mutex_lock(&intMutex); if (interruptsEnabled) { @@ -142,7 +142,8 @@ void *interruptHandler(void *args) { return NULL; } -void rpi_util::pinMode(uint8_t physPin, uint8_t mode) { +void rpi_util::pinMode(uint8_t physPin, uint8_t mode) +{ uint8_t gpioPin; if (get_gpio_number(physPin, &gpioPin)) { @@ -158,7 +159,8 @@ void rpi_util::pinMode(uint8_t physPin, uint8_t mode) { } } -void rpi_util::digitalWrite(uint8_t physPin, uint8_t value) { +void rpi_util::digitalWrite(uint8_t physPin, uint8_t value) +{ uint8_t gpioPin; if (get_gpio_number(physPin, &gpioPin)) { @@ -178,7 +180,8 @@ void rpi_util::digitalWrite(uint8_t physPin, uint8_t value) { } } -uint8_t rpi_util::digitalRead(uint8_t physPin) { +uint8_t rpi_util::digitalRead(uint8_t physPin) +{ uint8_t gpioPin; if (get_gpio_number(physPin, &gpioPin)) { @@ -194,7 +197,8 @@ uint8_t rpi_util::digitalRead(uint8_t physPin) { } } -void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode) { +void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode) +{ FILE *fd; char fName[40]; char c; @@ -220,7 +224,7 @@ void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode) { logError("attachInterrupt: Unable to export pin %d for interrupt: %s\n", physPin, strerror(errno)); exit(1); } - fprintf(fd, "%d\n", gpioPin); + fprintf(fd, "%d\n", gpioPin); fclose(fd); // Wait a bit the system to create /sys/class/gpio/gpio @@ -228,7 +232,8 @@ void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode) { snprintf(fName, sizeof(fName), "/sys/class/gpio/gpio%d/direction", gpioPin) ; if ((fd = fopen (fName, "w")) == NULL) { - fprintf (stderr, "attachInterrupt: Unable to open GPIO direction interface for pin %d: %s\n", physPin, strerror(errno)); + fprintf (stderr, "attachInterrupt: Unable to open GPIO direction interface for pin %d: %s\n", + physPin, strerror(errno)); exit(1) ; } fprintf(fd, "in\n") ; @@ -236,18 +241,27 @@ 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) { - fprintf (stderr, "attachInterrupt: Unable to open GPIO edge interface for pin %d: %s\n", physPin, strerror(errno)); + fprintf (stderr, "attachInterrupt: Unable to open GPIO edge interface for pin %d: %s\n", physPin, + strerror(errno)); exit(1) ; } switch (mode) { - case CHANGE: fprintf(fd, "both\n"); break; - case FALLING: fprintf(fd, "falling\n"); break; - case RISING: fprintf(fd, "rising\n"); break; - case NONE: fprintf(fd, "none\n"); break; - default: - logError("attachInterrupt: Invalid mode\n"); - fclose(fd); - return; + case CHANGE: + fprintf(fd, "both\n"); + break; + case FALLING: + fprintf(fd, "falling\n"); + break; + case RISING: + fprintf(fd, "rising\n"); + break; + case NONE: + fprintf(fd, "none\n"); + break; + default: + logError("attachInterrupt: Invalid mode\n"); + fclose(fd); + return; } fclose(fd); @@ -275,7 +289,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 rpi_util::detachInterrupt(uint8_t physPin) +{ uint8_t gpioPin; if (get_gpio_number(physPin, &gpioPin)) { @@ -301,22 +316,25 @@ void rpi_util::detachInterrupt(uint8_t physPin) { logError("Unable to unexport pin %d for interrupt\n", gpioPin); exit(1); } - fprintf(fp, "%d", gpioPin); + fprintf(fp, "%d", gpioPin); fclose(fp); } -uint8_t rpi_util::digitalPinToInterrupt(uint8_t physPin) { +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 rpi_util::interrupts() +{ pthread_mutex_lock(&intMutex); interruptsEnabled = true; pthread_mutex_unlock(&intMutex); } -void rpi_util::noInterrupts() { +void rpi_util::noInterrupts() +{ pthread_mutex_lock(&intMutex); interruptsEnabled = false; pthread_mutex_unlock(&intMutex); diff --git a/drivers/RPi/rpi_util.h b/drivers/RPi/rpi_util.h index 0a10981b0..9e115d2ce 100644 --- a/drivers/RPi/rpi_util.h +++ b/drivers/RPi/rpi_util.h @@ -29,7 +29,8 @@ const int pin_to_gpio_rev1[41] = {-1, -1, -1, 0, -1, 1, -1, 4, 14, -1, 15, 17, 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 { +namespace rpi_util +{ typedef enum { LSBFIRST = BCM2835_SPI_BIT_ORDER_LSBFIRST, diff --git a/drivers/SPIFlash/SPIFlash.cpp b/drivers/SPIFlash/SPIFlash.cpp index 52bf06ce3..cd3d8738a 100644 --- a/drivers/SPIFlash/SPIFlash.cpp +++ b/drivers/SPIFlash/SPIFlash.cpp @@ -47,46 +47,50 @@ uint8_t SPIFlash::UNIQUEID[8]; /// get this from the datasheet of your flash chip /// Example for Atmel-Adesto 4Mbit AT25DF041A: 0x1F44 (page 27: http://www.adestotech.com/sites/default/files/datasheets/doc3668.pdf) /// Example for Winbond 4Mbit W25X40CL: 0xEF30 (page 14: http://www.winbond.com/NR/rdonlyres/6E25084C-0BFE-4B25-903D-AE10221A0929/0/W25X40CL.pdf) -SPIFlash::SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID) { - _slaveSelectPin = slaveSelectPin; - _jedecID = jedecID; +SPIFlash::SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID) +{ + _slaveSelectPin = slaveSelectPin; + _jedecID = jedecID; } /// Select the flash chip -void SPIFlash::select() { - //save current SPI settings +void SPIFlash::select() +{ + //save current SPI settings #ifndef SPI_HAS_TRANSACTION - noInterrupts(); + noInterrupts(); #endif #ifndef ESP8266 - _SPCR = SPCR; - _SPSR = SPSR; + _SPCR = SPCR; + _SPSR = SPSR; #endif #ifdef SPI_HAS_TRANSACTION - SPI.beginTransaction(_settings); + SPI.beginTransaction(_settings); #else - // set FLASH SPI settings - SPI.setDataMode(SPI_MODE0); - SPI.setBitOrder(MSBFIRST); - SPI.setClockDivider(SPI_CLOCK_DIV4); //decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present - SPI.begin(); + // set FLASH SPI settings + SPI.setDataMode(SPI_MODE0); + SPI.setBitOrder(MSBFIRST); + SPI.setClockDivider( + SPI_CLOCK_DIV4); //decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present + SPI.begin(); #endif - hwDigitalWrite(_slaveSelectPin, LOW); + hwDigitalWrite(_slaveSelectPin, LOW); } /// UNselect the flash chip -void SPIFlash::unselect() { - hwDigitalWrite(_slaveSelectPin, HIGH); - //restore SPI settings to what they were before talking to the FLASH chip +void SPIFlash::unselect() +{ + hwDigitalWrite(_slaveSelectPin, HIGH); + //restore SPI settings to what they were before talking to the FLASH chip #ifdef SPI_HAS_TRANSACTION - SPI.endTransaction(); + SPI.endTransaction(); #else - interrupts(); + interrupts(); #endif #ifndef ESP8266 - SPCR = _SPCR; - SPSR = _SPSR; + SPCR = _SPCR; + SPSR = _SPSR; #endif } @@ -94,39 +98,39 @@ void SPIFlash::unselect() { boolean SPIFlash::initialize() { #ifndef ESP8266 - _SPCR = SPCR; - _SPSR = SPSR; + _SPCR = SPCR; + _SPSR = SPSR; #endif - hwPinMode(_slaveSelectPin, OUTPUT); + hwPinMode(_slaveSelectPin, OUTPUT); #ifdef SPI_HAS_TRANSACTION - _settings = SPISettings(4000000, MSBFIRST, SPI_MODE0); + _settings = SPISettings(4000000, MSBFIRST, SPI_MODE0); #endif - unselect(); - wakeup(); + unselect(); + wakeup(); - if (_jedecID == 0 || readDeviceId() == _jedecID) { - command(SPIFLASH_STATUSWRITE, true); // Write Status Register - SPI.transfer(0); // Global Unprotect - unselect(); - return true; - } - return false; + if (_jedecID == 0 || readDeviceId() == _jedecID) { + command(SPIFLASH_STATUSWRITE, true); // Write Status Register + SPI.transfer(0); // Global Unprotect + unselect(); + return true; + } + return false; } /// Get the manufacturer and device ID bytes (as a short word) uint16_t SPIFlash::readDeviceId() { #if defined(__AVR_ATmega32U4__) // Arduino Leonardo, MoteinoLeo - command(SPIFLASH_IDREAD); // Read JEDEC ID + command(SPIFLASH_IDREAD); // Read JEDEC ID #else - select(); - SPI.transfer(SPIFLASH_IDREAD); + select(); + SPI.transfer(SPIFLASH_IDREAD); #endif - uint16_t jedecid = SPI.transfer(0) << 8; - jedecid |= SPI.transfer(0); - unselect(); - return jedecid; + uint16_t jedecid = SPI.transfer(0) << 8; + jedecid |= SPI.transfer(0); + unselect(); + return jedecid; } /// Get the 64 bit unique identifier, stores it in UNIQUEID[8]. Only needs to be called once, ie after initialize @@ -137,97 +141,100 @@ uint16_t SPIFlash::readDeviceId() /// flash.readUniqueId(); uint8_t* MAC = flash.readUniqueId(); for (uint8_t i=0;i<8;i++) { Serial.print(MAC[i], HEX); Serial.print(' '); } uint8_t* SPIFlash::readUniqueId() { - command(SPIFLASH_MACREAD); - SPI.transfer(0); - SPI.transfer(0); - SPI.transfer(0); - SPI.transfer(0); - for (uint8_t i=0;i<8;i++) { - UNIQUEID[i] = SPI.transfer(0); - } - unselect(); - return UNIQUEID; + command(SPIFLASH_MACREAD); + SPI.transfer(0); + SPI.transfer(0); + SPI.transfer(0); + SPI.transfer(0); + for (uint8_t i=0; i<8; i++) { + UNIQUEID[i] = SPI.transfer(0); + } + unselect(); + return UNIQUEID; } /// read 1 byte from flash memory -uint8_t SPIFlash::readByte(uint32_t addr) { - command(SPIFLASH_ARRAYREADLOWFREQ); - SPI.transfer(addr >> 16); - SPI.transfer(addr >> 8); - SPI.transfer(addr); - uint8_t result = SPI.transfer(0); - unselect(); - return result; +uint8_t SPIFlash::readByte(uint32_t addr) +{ + command(SPIFLASH_ARRAYREADLOWFREQ); + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + uint8_t result = SPI.transfer(0); + unselect(); + return result; } /// read unlimited # of bytes -void SPIFlash::readBytes(uint32_t addr, void* buf, uint16_t len) { - command(SPIFLASH_ARRAYREAD); - SPI.transfer(addr >> 16); - SPI.transfer(addr >> 8); - SPI.transfer(addr); - SPI.transfer(0); //"dont care" - for (uint16_t i = 0; i < len; ++i) { - ((uint8_t*) buf)[i] = SPI.transfer(0); - } - unselect(); +void SPIFlash::readBytes(uint32_t addr, void* buf, uint16_t len) +{ + command(SPIFLASH_ARRAYREAD); + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + SPI.transfer(0); //"dont care" + for (uint16_t i = 0; i < len; ++i) { + ((uint8_t*) buf)[i] = SPI.transfer(0); + } + unselect(); } /// Send a command to the flash chip, pass TRUE for isWrite when its a write command -void SPIFlash::command(uint8_t cmd, boolean isWrite){ +void SPIFlash::command(uint8_t cmd, boolean isWrite) +{ #if defined(__AVR_ATmega32U4__) // Arduino Leonardo, MoteinoLeo - DDRB |= B00000001; // Make sure the SS pin (PB0 - used by RFM12B on MoteinoLeo R1) is set as output HIGH! - PORTB |= B00000001; + DDRB |= B00000001; // Make sure the SS pin (PB0 - used by RFM12B on MoteinoLeo R1) is set as output HIGH! + PORTB |= B00000001; #endif - if (isWrite) - { - command(SPIFLASH_WRITEENABLE); // Write Enable - unselect(); - } - //wait for any write/erase to complete - // a time limit cannot really be added here without it being a very large safe limit - // that is because some chips can take several seconds to carry out a chip erase or other similar multi block or entire-chip operations - // a recommended alternative to such situations where chip can be or not be present is to add a 10k or similar weak pulldown on the - // open drain MISO input which can read noise/static and hence return a non 0 status byte, causing the while() to hang when a flash chip is not present - while(busy()); - select(); - SPI.transfer(cmd); + if (isWrite) { + command(SPIFLASH_WRITEENABLE); // Write Enable + unselect(); + } + //wait for any write/erase to complete + // a time limit cannot really be added here without it being a very large safe limit + // that is because some chips can take several seconds to carry out a chip erase or other similar multi block or entire-chip operations + // a recommended alternative to such situations where chip can be or not be present is to add a 10k or similar weak pulldown on the + // open drain MISO input which can read noise/static and hence return a non 0 status byte, causing the while() to hang when a flash chip is not present + while(busy()); + select(); + SPI.transfer(cmd); } /// check if the chip is busy erasing/writing boolean SPIFlash::busy() { - /* - select(); - SPI.transfer(SPIFLASH_STATUSREAD); - uint8_t status = SPI.transfer(0); - unselect(); - return status & 1; - */ - return readStatus() & 1; + /* + select(); + SPI.transfer(SPIFLASH_STATUSREAD); + uint8_t status = SPI.transfer(0); + unselect(); + return status & 1; + */ + return readStatus() & 1; } /// return the STATUS register uint8_t SPIFlash::readStatus() { - select(); - SPI.transfer(SPIFLASH_STATUSREAD); - uint8_t status = SPI.transfer(0); - unselect(); - return status; + select(); + SPI.transfer(SPIFLASH_STATUSREAD); + uint8_t status = SPI.transfer(0); + unselect(); + return status; } /// Write 1 byte to flash memory /// WARNING: you can only write to previously erased memory locations (see datasheet) /// use the block erase commands to first clear memory (write 0xFFs) -void SPIFlash::writeByte(uint32_t addr, uint8_t byt) { - command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program - SPI.transfer(addr >> 16); - SPI.transfer(addr >> 8); - SPI.transfer(addr); - SPI.transfer(byt); - unselect(); +void SPIFlash::writeByte(uint32_t addr, uint8_t byt) +{ + command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + SPI.transfer(byt); + unselect(); } /// write multiple bytes to flash memory (up to 64K) @@ -235,74 +242,74 @@ void SPIFlash::writeByte(uint32_t addr, uint8_t byt) { /// use the block erase commands to first clear memory (write 0xFFs) /// This version handles both page alignment and data blocks larger than 256 bytes. /// See documentation of #MY_SPIFLASH_SST25TYPE define for more information -void SPIFlash::writeBytes(uint32_t addr, const void* buf, uint16_t len) { +void SPIFlash::writeBytes(uint32_t addr, const void* buf, uint16_t len) +{ #ifdef MY_SPIFLASH_SST25TYPE - //SST25 Type of Flash does not support Page Programming but AAI Word Programming - uint16_t i=0; - uint8_t oddAdr=0; - char s[5]; - - command(SPIFLASH_AAIWORDPROGRAM, true); // Byte/Page Program - SPI.transfer(addr >> 16); - SPI.transfer(addr >> 8); - SPI.transfer(addr); - - if (addr%2){ - //start address is not even, i.e. first byte of word must be 0xff - SPI.transfer(0xff); - SPI.transfer(((uint8_t*) buf)[0]); - unselect(); - oddAdr=1; //following addresses must all be shifted one off - len--; - if (len > 0) { - command(SPIFLASH_AAIWORDPROGRAM); //If for loop will run issue Wordprogram command - } - } - - for (i=0;i<(len/2);i++){ - //AAI command must be set before every new word - if (i>0) { - command(SPIFLASH_AAIWORDPROGRAM); //Wordprogram command for first write has been issued before - } - SPI.transfer(((uint8_t*) buf)[i*2+oddAdr]); - SPI.transfer(((uint8_t*) buf)[i*2+1+oddAdr]); - unselect(); - } - - if (len-i*2 == 1){ - //There is one byte (i.e. half word) left. This happens if len was odd or (len was even and addr odd) - if (i>0) { - command(SPIFLASH_AAIWORDPROGRAM); //if for loop had not run wordprogram command from before is still valid - } - SPI.transfer(((uint8_t*) buf)[i*2+oddAdr]); - SPI.transfer(0xff); - unselect(); - } - - command(SPIFLASH_WRITEDISABLE); //end AAI programming - unselect(); + //SST25 Type of Flash does not support Page Programming but AAI Word Programming + uint16_t i=0; + uint8_t oddAdr=0; + char s[5]; + + command(SPIFLASH_AAIWORDPROGRAM, true); // Byte/Page Program + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + + if (addr%2) { + //start address is not even, i.e. first byte of word must be 0xff + SPI.transfer(0xff); + SPI.transfer(((uint8_t*) buf)[0]); + unselect(); + oddAdr=1; //following addresses must all be shifted one off + len--; + if (len > 0) { + command(SPIFLASH_AAIWORDPROGRAM); //If for loop will run issue Wordprogram command + } + } + + for (i=0; i<(len/2); i++) { + //AAI command must be set before every new word + if (i>0) { + command(SPIFLASH_AAIWORDPROGRAM); //Wordprogram command for first write has been issued before + } + SPI.transfer(((uint8_t*) buf)[i*2+oddAdr]); + SPI.transfer(((uint8_t*) buf)[i*2+1+oddAdr]); + unselect(); + } + + if (len-i*2 == 1) { + //There is one byte (i.e. half word) left. This happens if len was odd or (len was even and addr odd) + if (i>0) { + command(SPIFLASH_AAIWORDPROGRAM); //if for loop had not run wordprogram command from before is still valid + } + SPI.transfer(((uint8_t*) buf)[i*2+oddAdr]); + SPI.transfer(0xff); + unselect(); + } + + command(SPIFLASH_WRITEDISABLE); //end AAI programming + unselect(); #else - uint16_t n; - uint16_t maxBytes = 256-(addr%256); // force the first set of bytes to stay within the first page - uint16_t offset = 0; - while (len>0) - { - n = (len<=maxBytes) ? len : maxBytes; - command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program - SPI.transfer(addr >> 16); - SPI.transfer(addr >> 8); - SPI.transfer(addr); - - for (uint16_t i = 0; i < n; i++) { - SPI.transfer(((uint8_t*) buf)[offset + i]); - } - unselect(); - - addr+=n; // adjust the addresses and remaining bytes by what we've just transferred. - offset +=n; - len -= n; - maxBytes = 256; // now we can do up to 256 bytes per loop - } + uint16_t n; + uint16_t maxBytes = 256-(addr%256); // force the first set of bytes to stay within the first page + uint16_t offset = 0; + while (len>0) { + n = (len<=maxBytes) ? len : maxBytes; + command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + + for (uint16_t i = 0; i < n; i++) { + SPI.transfer(((uint8_t*) buf)[offset + i]); + } + unselect(); + + addr+=n; // adjust the addresses and remaining bytes by what we've just transferred. + offset +=n; + len -= n; + maxBytes = 256; // now we can do up to 256 bytes per loop + } #endif } @@ -312,40 +319,46 @@ void SPIFlash::writeBytes(uint32_t addr, const void* buf, uint16_t len) { /// other things and later check if the chip is done with busy() /// note that any command will first wait for chip to become available using busy() /// so no need to do that twice -void SPIFlash::chipErase() { - command(SPIFLASH_CHIPERASE, true); - unselect(); +void SPIFlash::chipErase() +{ + command(SPIFLASH_CHIPERASE, true); + unselect(); } /// erase a 4Kbyte block -void SPIFlash::blockErase4K(uint32_t addr) { - command(SPIFLASH_BLOCKERASE_4K, true); // Block Erase - SPI.transfer(addr >> 16); - SPI.transfer(addr >> 8); - SPI.transfer(addr); - unselect(); +void SPIFlash::blockErase4K(uint32_t addr) +{ + command(SPIFLASH_BLOCKERASE_4K, true); // Block Erase + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + unselect(); } /// erase a 32Kbyte block -void SPIFlash::blockErase32K(uint32_t addr) { - command(SPIFLASH_BLOCKERASE_32K, true); // Block Erase - SPI.transfer(addr >> 16); - SPI.transfer(addr >> 8); - SPI.transfer(addr); - unselect(); +void SPIFlash::blockErase32K(uint32_t addr) +{ + command(SPIFLASH_BLOCKERASE_32K, true); // Block Erase + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + unselect(); } -void SPIFlash::sleep() { - command(SPIFLASH_SLEEP); - unselect(); +void SPIFlash::sleep() +{ + command(SPIFLASH_SLEEP); + unselect(); } -void SPIFlash::wakeup() { - command(SPIFLASH_WAKE); - unselect(); +void SPIFlash::wakeup() +{ + command(SPIFLASH_WAKE); + unselect(); } /// cleanup -void SPIFlash::end() { - SPI.end(); +void SPIFlash::end() +{ + SPI.end(); } diff --git a/drivers/SPIFlash/SPIFlash.h b/drivers/SPIFlash/SPIFlash.h index e08b6d51a..c3ac5f617 100644 --- a/drivers/SPIFlash/SPIFlash.h +++ b/drivers/SPIFlash/SPIFlash.h @@ -7,28 +7,28 @@ // > Updated Jan. 5, 2015, TomWS1, modified writeBytes to allow blocks > 256 bytes and handle page misalignment. // > Updated Feb. 26, 2015 TomWS1, added support for SPI Transactions (Arduino 1.5.8 and above) // > Selective merge by Felix after testing in IDE 1.0.6, 1.6.4 -// > Updated May 19, 2016 D-H-R, added support for SST25/Microchip Flash which does not support Page programming with OPCode 0x02, +// > Updated May 19, 2016 D-H-R, added support for SST25/Microchip Flash which does not support Page programming with OPCode 0x02, // > use define MY_SPIFLASH_SST25TYPE for SST25 Type Flash Memory. Added / changed comments to better suit doxygen // ********************************************************************************** // License // ********************************************************************************** -// This program is free software; you can redistribute it -// and/or modify it under the terms of the GNU General -// Public License as published by the Free Software -// Foundation; either version 3 of the License, or -// (at your option) any later version. -// -// This program 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 General Public -// License for more details. -// -// You should have received a copy of the GNU General +// This program is free software; you can redistribute it +// and/or modify it under the terms of the GNU General +// Public License as published by the Free Software +// Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public +// License for more details. +// +// You should have received a copy of the GNU General // Public License along with this program. // If not, see . -// -// Licence can be viewed at +// +// Licence can be viewed at // http://www.gnu.org/licenses/gpl-3.0.txt // // Please maintain this license information along with authorship @@ -82,7 +82,7 @@ #define SPIFLASH_BLOCKERASE_32K 0x52 //!< erase one 32K block of flash memory #define SPIFLASH_BLOCKERASE_64K 0xD8 //!< erase one 64K block of flash memory #define SPIFLASH_CHIPERASE 0x60 //!< @brief chip erase (may take several seconds depending on size) - //!< Chip is erased but not actually waited for completion (instead need to check the status register BUSY bit) +//!< Chip is erased but not actually waited for completion (instead need to check the status register BUSY bit) #define SPIFLASH_STATUSREAD 0x05 //!< read status register #define SPIFLASH_STATUSWRITE 0x01 //!< write status register #define SPIFLASH_ARRAYREAD 0x0B //!< read array (fast, need to add 1 dummy byte after 3 address bytes) @@ -92,13 +92,13 @@ #define SPIFLASH_WAKE 0xAB //!< deep power wake up #define SPIFLASH_BYTEPAGEPROGRAM 0x02 //!< write (1 to 256bytes). Writing more than one Byte is not supported on all devices (e.g. SST25 Series) #define SPIFLASH_AAIWORDPROGRAM 0xAD //!< @brief Auto Address Increment Programming on Microchip SST Family Devices which do not support page program.
- //!< Use define #MY_SPIFLASH_SST25TYPE to use AAI prog instead of Bytepageprogram which does not work on SST Family Chips - //!< tested with SST25PF020B80 http://ww1.microchip.com/downloads/en/DeviceDoc/20005135B.pdf +//!< Use define #MY_SPIFLASH_SST25TYPE to use AAI prog instead of Bytepageprogram which does not work on SST Family Chips +//!< tested with SST25PF020B80 http://ww1.microchip.com/downloads/en/DeviceDoc/20005135B.pdf #define SPIFLASH_IDREAD 0x9F //!< @brief read JEDEC manufacturer and device ID (2 bytes, specific bytes for each manufacturer and device) - //!< Example for Atmel-Adesto 4Mbit AT25DF041A: 0x1F44 (page 27: http://www.adestotech.com/sites/default/files/datasheets/doc3668.pdf) - //!< Example for Winbond 4Mbit W25X40CL: 0xEF30 (page 14: http://www.winbond.com/NR/rdonlyres/6E25084C-0BFE-4B25-903D-AE10221A0929/0/W25X40CL.pdf) +//!< Example for Atmel-Adesto 4Mbit AT25DF041A: 0x1F44 (page 27: http://www.adestotech.com/sites/default/files/datasheets/doc3668.pdf) +//!< Example for Winbond 4Mbit W25X40CL: 0xEF30 (page 14: http://www.winbond.com/NR/rdonlyres/6E25084C-0BFE-4B25-903D-AE10221A0929/0/W25X40CL.pdf) #define SPIFLASH_MACREAD 0x4B //!< read unique ID number (MAC) - + /// /// @def MY_SPIFLASH_SST25TYPE /// @brief If set AAI Word Programming is used to support SST25 Family SPI Flash. @@ -107,41 +107,44 @@ /// If SPIFLASH_SST25TYPE is set and writeBytes is called, it will use opcode 0xAD #SPIFLASH_AAIWORDPROGRAM and care for Byte alignment.
/// Note: AAI Wordprogramming is independent of Pages, so pagebreaking is not an issue when using AAI Wordprogramming. /// - #ifdef DOXYGEN //needed to tell doxygen not to ignore the define which is actually made somewhere else - #define MY_SPIFLASH_SST25TYPE - #endif - +#ifdef DOXYGEN //needed to tell doxygen not to ignore the define which is actually made somewhere else +#define MY_SPIFLASH_SST25TYPE +#endif + /** SPIFlash class */ -class SPIFlash { +class SPIFlash +{ public: - static uint8_t UNIQUEID[8]; //!< Storage for unique identifier - SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID=0); //!< Constructor - boolean initialize(); //!< setup SPI, read device ID etc... - void command(uint8_t cmd, boolean isWrite=false); //!< Send a command to the flash chip, pass TRUE for isWrite when its a write command - uint8_t readStatus(); //!< return the STATUS register - uint8_t readByte(uint32_t addr); //!< read 1 byte from flash memory - void readBytes(uint32_t addr, void* buf, uint16_t len); //!< read unlimited # of bytes - void writeByte(uint32_t addr, uint8_t byt); //!< Write 1 byte to flash memory - void writeBytes(uint32_t addr, const void* buf, uint16_t len); //!< write multiple bytes to flash memory (up to 64K), if define SPIFLASH_SST25TYPE is set AAI Word Programming will be used - boolean busy(); //!< check if the chip is busy erasing/writing - void chipErase(); //!< erase entire flash memory array - void blockErase4K(uint32_t address); //!< erase a 4Kbyte block - void blockErase32K(uint32_t address); //!< erase a 32Kbyte block - uint16_t readDeviceId(); //!< Get the manufacturer and device ID bytes (as a short word) - uint8_t* readUniqueId(); //!< Get the 64 bit unique identifier, stores it in @ref UNIQUEID[8] - - void sleep(); //!< Put device to sleep - void wakeup(); //!< Wake device - void end(); //!< end + static uint8_t UNIQUEID[8]; //!< Storage for unique identifier + SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID=0); //!< Constructor + boolean initialize(); //!< setup SPI, read device ID etc... + void command(uint8_t cmd, boolean isWrite= + false); //!< Send a command to the flash chip, pass TRUE for isWrite when its a write command + uint8_t readStatus(); //!< return the STATUS register + uint8_t readByte(uint32_t addr); //!< read 1 byte from flash memory + void readBytes(uint32_t addr, void* buf, uint16_t len); //!< read unlimited # of bytes + void writeByte(uint32_t addr, uint8_t byt); //!< Write 1 byte to flash memory + void writeBytes(uint32_t addr, const void* buf, + uint16_t len); //!< write multiple bytes to flash memory (up to 64K), if define SPIFLASH_SST25TYPE is set AAI Word Programming will be used + boolean busy(); //!< check if the chip is busy erasing/writing + void chipErase(); //!< erase entire flash memory array + void blockErase4K(uint32_t address); //!< erase a 4Kbyte block + void blockErase32K(uint32_t address); //!< erase a 32Kbyte block + uint16_t readDeviceId(); //!< Get the manufacturer and device ID bytes (as a short word) + uint8_t* readUniqueId(); //!< Get the 64 bit unique identifier, stores it in @ref UNIQUEID[8] + + void sleep(); //!< Put device to sleep + void wakeup(); //!< Wake device + void end(); //!< end protected: - void select(); //!< select - void unselect(); //!< unselect - uint8_t _slaveSelectPin; //!< Slave select pin - uint16_t _jedecID; //!< JEDEC ID - uint8_t _SPCR; //!< SPCR - uint8_t _SPSR; //!< SPSR + void select(); //!< select + void unselect(); //!< unselect + uint8_t _slaveSelectPin; //!< Slave select pin + uint16_t _jedecID; //!< JEDEC ID + uint8_t _SPCR; //!< SPCR + uint8_t _SPSR; //!< SPSR #ifdef SPI_HAS_TRANSACTION - SPISettings _settings; + SPISettings _settings; #endif }; diff --git a/examples/AirQualitySensor/AirQualitySensor.ino b/examples/AirQualitySensor/AirQualitySensor.ino index 07827aa4d..bdf77d0b8 100644 --- a/examples/AirQualitySensor/AirQualitySensor.ino +++ b/examples/AirQualitySensor/AirQualitySensor.ino @@ -48,14 +48,14 @@ #define MQ_SENSOR_ANALOG_PIN (0) //define which analog input channel you are going to use #define RL_VALUE (5) //define the load resistance on the board, in kilo ohms #define RO_CLEAN_AIR_FACTOR (9.83) //RO_CLEAR_AIR_FACTOR=(Sensor resistance in clean air)/RO, - //which is derived from the chart in datasheet +//which is derived from the chart in datasheet /***********************Software Related Macros************************************/ #define CALIBARAION_SAMPLE_TIMES (50) //define how many samples you are going to take in the calibration phase #define CALIBRATION_SAMPLE_INTERVAL (500) //define the time interal(in milisecond) between each samples in the - //cablibration phase +//cablibration phase #define READ_SAMPLE_INTERVAL (50) //define how many samples you are going to take in normal operation #define READ_SAMPLE_TIMES (5) //define the time interal(in milisecond) between each samples in - //normal operation +//normal operation /**********************Application Related Macros**********************************/ #define GAS_LPG (0) #define GAS_CO (1) @@ -68,58 +68,60 @@ int val = 0; // variable to store the value coming from the sensor float valMQ =0.0; float lastMQ =0.0; float LPGCurve[3] = {2.3,0.21,-0.47}; //two points are taken from the curve. - //with these two points, a line is formed which is "approximately equivalent" - //to the original curve. - //data format:{ x, y, slope}; point1: (lg200, 0.21), point2: (lg10000, -0.59) +//with these two points, a line is formed which is "approximately equivalent" +//to the original curve. +//data format:{ x, y, slope}; point1: (lg200, 0.21), point2: (lg10000, -0.59) float COCurve[3] = {2.3,0.72,-0.34}; //two points are taken from the curve. - //with these two points, a line is formed which is "approximately equivalent" - //to the original curve. - //data format:{ x, y, slope}; point1: (lg200, 0.72), point2: (lg10000, 0.15) -float SmokeCurve[3] ={2.3,0.53,-0.44}; //two points are taken from the curve. - //with these two points, a line is formed which is "approximately equivalent" - //to the original curve. - //data format:{ x, y, slope}; point1: (lg200, 0.53), point2:(lg10000,-0.22) +//with these two points, a line is formed which is "approximately equivalent" +//to the original curve. +//data format:{ x, y, slope}; point1: (lg200, 0.72), point2: (lg10000, 0.15) +float SmokeCurve[3] = {2.3,0.53,-0.44}; //two points are taken from the curve. +//with these two points, a line is formed which is "approximately equivalent" +//to the original curve. +//data format:{ x, y, slope}; point1: (lg200, 0.53), point2:(lg10000,-0.22) MyMessage msg(CHILD_ID_MQ, V_LEVEL); void setup() { - Ro = MQCalibration(MQ_SENSOR_ANALOG_PIN); //Calibrating the sensor. Please make sure the sensor is in clean air + Ro = MQCalibration( + MQ_SENSOR_ANALOG_PIN); //Calibrating the sensor. Please make sure the sensor is in clean air } -void presentation() { - // Send the sketch version information to the gateway and Controller - sendSketchInfo("Air Quality Sensor", "1.0"); +void presentation() +{ + // Send the sketch version information to the gateway and Controller + sendSketchInfo("Air Quality Sensor", "1.0"); - // Register all sensors to gateway (they will be created as child devices) - present(CHILD_ID_MQ, S_AIR_QUALITY); + // Register all sensors to gateway (they will be created as child devices) + present(CHILD_ID_MQ, S_AIR_QUALITY); } void loop() { - uint16_t valMQ = MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_CO); - Serial.println(val); - - Serial.print("LPG:"); - Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_LPG) ); - Serial.print( "ppm" ); - Serial.print(" "); - Serial.print("CO:"); - Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_CO) ); - Serial.print( "ppm" ); - Serial.print(" "); - Serial.print("SMOKE:"); - Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_SMOKE) ); - Serial.print( "ppm" ); - Serial.print("\n"); - - if (valMQ != lastMQ) { - send(msg.set((int16_t)ceil(valMQ))); - lastMQ = ceil(valMQ); - } - - sleep(SLEEP_TIME); //sleep for: sleepTime + uint16_t valMQ = MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_CO); + Serial.println(val); + + Serial.print("LPG:"); + Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_LPG) ); + Serial.print( "ppm" ); + Serial.print(" "); + Serial.print("CO:"); + Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_CO) ); + Serial.print( "ppm" ); + Serial.print(" "); + Serial.print("SMOKE:"); + Serial.print(MQGetGasPercentage(MQRead(MQ_SENSOR_ANALOG_PIN)/Ro,GAS_SMOKE) ); + Serial.print( "ppm" ); + Serial.print("\n"); + + if (valMQ != lastMQ) { + send(msg.set((int16_t)ceil(valMQ))); + lastMQ = ceil(valMQ); + } + + sleep(SLEEP_TIME); //sleep for: sleepTime } /****************** MQResistanceCalculation **************************************** @@ -131,7 +133,7 @@ Remarks: The sensor and the load resistor forms a voltage divider. Given the vol ************************************************************************************/ float MQResistanceCalculation(int raw_adc) { - return ( ((float)RL_VALUE*(1023-raw_adc)/raw_adc)); + return ( ((float)RL_VALUE*(1023-raw_adc)/raw_adc)); } /***************************** MQCalibration **************************************** @@ -144,19 +146,19 @@ Remarks: This function assumes that the sensor is in clean air. It use ************************************************************************************/ float MQCalibration(int mq_pin) { - int i; - float val=0; + int i; + float val=0; - for (i=0;i pin 6 * * From: http://davidegironi.blogspot.fr/2014/01/co2-meter-using-ndir-infrared-mh-z14.html @@ -39,13 +39,13 @@ */ // Enable debug prints to serial monitor -#define MY_DEBUG +#define MY_DEBUG // Enable and select radio type attached #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include +#include #define CHILD_ID_AIQ 0 #define AIQ_SENSOR_ANALOG_PIN 6 @@ -58,44 +58,48 @@ float lastAIQ =0.0; MyMessage msg(CHILD_ID_AIQ, V_LEVEL); MyMessage msg2(CHILD_ID_AIQ, V_UNIT_PREFIX); -void setup() +void setup() { - pinMode(AIQ_SENSOR_ANALOG_PIN, INPUT); + pinMode(AIQ_SENSOR_ANALOG_PIN, INPUT); } -void presentation() { - // Send the sketch version information to the gateway and Controller - sendSketchInfo("AIQ Sensor CO2 MH-Z14", "1.0"); +void presentation() +{ + // Send the sketch version information to the gateway and Controller + sendSketchInfo("AIQ Sensor CO2 MH-Z14", "1.0"); - // Register all sensors to gateway (they will be created as child devices) - present(CHILD_ID_AIQ, S_AIR_QUALITY); - send(msg2.set("ppm")); + // Register all sensors to gateway (they will be created as child devices) + present(CHILD_ID_AIQ, S_AIR_QUALITY); + send(msg2.set("ppm")); } -void loop() { +void loop() +{ + + //unsigned long duration = pulseIn(AIQ_SENSOR_ANALOG_PIN, HIGH); + while(digitalRead(AIQ_SENSOR_ANALOG_PIN) == HIGH) { + ; + } + //wait for the pin to go HIGH and measure HIGH time + unsigned long duration = pulseIn(AIQ_SENSOR_ANALOG_PIN, HIGH); - //unsigned long duration = pulseIn(AIQ_SENSOR_ANALOG_PIN, HIGH); - while(digitalRead(AIQ_SENSOR_ANALOG_PIN) == HIGH) {;} - //wait for the pin to go HIGH and measure HIGH time - unsigned long duration = pulseIn(AIQ_SENSOR_ANALOG_PIN, HIGH); - - //Serial.print(duration/1000); Serial.println(" ms "); - //from datasheet + //Serial.print(duration/1000); Serial.println(" ms "); + //from datasheet //CO2 ppm = 2000 * (Th - 2ms) / (Th + Tl - 4ms) // given Tl + Th = 1004 // Tl = 1004 - Th // = 2000 * (Th - 2ms) / (Th + 1004 - Th -4ms) // = 2000 * (Th - 2ms) / 1000 = 2 * (Th - 2ms) - long co2ppm = 2 * ((duration/1000) - 2); - //Serial.print(co2ppm); - if ((co2ppm != lastAIQ)&&(abs(co2ppm-lastAIQ)>=10)) { - send(msg.set((long)ceil(co2ppm))); - lastAIQ = ceil(co2ppm); - } - - //Serial.println(); - - // Power down the radio. Note that the radio will get powered back up - // on the next write() call. - sleep(SLEEP_TIME); //sleep for: sleepTime + long co2ppm = 2 * ((duration/1000) - 2); + //Serial.print(co2ppm); + if ((co2ppm != lastAIQ)&&(abs(co2ppm-lastAIQ)>=10)) { + send(msg.set((long)ceil(co2ppm))); + lastAIQ = ceil(co2ppm); + } + + //Serial.println(); + + // Power down the radio. Note that the radio will get powered back up + // on the next write() call. + sleep(SLEEP_TIME); //sleep for: sleepTime } diff --git a/examples/ClearEepromConfig/ClearEepromConfig.ino b/examples/ClearEepromConfig/ClearEepromConfig.ino index e885917fd..da7628d36 100644 --- a/examples/ClearEepromConfig/ClearEepromConfig.ino +++ b/examples/ClearEepromConfig/ClearEepromConfig.ino @@ -21,24 +21,24 @@ * DESCRIPTION * * This sketch clears radioId, relayId and other routing information in EEPROM back to factory default - * + * */ // load core modules only #define MY_CORE_ONLY -#include +#include -void setup() -{ - Serial.begin(MY_BAUD_RATE); - Serial.println("Started clearing. Please wait..."); - for (int i=0;i 100 ? 100 : requestedLevel; - requestedLevel = requestedLevel < 0 ? 0 : requestedLevel; + // Clip incoming level to valid range of 0 to 100 + requestedLevel = requestedLevel > 100 ? 100 : requestedLevel; + requestedLevel = requestedLevel < 0 ? 0 : requestedLevel; - Serial.print( "Changing level to " ); - Serial.print( requestedLevel ); - Serial.print( ", from " ); - Serial.println( currentLevel ); + Serial.print( "Changing level to " ); + Serial.print( requestedLevel ); + Serial.print( ", from " ); + Serial.println( currentLevel ); - fadeToLevel( requestedLevel ); + fadeToLevel( requestedLevel ); - // Inform the gateway of the current DimmableLED's SwitchPower1 and LoadLevelStatus value... - send(lightMsg.set(currentLevel > 0)); + // Inform the gateway of the current DimmableLED's SwitchPower1 and LoadLevelStatus value... + send(lightMsg.set(currentLevel > 0)); - // hek comment: Is this really nessesary? - send( dimmerMsg.set(currentLevel) ); + // hek comment: Is this really nessesary? + send( dimmerMsg.set(currentLevel) ); - } + } } /*** * This method provides a graceful fade up/down effect */ -void fadeToLevel( int toLevel ) { +void fadeToLevel( int toLevel ) +{ - int delta = ( toLevel - currentLevel ) < 0 ? -1 : 1; + int delta = ( toLevel - currentLevel ) < 0 ? -1 : 1; - while ( currentLevel != toLevel ) { - currentLevel += delta; - analogWrite( LED_PIN, (int)(currentLevel / 100. * 255) ); - delay( FADE_DELAY ); - } + while ( currentLevel != toLevel ) { + currentLevel += delta; + analogWrite( LED_PIN, (int)(currentLevel / 100. * 255) ); + delay( FADE_DELAY ); + } } diff --git a/examples/DimmableLight/DimmableLight.ino b/examples/DimmableLight/DimmableLight.ino index 12bac2ddb..e4bb52e0f 100644 --- a/examples/DimmableLight/DimmableLight.ino +++ b/examples/DimmableLight/DimmableLight.ino @@ -57,28 +57,29 @@ MyMessage dimmerMsg(CHILD_ID_LIGHT, V_DIMMER); void setup() { - //Retreive our last light state from the eprom - int LightState=loadState(EPROM_LIGHT_STATE); - if (LightState<=1) { - LastLightState=LightState; - int DimValue=loadState(EPROM_DIMMER_LEVEL); - if ((DimValue>0)&&(DimValue<=100)) { - //There should be no Dim value of 0, this would mean LIGHT_OFF - LastDimValue=DimValue; - } - } - - //Here you actualy switch on/off the light with the last known dim level - SetCurrentState2Hardware(); - - Serial.println( "Node ready to receive messages..." ); + //Retreive our last light state from the eprom + int LightState=loadState(EPROM_LIGHT_STATE); + if (LightState<=1) { + LastLightState=LightState; + int DimValue=loadState(EPROM_DIMMER_LEVEL); + if ((DimValue>0)&&(DimValue<=100)) { + //There should be no Dim value of 0, this would mean LIGHT_OFF + LastDimValue=DimValue; + } + } + + //Here you actualy switch on/off the light with the last known dim level + SetCurrentState2Hardware(); + + Serial.println( "Node ready to receive messages..." ); } -void presentation() { - // Send the Sketch Version Information to the Gateway - sendSketchInfo(SN, SV); +void presentation() +{ + // Send the Sketch Version Information to the Gateway + sendSketchInfo(SN, SV); - present(CHILD_ID_LIGHT, S_DIMMER ); + present(CHILD_ID_LIGHT, S_DIMMER ); } void loop() @@ -87,74 +88,69 @@ void loop() void receive(const MyMessage &message) { - if (message.type == V_LIGHT) { - Serial.println( "V_LIGHT command received..." ); - - int lstate= atoi( message.data ); - if ((lstate<0)||(lstate>1)) { - Serial.println( "V_LIGHT data invalid (should be 0/1)" ); - return; - } - LastLightState=lstate; - saveState(EPROM_LIGHT_STATE, LastLightState); - - if ((LastLightState==LIGHT_ON)&&(LastDimValue==0)) { - //In the case that the Light State = On, but the dimmer value is zero, - //then something (probably the controller) did something wrong, - //for the Dim value to 100% - LastDimValue=100; - saveState(EPROM_DIMMER_LEVEL, LastDimValue); - } - - //When receiving a V_LIGHT command we switch the light between OFF and the last received dimmer value - //This means if you previously set the lights dimmer value to 50%, and turn the light ON - //it will do so at 50% - } - else if (message.type == V_DIMMER) { - Serial.println( "V_DIMMER command received..." ); - int dimvalue= atoi( message.data ); - if ((dimvalue<0)||(dimvalue>100)) { - Serial.println( "V_DIMMER data invalid (should be 0..100)" ); - return; - } - if (dimvalue==0) { - LastLightState=LIGHT_OFF; - } - else { - LastLightState=LIGHT_ON; - LastDimValue=dimvalue; - saveState(EPROM_DIMMER_LEVEL, LastDimValue); - } - } - else { - Serial.println( "Invalid command received..." ); - return; - } - - //Here you set the actual light state/level - SetCurrentState2Hardware(); + if (message.type == V_LIGHT) { + Serial.println( "V_LIGHT command received..." ); + + int lstate= atoi( message.data ); + if ((lstate<0)||(lstate>1)) { + Serial.println( "V_LIGHT data invalid (should be 0/1)" ); + return; + } + LastLightState=lstate; + saveState(EPROM_LIGHT_STATE, LastLightState); + + if ((LastLightState==LIGHT_ON)&&(LastDimValue==0)) { + //In the case that the Light State = On, but the dimmer value is zero, + //then something (probably the controller) did something wrong, + //for the Dim value to 100% + LastDimValue=100; + saveState(EPROM_DIMMER_LEVEL, LastDimValue); + } + + //When receiving a V_LIGHT command we switch the light between OFF and the last received dimmer value + //This means if you previously set the lights dimmer value to 50%, and turn the light ON + //it will do so at 50% + } else if (message.type == V_DIMMER) { + Serial.println( "V_DIMMER command received..." ); + int dimvalue= atoi( message.data ); + if ((dimvalue<0)||(dimvalue>100)) { + Serial.println( "V_DIMMER data invalid (should be 0..100)" ); + return; + } + if (dimvalue==0) { + LastLightState=LIGHT_OFF; + } else { + LastLightState=LIGHT_ON; + LastDimValue=dimvalue; + saveState(EPROM_DIMMER_LEVEL, LastDimValue); + } + } else { + Serial.println( "Invalid command received..." ); + return; + } + + //Here you set the actual light state/level + SetCurrentState2Hardware(); } void SetCurrentState2Hardware() { - if (LastLightState==LIGHT_OFF) { - Serial.println( "Light state: OFF" ); - } - else { - Serial.print( "Light state: ON, Level: " ); - Serial.println( LastDimValue ); - } - - //Send current state to the controller - SendCurrentState2Controller(); + if (LastLightState==LIGHT_OFF) { + Serial.println( "Light state: OFF" ); + } else { + Serial.print( "Light state: ON, Level: " ); + Serial.println( LastDimValue ); + } + + //Send current state to the controller + SendCurrentState2Controller(); } void SendCurrentState2Controller() { - if ((LastLightState==LIGHT_OFF)||(LastDimValue==0)) { - send(dimmerMsg.set((int16_t)0)); - } - else { - send(dimmerMsg.set(LastDimValue)); - } + if ((LastLightState==LIGHT_OFF)||(LastDimValue==0)) { + send(dimmerMsg.set((int16_t)0)); + } else { + send(dimmerMsg.set(LastDimValue)); + } } diff --git a/examples/DustSensor/DustSensor.ino b/examples/DustSensor/DustSensor.ino index e6ea3b238..35524e2c7 100644 --- a/examples/DustSensor/DustSensor.ino +++ b/examples/DustSensor/DustSensor.ino @@ -21,21 +21,21 @@ * REVISION HISTORY * Version 1.0 - epierre * Converted to 1.4 by Henrik Ekblad - * + * * DESCRIPTION * Arduino Dust Sensort * * connect the sensor as follows : - * + * * VCC >>> 5V * A >>> A0 * GND >>> GND * - * Based on: http://www.dfrobot.com/wiki/index.php/Sharp_GP2Y1010AU + * Based on: http://www.dfrobot.com/wiki/index.php/Sharp_GP2Y1010AU * Authors: Cyrille Médard de Chardon (serialC), Christophe Trefois (Trefex) - * + * * http://www.mysensors.org/build/dust - * + * */ // Enable debug prints @@ -45,7 +45,7 @@ #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include +#include #define CHILD_ID_DUST 0 #define DUST_SENSOR_ANALOG_PIN 1 @@ -64,38 +64,40 @@ float dustDensity = 0; MyMessage dustMsg(CHILD_ID_DUST, V_LEVEL); -void presentation() { - // Send the sketch version information to the gateway and Controller - sendSketchInfo("Dust Sensor", "1.1"); +void presentation() +{ + // Send the sketch version information to the gateway and Controller + sendSketchInfo("Dust Sensor", "1.1"); - // Register all sensors to gateway (they will be created as child devices) - present(CHILD_ID_DUST, S_DUST); + // Register all sensors to gateway (they will be created as child devices) + present(CHILD_ID_DUST, S_DUST); } -void loop() { - uint16_t voMeasured = analogRead(DUST_SENSOR_ANALOG_PIN);// Get DUST value - - // 0 - 5V mapped to 0 - 1023 integer values - // recover voltage - calcVoltage = voMeasured * (5.0 / 1024.0); - - // linear eqaution taken from http://www.howmuchsnow.com/arduino/airquality/ - // Chris Nafis (c) 2012 - dustDensity = (0.17 * calcVoltage - 0.1)*1000; - - Serial.print("Raw Signal Value (0-1023): "); - Serial.print(voMeasured); - - Serial.print(" - Voltage: "); - Serial.print(calcVoltage); - - Serial.print(" - Dust Density: "); - Serial.println(dustDensity); // unit: ug/m3 - - if (ceil(dustDensity) != lastDUST) { - send(dustMsg.set((int16_t)ceil(dustDensity))); - lastDUST = ceil(dustDensity); - } - - sleep(SLEEP_TIME); +void loop() +{ + uint16_t voMeasured = analogRead(DUST_SENSOR_ANALOG_PIN);// Get DUST value + + // 0 - 5V mapped to 0 - 1023 integer values + // recover voltage + calcVoltage = voMeasured * (5.0 / 1024.0); + + // linear eqaution taken from http://www.howmuchsnow.com/arduino/airquality/ + // Chris Nafis (c) 2012 + dustDensity = (0.17 * calcVoltage - 0.1)*1000; + + Serial.print("Raw Signal Value (0-1023): "); + Serial.print(voMeasured); + + Serial.print(" - Voltage: "); + Serial.print(calcVoltage); + + Serial.print(" - Dust Density: "); + Serial.println(dustDensity); // unit: ug/m3 + + if (ceil(dustDensity) != lastDUST) { + send(dustMsg.set((int16_t)ceil(dustDensity))); + lastDUST = ceil(dustDensity); + } + + sleep(SLEEP_TIME); } diff --git a/examples/DustSensorDSM/DustSensorDSM.ino b/examples/DustSensorDSM/DustSensorDSM.ino index 665711023..5dcaf5497 100644 --- a/examples/DustSensorDSM/DustSensorDSM.ino +++ b/examples/DustSensorDSM/DustSensorDSM.ino @@ -19,12 +19,12 @@ ******************************* * * DESCRIPTION - * + * * Dust Sensor for SamYoung DSM501 * connect the sensor as follows : * Pin 2 of dust sensor PM1 -> Digital 3 (PMW) - * Pin 3 of dust sensor -> +5V - * Pin 4 of dust sensor PM2.5 -> Digital 6 (PWM) + * Pin 3 of dust sensor -> +5V + * Pin 4 of dust sensor PM2.5 -> Digital 6 (PWM) * Pin 5 of dust sensor -> Ground * Datasheet: http://www.samyoungsnc.com/products/3-1%20Specification%20DSM501.pdf * Contributor: epierre @@ -37,7 +37,7 @@ #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include +#include #define CHILD_ID_DUST_PM10 0 #define CHILD_ID_DUST_PM25 1 @@ -65,84 +65,85 @@ MyMessage msgPM10(CHILD_ID_DUST_PM10, V_UNIT_PREFIX); MyMessage dustMsgPM25(CHILD_ID_DUST_PM25, V_LEVEL); MyMessage msgPM25(CHILD_ID_DUST_PM25, V_UNIT_PREFIX); -void setup() +void setup() { - pinMode(DUST_SENSOR_DIGITAL_PIN_PM10,INPUT); - pinMode(DUST_SENSOR_DIGITAL_PIN_PM25,INPUT); + pinMode(DUST_SENSOR_DIGITAL_PIN_PM10,INPUT); + pinMode(DUST_SENSOR_DIGITAL_PIN_PM25,INPUT); } -void presentation() { - // Send the sketch version information to the gateway and Controller - sendSketchInfo("Dust Sensor DSM501", "1.4"); - - // Register all sensors to gateway (they will be created as child devices) - present(CHILD_ID_DUST_PM10, S_DUST); - send(msgPM10.set("ppm")); - present(CHILD_ID_DUST_PM25, S_DUST); - send(msgPM25.set("ppm")); +void presentation() +{ + // Send the sketch version information to the gateway and Controller + sendSketchInfo("Dust Sensor DSM501", "1.4"); + + // Register all sensors to gateway (they will be created as child devices) + present(CHILD_ID_DUST_PM10, S_DUST); + send(msgPM10.set("ppm")); + present(CHILD_ID_DUST_PM25, S_DUST); + send(msgPM25.set("ppm")); } -void loop() -{ - - //get PM 2.5 density of particles over 2.5 μm. - concentrationPM25=(long)getPM(DUST_SENSOR_DIGITAL_PIN_PM25); - Serial.print("PM25: "); - Serial.println(concentrationPM25); - Serial.print("\n"); - - if ((concentrationPM25 != lastDUSTPM25)&&(concentrationPM25>0)) { - send(dustMsgPM25.set((long)ceil(concentrationPM25))); - lastDUSTPM25 = ceil(concentrationPM25); - } - - //get PM 1.0 - density of particles over 1 μm. - concentrationPM10=getPM(DUST_SENSOR_DIGITAL_PIN_PM10); - Serial.print("PM10: "); - Serial.println(concentrationPM10); - Serial.print("\n"); - //ppmv=mg/m3 * (0.08205*Tmp)/Molecular_mass - //0.08205 = Universal gas constant in atm·m3/(kmol·K) - int temp=20; //external temperature, if you can replace this with a DHT11 or better - long ppmv=(concentrationPM10*0.0283168/100/1000) * (0.08205*temp)/0.01; - - if ((ceil(concentrationPM10) != lastDUSTPM10)&&((long)concentrationPM10>0)) { - send(dustMsgPM10.set((long)ppmv)); - lastDUSTPM10 = ceil(concentrationPM10); - } - - //sleep to save on radio - sleep(SLEEP_TIME); - +void loop() +{ + + //get PM 2.5 density of particles over 2.5 μm. + concentrationPM25=(long)getPM(DUST_SENSOR_DIGITAL_PIN_PM25); + Serial.print("PM25: "); + Serial.println(concentrationPM25); + Serial.print("\n"); + + if ((concentrationPM25 != lastDUSTPM25)&&(concentrationPM25>0)) { + send(dustMsgPM25.set((long)ceil(concentrationPM25))); + lastDUSTPM25 = ceil(concentrationPM25); + } + + //get PM 1.0 - density of particles over 1 μm. + concentrationPM10=getPM(DUST_SENSOR_DIGITAL_PIN_PM10); + Serial.print("PM10: "); + Serial.println(concentrationPM10); + Serial.print("\n"); + //ppmv=mg/m3 * (0.08205*Tmp)/Molecular_mass + //0.08205 = Universal gas constant in atm·m3/(kmol·K) + int temp=20; //external temperature, if you can replace this with a DHT11 or better + long ppmv=(concentrationPM10*0.0283168/100/1000) * (0.08205*temp)/0.01; + + if ((ceil(concentrationPM10) != lastDUSTPM10)&&((long)concentrationPM10>0)) { + send(dustMsgPM10.set((long)ppmv)); + lastDUSTPM10 = ceil(concentrationPM10); + } + + //sleep to save on radio + sleep(SLEEP_TIME); + } -long getPM(int DUST_SENSOR_DIGITAL_PIN) { - - starttime = millis(); - - while (1) { - - duration = pulseIn(DUST_SENSOR_DIGITAL_PIN, LOW); - lowpulseoccupancy += duration; - endtime = millis(); - - if ((endtime-starttime) > sampletime_ms) - { - ratio = (lowpulseoccupancy-endtime+starttime)/(sampletime_ms*10.0); // Integer percentage 0=>100 - long concentration = 1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62; // using spec sheet curve - //Serial.print("lowpulseoccupancy:"); - //Serial.print(lowpulseoccupancy); - //Serial.print("\n"); - //Serial.print("ratio:"); - //Serial.print(ratio); - //Serial.print("\n"); - //Serial.print("DSM501A:"); - //Serial.println(concentration); - //Serial.print("\n"); - - lowpulseoccupancy = 0; - return(concentration); - } - } +long getPM(int DUST_SENSOR_DIGITAL_PIN) +{ + + starttime = millis(); + + while (1) { + + duration = pulseIn(DUST_SENSOR_DIGITAL_PIN, LOW); + lowpulseoccupancy += duration; + endtime = millis(); + + if ((endtime-starttime) > sampletime_ms) { + ratio = (lowpulseoccupancy-endtime+starttime)/(sampletime_ms*10.0); // Integer percentage 0=>100 + long concentration = 1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62; // using spec sheet curve + //Serial.print("lowpulseoccupancy:"); + //Serial.print(lowpulseoccupancy); + //Serial.print("\n"); + //Serial.print("ratio:"); + //Serial.print(ratio); + //Serial.print("\n"); + //Serial.print("DSM501A:"); + //Serial.println(concentration); + //Serial.print("\n"); + + lowpulseoccupancy = 0; + return(concentration); + } + } } diff --git a/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino b/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino index 041f0b2d4..0ae30dfbc 100644 --- a/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino +++ b/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino @@ -20,16 +20,16 @@ * * REVISION HISTORY * Version 1.0 - Henrik EKblad - * + * * DESCRIPTION - * This sketch provides an example how to implement a distance sensor using HC-SR04 + * This sketch provides an example how to implement a distance sensor using HC-SR04 * Use this sensor to measure KWH and Watt of your house meeter * You need to set the correct pulsefactor of your meeter (blinks per KWH). * The sensor starts by fetching current KWH value from gateway. * Reports both KWH and Watt back to gateway. * - * Unfortunately millis() won't increment when the Arduino is in - * sleepmode. So we cannot make this sensor sleep if we also want + * Unfortunately millis() won't increment when the Arduino is in + * sleepmode. So we cannot make this sensor sleep if we also want * to calculate/report watt-number. * http://www.mysensors.org/build/pulse_power */ @@ -41,7 +41,7 @@ #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include +#include #define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your light sensor. (Only 2 and 3 generates interrupt!) #define PULSE_FACTOR 1000 // Nummber of blinks per KWH of your meeter @@ -49,13 +49,14 @@ #define MAX_WATT 10000 // Max watt value to report. This filetrs outliers. #define CHILD_ID 1 // Id of the sensor child -unsigned long SEND_FREQUENCY = 20000; // Minimum time between send (in milliseconds). We don't wnat to spam the gateway. +unsigned long SEND_FREQUENCY = + 20000; // Minimum time between send (in milliseconds). We don't wnat to spam the gateway. double ppwh = ((double)PULSE_FACTOR)/1000; // Pulses per watt hour bool pcReceived = false; -volatile unsigned long pulseCount = 0; +volatile unsigned long pulseCount = 0; volatile unsigned long lastBlink = 0; volatile unsigned long watt = 0; -unsigned long oldPulseCount = 0; +unsigned long oldPulseCount = 0; unsigned long oldWatt = 0; double oldKwh; unsigned long lastSend; @@ -64,88 +65,90 @@ MyMessage kwhMsg(CHILD_ID,V_KWH); MyMessage pcMsg(CHILD_ID,V_VAR1); -void setup() -{ - // Fetch last known pulse count value from gw - request(CHILD_ID, V_VAR1); +void setup() +{ + // Fetch last known pulse count value from gw + request(CHILD_ID, V_VAR1); - // Use the internal pullup to be able to hook up this sketch directly to an energy meter with S0 output - // If no pullup is used, the reported usage will be too high because of the floating pin - pinMode(DIGITAL_INPUT_SENSOR,INPUT_PULLUP); + // Use the internal pullup to be able to hook up this sketch directly to an energy meter with S0 output + // If no pullup is used, the reported usage will be too high because of the floating pin + pinMode(DIGITAL_INPUT_SENSOR,INPUT_PULLUP); - attachInterrupt(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR), onPulse, RISING); - lastSend=millis(); + attachInterrupt(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR), onPulse, RISING); + lastSend=millis(); } -void presentation() { - // Send the sketch version information to the gateway and Controller - sendSketchInfo("Energy Meter", "1.0"); +void presentation() +{ + // Send the sketch version information to the gateway and Controller + sendSketchInfo("Energy Meter", "1.0"); - // Register this device as power sensor - present(CHILD_ID, S_POWER); + // Register this device as power sensor + present(CHILD_ID, S_POWER); } -void loop() -{ - unsigned long now = millis(); - // Only send values at a maximum frequency or woken up from sleep - bool sendTime = now - lastSend > SEND_FREQUENCY; - if (pcReceived && (SLEEP_MODE || sendTime)) { - // New watt value has been calculated - if (!SLEEP_MODE && watt != oldWatt) { - // Check that we dont get unresonable large watt value. - // could hapen when long wraps or false interrupt triggered - if (watt<((unsigned long)MAX_WATT)) { - send(wattMsg.set(watt)); // Send watt value to gw - } - Serial.print("Watt:"); - Serial.println(watt); - oldWatt = watt; - } - - // Pulse cout has changed - if (pulseCount != oldPulseCount) { - send(pcMsg.set(pulseCount)); // Send pulse count value to gw - double kwh = ((double)pulseCount/((double)PULSE_FACTOR)); - oldPulseCount = pulseCount; - if (kwh != oldKwh) { - send(kwhMsg.set(kwh, 4)); // Send kwh value to gw - oldKwh = kwh; - } - } - lastSend = now; - } else if (sendTime && !pcReceived) { - // No count received. Try requesting it again - request(CHILD_ID, V_VAR1); - lastSend=now; - } - - if (SLEEP_MODE) { - sleep(SEND_FREQUENCY); - } +void loop() +{ + unsigned long now = millis(); + // Only send values at a maximum frequency or woken up from sleep + bool sendTime = now - lastSend > SEND_FREQUENCY; + if (pcReceived && (SLEEP_MODE || sendTime)) { + // New watt value has been calculated + if (!SLEEP_MODE && watt != oldWatt) { + // Check that we dont get unresonable large watt value. + // could hapen when long wraps or false interrupt triggered + if (watt<((unsigned long)MAX_WATT)) { + send(wattMsg.set(watt)); // Send watt value to gw + } + Serial.print("Watt:"); + Serial.println(watt); + oldWatt = watt; + } + + // Pulse cout has changed + if (pulseCount != oldPulseCount) { + send(pcMsg.set(pulseCount)); // Send pulse count value to gw + double kwh = ((double)pulseCount/((double)PULSE_FACTOR)); + oldPulseCount = pulseCount; + if (kwh != oldKwh) { + send(kwhMsg.set(kwh, 4)); // Send kwh value to gw + oldKwh = kwh; + } + } + lastSend = now; + } else if (sendTime && !pcReceived) { + // No count received. Try requesting it again + request(CHILD_ID, V_VAR1); + lastSend=now; + } + + if (SLEEP_MODE) { + sleep(SEND_FREQUENCY); + } } -void receive(const MyMessage &message) { - if (message.type==V_VAR1) { - pulseCount = oldPulseCount = message.getLong(); - Serial.print("Received last pulse count from gw:"); - Serial.println(pulseCount); - pcReceived = true; - } +void receive(const MyMessage &message) +{ + if (message.type==V_VAR1) { + pulseCount = oldPulseCount = message.getLong(); + Serial.print("Received last pulse count from gw:"); + Serial.println(pulseCount); + pcReceived = true; + } } -void onPulse() -{ - if (!SLEEP_MODE) { - unsigned long newBlink = micros(); - unsigned long interval = newBlink-lastBlink; - if (interval<10000L) { // Sometimes we get interrupt on RISING - return; - } - watt = (3600000000.0 /interval) / ppwh; - lastBlink = newBlink; - } - pulseCount++; +void onPulse() +{ + if (!SLEEP_MODE) { + unsigned long newBlink = micros(); + unsigned long interval = newBlink-lastBlink; + if (interval<10000L) { // Sometimes we get interrupt on RISING + return; + } + watt = (3600000000.0 /interval) / ppwh; + lastBlink = newBlink; + } + pulseCount++; } diff --git a/examples/GatewayESP8266/GatewayESP8266.ino b/examples/GatewayESP8266/GatewayESP8266.ino index 4e7f38dd2..950bd3102 100644 --- a/examples/GatewayESP8266/GatewayESP8266.ino +++ b/examples/GatewayESP8266/GatewayESP8266.ino @@ -126,21 +126,24 @@ #define MY_DEFAULT_TX_LED_PIN 16 // the PCB, on board LED #if defined(MY_USE_UDP) - #include +#include #endif #include #include -void setup() { +void setup() +{ } -void presentation() { - // Present locally attached sensors here +void presentation() +{ + // Present locally attached sensors here } -void loop() { - // Send locally attached sensors data here +void loop() +{ + // Send locally attached sensors data here } diff --git a/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino b/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino index 0b4933b16..2f2aecd1d 100644 --- a/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino +++ b/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino @@ -104,7 +104,7 @@ // The MQTT broker port to to open #define MY_PORT 1883 - /* +/* // Enable inclusion mode #define MY_INCLUSION_MODE_FEATURE // Enable Inclusion mode button on gateway @@ -126,14 +126,17 @@ #include #include -void setup() { +void setup() +{ } -void presentation() { - // Present locally attached sensors here +void presentation() +{ + // Present locally attached sensors here } -void loop() { - // Send locally attech sensors data here +void loop() +{ + // Send locally attech sensors data here } diff --git a/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino b/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino index 353a5f2e2..5de0965f0 100644 --- a/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino +++ b/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino @@ -128,45 +128,54 @@ #define MY_DEFAULT_TX_LED_PIN 16 // the PCB, on board LED #if defined(MY_USE_UDP) - #include +#include #else - #include +#include #endif #include -void setup() { - - ArduinoOTA.onStart([]() { - Serial.println("ArduinoOTA start"); - }); - ArduinoOTA.onEnd([]() { - Serial.println("\nArduinoOTA end"); - }); - ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { - Serial.printf("OTA Progress: %u%%\r", (progress / (total / 100))); - }); - ArduinoOTA.onError([](ota_error_t error) { - Serial.printf("Error[%u]: ", error); - if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); - else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); - else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); - else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); - else if (error == OTA_END_ERROR) Serial.println("End Failed"); - }); - ArduinoOTA.begin(); - Serial.println("Ready"); - Serial.print("IP address: "); - Serial.println(WiFi.localIP()); +void setup() +{ + + ArduinoOTA.onStart([]() { + Serial.println("ArduinoOTA start"); + }); + ArduinoOTA.onEnd([]() { + Serial.println("\nArduinoOTA end"); + }); + ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { + Serial.printf("OTA Progress: %u%%\r", (progress / (total / 100))); + }); + ArduinoOTA.onError([](ota_error_t error) { + Serial.printf("Error[%u]: ", error); + if (error == OTA_AUTH_ERROR) { + Serial.println("Auth Failed"); + } else if (error == OTA_BEGIN_ERROR) { + Serial.println("Begin Failed"); + } else if (error == OTA_CONNECT_ERROR) { + Serial.println("Connect Failed"); + } else if (error == OTA_RECEIVE_ERROR) { + Serial.println("Receive Failed"); + } else if (error == OTA_END_ERROR) { + Serial.println("End Failed"); + } + }); + ArduinoOTA.begin(); + Serial.println("Ready"); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); } -void presentation() { - // Present locally attached sensors here +void presentation() +{ + // Present locally attached sensors here } -void loop() { - // Send locally attech sensors data here - ArduinoOTA.handle(); +void loop() +{ + // Send locally attech sensors data here + ArduinoOTA.handle(); } diff --git a/examples/GatewaySerial/GatewaySerial.ino b/examples/GatewaySerial/GatewaySerial.ino index 747ba9f60..7ddcdbfb4 100644 --- a/examples/GatewaySerial/GatewaySerial.ino +++ b/examples/GatewaySerial/GatewaySerial.ino @@ -1,40 +1,40 @@ - /** - * 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. - * - ******************************* - * - * DESCRIPTION - * The ArduinoGateway prints data received from sensors on the serial link. - * The gateway accepts input on seral which will be sent out on radio network. - * - * The GW code is designed for Arduino Nano 328p / 16MHz - * - * Wire connections (OPTIONAL): - * - Inclusion button should be connected between digital pin 3 and GND - * - RX/TX/ERR leds need to be connected between +5V (anode) and digital pin 6/5/4 with resistor 270-330R in a series - * - * LEDs (OPTIONAL): - * - To use the feature, uncomment any of the MY_DEFAULT_xx_LED_PINs - * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved - * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly - * - ERR (red) - fast blink on error during transmission error or recieve crc error - * - */ +/** +* 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. +* +******************************* +* +* DESCRIPTION +* The ArduinoGateway prints data received from sensors on the serial link. +* The gateway accepts input on seral which will be sent out on radio network. +* +* The GW code is designed for Arduino Nano 328p / 16MHz +* +* Wire connections (OPTIONAL): +* - Inclusion button should be connected between digital pin 3 and GND +* - RX/TX/ERR leds need to be connected between +5V (anode) and digital pin 6/5/4 with resistor 270-330R in a series +* +* LEDs (OPTIONAL): +* - To use the feature, uncomment any of the MY_DEFAULT_xx_LED_PINs +* - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved +* - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly +* - ERR (red) - fast blink on error during transmission error or recieve crc error +* +*/ // Enable debug prints to serial monitor #define MY_DEBUG @@ -83,14 +83,17 @@ #include -void setup() { - // Setup locally attached sensors +void setup() +{ + // Setup locally attached sensors } -void presentation() { - // Present locally attached sensors +void presentation() +{ + // Present locally attached sensors } -void loop() { - // Send locally attached sensor data here +void loop() +{ + // Send locally attached sensor data here } diff --git a/examples/GatewaySerialRS485/GatewaySerialRS485.ino b/examples/GatewaySerialRS485/GatewaySerialRS485.ino index 2db67c9de..1cca1b0be 100644 --- a/examples/GatewaySerialRS485/GatewaySerialRS485.ino +++ b/examples/GatewaySerialRS485/GatewaySerialRS485.ino @@ -1,54 +1,54 @@ - /** - * 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. - * - ******************************* - * - * DESCRIPTION - * The RS485 Gateway prints data received from sensors on the serial link. - * The gateway accepts input on seral which will be sent out on - * the RS485 link. - * - * Wire connections (OPTIONAL): - * - Inclusion button should be connected between digital pin 3 and GND - * - RX/TX/ERR leds need to be connected between +5V (anode) and digital pin 6/5/4 with resistor 270-330R in a series - * - * LEDs (OPTIONAL): - * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved - * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly - * - ERR (red) - fast blink on error during transmission error or recieve crc error - * - * If your Arduino board has additional serial ports - * you can use to connect the RS485 module. - * Otherwise, the gateway uses AltSoftSerial to handle two serial - * links on one Arduino. Use the following pins for RS485 link - * - * Board Transmit Receive PWM Unusable - * ----- -------- ------- ------------ - * Teensy 3.0 & 3.1 21 20 22 - * Teensy 2.0 9 10 (none) - * Teensy++ 2.0 25 4 26, 27 - * Arduino Uno 9 8 10 - * Arduino Leonardo 5 13 (none) - * Arduino Mega 46 48 44, 45 - * Wiring-S 5 6 4 - * Sanguino 13 14 12 - * - */ +/** +* 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. +* +******************************* +* +* DESCRIPTION +* The RS485 Gateway prints data received from sensors on the serial link. +* The gateway accepts input on seral which will be sent out on +* the RS485 link. +* +* Wire connections (OPTIONAL): +* - Inclusion button should be connected between digital pin 3 and GND +* - RX/TX/ERR leds need to be connected between +5V (anode) and digital pin 6/5/4 with resistor 270-330R in a series +* +* LEDs (OPTIONAL): +* - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved +* - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly +* - ERR (red) - fast blink on error during transmission error or recieve crc error +* +* If your Arduino board has additional serial ports +* you can use to connect the RS485 module. +* Otherwise, the gateway uses AltSoftSerial to handle two serial +* links on one Arduino. Use the following pins for RS485 link +* +* Board Transmit Receive PWM Unusable +* ----- -------- ------- ------------ +* Teensy 3.0 & 3.1 21 20 22 +* Teensy 2.0 9 10 (none) +* Teensy++ 2.0 25 4 26, 27 +* Arduino Uno 9 8 10 +* Arduino Leonardo 5 13 (none) +* Arduino Mega 46 48 44, 45 +* Wiring-S 5 6 4 +* Sanguino 13 14 12 +* +*/ // Enable debug prints to serial monitor #define MY_DEBUG @@ -88,14 +88,17 @@ #include -void setup() { - // Setup locally attached sensors +void setup() +{ + // Setup locally attached sensors } -void presentation() { - // Present locally attached sensors +void presentation() +{ + // Present locally attached sensors } -void loop() { - // Send locally attached sensor data here +void loop() +{ + // Send locally attached sensor data here } diff --git a/examples/GatewayW5100/GatewayW5100.ino b/examples/GatewayW5100/GatewayW5100.ino index 99d0ac2b4..868a15003 100644 --- a/examples/GatewayW5100/GatewayW5100.ino +++ b/examples/GatewayW5100/GatewayW5100.ino @@ -58,18 +58,18 @@ // The W5100 ethernet module seems to have a hard time co-operate with // radio on the same spi bus. #if !defined(MY_W5100_SPI_EN) && !defined(ARDUINO_ARCH_SAMD) - #define MY_SOFTSPI - #define MY_SOFT_SPI_SCK_PIN 14 - #define MY_SOFT_SPI_MISO_PIN 16 - #define MY_SOFT_SPI_MOSI_PIN 15 +#define MY_SOFTSPI +#define MY_SOFT_SPI_SCK_PIN 14 +#define MY_SOFT_SPI_MISO_PIN 16 +#define MY_SOFT_SPI_MOSI_PIN 15 #endif // When W5100 is connected we have to move CE/CSN pins for NRF radio #ifndef MY_RF24_CE_PIN - #define MY_RF24_CE_PIN 5 +#define MY_RF24_CE_PIN 5 #endif #ifndef MY_RF24_CS_PIN - #define MY_RF24_CS_PIN 6 +#define MY_RF24_CS_PIN 6 #endif // Enable to UDP @@ -110,7 +110,7 @@ #if defined(MY_USE_UDP) - #include +#include #endif #include #include @@ -120,5 +120,6 @@ void setup() { } -void loop() { +void loop() +{ } diff --git a/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino b/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino index 59dad451c..2b59372a0 100644 --- a/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino +++ b/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino @@ -81,18 +81,18 @@ // The W5100 ethernet module seems to have a hard time co-operate with // radio on the same spi bus. #if !defined(MY_W5100_SPI_EN) && !defined(ARDUINO_ARCH_SAMD) - #define MY_SOFTSPI - #define MY_SOFT_SPI_SCK_PIN 14 - #define MY_SOFT_SPI_MISO_PIN 16 - #define MY_SOFT_SPI_MOSI_PIN 15 +#define MY_SOFTSPI +#define MY_SOFT_SPI_SCK_PIN 14 +#define MY_SOFT_SPI_MISO_PIN 16 +#define MY_SOFT_SPI_MOSI_PIN 15 #endif // When W5100 is connected we have to move CE/CSN pins for NRF radio #ifndef MY_RF24_CE_PIN - #define MY_RF24_CE_PIN 5 +#define MY_RF24_CE_PIN 5 #endif #ifndef MY_RF24_CS_PIN - #define MY_RF24_CS_PIN 6 +#define MY_RF24_CS_PIN 6 #endif // Enable these if your MQTT broker requires usenrame/password @@ -113,7 +113,7 @@ // The MQTT broker port to to open #define MY_PORT 1883 - /* +/* // Enable inclusion mode #define MY_INCLUSION_MODE_FEATURE // Enable Inclusion mode button on gateway @@ -136,14 +136,17 @@ #include #include -void setup() { +void setup() +{ } -void presentation() { - // Present locally attached sensors here +void presentation() +{ + // Present locally attached sensors here } -void loop() { - // Send locally attached sensors data here +void loop() +{ + // Send locally attached sensors data here } diff --git a/examples/LightSensor/LightSensor.ino b/examples/LightSensor/LightSensor.ino index baa8280f1..45a8ded2e 100644 --- a/examples/LightSensor/LightSensor.ino +++ b/examples/LightSensor/LightSensor.ino @@ -20,20 +20,20 @@ * * REVISION HISTORY * Version 1.0 - Henrik EKblad - * + * * DESCRIPTION - * Example sketch showing how to measue light level using a LM393 photo-resistor + * Example sketch showing how to measue light level using a LM393 photo-resistor * http://www.mysensors.org/build/light */ // Enable debug prints to serial monitor -#define MY_DEBUG +#define MY_DEBUG // Enable and select radio type attached #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include +#include #define CHILD_ID_LIGHT 0 #define LIGHT_SENSOR_ANALOG_PIN 0 @@ -44,23 +44,24 @@ MyMessage msg(CHILD_ID_LIGHT, V_LIGHT_LEVEL); int lastLightLevel; -void presentation() { - // Send the sketch version information to the gateway and Controller - sendSketchInfo("Light Sensor", "1.0"); +void presentation() +{ + // Send the sketch version information to the gateway and Controller + sendSketchInfo("Light Sensor", "1.0"); - // Register all sensors to gateway (they will be created as child devices) - present(CHILD_ID_LIGHT, S_LIGHT_LEVEL); + // Register all sensors to gateway (they will be created as child devices) + present(CHILD_ID_LIGHT, S_LIGHT_LEVEL); } -void loop() -{ - int16_t lightLevel = (1023-analogRead(LIGHT_SENSOR_ANALOG_PIN))/10.23; - Serial.println(lightLevel); - if (lightLevel != lastLightLevel) { - send(msg.set(lightLevel)); - lastLightLevel = lightLevel; - } - sleep(SLEEP_TIME); +void loop() +{ + int16_t lightLevel = (1023-analogRead(LIGHT_SENSOR_ANALOG_PIN))/10.23; + Serial.println(lightLevel); + if (lightLevel != lastLightLevel) { + send(msg.set(lightLevel)); + lastLightLevel = lightLevel; + } + sleep(SLEEP_TIME); } diff --git a/examples/MockMySensors/MockMySensors.ino b/examples/MockMySensors/MockMySensors.ino index 7b801c932..6850f9a47 100644 --- a/examples/MockMySensors/MockMySensors.ino +++ b/examples/MockMySensors/MockMySensors.ino @@ -92,216 +92,218 @@ long randNumber; //Instanciate Messages objects #ifdef ID_S_ARMED - bool isArmed; +bool isArmed; #endif #ifdef ID_S_DOOR // V_TRIPPED, V_ARMED - MyMessage msg_S_DOOR_T(ID_S_DOOR,V_TRIPPED); - MyMessage msg_S_DOOR_A(ID_S_DOOR,V_ARMED); +MyMessage msg_S_DOOR_T(ID_S_DOOR,V_TRIPPED); +MyMessage msg_S_DOOR_A(ID_S_DOOR,V_ARMED); #endif #ifdef ID_S_MOTION // V_TRIPPED, V_ARMED - MyMessage msg_S_MOTION_A(ID_S_MOTION,V_ARMED); - MyMessage msg_S_MOTION_T(ID_S_MOTION,V_TRIPPED); +MyMessage msg_S_MOTION_A(ID_S_MOTION,V_ARMED); +MyMessage msg_S_MOTION_T(ID_S_MOTION,V_TRIPPED); #endif #ifdef ID_S_SMOKE // V_TRIPPED, V_ARMED - MyMessage msg_S_SMOKE_T(ID_S_SMOKE,V_TRIPPED); - MyMessage msg_S_SMOKE_A(ID_S_SMOKE,V_ARMED); +MyMessage msg_S_SMOKE_T(ID_S_SMOKE,V_TRIPPED); +MyMessage msg_S_SMOKE_A(ID_S_SMOKE,V_ARMED); #endif #ifdef ID_S_LIGHT - MyMessage msg_S_LIGHT(ID_S_LIGHT,V_LIGHT); - bool isLightOn=0; +MyMessage msg_S_LIGHT(ID_S_LIGHT,V_LIGHT); +bool isLightOn=0; #endif #ifdef ID_S_DIMMER - MyMessage msg_S_DIMMER(ID_S_DIMMER,V_DIMMER); - int dimmerVal=100; +MyMessage msg_S_DIMMER(ID_S_DIMMER,V_DIMMER); +int dimmerVal=100; #endif #ifdef ID_S_COVER - MyMessage msg_S_COVER_U(ID_S_COVER,V_UP); - MyMessage msg_S_COVER_D(ID_S_COVER,V_DOWN); - MyMessage msg_S_COVER_S(ID_S_COVER,V_STOP); - MyMessage msg_S_COVER_V(ID_S_COVER,V_VAR1); - int coverState=0; //0=Stop; 1=up; -1=down +MyMessage msg_S_COVER_U(ID_S_COVER,V_UP); +MyMessage msg_S_COVER_D(ID_S_COVER,V_DOWN); +MyMessage msg_S_COVER_S(ID_S_COVER,V_STOP); +MyMessage msg_S_COVER_V(ID_S_COVER,V_VAR1); +int coverState=0; //0=Stop; 1=up; -1=down #endif #ifdef ID_S_TEMP - MyMessage msg_S_TEMP(ID_S_TEMP,V_TEMP); +MyMessage msg_S_TEMP(ID_S_TEMP,V_TEMP); #endif #ifdef ID_S_HUM - MyMessage msg_S_HUM(ID_S_HUM,V_HUM); +MyMessage msg_S_HUM(ID_S_HUM,V_HUM); #endif #ifdef ID_S_BARO - MyMessage msg_S_BARO_P(ID_S_BARO,V_PRESSURE); - MyMessage msg_S_BARO_F(ID_S_BARO,V_FORECAST); +MyMessage msg_S_BARO_P(ID_S_BARO,V_PRESSURE); +MyMessage msg_S_BARO_F(ID_S_BARO,V_FORECAST); #endif #ifdef ID_S_WIND - MyMessage msg_S_WIND_S(ID_S_WIND,V_WIND); - MyMessage msg_S_WIND_G(ID_S_WIND,V_GUST); - MyMessage msg_S_WIND_D(ID_S_WIND,V_DIRECTION); +MyMessage msg_S_WIND_S(ID_S_WIND,V_WIND); +MyMessage msg_S_WIND_G(ID_S_WIND,V_GUST); +MyMessage msg_S_WIND_D(ID_S_WIND,V_DIRECTION); #endif #ifdef ID_S_RAIN - MyMessage msg_S_RAIN_A(ID_S_RAIN,V_RAIN); - MyMessage msg_S_RAIN_R(ID_S_RAIN,V_RAINRATE); +MyMessage msg_S_RAIN_A(ID_S_RAIN,V_RAIN); +MyMessage msg_S_RAIN_R(ID_S_RAIN,V_RAINRATE); #endif #ifdef ID_S_UV - MyMessage msg_S_UV(ID_S_UV,V_UV); +MyMessage msg_S_UV(ID_S_UV,V_UV); #endif #ifdef ID_S_WEIGHT - MyMessage msg_S_WEIGHT(ID_S_WEIGHT,V_WEIGHT); +MyMessage msg_S_WEIGHT(ID_S_WEIGHT,V_WEIGHT); #endif #ifdef ID_S_POWER - MyMessage msg_S_POWER_W(ID_S_POWER,V_WATT); - MyMessage msg_S_POWER_K(ID_S_POWER,V_KWH); +MyMessage msg_S_POWER_W(ID_S_POWER,V_WATT); +MyMessage msg_S_POWER_K(ID_S_POWER,V_KWH); #endif #ifdef ID_S_HEATER - //////// REVIEW IMPLEMENTATION //////////// +//////// REVIEW IMPLEMENTATION //////////// - MyMessage msg_S_HEATER_SET_POINT(ID_S_HEATER,V_HVAC_SETPOINT_HEAT); // HVAC/Heater setpoint (Integer between 0-100). S_HEATER, S_HVAC - MyMessage msg_S_HEATER_FLOW_STATE(ID_S_HEATER,V_HVAC_FLOW_STATE); // Mode of header. One of "Off", "HeatOn", "CoolOn", or "AutoChangeOver" // S_HVAC, S_HEATER +MyMessage msg_S_HEATER_SET_POINT(ID_S_HEATER, + V_HVAC_SETPOINT_HEAT); // HVAC/Heater setpoint (Integer between 0-100). S_HEATER, S_HVAC +MyMessage msg_S_HEATER_FLOW_STATE(ID_S_HEATER, + V_HVAC_FLOW_STATE); // Mode of header. One of "Off", "HeatOn", "CoolOn", or "AutoChangeOver" // S_HVAC, S_HEATER - //MyMessage msg_S_HEATER_STATUS(ID_S_HEATER,V_STATUS); - //MyMessage msg_S_HEATER_TEMP(ID_S_HEATER,V_TEMP); +//MyMessage msg_S_HEATER_STATUS(ID_S_HEATER,V_STATUS); +//MyMessage msg_S_HEATER_TEMP(ID_S_HEATER,V_TEMP); - float heater_setpoint=21.5; - String heater_flow_state="Off"; +float heater_setpoint=21.5; +String heater_flow_state="Off"; // float heater_temp=23.5; // bool heater_status=false; - // V_TEMP // Temperature - // V_STATUS // Binary status. 0=off 1=on - // V_HVAC_FLOW_STATE // Mode of header. One of "Off", "HeatOn", "CoolOn", or "AutoChangeOver" - // V_HVAC_SPEED // HVAC/Heater fan speed ("Min", "Normal", "Max", "Auto") - // V_HVAC_SETPOINT_HEAT // HVAC/Heater setpoint +// V_TEMP // Temperature +// V_STATUS // Binary status. 0=off 1=on +// V_HVAC_FLOW_STATE // Mode of header. One of "Off", "HeatOn", "CoolOn", or "AutoChangeOver" +// V_HVAC_SPEED // HVAC/Heater fan speed ("Min", "Normal", "Max", "Auto") +// V_HVAC_SETPOINT_HEAT // HVAC/Heater setpoint #endif #ifdef ID_S_DISTANCE - MyMessage msg_S_DISTANCE(ID_S_DISTANCE,V_DISTANCE); +MyMessage msg_S_DISTANCE(ID_S_DISTANCE,V_DISTANCE); #endif #ifdef ID_S_LIGHT_LEVEL - MyMessage msg_S_LIGHT_LEVEL(ID_S_LIGHT_LEVEL,V_LIGHT_LEVEL); +MyMessage msg_S_LIGHT_LEVEL(ID_S_LIGHT_LEVEL,V_LIGHT_LEVEL); #endif #ifdef ID_S_LOCK - MyMessage msg_S_LOCK(ID_S_LOCK,V_LOCK_STATUS); - bool isLocked = 0; +MyMessage msg_S_LOCK(ID_S_LOCK,V_LOCK_STATUS); +bool isLocked = 0; #endif #ifdef ID_S_IR - MyMessage msg_S_IR_S(ID_S_IR,V_IR_SEND); - MyMessage msg_S_IR_R(ID_S_IR,V_IR_RECEIVE); - long irVal = 0; +MyMessage msg_S_IR_S(ID_S_IR,V_IR_SEND); +MyMessage msg_S_IR_R(ID_S_IR,V_IR_RECEIVE); +long irVal = 0; #endif #ifdef ID_S_WATER - MyMessage msg_S_WATER_F(ID_S_WATER,V_FLOW); - MyMessage msg_S_WATER_V(ID_S_WATER,V_VOLUME); +MyMessage msg_S_WATER_F(ID_S_WATER,V_FLOW); +MyMessage msg_S_WATER_V(ID_S_WATER,V_VOLUME); #endif #ifdef ID_S_AIR_QUALITY - MyMessage msg_S_AIR_QUALITY(ID_S_AIR_QUALITY,V_LEVEL); +MyMessage msg_S_AIR_QUALITY(ID_S_AIR_QUALITY,V_LEVEL); #endif #ifdef ID_S_DUST - MyMessage msg_S_DUST(ID_S_DUST,V_LEVEL); +MyMessage msg_S_DUST(ID_S_DUST,V_LEVEL); #endif #ifdef ID_S_SCENE_CONTROLLER - MyMessage msg_S_SCENE_CONTROLLER_ON(ID_S_SCENE_CONTROLLER,V_SCENE_ON); - MyMessage msg_S_SCENE_CONTROLLER_OF(ID_S_SCENE_CONTROLLER,V_SCENE_OFF); - // not sure if scene controller sends int or chars - // betting on ints as Touch Display Scen by Hek // compiler warnings - char *scenes[] = { - (char *)"Good Morning", - (char *)"Clean Up!", - (char *)"All Lights Off", - (char *)"Music On/Off" - }; +MyMessage msg_S_SCENE_CONTROLLER_ON(ID_S_SCENE_CONTROLLER,V_SCENE_ON); +MyMessage msg_S_SCENE_CONTROLLER_OF(ID_S_SCENE_CONTROLLER,V_SCENE_OFF); +// not sure if scene controller sends int or chars +// betting on ints as Touch Display Scen by Hek // compiler warnings +char *scenes[] = { + (char *)"Good Morning", + (char *)"Clean Up!", + (char *)"All Lights Off", + (char *)"Music On/Off" +}; - int sceneVal=0; - int sceneValPrevious=0; +int sceneVal=0; +int sceneValPrevious=0; #endif #ifdef ID_S_RGB_LIGHT - MyMessage msg_S_RGB_LIGHT_V_RGB(ID_S_RGB_LIGHT,V_RGB); - MyMessage msg_S_RGB_LIGHT_V_WATT(ID_S_RGB_LIGHT,V_WATT); - String rgbState="000000"; - //RGB light V_RGB, V_WATT - //RGB value transmitted as ASCII hex string (I.e "ff0000" for red) +MyMessage msg_S_RGB_LIGHT_V_RGB(ID_S_RGB_LIGHT,V_RGB); +MyMessage msg_S_RGB_LIGHT_V_WATT(ID_S_RGB_LIGHT,V_WATT); +String rgbState="000000"; +//RGB light V_RGB, V_WATT +//RGB value transmitted as ASCII hex string (I.e "ff0000" for red) #endif #ifdef ID_S_RGBW_LIGHT - MyMessage msg_S_RGBW_LIGHT_V_RGBW(ID_S_RGBW_LIGHT,V_RGBW); - MyMessage msg_S_RGBW_LIGHT_V_WATT(ID_S_RGBW_LIGHT,V_WATT); - String rgbwState="00000000"; - //RGBW light (with separate white component) V_RGBW, V_WATT - //RGBW value transmitted as ASCII hex string (I.e "ff0000ff" for red + full white) S_RGBW_LIGHT +MyMessage msg_S_RGBW_LIGHT_V_RGBW(ID_S_RGBW_LIGHT,V_RGBW); +MyMessage msg_S_RGBW_LIGHT_V_WATT(ID_S_RGBW_LIGHT,V_WATT); +String rgbwState="00000000"; +//RGBW light (with separate white component) V_RGBW, V_WATT +//RGBW value transmitted as ASCII hex string (I.e "ff0000ff" for red + full white) S_RGBW_LIGHT #endif #ifdef ID_S_COLOR_SENSOR - MyMessage msg_S_COLOR_SENSOR_V_RGB(ID_S_COLOR_SENSOR,V_RGB); - //Color sensor V_RGB - //RGB value transmitted as ASCII hex string (I.e "ff0000" for red) S_RGB_LIGHT, S_COLOR_SENSOR +MyMessage msg_S_COLOR_SENSOR_V_RGB(ID_S_COLOR_SENSOR,V_RGB); +//Color sensor V_RGB +//RGB value transmitted as ASCII hex string (I.e "ff0000" for red) S_RGB_LIGHT, S_COLOR_SENSOR #endif #ifdef ID_S_HVAC - MyMessage msg_S_HVAC_V_HVAC_SETPOINT_HEAT(ID_S_HVAC,V_HVAC_SETPOINT_HEAT); - MyMessage msg_S_HVAC_V_HVAC_SETPOINT_COOL(ID_S_HVAC,V_HVAC_SETPOINT_COOL); - MyMessage msg_S_HVAC_V_HVAC_FLOW_STATET(ID_S_HVAC,V_HVAC_FLOW_STATE); - MyMessage msg_S_HVAC_V_HVAC_FLOW_MODE(ID_S_HVAC,V_HVAC_FLOW_MODE); - MyMessage msg_S_HVAC_V_HVAC_SPEED(ID_S_HVAC,V_HVAC_SPEED); - - float hvac_SetPointHeat = 16.5; - float hvac_SetPointCool = 25.5; - String hvac_FlowState = "AutoChangeOver"; - String hvac_FlowMode = "Auto"; - String hvac_Speed = "Normal"; - - //Thermostat/HVAC device - //V_HVAC_SETPOINT_HEAT, // HVAC/Heater setpoint - //V_HVAC_SETPOINT_COOL, // HVAC cold setpoint - //V_HVAC_FLOW_STATE, // Mode of header. One of "Off", "HeatOn", "CoolOn", or "AutoChangeOver" - //V_HVAC_FLOW_MODE, // Flow mode for HVAC ("Auto", "ContinuousOn", "PeriodicOn") - //V_HVAC_SPEED // HVAC/Heater fan speed ("Min", "Normal", "Max", "Auto") - - // NOT IMPLEMENTED YET - //V_TEMP // Temperature - //V_STATUS // Binary status. 0=off 1=on +MyMessage msg_S_HVAC_V_HVAC_SETPOINT_HEAT(ID_S_HVAC,V_HVAC_SETPOINT_HEAT); +MyMessage msg_S_HVAC_V_HVAC_SETPOINT_COOL(ID_S_HVAC,V_HVAC_SETPOINT_COOL); +MyMessage msg_S_HVAC_V_HVAC_FLOW_STATET(ID_S_HVAC,V_HVAC_FLOW_STATE); +MyMessage msg_S_HVAC_V_HVAC_FLOW_MODE(ID_S_HVAC,V_HVAC_FLOW_MODE); +MyMessage msg_S_HVAC_V_HVAC_SPEED(ID_S_HVAC,V_HVAC_SPEED); + +float hvac_SetPointHeat = 16.5; +float hvac_SetPointCool = 25.5; +String hvac_FlowState = "AutoChangeOver"; +String hvac_FlowMode = "Auto"; +String hvac_Speed = "Normal"; + +//Thermostat/HVAC device +//V_HVAC_SETPOINT_HEAT, // HVAC/Heater setpoint +//V_HVAC_SETPOINT_COOL, // HVAC cold setpoint +//V_HVAC_FLOW_STATE, // Mode of header. One of "Off", "HeatOn", "CoolOn", or "AutoChangeOver" +//V_HVAC_FLOW_MODE, // Flow mode for HVAC ("Auto", "ContinuousOn", "PeriodicOn") +//V_HVAC_SPEED // HVAC/Heater fan speed ("Min", "Normal", "Max", "Auto") + +// NOT IMPLEMENTED YET +//V_TEMP // Temperature +//V_STATUS // Binary status. 0=off 1=on #endif #ifdef ID_S_MULTIMETER - MyMessage msg_S_MULTIMETER_V_IMPEDANCE(ID_S_MULTIMETER,V_IMPEDANCE); - MyMessage msg_S_MULTIMETER_V_VOLTAGE(ID_S_MULTIMETER,V_VOLTAGE); - MyMessage msg_S_MULTIMETER_V_CURRENT(ID_S_MULTIMETER,V_CURRENT); +MyMessage msg_S_MULTIMETER_V_IMPEDANCE(ID_S_MULTIMETER,V_IMPEDANCE); +MyMessage msg_S_MULTIMETER_V_VOLTAGE(ID_S_MULTIMETER,V_VOLTAGE); +MyMessage msg_S_MULTIMETER_V_CURRENT(ID_S_MULTIMETER,V_CURRENT); - // Multimeter device V_VOLTAGE, V_CURRENT, V_IMPEDANCE - // V_IMPEDANCE 14 Impedance value - // V_VOLTAGE 38 Voltage level - // V_CURRENT 39 Current level +// Multimeter device V_VOLTAGE, V_CURRENT, V_IMPEDANCE +// V_IMPEDANCE 14 Impedance value +// V_VOLTAGE 38 Voltage level +// V_CURRENT 39 Current level #endif #ifdef ID_S_SPRINKLER - // S_SPRINKLER 31 Sprinkler device V_STATUS (turn on/off), V_TRIPPED (if fire detecting device) - // V_STATUS 2 Binary status. 0=off 1=on - // V_ARMED 15 Armed status of a security sensor. 1=Armed, 0=Bypassed - // V_TRIPPED 16 Tripped status of a security sensor. 1=Tripped, 0=Untripped +// S_SPRINKLER 31 Sprinkler device V_STATUS (turn on/off), V_TRIPPED (if fire detecting device) +// V_STATUS 2 Binary status. 0=off 1=on +// V_ARMED 15 Armed status of a security sensor. 1=Armed, 0=Bypassed +// V_TRIPPED 16 Tripped status of a security sensor. 1=Tripped, 0=Untripped #endif #ifdef ID_S_WATER_LEAK @@ -314,15 +316,15 @@ long randNumber; #endif #ifdef ID_S_MOISTURE - MyMessage msg_S_MOISTURE(ID_S_MOISTURE,V_LEVEL); +MyMessage msg_S_MOISTURE(ID_S_MOISTURE,V_LEVEL); #endif #ifdef ID_S_CUSTOM - MyMessage msg_S_CUSTOM_1(ID_S_CUSTOM,V_VAR1); - MyMessage msg_S_CUSTOM_2(ID_S_CUSTOM,V_VAR2); - MyMessage msg_S_CUSTOM_3(ID_S_CUSTOM,V_VAR3); - MyMessage msg_S_CUSTOM_4(ID_S_CUSTOM,V_VAR4); - MyMessage msg_S_CUSTOM_5(ID_S_CUSTOM,V_VAR5); +MyMessage msg_S_CUSTOM_1(ID_S_CUSTOM,V_VAR1); +MyMessage msg_S_CUSTOM_2(ID_S_CUSTOM,V_VAR2); +MyMessage msg_S_CUSTOM_3(ID_S_CUSTOM,V_VAR3); +MyMessage msg_S_CUSTOM_4(ID_S_CUSTOM,V_VAR4); +MyMessage msg_S_CUSTOM_5(ID_S_CUSTOM,V_VAR5); #endif @@ -330,831 +332,861 @@ long randNumber; void setup() { - // Random SEED - randomSeed(analogRead(0)); + // Random SEED + randomSeed(analogRead(0)); - wait(LONG_WAIT); - Serial.println("GW Started"); + wait(LONG_WAIT); + Serial.println("GW Started"); } -void presentation() { - // Send the Sketch Version Information to the Gateway - Serial.print("Send Sketch Info: "); - sendSketchInfo(SKETCH_NAME, SKETCH_VERSION); - Serial.print(SKETCH_NAME); - Serial.println(SKETCH_VERSION); - wait(LONG_WAIT); - - // Get controller configuration - Serial.print("Get Config: "); - metric = getConfig().isMetric; - Serial.println(metric ? "Metric":"Imperial"); - wait(LONG_WAIT); - - // Init Armed - #ifdef ID_S_ARMED - isArmed = true; - #endif - - // Register all sensors to gw (they will be created as child devices) - Serial.println("Presenting Nodes"); - Serial.println("________________"); - - #ifdef ID_S_DOOR - Serial.println(" S_DOOR"); - present(ID_S_DOOR,S_DOOR,"Outside Door"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_MOTION - Serial.println(" S_MOTION"); - present(ID_S_MOTION,S_MOTION,"Outside Motion"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_SMOKE - Serial.println(" S_SMOKE"); - present(ID_S_SMOKE,S_SMOKE,"Kitchen Smoke"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_LIGHT - Serial.println(" S_LIGHT"); - present(ID_S_LIGHT,S_LIGHT,"Hall Light"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_DIMMER - Serial.println(" S_DIMMER"); - present(ID_S_DIMMER,S_DIMMER,"Living room dimmer"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_COVER - Serial.println(" S_COVER"); - present(ID_S_COVER,S_COVER,"Window cover"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_TEMP - Serial.println(" S_TEMP"); - present(ID_S_TEMP,S_TEMP,"House Temperarue"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_HUM - Serial.println(" S_HUM"); - present(ID_S_HUM,S_HUM,"Current Humidity"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_BARO - Serial.println(" S_BARO"); - present(ID_S_BARO,S_BARO," Air pressure"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_WIND - Serial.println(" S_WIND"); - present(ID_S_WIND,S_WIND,"Wind Station"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_RAIN - Serial.println(" S_RAIN"); - present(ID_S_RAIN,S_RAIN,"Rain Station"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_UV - Serial.println(" S_UV"); - present(ID_S_UV,S_UV,"Ultra Violet"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_WEIGHT - Serial.println(" S_WEIGHT"); - present(ID_S_WEIGHT,S_WEIGHT,"Outdoor Scale"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_POWER - Serial.println(" S_POWER"); - present(ID_S_POWER,S_POWER,"Power Metric"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_HEATER - Serial.println(" S_HEATER"); - present(ID_S_HEATER,S_HEATER,"Garage Heater"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_DISTANCE - Serial.println(" S_DISTANCE"); - present(ID_S_DISTANCE,S_DISTANCE,"Distance Measure"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_LIGHT_LEVEL - Serial.println(" S_LIGHT_LEVEL"); - present(ID_S_LIGHT_LEVEL,S_LIGHT_LEVEL,"Outside Light Level"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_LOCK - Serial.println(" S_LOCK"); - present(ID_S_LOCK,S_LOCK,"Front Door Lock"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_IR - Serial.println(" S_IR"); - present(ID_S_IR,S_IR,"Univeral Command"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_WATER - Serial.println(" S_WATER"); - present(ID_S_WATER,S_WATER,"Water Level"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_AIR_QUALITY - Serial.println(" S_AIR_QUALITY"); - present(ID_S_AIR_QUALITY,S_AIR_QUALITY,"Air Station"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_DUST - Serial.println(" S_DUST"); - present(ID_S_DUST,S_DUST,"Dust Level"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_SCENE_CONTROLLER - Serial.println(" S_SCENE_CONTROLLER"); - present(ID_S_SCENE_CONTROLLER,S_SCENE_CONTROLLER,"Scene Controller"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_RGB_LIGHT - Serial.println(" RGB_LIGHT"); - present(ID_S_RGB_LIGHT,S_RGB_LIGHT,"Mood Light"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_RGBW_LIGHT - Serial.println(" RGBW_LIGHT"); - present(ID_S_RGBW_LIGHT,S_RGBW_LIGHT,"Mood Light 2"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_COLOR_SENSOR - Serial.println(" COLOR_SENSOR"); - present(ID_S_COLOR_SENSOR,S_COLOR_SENSOR,"Hall Painting"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_HVAC - Serial.println(" HVAC"); - present(ID_S_HVAC,S_HVAC,"HVAC"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_MULTIMETER - Serial.println(" MULTIMETER"); - present(ID_S_MULTIMETER,S_MULTIMETER,"Electric Staion"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_SPRINKLER - #endif - #ifdef ID_S_WATER_LEAK - #endif - #ifdef ID_S_SOUND - #endif - #ifdef ID_S_VIBRATION - #endif - #ifdef ID_S_MOISTURE - #endif - - #ifdef ID_S_MOISTURE - Serial.println(" S_MOISTURE"); - present(ID_S_MOISTURE,S_MOISTURE,"Basement Sensor"); - wait(SHORT_WAIT); - #endif - - #ifdef ID_S_CUSTOM - Serial.println(" S_CUSTOM"); - present(ID_S_CUSTOM,S_CUSTOM,"Other Stuff"); - wait(SHORT_WAIT); - #endif - - - -Serial.println("________________"); +void presentation() +{ + // Send the Sketch Version Information to the Gateway + Serial.print("Send Sketch Info: "); + sendSketchInfo(SKETCH_NAME, SKETCH_VERSION); + Serial.print(SKETCH_NAME); + Serial.println(SKETCH_VERSION); + wait(LONG_WAIT); + + // Get controller configuration + Serial.print("Get Config: "); + metric = getConfig().isMetric; + Serial.println(metric ? "Metric":"Imperial"); + wait(LONG_WAIT); + + // Init Armed +#ifdef ID_S_ARMED + isArmed = true; +#endif + + // Register all sensors to gw (they will be created as child devices) + Serial.println("Presenting Nodes"); + Serial.println("________________"); + +#ifdef ID_S_DOOR + Serial.println(" S_DOOR"); + present(ID_S_DOOR,S_DOOR,"Outside Door"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_MOTION + Serial.println(" S_MOTION"); + present(ID_S_MOTION,S_MOTION,"Outside Motion"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_SMOKE + Serial.println(" S_SMOKE"); + present(ID_S_SMOKE,S_SMOKE,"Kitchen Smoke"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_LIGHT + Serial.println(" S_LIGHT"); + present(ID_S_LIGHT,S_LIGHT,"Hall Light"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_DIMMER + Serial.println(" S_DIMMER"); + present(ID_S_DIMMER,S_DIMMER,"Living room dimmer"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_COVER + Serial.println(" S_COVER"); + present(ID_S_COVER,S_COVER,"Window cover"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_TEMP + Serial.println(" S_TEMP"); + present(ID_S_TEMP,S_TEMP,"House Temperarue"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_HUM + Serial.println(" S_HUM"); + present(ID_S_HUM,S_HUM,"Current Humidity"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_BARO + Serial.println(" S_BARO"); + present(ID_S_BARO,S_BARO," Air pressure"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_WIND + Serial.println(" S_WIND"); + present(ID_S_WIND,S_WIND,"Wind Station"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_RAIN + Serial.println(" S_RAIN"); + present(ID_S_RAIN,S_RAIN,"Rain Station"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_UV + Serial.println(" S_UV"); + present(ID_S_UV,S_UV,"Ultra Violet"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_WEIGHT + Serial.println(" S_WEIGHT"); + present(ID_S_WEIGHT,S_WEIGHT,"Outdoor Scale"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_POWER + Serial.println(" S_POWER"); + present(ID_S_POWER,S_POWER,"Power Metric"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_HEATER + Serial.println(" S_HEATER"); + present(ID_S_HEATER,S_HEATER,"Garage Heater"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_DISTANCE + Serial.println(" S_DISTANCE"); + present(ID_S_DISTANCE,S_DISTANCE,"Distance Measure"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_LIGHT_LEVEL + Serial.println(" S_LIGHT_LEVEL"); + present(ID_S_LIGHT_LEVEL,S_LIGHT_LEVEL,"Outside Light Level"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_LOCK + Serial.println(" S_LOCK"); + present(ID_S_LOCK,S_LOCK,"Front Door Lock"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_IR + Serial.println(" S_IR"); + present(ID_S_IR,S_IR,"Univeral Command"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_WATER + Serial.println(" S_WATER"); + present(ID_S_WATER,S_WATER,"Water Level"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_AIR_QUALITY + Serial.println(" S_AIR_QUALITY"); + present(ID_S_AIR_QUALITY,S_AIR_QUALITY,"Air Station"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_DUST + Serial.println(" S_DUST"); + present(ID_S_DUST,S_DUST,"Dust Level"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_SCENE_CONTROLLER + Serial.println(" S_SCENE_CONTROLLER"); + present(ID_S_SCENE_CONTROLLER,S_SCENE_CONTROLLER,"Scene Controller"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_RGB_LIGHT + Serial.println(" RGB_LIGHT"); + present(ID_S_RGB_LIGHT,S_RGB_LIGHT,"Mood Light"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_RGBW_LIGHT + Serial.println(" RGBW_LIGHT"); + present(ID_S_RGBW_LIGHT,S_RGBW_LIGHT,"Mood Light 2"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_COLOR_SENSOR + Serial.println(" COLOR_SENSOR"); + present(ID_S_COLOR_SENSOR,S_COLOR_SENSOR,"Hall Painting"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_HVAC + Serial.println(" HVAC"); + present(ID_S_HVAC,S_HVAC,"HVAC"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_MULTIMETER + Serial.println(" MULTIMETER"); + present(ID_S_MULTIMETER,S_MULTIMETER,"Electric Staion"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_SPRINKLER +#endif +#ifdef ID_S_WATER_LEAK +#endif +#ifdef ID_S_SOUND +#endif +#ifdef ID_S_VIBRATION +#endif +#ifdef ID_S_MOISTURE +#endif + +#ifdef ID_S_MOISTURE + Serial.println(" S_MOISTURE"); + present(ID_S_MOISTURE,S_MOISTURE,"Basement Sensor"); + wait(SHORT_WAIT); +#endif + +#ifdef ID_S_CUSTOM + Serial.println(" S_CUSTOM"); + present(ID_S_CUSTOM,S_CUSTOM,"Other Stuff"); + wait(SHORT_WAIT); +#endif + + + + Serial.println("________________"); } void loop() { - Serial.println(""); - Serial.println(""); - Serial.println(""); - Serial.println("#########################"); - randNumber=random(0,101); - - Serial.print("RandomNumber:"); - Serial.println(randNumber); - // Send fake battery level - Serial.println("Send Battery Level"); - sendBatteryLevel(randNumber); - wait(LONG_WAIT); - - // Request time - Serial.println("Request Time"); - requestTime(); - wait(LONG_WAIT); - - //Read Sensors - #ifdef ID_S_DOOR - door(); - #endif - - #ifdef ID_S_MOTION - motion(); - #endif - - #ifdef ID_S_SMOKE - smoke(); - #endif - - #ifdef ID_S_LIGHT - light(); - #endif - - #ifdef ID_S_DIMMER - dimmer(); - #endif - - #ifdef ID_S_COVER - cover(); - #endif - - #ifdef ID_S_TEMP - temp(); - #endif - - #ifdef ID_S_HUM - hum(); - #endif - - #ifdef ID_S_BARO - baro(); - #endif - - #ifdef ID_S_WIND - wind(); - #endif - - #ifdef ID_S_RAIN - rain(); - #endif - - #ifdef ID_S_UV - uv(); - #endif - - #ifdef ID_S_WEIGHT - weight(); - #endif - - #ifdef ID_S_POWER - power(); - #endif - - #ifdef ID_S_HEATER - heater(); - #endif - - #ifdef ID_S_DISTANCE - distance(); - #endif - - #ifdef ID_S_LIGHT_LEVEL - light_level(); - #endif - - #ifdef ID_S_LOCK - lock(); - #endif - - #ifdef ID_S_IR - ir(); - #endif - - #ifdef ID_S_WATER - water(); - #endif - - #ifdef ID_S_AIR_QUALITY - air(); - #endif - - #ifdef ID_S_DUST - dust(); - #endif - - #ifdef ID_S_SCENE_CONTROLLER - scene(); - #endif - - #ifdef ID_S_RGB_LIGHT - rgbLight(); - #endif - - #ifdef ID_S_RGBW_LIGHT - rgbwLight(); - #endif - - #ifdef ID_S_COLOR_SENSOR - color(); - #endif - - #ifdef ID_S_HVAC - hvac(); - #endif - - #ifdef ID_S_MULTIMETER - multimeter(); - #endif - - #ifdef ID_S_SPRINKLER - #endif - #ifdef ID_S_WATER_LEAK - #endif - #ifdef ID_S_SOUND - #endif - #ifdef ID_S_VIBRATION - #endif - #ifdef ID_S_MOISTURE - #endif - - #ifdef ID_S_MOISTURE - moisture(); - #endif - - #ifdef ID_S_CUSTOM - custom(); - #endif - - sendBatteryLevel(randNumber); - wait(SHORT_WAIT); - Serial.println("#########################"); - wait(SLEEP_TIME); //sleep a bit + Serial.println(""); + Serial.println(""); + Serial.println(""); + Serial.println("#########################"); + randNumber=random(0,101); + + Serial.print("RandomNumber:"); + Serial.println(randNumber); + // Send fake battery level + Serial.println("Send Battery Level"); + sendBatteryLevel(randNumber); + wait(LONG_WAIT); + + // Request time + Serial.println("Request Time"); + requestTime(); + wait(LONG_WAIT); + + //Read Sensors +#ifdef ID_S_DOOR + door(); +#endif + +#ifdef ID_S_MOTION + motion(); +#endif + +#ifdef ID_S_SMOKE + smoke(); +#endif + +#ifdef ID_S_LIGHT + light(); +#endif + +#ifdef ID_S_DIMMER + dimmer(); +#endif + +#ifdef ID_S_COVER + cover(); +#endif + +#ifdef ID_S_TEMP + temp(); +#endif + +#ifdef ID_S_HUM + hum(); +#endif + +#ifdef ID_S_BARO + baro(); +#endif + +#ifdef ID_S_WIND + wind(); +#endif + +#ifdef ID_S_RAIN + rain(); +#endif + +#ifdef ID_S_UV + uv(); +#endif + +#ifdef ID_S_WEIGHT + weight(); +#endif + +#ifdef ID_S_POWER + power(); +#endif + +#ifdef ID_S_HEATER + heater(); +#endif + +#ifdef ID_S_DISTANCE + distance(); +#endif + +#ifdef ID_S_LIGHT_LEVEL + light_level(); +#endif + +#ifdef ID_S_LOCK + lock(); +#endif + +#ifdef ID_S_IR + ir(); +#endif + +#ifdef ID_S_WATER + water(); +#endif + +#ifdef ID_S_AIR_QUALITY + air(); +#endif + +#ifdef ID_S_DUST + dust(); +#endif + +#ifdef ID_S_SCENE_CONTROLLER + scene(); +#endif + +#ifdef ID_S_RGB_LIGHT + rgbLight(); +#endif + +#ifdef ID_S_RGBW_LIGHT + rgbwLight(); +#endif + +#ifdef ID_S_COLOR_SENSOR + color(); +#endif + +#ifdef ID_S_HVAC + hvac(); +#endif + +#ifdef ID_S_MULTIMETER + multimeter(); +#endif + +#ifdef ID_S_SPRINKLER +#endif +#ifdef ID_S_WATER_LEAK +#endif +#ifdef ID_S_SOUND +#endif +#ifdef ID_S_VIBRATION +#endif +#ifdef ID_S_MOISTURE +#endif + +#ifdef ID_S_MOISTURE + moisture(); +#endif + +#ifdef ID_S_CUSTOM + custom(); +#endif + + sendBatteryLevel(randNumber); + wait(SHORT_WAIT); + Serial.println("#########################"); + wait(SLEEP_TIME); //sleep a bit } // This is called when a new time value was received -void receiveTime(unsigned long controllerTime) { +void receiveTime(unsigned long controllerTime) +{ - Serial.print("Time value received: "); - Serial.println(controllerTime); + Serial.print("Time value received: "); + Serial.println(controllerTime); } //void door(){} #ifdef ID_S_DOOR -void door(){ - - Serial.print("Door is: " ); - - if (randNumber <= 50) { - Serial.println("Open"); - send(msg_S_DOOR_T.set((int16_t)1)); - } else { - Serial.println("Closed"); - send(msg_S_DOOR_T.set((int16_t)0)); - } - #ifdef ID_S_ARMED - Serial.print("System is: " ); - Serial.println((isArmed ? "Armed":"Disarmed")); - send(msg_S_DOOR_A.set(isArmed)); - #endif +void door() +{ + + Serial.print("Door is: " ); + + if (randNumber <= 50) { + Serial.println("Open"); + send(msg_S_DOOR_T.set((int16_t)1)); + } else { + Serial.println("Closed"); + send(msg_S_DOOR_T.set((int16_t)0)); + } +#ifdef ID_S_ARMED + Serial.print("System is: " ); + Serial.println((isArmed ? "Armed":"Disarmed")); + send(msg_S_DOOR_A.set(isArmed)); +#endif } #endif #ifdef ID_S_MOTION -void motion(){ - - Serial.print("Motion is: " ); - - if (randNumber <= 50) { - Serial.println("Active"); - send(msg_S_MOTION_T.set(1)); - } else { - Serial.println("Quiet"); - send(msg_S_MOTION_T.set(0)); - } - - #ifdef ID_S_ARMED - Serial.print("System is: " ); - Serial.println((isArmed ? "Armed":"Disarmed")); - send(msg_S_MOTION_A.set(isArmed)); - #endif +void motion() +{ + + Serial.print("Motion is: " ); + + if (randNumber <= 50) { + Serial.println("Active"); + send(msg_S_MOTION_T.set(1)); + } else { + Serial.println("Quiet"); + send(msg_S_MOTION_T.set(0)); + } + +#ifdef ID_S_ARMED + Serial.print("System is: " ); + Serial.println((isArmed ? "Armed":"Disarmed")); + send(msg_S_MOTION_A.set(isArmed)); +#endif } #endif #ifdef ID_S_SMOKE -void smoke(){ +void smoke() +{ - Serial.print("Smoke is: " ); + Serial.print("Smoke is: " ); - if (randNumber <= 50) { - Serial.println("Active"); - send(msg_S_SMOKE_T.set(1)); - } else { - Serial.println("Quiet"); - send(msg_S_SMOKE_T.set(0)); - } + if (randNumber <= 50) { + Serial.println("Active"); + send(msg_S_SMOKE_T.set(1)); + } else { + Serial.println("Quiet"); + send(msg_S_SMOKE_T.set(0)); + } - #ifdef ID_S_ARMED - Serial.print("System is: " ); - Serial.println((isArmed ? "Armed":"Disarmed")); - send(msg_S_SMOKE_A.set(isArmed)); - #endif +#ifdef ID_S_ARMED + Serial.print("System is: " ); + Serial.println((isArmed ? "Armed":"Disarmed")); + send(msg_S_SMOKE_A.set(isArmed)); +#endif } #endif #ifdef ID_S_LIGHT -void light(){ +void light() +{ - Serial.print("Light is: " ); - Serial.println((isLightOn ? "On":"Off")); + Serial.print("Light is: " ); + Serial.println((isLightOn ? "On":"Off")); - send(msg_S_LIGHT.set(isLightOn)); + send(msg_S_LIGHT.set(isLightOn)); } #endif #ifdef ID_S_DIMMER -void dimmer(){ +void dimmer() +{ - Serial.print("Dimmer is set to: " ); - Serial.println(dimmerVal); + Serial.print("Dimmer is set to: " ); + Serial.println(dimmerVal); - send(msg_S_DIMMER.set(dimmerVal)); + send(msg_S_DIMMER.set(dimmerVal)); } #endif #ifdef ID_S_COVER -void cover(){ - - Serial.print("Cover is : " ); - - if (coverState == 1){ - Serial.println("Opening"); - send(msg_S_COVER_U.set(1)); - }else if (coverState == -1){ - Serial.println("Closing"); - send(msg_S_COVER_D.set(0)); - }else{ - Serial.println("Idle"); - send(msg_S_COVER_S.set(-1)); - } - send(msg_S_COVER_V.set(coverState)); +void cover() +{ + + Serial.print("Cover is : " ); + + if (coverState == 1) { + Serial.println("Opening"); + send(msg_S_COVER_U.set(1)); + } else if (coverState == -1) { + Serial.println("Closing"); + send(msg_S_COVER_D.set(0)); + } else { + Serial.println("Idle"); + send(msg_S_COVER_S.set(-1)); + } + send(msg_S_COVER_V.set(coverState)); } #endif #ifdef ID_S_TEMP -void temp(){ +void temp() +{ - Serial.print("Temperature is: " ); - Serial.println(map(randNumber,1,100,0,45)); + Serial.print("Temperature is: " ); + Serial.println(map(randNumber,1,100,0,45)); - send(msg_S_TEMP.set(map(randNumber,1,100,0,45))); + send(msg_S_TEMP.set(map(randNumber,1,100,0,45))); } #endif #ifdef ID_S_HUM -void hum(){ +void hum() +{ - Serial.print("Humitidty is: " ); - Serial.println(randNumber); + Serial.print("Humitidty is: " ); + Serial.println(randNumber); - send(msg_S_HUM.set(randNumber)); + send(msg_S_HUM.set(randNumber)); } #endif #ifdef ID_S_BARO -void baro(){ +void baro() +{ - const char *weather[] = {"stable","sunny","cloudy","unstable","thunderstorm","unknown"}; - long pressure = map(randNumber,1,100,870,1086);// hPa? - int forecast = map(randNumber,1,100,0,5); + const char *weather[] = {"stable","sunny","cloudy","unstable","thunderstorm","unknown"}; + long pressure = map(randNumber,1,100,870,1086);// hPa? + int forecast = map(randNumber,1,100,0,5); - Serial.print("Atmosferic Pressure is: " ); - Serial.println(pressure); - send(msg_S_BARO_P.set(pressure)); + Serial.print("Atmosferic Pressure is: " ); + Serial.println(pressure); + send(msg_S_BARO_P.set(pressure)); - Serial.print("Weather forecast: " ); - Serial.println(weather[forecast]); - send(msg_S_BARO_F.set(weather[forecast])); + Serial.print("Weather forecast: " ); + Serial.println(weather[forecast]); + send(msg_S_BARO_F.set(weather[forecast])); } #endif #ifdef ID_S_WIND -void wind(){ +void wind() +{ - Serial.print("Wind Speed is: " ); - Serial.println(randNumber); - send(msg_S_WIND_S.set(randNumber)); + Serial.print("Wind Speed is: " ); + Serial.println(randNumber); + send(msg_S_WIND_S.set(randNumber)); - Serial.print("Wind Gust is: " ); - Serial.println(randNumber+10); - send(msg_S_WIND_G.set(randNumber+10)); + Serial.print("Wind Gust is: " ); + Serial.println(randNumber+10); + send(msg_S_WIND_G.set(randNumber+10)); - Serial.print("Wind Direction is: " ); - Serial.println(map(randNumber,1,100,0,360)); - send(msg_S_WIND_D.set(map(randNumber,1,100,0,360))); + Serial.print("Wind Direction is: " ); + Serial.println(map(randNumber,1,100,0,360)); + send(msg_S_WIND_D.set(map(randNumber,1,100,0,360))); } #endif #ifdef ID_S_RAIN -void rain(){ +void rain() +{ - Serial.print("Rain ammount is: " ); - Serial.println(randNumber); + Serial.print("Rain ammount is: " ); + Serial.println(randNumber); - send(msg_S_RAIN_A.set(randNumber)); + send(msg_S_RAIN_A.set(randNumber)); - Serial.print("Rain rate is: " ); - Serial.println(randNumber/60); + Serial.print("Rain rate is: " ); + Serial.println(randNumber/60); - send(msg_S_RAIN_R.set(randNumber/60,1)); + send(msg_S_RAIN_R.set(randNumber/60,1)); } #endif #ifdef ID_S_UV -void uv(){ +void uv() +{ - Serial.print("Ultra Violet level is: " ); - Serial.println(map(randNumber,1,100,0,15)); + Serial.print("Ultra Violet level is: " ); + Serial.println(map(randNumber,1,100,0,15)); - send(msg_S_UV.set(map(randNumber,1,100,0,15))); + send(msg_S_UV.set(map(randNumber,1,100,0,15))); } #endif #ifdef ID_S_WEIGHT -void weight(){ +void weight() +{ - Serial.print("Weight is: " ); - Serial.println(map(randNumber,1,100,0,150)); + Serial.print("Weight is: " ); + Serial.println(map(randNumber,1,100,0,150)); - send(msg_S_WEIGHT.set(map(randNumber,1,100,0,150))); + send(msg_S_WEIGHT.set(map(randNumber,1,100,0,150))); } #endif #ifdef ID_S_POWER -void power(){ +void power() +{ - Serial.print("Watt is: " ); - Serial.println(map(randNumber,1,100,0,150)); - send(msg_S_POWER_W.set(map(randNumber,1,100,0,150))); + Serial.print("Watt is: " ); + Serial.println(map(randNumber,1,100,0,150)); + send(msg_S_POWER_W.set(map(randNumber,1,100,0,150))); - Serial.print("KWH is: " ); - Serial.println(map(randNumber,1,100,0,150)); - send(msg_S_POWER_K.set(map(randNumber,1,100,0,150))); + Serial.print("KWH is: " ); + Serial.println(map(randNumber,1,100,0,150)); + send(msg_S_POWER_K.set(map(randNumber,1,100,0,150))); } #endif #ifdef ID_S_HEATER -void heater(){ -// float heater_setpoint=21.5; -// float heater_temp=23.5; -// bool heater_status=false; -// String heatState="Off"; - - Serial.print("Heater flow state is: " ); - Serial.println(heater_flow_state); - send(msg_S_HEATER_FLOW_STATE.set(heater_flow_state.c_str())); - -// Serial.print("Heater on/off is: " ); -// Serial.println((heater_status==true)?"On":"Off"); -// send(msg_S_HEATER_STATUS.set(heater_status)); - -// Serial.print("Heater Temperature is: " ); -// Serial.println(heater_temp,1); -// send(msg_S_HEATER_TEMP.set(heater_temp,1)); - - Serial.print("Heater Setpoint: " ); - Serial.println(heater_setpoint,1); - send(msg_S_HEATER_SET_POINT.set(heater_setpoint,1)); +void heater() +{ + // float heater_setpoint=21.5; + // float heater_temp=23.5; + // bool heater_status=false; + // String heatState="Off"; + + Serial.print("Heater flow state is: " ); + Serial.println(heater_flow_state); + send(msg_S_HEATER_FLOW_STATE.set(heater_flow_state.c_str())); + + // Serial.print("Heater on/off is: " ); + // Serial.println((heater_status==true)?"On":"Off"); + // send(msg_S_HEATER_STATUS.set(heater_status)); + + // Serial.print("Heater Temperature is: " ); + // Serial.println(heater_temp,1); + // send(msg_S_HEATER_TEMP.set(heater_temp,1)); + + Serial.print("Heater Setpoint: " ); + Serial.println(heater_setpoint,1); + send(msg_S_HEATER_SET_POINT.set(heater_setpoint,1)); } #endif #ifdef ID_S_DISTANCE -void distance(){ +void distance() +{ - Serial.print("Distance is: " ); - Serial.println(map(randNumber,1,100,0,150)); + Serial.print("Distance is: " ); + Serial.println(map(randNumber,1,100,0,150)); - send(msg_S_DISTANCE.set(map(randNumber,1,100,0,150))); + send(msg_S_DISTANCE.set(map(randNumber,1,100,0,150))); } #endif #ifdef ID_S_LIGHT_LEVEL -void light_level(){ +void light_level() +{ - Serial.print("Light is: " ); - Serial.println(map(randNumber,1,100,0,150)); + Serial.print("Light is: " ); + Serial.println(map(randNumber,1,100,0,150)); - send(msg_S_LIGHT_LEVEL.set(map(randNumber,1,100,0,150))); + send(msg_S_LIGHT_LEVEL.set(map(randNumber,1,100,0,150))); } #endif #ifdef ID_S_LOCK -void lock(){ +void lock() +{ - Serial.print("Lock is: " ); - Serial.println((isLocked ? "Locked":"Unlocked")); - send(msg_S_LOCK.set(isLocked)); + Serial.print("Lock is: " ); + Serial.println((isLocked ? "Locked":"Unlocked")); + send(msg_S_LOCK.set(isLocked)); } #endif #ifdef ID_S_IR -void ir(){ +void ir() +{ - Serial.print("Infrared is: " ); - Serial.println(irVal); + Serial.print("Infrared is: " ); + Serial.println(irVal); - send(msg_S_IR_S.set(irVal)); - send(msg_S_IR_R.set(irVal)); + send(msg_S_IR_S.set(irVal)); + send(msg_S_IR_R.set(irVal)); } #endif #ifdef ID_S_WATER -void water(){ +void water() +{ - Serial.print("Water flow is: " ); - Serial.println(map(randNumber,1,100,0,150)); + Serial.print("Water flow is: " ); + Serial.println(map(randNumber,1,100,0,150)); - send(msg_S_WATER_F.set(map(randNumber,1,100,0,150))); + send(msg_S_WATER_F.set(map(randNumber,1,100,0,150))); - Serial.print("Water volume is: " ); - Serial.println(map(randNumber,1,100,0,150)); + Serial.print("Water volume is: " ); + Serial.println(map(randNumber,1,100,0,150)); - send(msg_S_WATER_V.set(map(randNumber,1,100,0,150))); + send(msg_S_WATER_V.set(map(randNumber,1,100,0,150))); } #endif #ifdef ID_S_AIR_QUALITY -void air(){ +void air() +{ - Serial.print("Air Quality is: " ); - Serial.println(randNumber); + Serial.print("Air Quality is: " ); + Serial.println(randNumber); - send(msg_S_AIR_QUALITY.set(randNumber)); + send(msg_S_AIR_QUALITY.set(randNumber)); } #endif #ifdef ID_S_DUST -void dust(){ +void dust() +{ - Serial.print("Dust level is: " ); - Serial.println(randNumber); + Serial.print("Dust level is: " ); + Serial.println(randNumber); - send(msg_S_DUST.set(randNumber)); + send(msg_S_DUST.set(randNumber)); } #endif #ifdef ID_S_SCENE_CONTROLLER -void scene(){ +void scene() +{ - Serial.print("Scene is: " ); - Serial.println(scenes[sceneVal]); + Serial.print("Scene is: " ); + Serial.println(scenes[sceneVal]); - if(sceneValPrevious != sceneVal){ - send(msg_S_SCENE_CONTROLLER_OF.set(sceneValPrevious)); - send(msg_S_SCENE_CONTROLLER_ON.set(sceneVal)); - sceneValPrevious=sceneVal; - } + if(sceneValPrevious != sceneVal) { + send(msg_S_SCENE_CONTROLLER_OF.set(sceneValPrevious)); + send(msg_S_SCENE_CONTROLLER_ON.set(sceneVal)); + sceneValPrevious=sceneVal; + } } #endif #ifdef ID_S_RGB_LIGHT -void rgbLight(){ +void rgbLight() +{ - Serial.print("RGB Light state is: " ); - Serial.println(rgbState); - send(msg_S_RGB_LIGHT_V_RGB.set(rgbState.c_str())); + Serial.print("RGB Light state is: " ); + Serial.println(rgbState); + send(msg_S_RGB_LIGHT_V_RGB.set(rgbState.c_str())); - Serial.print("RGB Light Watt is: " ); - Serial.println(map(randNumber,1,100,0,150)); - send(msg_S_RGB_LIGHT_V_WATT.set(map(randNumber,1,100,0,150))); + Serial.print("RGB Light Watt is: " ); + Serial.println(map(randNumber,1,100,0,150)); + send(msg_S_RGB_LIGHT_V_WATT.set(map(randNumber,1,100,0,150))); } #endif #ifdef ID_S_RGBW_LIGHT -void rgbwLight(){ +void rgbwLight() +{ - Serial.print("RGBW Light state is: " ); - Serial.println(rgbwState); - send(msg_S_RGBW_LIGHT_V_RGBW.set(rgbwState.c_str())); + Serial.print("RGBW Light state is: " ); + Serial.println(rgbwState); + send(msg_S_RGBW_LIGHT_V_RGBW.set(rgbwState.c_str())); - Serial.print("RGBW Light Watt is: " ); - Serial.println(map(randNumber,1,100,0,150)); - send(msg_S_RGBW_LIGHT_V_WATT.set(map(randNumber,1,100,0,150))); + Serial.print("RGBW Light Watt is: " ); + Serial.println(map(randNumber,1,100,0,150)); + send(msg_S_RGBW_LIGHT_V_WATT.set(map(randNumber,1,100,0,150))); } #endif #ifdef ID_S_COLOR_SENSOR -void color(){ - String colorState; +void color() +{ + String colorState; - String red = String(random(0,256),HEX); - String green = String(random(0,256),HEX); - String blue = String(random(0,256),HEX); + String red = String(random(0,256),HEX); + String green = String(random(0,256),HEX); + String blue = String(random(0,256),HEX); - colorState=String(red + green + blue); + colorState=String(red + green + blue); - Serial.print("Color state is: " ); - Serial.println(colorState); - send(msg_S_COLOR_SENSOR_V_RGB.set(colorState.c_str())); + Serial.print("Color state is: " ); + Serial.println(colorState); + send(msg_S_COLOR_SENSOR_V_RGB.set(colorState.c_str())); } #endif #ifdef ID_S_HVAC -void hvac(){ +void hvac() +{ -// float hvac_SetPointHeat = 16.5; -// float hvac_SetPointCool = 25.5; -// String hvac_FlowState = "AutoChangeOver"; -// String hvac_FlowMode = "Auto"; -// String hvac_Speed = "Normal"; + // float hvac_SetPointHeat = 16.5; + // float hvac_SetPointCool = 25.5; + // String hvac_FlowState = "AutoChangeOver"; + // String hvac_FlowMode = "Auto"; + // String hvac_Speed = "Normal"; - Serial.print("HVAC Set Point Heat is: " ); - Serial.println(hvac_SetPointHeat); - send(msg_S_HVAC_V_HVAC_SETPOINT_HEAT.set(hvac_SetPointHeat,1)); + Serial.print("HVAC Set Point Heat is: " ); + Serial.println(hvac_SetPointHeat); + send(msg_S_HVAC_V_HVAC_SETPOINT_HEAT.set(hvac_SetPointHeat,1)); - Serial.print("HVAC Set Point Cool is: " ); - Serial.println(hvac_SetPointCool); - send(msg_S_HVAC_V_HVAC_SETPOINT_COOL.set(hvac_SetPointCool,1)); + Serial.print("HVAC Set Point Cool is: " ); + Serial.println(hvac_SetPointCool); + send(msg_S_HVAC_V_HVAC_SETPOINT_COOL.set(hvac_SetPointCool,1)); - Serial.print("HVAC Flow State is: " ); - Serial.println(hvac_FlowState); - send(msg_S_HVAC_V_HVAC_FLOW_STATET.set(hvac_FlowState.c_str())); + Serial.print("HVAC Flow State is: " ); + Serial.println(hvac_FlowState); + send(msg_S_HVAC_V_HVAC_FLOW_STATET.set(hvac_FlowState.c_str())); - Serial.print("HVAC Flow Mode is: " ); - Serial.println(hvac_FlowMode); - send(msg_S_HVAC_V_HVAC_FLOW_MODE.set(hvac_FlowMode.c_str())); + Serial.print("HVAC Flow Mode is: " ); + Serial.println(hvac_FlowMode); + send(msg_S_HVAC_V_HVAC_FLOW_MODE.set(hvac_FlowMode.c_str())); - Serial.print("HVAC Speed is: " ); - Serial.println(hvac_Speed); - send(msg_S_HVAC_V_HVAC_SPEED.set(hvac_Speed.c_str())); + Serial.print("HVAC Speed is: " ); + Serial.println(hvac_Speed); + send(msg_S_HVAC_V_HVAC_SPEED.set(hvac_Speed.c_str())); } #endif #ifdef ID_S_MULTIMETER -void multimeter(){ - int impedance=map(randNumber,1,100,0,15000); - int volt=map(randNumber,1,100,0,380); - int amps=map(randNumber,1,100,0,16); +void multimeter() +{ + int impedance=map(randNumber,1,100,0,15000); + int volt=map(randNumber,1,100,0,380); + int amps=map(randNumber,1,100,0,16); - Serial.print("Impedance is: " ); - Serial.println(impedance); - send(msg_S_MULTIMETER_V_IMPEDANCE.set(impedance)); + Serial.print("Impedance is: " ); + Serial.println(impedance); + send(msg_S_MULTIMETER_V_IMPEDANCE.set(impedance)); - Serial.print("Voltage is: " ); - Serial.println(volt); - send(msg_S_MULTIMETER_V_VOLTAGE.set(volt)); + Serial.print("Voltage is: " ); + Serial.println(volt); + send(msg_S_MULTIMETER_V_VOLTAGE.set(volt)); - Serial.print("Current is: " ); - Serial.println(amps); - send(msg_S_MULTIMETER_V_CURRENT.set(amps)); + Serial.print("Current is: " ); + Serial.println(amps); + send(msg_S_MULTIMETER_V_CURRENT.set(amps)); } #endif @@ -1171,288 +1203,291 @@ void multimeter(){ #endif #ifdef ID_S_MOISTURE -void moisture(){ +void moisture() +{ - Serial.print("Moisture level is: " ); - Serial.println(randNumber); + Serial.print("Moisture level is: " ); + Serial.println(randNumber); - send(msg_S_MOISTURE.set(randNumber)); + send(msg_S_MOISTURE.set(randNumber)); } #endif #ifdef ID_S_CUSTOM -void custom(){ +void custom() +{ - Serial.print("Custom value is: " ); - Serial.println(randNumber); + Serial.print("Custom value is: " ); + Serial.println(randNumber); - send(msg_S_CUSTOM_1.set(randNumber)); - send(msg_S_CUSTOM_2.set(randNumber)); - send(msg_S_CUSTOM_3.set(randNumber)); - send(msg_S_CUSTOM_4.set(randNumber)); - send(msg_S_CUSTOM_5.set(randNumber)); + send(msg_S_CUSTOM_1.set(randNumber)); + send(msg_S_CUSTOM_2.set(randNumber)); + send(msg_S_CUSTOM_3.set(randNumber)); + send(msg_S_CUSTOM_4.set(randNumber)); + send(msg_S_CUSTOM_5.set(randNumber)); } #endif -void receive(const MyMessage &message) { - switch (message.type) { - #ifdef ID_S_ARMED - case V_ARMED: - isArmed = message.getBool(); - Serial.print("Incoming change for ID_S_ARMED:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println((isArmed ? "Armed":"Disarmed" )); - #ifdef ID_S_DOOR - door();//temp ack for door - #endif - #ifdef ID_S_MOTION - motion();//temp ack - #endif - #ifdef ID_S_SMOKE - smoke();//temp ack - #endif - break; - #endif - - - case V_STATUS: // V_LIGHT: - #ifdef ID_S_LIGHT - if(message.sensor==ID_S_LIGHT){ - isLightOn = message.getBool(); - Serial.print("Incoming change for ID_S_LIGHT:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println((isLightOn ? "On":"Off")); - light(); // temp ack - } - #endif -// #ifdef ID_S_HEATER -// if(message.sensor == ID_S_HEATER){ -// heater_status = message.getBool(); -// Serial.print("Incoming change for ID_S_HEATER:"); -// Serial.print(message.sensor); -// Serial.print(", New status: "); -// Serial.println(heater_status); -// heater();//temp ack -// } -// #endif - break; - - - #ifdef ID_S_DIMMER - case V_DIMMER: - if ((message.getInt()<0)||(message.getInt()>100)) { - Serial.println( "V_DIMMER data invalid (should be 0..100)" ); - break; - } - dimmerVal= message.getInt(); - Serial.print("Incoming change for ID_S_DIMMER:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println(message.getInt()); - dimmer();// temp ack - break; - #endif - - #ifdef ID_S_COVER - case V_UP: - coverState=1; - Serial.print("Incoming change for ID_S_COVER:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println("V_UP"); - cover(); // temp ack - break; - - case V_DOWN: - coverState=-1; - Serial.print("Incoming change for ID_S_COVER:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println("V_DOWN"); - cover(); //temp ack - break; - - case V_STOP: - coverState=0; - Serial.print("Incoming change for ID_S_COVER:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println("V_STOP"); - cover(); //temp ack - break; - #endif - - - case V_HVAC_SETPOINT_HEAT: - - #ifdef ID_S_HEATER - if(message.sensor == ID_S_HEATER){ - heater_setpoint=message.getFloat(); - - Serial.print("Incoming set point for ID_S_HEATER:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println(heater_setpoint,1); - heater();//temp ack - } - #endif - - #ifdef ID_S_HVAC - if(message.sensor == ID_S_HVAC){ - hvac_SetPointHeat=message.getFloat(); - Serial.print("Incoming set point for ID_S_HVAC:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println(hvac_SetPointHeat,1); - hvac();//temp ack - } - #endif - break; - - case V_HVAC_FLOW_STATE: - #ifdef ID_S_HEATER - if(message.sensor == ID_S_HEATER){ - heater_flow_state=message.getString(); - Serial.print("Incoming flow state change for ID_S_HEATER:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println(heater_flow_state); - heater();//temp ack - } - #endif - - #ifdef ID_S_HVAC - if(message.sensor == ID_S_HVAC){ - hvac_FlowState=message.getString(); - - Serial.print("Incoming set point for ID_S_HVAC:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println(hvac_FlowState); - hvac();//temp ack - } - #endif - break; - - #ifdef ID_S_LOCK - case V_LOCK_STATUS: - isLocked = message.getBool(); - Serial.print("Incoming change for ID_S_LOCK:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println(message.getBool()?"Locked":"Unlocked"); - lock(); //temp ack - break; - #endif - - #ifdef ID_S_IR - case V_IR_SEND: - irVal = message.getLong(); - Serial.print("Incoming change for ID_S_IR:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println(irVal); - ir(); // temp ack - break; - case V_IR_RECEIVE: - irVal = message.getLong(); - Serial.print("Incoming change for ID_S_IR:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println(irVal); - ir(); // temp ack - break; - #endif - - #ifdef ID_S_SCENE_CONTROLLER - case V_SCENE_ON: - sceneVal = message.getInt(); - Serial.print("Incoming change for ID_S_SCENE_CONTROLLER:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.print(scenes[sceneVal]); - Serial.println(" On"); - scene();// temp ack - break; - case V_SCENE_OFF: - sceneVal = message.getInt(); - Serial.print("Incoming change for ID_S_SCENE_CONTROLLER:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.print(scenes[sceneVal]); - Serial.println(" Off"); - scene();// temp ack - break; - #endif - - #ifdef ID_S_RGB_LIGHT - case V_RGB: - rgbState=message.getString(); - Serial.print("Incoming flow state change for ID_S_RGB_LIGHT:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println(rgbState); - rgbLight(); // temp ack - - break; - #endif - - #ifdef ID_S_RGBW_LIGHT - case V_RGBW: - rgbwState=message.getString(); - Serial.print("Incoming flow state change for ID_S_RGBW_LIGHT:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println(rgbwState); - rgbwLight(); - break; - #endif - - #ifdef ID_S_HVAC - // hvac_SetPointHeat - // hvac_SetPointCool - // hvac_FlowState - // hvac_FlowMode - // hvac_Speed - - case V_HVAC_SETPOINT_COOL: - hvac_SetPointCool=message.getFloat(); - - Serial.print("Incoming set point for ID_S_HVAC:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println(hvac_SetPointCool,1); - hvac();//temp ack - break; - - case V_HVAC_FLOW_MODE: - hvac_Speed=message.getString(); - - Serial.print("Incoming set point for ID_S_HVAC:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println(hvac_Speed); - hvac();//temp ack - break; - - case V_HVAC_SPEED: - hvac_FlowMode=message.getString(); - - Serial.print("Incoming set point for ID_S_HVAC:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println(hvac_FlowMode); - hvac();//temp ack - break; - #endif - - default: - Serial.print("Unknown/UnImplemented message type: "); - Serial.println(message.type); - } +void receive(const MyMessage &message) +{ + switch (message.type) { +#ifdef ID_S_ARMED + case V_ARMED: + isArmed = message.getBool(); + Serial.print("Incoming change for ID_S_ARMED:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println((isArmed ? "Armed":"Disarmed" )); +#ifdef ID_S_DOOR + door();//temp ack for door +#endif +#ifdef ID_S_MOTION + motion();//temp ack +#endif +#ifdef ID_S_SMOKE + smoke();//temp ack +#endif + break; +#endif + + + case V_STATUS: // V_LIGHT: +#ifdef ID_S_LIGHT + if(message.sensor==ID_S_LIGHT) { + isLightOn = message.getBool(); + Serial.print("Incoming change for ID_S_LIGHT:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println((isLightOn ? "On":"Off")); + light(); // temp ack + } +#endif + // #ifdef ID_S_HEATER + // if(message.sensor == ID_S_HEATER){ + // heater_status = message.getBool(); + // Serial.print("Incoming change for ID_S_HEATER:"); + // Serial.print(message.sensor); + // Serial.print(", New status: "); + // Serial.println(heater_status); + // heater();//temp ack + // } + // #endif + break; + + +#ifdef ID_S_DIMMER + case V_DIMMER: + if ((message.getInt()<0)||(message.getInt()>100)) { + Serial.println( "V_DIMMER data invalid (should be 0..100)" ); + break; + } + dimmerVal= message.getInt(); + Serial.print("Incoming change for ID_S_DIMMER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(message.getInt()); + dimmer();// temp ack + break; +#endif + +#ifdef ID_S_COVER + case V_UP: + coverState=1; + Serial.print("Incoming change for ID_S_COVER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println("V_UP"); + cover(); // temp ack + break; + + case V_DOWN: + coverState=-1; + Serial.print("Incoming change for ID_S_COVER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println("V_DOWN"); + cover(); //temp ack + break; + + case V_STOP: + coverState=0; + Serial.print("Incoming change for ID_S_COVER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println("V_STOP"); + cover(); //temp ack + break; +#endif + + + case V_HVAC_SETPOINT_HEAT: + +#ifdef ID_S_HEATER + if(message.sensor == ID_S_HEATER) { + heater_setpoint=message.getFloat(); + + Serial.print("Incoming set point for ID_S_HEATER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(heater_setpoint,1); + heater();//temp ack + } +#endif + +#ifdef ID_S_HVAC + if(message.sensor == ID_S_HVAC) { + hvac_SetPointHeat=message.getFloat(); + Serial.print("Incoming set point for ID_S_HVAC:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(hvac_SetPointHeat,1); + hvac();//temp ack + } +#endif + break; + + case V_HVAC_FLOW_STATE: +#ifdef ID_S_HEATER + if(message.sensor == ID_S_HEATER) { + heater_flow_state=message.getString(); + Serial.print("Incoming flow state change for ID_S_HEATER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(heater_flow_state); + heater();//temp ack + } +#endif + +#ifdef ID_S_HVAC + if(message.sensor == ID_S_HVAC) { + hvac_FlowState=message.getString(); + + Serial.print("Incoming set point for ID_S_HVAC:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(hvac_FlowState); + hvac();//temp ack + } +#endif + break; + +#ifdef ID_S_LOCK + case V_LOCK_STATUS: + isLocked = message.getBool(); + Serial.print("Incoming change for ID_S_LOCK:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(message.getBool()?"Locked":"Unlocked"); + lock(); //temp ack + break; +#endif + +#ifdef ID_S_IR + case V_IR_SEND: + irVal = message.getLong(); + Serial.print("Incoming change for ID_S_IR:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(irVal); + ir(); // temp ack + break; + case V_IR_RECEIVE: + irVal = message.getLong(); + Serial.print("Incoming change for ID_S_IR:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(irVal); + ir(); // temp ack + break; +#endif + +#ifdef ID_S_SCENE_CONTROLLER + case V_SCENE_ON: + sceneVal = message.getInt(); + Serial.print("Incoming change for ID_S_SCENE_CONTROLLER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.print(scenes[sceneVal]); + Serial.println(" On"); + scene();// temp ack + break; + case V_SCENE_OFF: + sceneVal = message.getInt(); + Serial.print("Incoming change for ID_S_SCENE_CONTROLLER:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.print(scenes[sceneVal]); + Serial.println(" Off"); + scene();// temp ack + break; +#endif + +#ifdef ID_S_RGB_LIGHT + case V_RGB: + rgbState=message.getString(); + Serial.print("Incoming flow state change for ID_S_RGB_LIGHT:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(rgbState); + rgbLight(); // temp ack + + break; +#endif + +#ifdef ID_S_RGBW_LIGHT + case V_RGBW: + rgbwState=message.getString(); + Serial.print("Incoming flow state change for ID_S_RGBW_LIGHT:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(rgbwState); + rgbwLight(); + break; +#endif + +#ifdef ID_S_HVAC + // hvac_SetPointHeat + // hvac_SetPointCool + // hvac_FlowState + // hvac_FlowMode + // hvac_Speed + + case V_HVAC_SETPOINT_COOL: + hvac_SetPointCool=message.getFloat(); + + Serial.print("Incoming set point for ID_S_HVAC:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(hvac_SetPointCool,1); + hvac();//temp ack + break; + + case V_HVAC_FLOW_MODE: + hvac_Speed=message.getString(); + + Serial.print("Incoming set point for ID_S_HVAC:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(hvac_Speed); + hvac();//temp ack + break; + + case V_HVAC_SPEED: + hvac_FlowMode=message.getString(); + + Serial.print("Incoming set point for ID_S_HVAC:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(hvac_FlowMode); + hvac();//temp ack + break; +#endif + + default: + Serial.print("Unknown/UnImplemented message type: "); + Serial.println(message.type); + } } diff --git a/examples/MotionSensor/MotionSensor.ino b/examples/MotionSensor/MotionSensor.ino index 17bdc48a5..c7cd1e581 100644 --- a/examples/MotionSensor/MotionSensor.ino +++ b/examples/MotionSensor/MotionSensor.ino @@ -20,9 +20,9 @@ * * REVISION HISTORY * Version 1.0 - Henrik Ekblad - * + * * DESCRIPTION - * Motion Sensor example using HC-SR501 + * Motion Sensor example using HC-SR501 * http://www.mysensors.org/build/motion * */ @@ -43,29 +43,30 @@ unsigned long SLEEP_TIME = 120000; // Sleep time between reports (in millisecond // Initialize motion message MyMessage msg(CHILD_ID, V_TRIPPED); -void setup() -{ - pinMode(DIGITAL_INPUT_SENSOR, INPUT); // sets the motion sensor digital pin as input +void setup() +{ + pinMode(DIGITAL_INPUT_SENSOR, INPUT); // sets the motion sensor digital pin as input } -void presentation() { - // Send the sketch version information to the gateway and Controller - sendSketchInfo("Motion Sensor", "1.0"); +void presentation() +{ + // Send the sketch version information to the gateway and Controller + sendSketchInfo("Motion Sensor", "1.0"); - // Register all sensors to gw (they will be created as child devices) - present(CHILD_ID, S_MOTION); + // Register all sensors to gw (they will be created as child devices) + present(CHILD_ID, S_MOTION); } -void loop() -{ - // Read digital motion value - bool tripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH; - - Serial.println(tripped); - send(msg.set(tripped?"1":"0")); // Send tripped value to gw +void loop() +{ + // Read digital motion value + bool tripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH; + + Serial.println(tripped); + send(msg.set(tripped?"1":"0")); // Send tripped value to gw - // Sleep until interrupt comes in on motion sensor. Send update every two minute. - sleep(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR), CHANGE, SLEEP_TIME); + // Sleep until interrupt comes in on motion sensor. Send update every two minute. + sleep(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR), CHANGE, SLEEP_TIME); } diff --git a/examples/MotionSensorRS485/MotionSensorRS485.ino b/examples/MotionSensorRS485/MotionSensorRS485.ino index e034ab43f..5518bff91 100644 --- a/examples/MotionSensorRS485/MotionSensorRS485.ino +++ b/examples/MotionSensorRS485/MotionSensorRS485.ino @@ -20,18 +20,18 @@ * * REVISION HISTORY * Version 1.0 - Henrik Ekblad - * + * * DESCRIPTION * This is an example of sensors using RS485 as transport layer - * - * Motion Sensor example using HC-SR501 + * + * Motion Sensor example using HC-SR501 * http://www.mysensors.org/build/motion - * + * * If your Arduino board has additional serial ports * you can use to connect the RS485 module. * Otherwise, the transport uses AltSoftSerial to handle two serial * links on one Arduino. Use the following pins for RS485 link - * + * * Board Transmit Receive PWM Unusable * ----- -------- ------- ------------ * Teensy 3.0 & 3.1 21 20 22 @@ -41,8 +41,8 @@ * Arduino Leonardo 5 13 (none) * Arduino Mega 46 48 44, 45 * Wiring-S 5 6 4 - * Sanguino 13 14 12 * - * + * Sanguino 13 14 12 * + * */ // Enable debug prints to serial monitor @@ -51,7 +51,7 @@ // Enable RS485 transport layer #define MY_RS485 -// Define this to enables DE-pin management on defined pin +// Define this to enables DE-pin management on defined pin #define MY_RS485_DE_PIN 2 // Set RS485 baud rate to use @@ -69,29 +69,30 @@ unsigned long SLEEP_TIME = 120000; // Sleep time between reports (in millisecond // Initialize motion message MyMessage msg(CHILD_ID, V_TRIPPED); -void setup() -{ - pinMode(DIGITAL_INPUT_SENSOR, INPUT); // sets the motion sensor digital pin as input +void setup() +{ + pinMode(DIGITAL_INPUT_SENSOR, INPUT); // sets the motion sensor digital pin as input } -void presentation() { - // Send the sketch version information to the gateway and Controller - sendSketchInfo("Motion Sensor", "1.0"); +void presentation() +{ + // Send the sketch version information to the gateway and Controller + sendSketchInfo("Motion Sensor", "1.0"); - // Register all sensors to gw (they will be created as child devices) - present(CHILD_ID, S_MOTION); + // Register all sensors to gw (they will be created as child devices) + present(CHILD_ID, S_MOTION); } -void loop() -{ - // Read digital motion value - bool tripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH; - - Serial.println(tripped); - send(msg.set(tripped?"1":"0")); // Send tripped value to gw +void loop() +{ + // Read digital motion value + bool tripped = digitalRead(DIGITAL_INPUT_SENSOR) == HIGH; + + Serial.println(tripped); + send(msg.set(tripped?"1":"0")); // Send tripped value to gw - // Sleep until interrupt comes in on motion sensor. Send update every two minute. - sleep(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR), CHANGE, SLEEP_TIME); + // Sleep until interrupt comes in on motion sensor. Send update every two minute. + sleep(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR), CHANGE, SLEEP_TIME); } diff --git a/examples/PHSensor/PHSensor.ino b/examples/PHSensor/PHSensor.ino index 4eb7b8f5c..8bda2fe4f 100644 --- a/examples/PHSensor/PHSensor.ino +++ b/examples/PHSensor/PHSensor.ino @@ -42,37 +42,39 @@ MyMessage msg(0, V_PH); void setup() { - //Setup your PH sensor here (I2C,Serial,Phidget...) + //Setup your PH sensor here (I2C,Serial,Phidget...) } -float getPH() { - //query your PH sensor here (I2C,Serial,Phidget...) - float dummy = 7; - return dummy; +float getPH() +{ + //query your PH sensor here (I2C,Serial,Phidget...) + float dummy = 7; + return dummy; } -void presentation() { - // Send the sketch version information to the gateway and Controller - sendSketchInfo("PH Sensor", "1.1"); - present(0, S_WATER_QUALITY); +void presentation() +{ + // Send the sketch version information to the gateway and Controller + sendSketchInfo("PH Sensor", "1.1"); + present(0, S_WATER_QUALITY); } void loop() { - float ph = getPH(); + float ph = getPH(); #if COMPARE_PH == 1 - if (lastPH != ph) { + if (lastPH != ph) { #endif - // Send in the new PH value - send(msg.set(ph, 1)); - // Save new PH value for next compare - lastPH = ph; + // Send in the new PH value + send(msg.set(ph, 1)); + // Save new PH value for next compare + lastPH = ph; #if COMPARE_PH == 1 - } + } #endif - sleep(SLEEP_TIME); + sleep(SLEEP_TIME); } diff --git a/examples/PingPongSensor/MYSLog.h b/examples/PingPongSensor/MYSLog.h index ce4d37cf7..dbf7e8fe3 100644 --- a/examples/PingPongSensor/MYSLog.h +++ b/examples/PingPongSensor/MYSLog.h @@ -13,32 +13,34 @@ #define LOGDEBUG 1 #if defined ( LOGDEBUG ) - #define LOG(fmt, args... ) log( fmt, ## args ); +#define LOG(fmt, args... ) log( fmt, ## args ); #else - #define log(fmt, args... ) +#define log(fmt, args... ) #endif -void log(const char *fmt, ... ) { - char buff[128]; - va_list args; - va_start (args, fmt); - vsnprintf(buff, sizeof(buff), fmt, args); - va_end (args); - buff[sizeof(buff)/sizeof(buff[0])-1]='\0'; - Serial.print(buff); +void log(const char *fmt, ... ) +{ + char buff[128]; + va_list args; + va_start (args, fmt); + vsnprintf(buff, sizeof(buff), fmt, args); + va_end (args); + buff[sizeof(buff)/sizeof(buff[0])-1]='\0'; + Serial.print(buff); } -void log(const __FlashStringHelper *fmt, ... ){ - char buf[128]; // resulting string limited to 128 chars - va_list args; - va_start (args, fmt); +void log(const __FlashStringHelper *fmt, ... ) +{ + char buf[128]; // resulting string limited to 128 chars + va_list args; + va_start (args, fmt); #ifdef __AVR__ - vsnprintf_P(buf, sizeof(buf), (const char *)fmt, args); // progmem for AVR + vsnprintf_P(buf, sizeof(buf), (const char *)fmt, args); // progmem for AVR #else - vsnprintf(buf, sizeof(buf), (const char *)fmt, args); // for the rest of the world + vsnprintf(buf, sizeof(buf), (const char *)fmt, args); // for the rest of the world #endif - va_end(args); - Serial.print(buf); + va_end(args); + Serial.print(buf); } #endif diff --git a/examples/PingPongSensor/PingPongSensor.ino b/examples/PingPongSensor/PingPongSensor.ino index 67249dec4..b21de5637 100644 --- a/examples/PingPongSensor/PingPongSensor.ino +++ b/examples/PingPongSensor/PingPongSensor.ino @@ -9,7 +9,7 @@ */ // Enable debug prints to serial monitor -#define MY_DEBUG +#define MY_DEBUG // Enable and select radio type attached #define MY_RADIO_NRF24 @@ -28,71 +28,79 @@ MyMessage mPing(CHILD, V_VAR1); //Ping message MyMessage mPong(CHILD, V_VAR2); //Pong message -void setup() { +void setup() +{ } -void presentation() { - present(CHILD, S_CUSTOM); // - - sendSketchInfo( nodeTypeAsCharRepresentation( getNodeId() ), VSN ); - LOG(F("\n%sReady.\n"), nodeTypeAsCharRepresentation(getNodeId())); +void presentation() +{ + present(CHILD, S_CUSTOM); // + + sendSketchInfo( nodeTypeAsCharRepresentation( getNodeId() ), VSN ); + LOG(F("\n%sReady.\n"), nodeTypeAsCharRepresentation(getNodeId())); } -void loop() { - - // Interactive command and control - // Entering a number from 0 or 1 will write the node 200 (YING) or 201 (YANG) to EEPROM - // Entering T on either node will initiatve a ping-pong test. - if (Serial.available()) { - byte inChar = Serial.read(); - uint8_t node = getNodeId(); - - // Manual Test Mode - if (inChar == 'T' || inChar == 't') { - LOG(F("T received - starting test...\n")); - MyMessage msg = mPong; - msg.sender = (node == YING ? YANG : YING); - sendPingOrPongResponse( msg ); - } - else if (inChar == '0' or inChar == '1') { - byte nodeID = 200 + (inChar - '0'); - setNodeId(nodeID); - } - else { - LOG("Invalid input\n"); - } - } +void loop() +{ + + // Interactive command and control + // Entering a number from 0 or 1 will write the node 200 (YING) or 201 (YANG) to EEPROM + // Entering T on either node will initiatve a ping-pong test. + if (Serial.available()) { + byte inChar = Serial.read(); + uint8_t node = getNodeId(); + + // Manual Test Mode + if (inChar == 'T' || inChar == 't') { + LOG(F("T received - starting test...\n")); + MyMessage msg = mPong; + msg.sender = (node == YING ? YANG : YING); + sendPingOrPongResponse( msg ); + } else if (inChar == '0' or inChar == '1') { + byte nodeID = 200 + (inChar - '0'); + setNodeId(nodeID); + } else { + LOG("Invalid input\n"); + } + } } -void receive(const MyMessage &message) { - - LOG(F("Received %s from %s\n"), msgTypeAsCharRepresentation((mysensor_data)message.type), nodeTypeAsCharRepresentation(message.sender)); +void receive(const MyMessage &message) +{ + + LOG(F("Received %s from %s\n"), msgTypeAsCharRepresentation((mysensor_data)message.type), + nodeTypeAsCharRepresentation(message.sender)); - delay(250); - sendPingOrPongResponse( message ); + delay(250); + sendPingOrPongResponse( message ); } -void sendPingOrPongResponse( MyMessage msg ) { - - MyMessage response = (msg.type == V_VAR1 ? mPong : mPing); - - LOG(F("Sending %s to %s\n"), msgTypeAsCharRepresentation( (mysensor_data)response.type ), nodeTypeAsCharRepresentation(msg.sender)); - - // Set payload to current time in millis to ensure each message is unique - response.set( millis() ); - response.setDestination(msg.sender); - send(response); +void sendPingOrPongResponse( MyMessage msg ) +{ + + MyMessage response = (msg.type == V_VAR1 ? mPong : mPing); + + LOG(F("Sending %s to %s\n"), msgTypeAsCharRepresentation( (mysensor_data)response.type ), + nodeTypeAsCharRepresentation(msg.sender)); + + // Set payload to current time in millis to ensure each message is unique + response.set( millis() ); + response.setDestination(msg.sender); + send(response); } -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); +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); } -const char * msgTypeAsCharRepresentation( mysensor_data mType ) { - return mType == V_VAR1 ? "Ping" : "Pong"; +const char * msgTypeAsCharRepresentation( mysensor_data mType ) +{ + return mType == V_VAR1 ? "Ping" : "Pong"; } -const char * nodeTypeAsCharRepresentation( uint8_t node ) { - return node == YING ? "Ying Node" : "Yang Node"; +const char * nodeTypeAsCharRepresentation( uint8_t node ) +{ + return node == YING ? "Ying Node" : "Yang Node"; } diff --git a/examples/RelayActuator/RelayActuator.ino b/examples/RelayActuator/RelayActuator.ino index 908cb9b17..713b8af42 100644 --- a/examples/RelayActuator/RelayActuator.ino +++ b/examples/RelayActuator/RelayActuator.ino @@ -20,15 +20,15 @@ * * REVISION HISTORY * Version 1.0 - Henrik Ekblad - * + * * DESCRIPTION - * Example sketch showing how to control physical relays. + * Example sketch showing how to control physical relays. * This example will remember relay state after power failure. * http://www.mysensors.org/build/relay - */ + */ // Enable debug prints to serial monitor -#define MY_DEBUG +#define MY_DEBUG // Enable and select radio type attached #define MY_RADIO_NRF24 @@ -45,48 +45,51 @@ #define RELAY_OFF 0 // GPIO value to write to turn off attached relay -void before() { - for (int sensor=1, pin=RELAY_1; sensor<=NUMBER_OF_RELAYS;sensor++, pin++) { - // Then set relay pins in output mode - pinMode(pin, OUTPUT); - // Set relay to last known state (using eeprom storage) - digitalWrite(pin, loadState(sensor)?RELAY_ON:RELAY_OFF); - } +void before() +{ + for (int sensor=1, pin=RELAY_1; sensor<=NUMBER_OF_RELAYS; sensor++, pin++) { + // Then set relay pins in output mode + pinMode(pin, OUTPUT); + // Set relay to last known state (using eeprom storage) + digitalWrite(pin, loadState(sensor)?RELAY_ON:RELAY_OFF); + } } -void setup() { - +void setup() +{ + } -void presentation() -{ - // Send the sketch version information to the gateway and Controller - sendSketchInfo("Relay", "1.0"); +void presentation() +{ + // Send the sketch version information to the gateway and Controller + sendSketchInfo("Relay", "1.0"); - for (int sensor=1, pin=RELAY_1; sensor<=NUMBER_OF_RELAYS;sensor++, pin++) { - // Register all sensors to gw (they will be created as child devices) - present(sensor, S_BINARY); - } + for (int sensor=1, pin=RELAY_1; sensor<=NUMBER_OF_RELAYS; sensor++, pin++) { + // Register all sensors to gw (they will be created as child devices) + present(sensor, S_BINARY); + } } -void loop() +void loop() { - + } -void receive(const MyMessage &message) { - // We only expect one type of message from controller. But we better check anyway. - if (message.type==V_STATUS) { - // Change relay state - digitalWrite(message.sensor-1+RELAY_1, message.getBool()?RELAY_ON:RELAY_OFF); - // Store state in eeprom - saveState(message.sensor, message.getBool()); - // Write some debug info - Serial.print("Incoming change for sensor:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println(message.getBool()); - } +void receive(const MyMessage &message) +{ + // We only expect one type of message from controller. But we better check anyway. + if (message.type==V_STATUS) { + // Change relay state + digitalWrite(message.sensor-1+RELAY_1, message.getBool()?RELAY_ON:RELAY_OFF); + // Store state in eeprom + saveState(message.sensor, message.getBool()); + // Write some debug info + Serial.print("Incoming change for sensor:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(message.getBool()); + } } diff --git a/examples/RepeaterNode/RepeaterNode.ino b/examples/RepeaterNode/RepeaterNode.ino index 90791f6dc..ec768476c 100644 --- a/examples/RepeaterNode/RepeaterNode.ino +++ b/examples/RepeaterNode/RepeaterNode.ino @@ -20,16 +20,16 @@ * * REVISION HISTORY * Version 1.0 - Henrik Ekblad - * + * * DESCRIPTION * Example sketch showing how to create a node thay repeates messages - * from nodes far from gateway back to gateway. - * It is important that nodes that has enabled repeater mode calls - * process() frequently. Repeaters should never sleep. + * from nodes far from gateway back to gateway. + * It is important that nodes that has enabled repeater mode calls + * process() frequently. Repeaters should never sleep. */ // Enable debug prints to serial monitor -#define MY_DEBUG +#define MY_DEBUG // Enable and select radio type attached #define MY_RADIO_NRF24 @@ -40,17 +40,18 @@ #include -void setup() { - +void setup() +{ + } -void presentation() -{ - //Send the sensor node sketch version information to the gateway - sendSketchInfo("Repeater Node", "1.0"); +void presentation() +{ + //Send the sensor node sketch version information to the gateway + sendSketchInfo("Repeater Node", "1.0"); } -void loop() +void loop() { } diff --git a/examples/SecretKnockSensor/SecretKnockSensor.ino b/examples/SecretKnockSensor/SecretKnockSensor.ino index 7859d2ecd..9cb40edc9 100644 --- a/examples/SecretKnockSensor/SecretKnockSensor.ino +++ b/examples/SecretKnockSensor/SecretKnockSensor.ino @@ -20,67 +20,75 @@ * * REVISION HISTORY * Version 1.0 - Henrik Ekblad - * + * * DESCRIPTION * * Secret Knock Sensor * http://www.mysensors.org/build/knock * * See original instructions here (note: The MySensors adopted code might differ in wiring. The instructions below is correct): - * https://learn.adafruit.com/secret-knock-activated-drawer-lock/ + * https://learn.adafruit.com/secret-knock-activated-drawer-lock/ * Version 13.10.31 Built with Arduino IDE 1.0.5 - * + * * By Steve Hoefer http://grathio.com * Adapted to MySensors by Henrik Ekblad - * + * * Licensed under Creative Commons Attribution-Noncommercial-Share Alike 3.0 * http://creativecommons.org/licenses/by-nc-sa/3.0/us/ * (In short: Do what you want, as long as you credit me, don't relicense it, and don't sell it or use it in anything you sell without contacting me.) - * + * * ------Wiring------ - * Pin 0: Program button used for recording a new Knock (connect Pin0 -> button -> GND) + * Pin 0: Program button used for recording a new Knock (connect Pin0 -> button -> GND) * Pin 1: Optional: Connect LED here (remember resisor in series) - * Pin 2: Optional: Piezo element (for beeps). - * Pin 5: A sound sensor (digital output) for sensing knocks. See MySensors purchase guide. I used this: http://rover.ebay.com/rover/1/711-53200-19255-0/1?icep_ff3=2&pub=5575069610&toolid=10001&campid=5337433187&customid=&icep_item=200941260251&ipn=psmain&icep_vectorid=229466&kwid=902099&mtid=824&kw=lg - * Pin 4: Connects to either 1. Relay which open door or lock or + * Pin 2: Optional: Piezo element (for beeps). + * Pin 5: A sound sensor (digital output) for sensing knocks. See MySensors purchase guide. I used this: http://rover.ebay.com/rover/1/711-53200-19255-0/1?icep_ff3=2&pub=5575069610&toolid=10001&campid=5337433187&customid=&icep_item=200941260251&ipn=psmain&icep_vectorid=229466&kwid=902099&mtid=824&kw=lg + * Pin 4: Connects to either 1. Relay which open door or lock or * 2. transistor that opens a solenoid lock when HIGH (see adafruit guide for this option). - * * - * Connect radio according as usual(you can skip IRQ pin) - * http://www.mysensors.org/build/connect_radio + * + * Connect radio according as usual(you can skip IRQ pin) + * http://www.mysensors.org/build/connect_radio */ // Enable debug prints to serial monitor -#define MY_DEBUG +#define MY_DEBUG // Enable and select radio type attached #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include +#include #define CHILD_ID 99 // Id of the sensor child const byte eepromValid = 121; // If the first byte in eeprom is this then the data is valid. - + /*Pin definitions*/ const int programButton = 0; // (Digital 0) Record A New Knock button. const int ledPin = 1; // (Digital 1) The LED pin (if any) -const int knockSensor = 5; // (Digital 5) for using the microphone digital output (tune knob to register knock) -const int audioOut = 2; // (Digital 2) for using the peizo as an output device. (Thing that goes beep.) +const int knockSensor = + 5; // (Digital 5) for using the microphone digital output (tune knob to register knock) +const int audioOut = + 2; // (Digital 2) for using the peizo as an output device. (Thing that goes beep.) const int lockPin = 4; // (Digital 4) The pin that activates the relay/solenoid lock. - + /*Tuning constants. Changing the values below changes the behavior of the device.*/ -int threshold = 3; // Minimum signal from the piezo to register as a knock. Higher = less sensitive. Typical values 1 - 10 -const int rejectValue = 25; // If an individual knock is off by this percentage of a knock we don't unlock. Typical values 10-30 -const int averageRejectValue = 15; // If the average timing of all the knocks is off by this percent we don't unlock. Typical values 5-20 -const int knockFadeTime = 150; // Milliseconds we allow a knock to fade before we listen for another one. (Debounce timer.) -const int lockOperateTime = 2500; // Milliseconds that we operate the lock solenoid latch before releasing it. +int threshold = + 3; // Minimum signal from the piezo to register as a knock. Higher = less sensitive. Typical values 1 - 10 +const int rejectValue = + 25; // If an individual knock is off by this percentage of a knock we don't unlock. Typical values 10-30 +const int averageRejectValue = + 15; // If the average timing of all the knocks is off by this percent we don't unlock. Typical values 5-20 +const int knockFadeTime = + 150; // Milliseconds we allow a knock to fade before we listen for another one. (Debounce timer.) +const int lockOperateTime = + 2500; // Milliseconds that we operate the lock solenoid latch before releasing it. const int maximumKnocks = 20; // Maximum number of knocks to listen for. -const int knockComplete = 1200; // Longest time to wait for a knock before we assume that it's finished. (milliseconds) - +const int knockComplete = + 1200; // Longest time to wait for a knock before we assume that it's finished. (milliseconds) + byte secretCode[maximumKnocks] = {50, 25, 25, 50, 100, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Initial setup: "Shave and a Hair Cut, two bits." int knockReadings[maximumKnocks]; // When someone knocks this array fills with the delays between knocks. int knockSensorValue = 0; // Last reading of the knock sensor. @@ -90,290 +98,311 @@ bool lockStatus; MyMessage lockMsg(CHILD_ID, V_LOCK_STATUS); -void setup() { - - pinMode(ledPin, OUTPUT); - pinMode(knockSensor, INPUT); - pinMode(lockPin, OUTPUT); - pinMode(programButton, INPUT); - digitalWrite(programButton, HIGH); // Enable internal pull up - - readSecretKnock(); // Load the secret knock (if any) from EEPROM. - - digitalWrite(lockPin, HIGH); // Unlock the door for a bit when we power up. For system check and to allow a way in if the key is forgotten - delay(500); // Wait a short time - - lockStatus = loadState(0); // Read last lock status from eeprom - setLockState(lockStatus, true); // Now set the last known state and send it to controller - - delay(500); // This delay is here because the solenoid lock returning to place can otherwise trigger and inadvertent knock. +void setup() +{ + + pinMode(ledPin, OUTPUT); + pinMode(knockSensor, INPUT); + pinMode(lockPin, OUTPUT); + pinMode(programButton, INPUT); + digitalWrite(programButton, HIGH); // Enable internal pull up + + readSecretKnock(); // Load the secret knock (if any) from EEPROM. + + digitalWrite(lockPin, + HIGH); // Unlock the door for a bit when we power up. For system check and to allow a way in if the key is forgotten + delay(500); // Wait a short time + + lockStatus = loadState(0); // Read last lock status from eeprom + setLockState(lockStatus, true); // Now set the last known state and send it to controller + + delay(500); // This delay is here because the solenoid lock returning to place can otherwise trigger and inadvertent knock. +} + +void presentation() +{ + sendSketchInfo("Secret Knock", "1.0"); + present(CHILD_ID, S_LOCK); } -void presentation() { - sendSketchInfo("Secret Knock", "1.0"); - present(CHILD_ID, S_LOCK); +void loop() +{ + // Listen for any knock at all. + knockSensorValue = digitalRead(knockSensor); + if (digitalRead(programButton) == LOW) { // is the program button pressed? + delay(100); // Cheap debounce. + if (digitalRead(programButton) == LOW) { + if (programModeActive == false) { // If we're not in programming mode, turn it on. + programModeActive = true; // Remember we're in programming mode. + digitalWrite(ledPin, HIGH); // Turn on the red light too so the user knows we're programming. + chirp(500, 1500); // And play a tone in case the user can't see the LED. + chirp(500, 1000); + } else { // If we are in programing mode, turn it off. + programModeActive = false; + digitalWrite(ledPin, LOW); + chirp(500, 1000); // Turn off the programming LED and play a sad note. + chirp(500, 1500); + delay(500); + } + while (digitalRead(programButton) == LOW) { + delay(10); // Hang around until the button is released. + } + } + delay(250); // Another cheap debounce. Longer because releasing the button can sometimes be sensed as a knock. + } + + + if (knockSensorValue == 0) { + if (programModeActive == true) { // Blink the LED when we sense a knock. + digitalWrite(ledPin, LOW); + } else { + digitalWrite(ledPin, HIGH); + } + knockDelay(); + if (programModeActive == true) { // Un-blink the LED. + digitalWrite(ledPin, HIGH); + } else { + digitalWrite(ledPin, LOW); + } + listenToSecretKnock(); // We have our first knock. Go and see what other knocks are in store... + } + } - -void loop() { - // Listen for any knock at all. - knockSensorValue = digitalRead(knockSensor); - if (digitalRead(programButton) == LOW){ // is the program button pressed? - delay(100); // Cheap debounce. - if (digitalRead(programButton) == LOW){ - if (programModeActive == false){ // If we're not in programming mode, turn it on. - programModeActive = true; // Remember we're in programming mode. - digitalWrite(ledPin, HIGH); // Turn on the red light too so the user knows we're programming. - chirp(500, 1500); // And play a tone in case the user can't see the LED. - chirp(500, 1000); - } else { // If we are in programing mode, turn it off. - programModeActive = false; - digitalWrite(ledPin, LOW); - chirp(500, 1000); // Turn off the programming LED and play a sad note. - chirp(500, 1500); - delay(500); - } - while (digitalRead(programButton) == LOW){ - delay(10); // Hang around until the button is released. - } - } - delay(250); // Another cheap debounce. Longer because releasing the button can sometimes be sensed as a knock. - } - - - if (knockSensorValue == 0) { - if (programModeActive == true){ // Blink the LED when we sense a knock. - digitalWrite(ledPin, LOW); - } else { - digitalWrite(ledPin, HIGH); - } - knockDelay(); - if (programModeActive == true){ // Un-blink the LED. - digitalWrite(ledPin, HIGH); - } else { - digitalWrite(ledPin, LOW); - } - listenToSecretKnock(); // We have our first knock. Go and see what other knocks are in store... - } - -} - + // Records the timing of knocks. -void listenToSecretKnock(){ - int i = 0; - // First reset the listening array. - for (i=0; i < maximumKnocks; i++){ - knockReadings[i] = 0; - } - - int currentKnockNumber = 0; // Position counter for the array. - int startTime = millis(); // Reference for when this knock started. - int now = millis(); - - do { // Listen for the next knock or wait for it to timeout. - knockSensorValue = digitalRead(knockSensor); - - if (knockSensorValue == 0){ // Here's another knock. Save the time between knocks. - Serial.println("knock"); - - now=millis(); - knockReadings[currentKnockNumber] = now - startTime; - currentKnockNumber ++; - startTime = now; - - if (programModeActive==true){ // Blink the LED when we sense a knock. - digitalWrite(ledPin, LOW); - } else { - digitalWrite(ledPin, HIGH); - } - knockDelay(); - if (programModeActive == true){ // Un-blink the LED. - digitalWrite(ledPin, HIGH); - } else { - digitalWrite(ledPin, LOW); - } - } - - now = millis(); - - // Stop listening if there are too many knocks or there is too much time between knocks. - } while ((now-startTime < knockComplete) && (currentKnockNumber < maximumKnocks)); - Serial.println("end"); - - //we've got our knock recorded, lets see if it's valid - if (programModeActive == false){ // Only do this if we're not recording a new knock. - if (validateKnock() == true){ - // Lock/unlock door - chirp(500, 1500); // And play a tone in case the user can't see the LED. - chirp(500, 1000); - setLockState(!lockStatus, true); - } else { - Serial.println("fail unlock"); - - // knock is invalid. Blink the LED as a warning to others. - for (i=0; i < 4; i++){ - digitalWrite(ledPin, HIGH); - delay(50); - digitalWrite(ledPin, LOW); - delay(50); - } - } - } else { // If we're in programming mode we still validate the lock because it makes some numbers we need, we just don't do anything with the return. - validateKnock(); - } +void listenToSecretKnock() +{ + int i = 0; + // First reset the listening array. + for (i=0; i < maximumKnocks; i++) { + knockReadings[i] = 0; + } + + int currentKnockNumber = 0; // Position counter for the array. + int startTime = millis(); // Reference for when this knock started. + int now = millis(); + + do { // Listen for the next knock or wait for it to timeout. + knockSensorValue = digitalRead(knockSensor); + + if (knockSensorValue == 0) { // Here's another knock. Save the time between knocks. + Serial.println("knock"); + + now=millis(); + knockReadings[currentKnockNumber] = now - startTime; + currentKnockNumber ++; + startTime = now; + + if (programModeActive==true) { // Blink the LED when we sense a knock. + digitalWrite(ledPin, LOW); + } else { + digitalWrite(ledPin, HIGH); + } + knockDelay(); + if (programModeActive == true) { // Un-blink the LED. + digitalWrite(ledPin, HIGH); + } else { + digitalWrite(ledPin, LOW); + } + } + + now = millis(); + + // Stop listening if there are too many knocks or there is too much time between knocks. + } while ((now-startTime < knockComplete) && (currentKnockNumber < maximumKnocks)); + Serial.println("end"); + + //we've got our knock recorded, lets see if it's valid + if (programModeActive == false) { // Only do this if we're not recording a new knock. + if (validateKnock() == true) { + // Lock/unlock door + chirp(500, 1500); // And play a tone in case the user can't see the LED. + chirp(500, 1000); + setLockState(!lockStatus, true); + } else { + Serial.println("fail unlock"); + + // knock is invalid. Blink the LED as a warning to others. + for (i=0; i < 4; i++) { + digitalWrite(ledPin, HIGH); + delay(50); + digitalWrite(ledPin, LOW); + delay(50); + } + } + } else { // If we're in programming mode we still validate the lock because it makes some numbers we need, we just don't do anything with the return. + validateKnock(); + } } - - + + // Unlocks the door. -void setLockState(bool state, bool doSend){ - if (state) - Serial.println("open lock"); - else - Serial.println("close lock"); - if (doSend) - send(lockMsg.set(state)); - - digitalWrite(ledPin, state); - digitalWrite(lockPin, state); - saveState(0,state); - lockStatus = state; - delay(500); // This delay is here because releasing the latch can cause a vibration that will be sensed as a knock. +void setLockState(bool state, bool doSend) +{ + if (state) { + Serial.println("open lock"); + } else { + Serial.println("close lock"); + } + if (doSend) { + send(lockMsg.set(state)); + } + + digitalWrite(ledPin, state); + digitalWrite(lockPin, state); + saveState(0,state); + lockStatus = state; + delay(500); // This delay is here because releasing the latch can cause a vibration that will be sensed as a knock. } - + // Checks to see if our knock matches the secret. // Returns true if it's a good knock, false if it's not. -bool validateKnock(){ - int i = 0; - - int currentKnockCount = 0; - int secretKnockCount = 0; - int maxKnockInterval = 0; // We use this later to normalize the times. - - for (i=0;i 0){ - currentKnockCount++; - } - if (secretCode[i] > 0){ - secretKnockCount++; - } - - if (knockReadings[i] > maxKnockInterval){ // Collect normalization data while we're looping. - maxKnockInterval = knockReadings[i]; - } - } - - // If we're recording a new knock, save the info and get out of here. - if (programModeActive == true){ - for (i=0; i < maximumKnocks; i++){ // Normalize the time between knocks. (the longest time = 100) - secretCode[i] = map(knockReadings[i], 0, maxKnockInterval, 0, 100); - } - saveSecretKnock(); // save the result to EEPROM - programModeActive = false; - playbackKnock(maxKnockInterval); - return false; - } - - if (currentKnockCount != secretKnockCount){ // Easiest check first. If the number of knocks is wrong, don't unlock. - return false; - } - - /* Now we compare the relative intervals of our knocks, not the absolute time between them. - (ie: if you do the same pattern slow or fast it should still open the door.) - This makes it less picky, which while making it less secure can also make it - less of a pain to use if you're tempo is a little slow or fast. - */ - int totaltimeDifferences = 0; - int timeDiff = 0; - for (i=0; i < maximumKnocks; i++){ // Normalize the times - knockReadings[i]= map(knockReadings[i], 0, maxKnockInterval, 0, 100); - timeDiff = abs(knockReadings[i] - secretCode[i]); - if (timeDiff > rejectValue){ // Individual value too far out of whack. No access for this knock! - return false; - } - totaltimeDifferences += timeDiff; - } - // It can also fail if the whole thing is too inaccurate. - if (totaltimeDifferences / secretKnockCount > averageRejectValue){ - return false; - } - - return true; +bool validateKnock() +{ + int i = 0; + + int currentKnockCount = 0; + int secretKnockCount = 0; + int maxKnockInterval = 0; // We use this later to normalize the times. + + for (i=0; i 0) { + currentKnockCount++; + } + if (secretCode[i] > 0) { + secretKnockCount++; + } + + if (knockReadings[i] > maxKnockInterval) { // Collect normalization data while we're looping. + maxKnockInterval = knockReadings[i]; + } + } + + // If we're recording a new knock, save the info and get out of here. + if (programModeActive == true) { + for (i=0; i < maximumKnocks; i++) { // Normalize the time between knocks. (the longest time = 100) + secretCode[i] = map(knockReadings[i], 0, maxKnockInterval, 0, 100); + } + saveSecretKnock(); // save the result to EEPROM + programModeActive = false; + playbackKnock(maxKnockInterval); + return false; + } + + if (currentKnockCount != + secretKnockCount) { // Easiest check first. If the number of knocks is wrong, don't unlock. + return false; + } + + /* Now we compare the relative intervals of our knocks, not the absolute time between them. + (ie: if you do the same pattern slow or fast it should still open the door.) + This makes it less picky, which while making it less secure can also make it + less of a pain to use if you're tempo is a little slow or fast. + */ + int totaltimeDifferences = 0; + int timeDiff = 0; + for (i=0; i < maximumKnocks; i++) { // Normalize the times + knockReadings[i]= map(knockReadings[i], 0, maxKnockInterval, 0, 100); + timeDiff = abs(knockReadings[i] - secretCode[i]); + if (timeDiff > + rejectValue) { // Individual value too far out of whack. No access for this knock! + return false; + } + totaltimeDifferences += timeDiff; + } + // It can also fail if the whole thing is too inaccurate. + if (totaltimeDifferences / secretKnockCount > averageRejectValue) { + return false; + } + + return true; } - - + + // reads the secret knock from EEPROM. (if any.) -void readSecretKnock(){ - byte reading; - reading = loadState(1); - if (reading == eepromValid){ // only read EEPROM if the signature byte is correct. - for (int i=0; i < maximumKnocks ;i++){ - secretCode[i] = loadState(i+2); - } - } +void readSecretKnock() +{ + byte reading; + reading = loadState(1); + if (reading == eepromValid) { // only read EEPROM if the signature byte is correct. + for (int i=0; i < maximumKnocks ; i++) { + secretCode[i] = loadState(i+2); + } + } } - - + + //saves a new pattern too eeprom -void saveSecretKnock(){ - saveState(1, 0); // clear out the signature. That way we know if we didn't finish the write successfully. - for (int i=0; i < maximumKnocks; i++){ - saveState(i+2, secretCode[i]); - } - saveState(1, eepromValid); // all good. Write the signature so we'll know it's all good. +void saveSecretKnock() +{ + saveState(1, + 0); // clear out the signature. That way we know if we didn't finish the write successfully. + for (int i=0; i < maximumKnocks; i++) { + saveState(i+2, secretCode[i]); + } + saveState(1, eepromValid); // all good. Write the signature so we'll know it's all good. } - + // Plays back the pattern of the knock in blinks and beeps -void playbackKnock(int maxKnockInterval){ - digitalWrite(ledPin, LOW); - delay(1000); - digitalWrite(ledPin, HIGH); - chirp(200, 1800); - for (int i = 0; i < maximumKnocks ; i++){ - digitalWrite(ledPin, LOW); - // only turn it on if there's a delay - if (secretCode[i] > 0){ - delay(map(secretCode[i], 0, 100, 0, maxKnockInterval)); // Expand the time back out to what it was. Roughly. - digitalWrite(ledPin, HIGH); - chirp(200, 1800); - } - } - digitalWrite(ledPin, LOW); +void playbackKnock(int maxKnockInterval) +{ + digitalWrite(ledPin, LOW); + delay(1000); + digitalWrite(ledPin, HIGH); + chirp(200, 1800); + for (int i = 0; i < maximumKnocks ; i++) { + digitalWrite(ledPin, LOW); + // only turn it on if there's a delay + if (secretCode[i] > 0) { + delay(map(secretCode[i], 0, 100, 0, + maxKnockInterval)); // Expand the time back out to what it was. Roughly. + digitalWrite(ledPin, HIGH); + chirp(200, 1800); + } + } + digitalWrite(ledPin, LOW); } - + // Deals with the knock delay thingy. -void knockDelay(){ - int itterations = (knockFadeTime / 20); // Wait for the peak to dissipate before listening to next one. - for (int i=0; i < itterations; i++){ - delay(10); - analogRead(knockSensor); // This is done in an attempt to defuse the analog sensor's capacitor that will give false readings on high impedance sensors. - delay(10); - } +void knockDelay() +{ + int itterations = (knockFadeTime / + 20); // Wait for the peak to dissipate before listening to next one. + for (int i=0; i < itterations; i++) { + delay(10); + analogRead( + knockSensor); // This is done in an attempt to defuse the analog sensor's capacitor that will give false readings on high impedance sensors. + delay(10); + } } - + // Plays a non-musical tone on the piezo. // playTime = milliseconds to play the tone // delayTime = time in microseconds between ticks. (smaller=higher pitch tone.) -void chirp(int playTime, int delayTime){ - long loopTime = (playTime * 1000L) / delayTime; - pinMode(audioOut, OUTPUT); - for(int i=0; i < loopTime; i++){ - digitalWrite(audioOut, HIGH); - delayMicroseconds(delayTime); - digitalWrite(audioOut, LOW); - } - pinMode(audioOut, INPUT); +void chirp(int playTime, int delayTime) +{ + long loopTime = (playTime * 1000L) / delayTime; + pinMode(audioOut, OUTPUT); + for(int i=0; i < loopTime; i++) { + digitalWrite(audioOut, HIGH); + delayMicroseconds(delayTime); + digitalWrite(audioOut, LOW); + } + pinMode(audioOut, INPUT); } -void receive(const MyMessage &message) { - // We only expect one type of message from controller. But we better check anyway. - if (message.type==V_LOCK_STATUS) { - // Change relay state - setLockState(message.getBool(), false); - - // Write some debug info - Serial.print("Incoming lock status:"); - Serial.println(message.getBool()); - } +void receive(const MyMessage &message) +{ + // We only expect one type of message from controller. But we better check anyway. + if (message.type==V_LOCK_STATUS) { + // Change relay state + setLockState(message.getBool(), false); + + // Write some debug info + Serial.print("Incoming lock status:"); + Serial.println(message.getBool()); + } } diff --git a/examples/SecureActuator/SecureActuator.ino b/examples/SecureActuator/SecureActuator.ino index b3a67f991..8513c0966 100644 --- a/examples/SecureActuator/SecureActuator.ino +++ b/examples/SecureActuator/SecureActuator.ino @@ -48,7 +48,7 @@ // Enable and select radio type attached #define MY_RADIO_NRF24 //!< NRF24L01 radio driver //#define MY_RADIO_RFM69 //!< RFM69 radio driver - + // Select soft/hardware signing method #define MY_SIGNING_SOFT //!< Software signing //#define MY_SIGNING_ATSHA204 //!< Hardware signing using ATSHA204A @@ -73,29 +73,30 @@ #define LOCK_LOCK 1 //!< GPIO value to write to lock attached lock #define LOCK_UNLOCK 0 //!< GPIO value to write to unlock attached lock -void setup() { - for (int lock=1, pin=LOCK_1; lock<=NOF_LOCKS;lock++, pin++) { - // Set lock pins in output mode - pinMode(pin, OUTPUT); - // Set lock to last known state (using eeprom storage) - digitalWrite(pin, loadState(lock)?LOCK_LOCK:LOCK_UNLOCK); - } +void setup() +{ + for (int lock=1, pin=LOCK_1; lock<=NOF_LOCKS; lock++, pin++) { + // Set lock pins in output mode + pinMode(pin, OUTPUT); + // Set lock to last known state (using eeprom storage) + digitalWrite(pin, loadState(lock)?LOCK_LOCK:LOCK_UNLOCK); + } } -void presentation() +void presentation() { - // Send the sketch version information to the gateway and Controller - sendSketchInfo("Secure Lock", "1.0"); - - // Fetch lock status - for (int lock=1, pin=LOCK_1; lock<=NOF_LOCKS;lock++, pin++) { - // Register all locks to gw (they will be created as child devices) - present(lock, S_LOCK, "SecureActuator", false); - } + // Send the sketch version information to the gateway and Controller + sendSketchInfo("Secure Lock", "1.0"); + + // Fetch lock status + for (int lock=1, pin=LOCK_1; lock<=NOF_LOCKS; lock++, pin++) { + // Register all locks to gw (they will be created as child devices) + present(lock, S_LOCK, "SecureActuator", false); + } } /** @brief Sketch execution code */ -void loop() +void loop() { } @@ -104,19 +105,20 @@ void loop() * * @param message The message to handle. */ -void receive(const MyMessage &message) { - // We only expect one type of message from controller. But we better check anyway. - // And acks are not accepted as control messages - if (message.type==V_LOCK_STATUS && message.sensor<=NOF_LOCKS && !mGetAck(message)) { - // Change relay state - digitalWrite(message.sensor-1+LOCK_1, message.getBool()?LOCK_LOCK:LOCK_UNLOCK); - // Store state in eeprom - saveState(message.sensor, message.getBool()); - // Write some debug info - Serial.print("Incoming change for lock:"); - Serial.print(message.sensor); - Serial.print(", New status: "); - Serial.println(message.getBool()); - } +void receive(const MyMessage &message) +{ + // We only expect one type of message from controller. But we better check anyway. + // And acks are not accepted as control messages + if (message.type==V_LOCK_STATUS && message.sensor<=NOF_LOCKS && !mGetAck(message)) { + // Change relay state + digitalWrite(message.sensor-1+LOCK_1, message.getBool()?LOCK_LOCK:LOCK_UNLOCK); + // Store state in eeprom + saveState(message.sensor, message.getBool()); + // Write some debug info + Serial.print("Incoming change for lock:"); + Serial.print(message.sensor); + Serial.print(", New status: "); + Serial.println(message.getBool()); + } } /** @}*/ \ No newline at end of file diff --git a/examples/SecurityPersonalizer/SecurityPersonalizer.ino b/examples/SecurityPersonalizer/SecurityPersonalizer.ino index 7c7954be2..b03a724db 100644 --- a/examples/SecurityPersonalizer/SecurityPersonalizer.ino +++ b/examples/SecurityPersonalizer/SecurityPersonalizer.ino @@ -225,8 +225,8 @@ atsha204Class sha204(sha204Pin); /** @brief Print a error notice and halt the execution */ void halt() { - Serial.println(F("Halting!")); - while(1); + Serial.println(F("Halting!")); + while(1); } #ifndef USE_SOFT_SIGNING @@ -236,126 +236,104 @@ void halt() */ uint16_t write_config_and_get_crc() { - uint16_t crc = 0; - uint8_t config_word[4]; - uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; - uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; - uint8_t ret_code; - bool do_write; + uint16_t crc = 0; + uint8_t config_word[4]; + uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; + uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; + uint8_t ret_code; + bool do_write; - // We will set default settings from datasheet on all slots. This means that we can use slot 0 for the key - // as that slot will not be readable (key will therefore be secure) and slot 8 for the payload digest - // calculationon as that slot can be written in clear text even when the datazone is locked. - // Other settings which are not relevant are kept as is. + // We will set default settings from datasheet on all slots. This means that we can use slot 0 for the key + // as that slot will not be readable (key will therefore be secure) and slot 8 for the payload digest + // calculationon as that slot can be written in clear text even when the datazone is locked. + // Other settings which are not relevant are kept as is. - for (int i=0; i < 88; i += 4) - { - do_write = true; - if (i == 20) - { - config_word[0] = 0x8F; - config_word[1] = 0x80; - config_word[2] = 0x80; - config_word[3] = 0xA1; - } - else if (i == 24) - { - config_word[0] = 0x82; - config_word[1] = 0xE0; - config_word[2] = 0xA3; - config_word[3] = 0x60; - } - else if (i == 28) - { - config_word[0] = 0x94; - config_word[1] = 0x40; - config_word[2] = 0xA0; - config_word[3] = 0x85; - } - else if (i == 32) - { - config_word[0] = 0x86; - config_word[1] = 0x40; - config_word[2] = 0x87; - config_word[3] = 0x07; - } - else if (i == 36) - { - config_word[0] = 0x0F; - config_word[1] = 0x00; - config_word[2] = 0x89; - config_word[3] = 0xF2; - } - else if (i == 40) - { - config_word[0] = 0x8A; - config_word[1] = 0x7A; - config_word[2] = 0x0B; - config_word[3] = 0x8B; - } - else if (i == 44) - { - config_word[0] = 0x0C; - config_word[1] = 0x4C; - config_word[2] = 0xDD; - config_word[3] = 0x4D; - } - else if (i == 48) - { - config_word[0] = 0xC2; - config_word[1] = 0x42; - config_word[2] = 0xAF; - config_word[3] = 0x8F; - } - else if (i == 52 || i == 56 || i == 60 || i == 64) - { - config_word[0] = 0xFF; - config_word[1] = 0x00; - config_word[2] = 0xFF; - config_word[3] = 0x00; - } - else if (i == 68 || i == 72 || i == 76 || i == 80) - { - config_word[0] = 0xFF; - config_word[1] = 0xFF; - config_word[2] = 0xFF; - config_word[3] = 0xFF; - } - else - { - // All other configs are untouched - ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, i); - if (ret_code != SHA204_SUCCESS) - { - Serial.print(F("Failed to read config. Response: ")); Serial.println(ret_code, HEX); - halt(); - } - // Set config_word to the read data - config_word[0] = rx_buffer[SHA204_BUFFER_POS_DATA+0]; - config_word[1] = rx_buffer[SHA204_BUFFER_POS_DATA+1]; - config_word[2] = rx_buffer[SHA204_BUFFER_POS_DATA+2]; - config_word[3] = rx_buffer[SHA204_BUFFER_POS_DATA+3]; - do_write = false; - } + for (int i=0; i < 88; i += 4) { + do_write = true; + if (i == 20) { + config_word[0] = 0x8F; + config_word[1] = 0x80; + config_word[2] = 0x80; + config_word[3] = 0xA1; + } else if (i == 24) { + config_word[0] = 0x82; + config_word[1] = 0xE0; + config_word[2] = 0xA3; + config_word[3] = 0x60; + } else if (i == 28) { + config_word[0] = 0x94; + config_word[1] = 0x40; + config_word[2] = 0xA0; + config_word[3] = 0x85; + } else if (i == 32) { + config_word[0] = 0x86; + config_word[1] = 0x40; + config_word[2] = 0x87; + config_word[3] = 0x07; + } else if (i == 36) { + config_word[0] = 0x0F; + config_word[1] = 0x00; + config_word[2] = 0x89; + config_word[3] = 0xF2; + } else if (i == 40) { + config_word[0] = 0x8A; + config_word[1] = 0x7A; + config_word[2] = 0x0B; + config_word[3] = 0x8B; + } else if (i == 44) { + config_word[0] = 0x0C; + config_word[1] = 0x4C; + config_word[2] = 0xDD; + config_word[3] = 0x4D; + } else if (i == 48) { + config_word[0] = 0xC2; + config_word[1] = 0x42; + config_word[2] = 0xAF; + config_word[3] = 0x8F; + } else if (i == 52 || i == 56 || i == 60 || i == 64) { + config_word[0] = 0xFF; + config_word[1] = 0x00; + config_word[2] = 0xFF; + config_word[3] = 0x00; + } else if (i == 68 || i == 72 || i == 76 || i == 80) { + config_word[0] = 0xFF; + config_word[1] = 0xFF; + config_word[2] = 0xFF; + config_word[3] = 0xFF; + } else { + // All other configs are untouched + ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, i); + if (ret_code != SHA204_SUCCESS) { + Serial.print(F("Failed to read config. Response: ")); + Serial.println(ret_code, HEX); + halt(); + } + // Set config_word to the read data + config_word[0] = rx_buffer[SHA204_BUFFER_POS_DATA+0]; + config_word[1] = rx_buffer[SHA204_BUFFER_POS_DATA+1]; + config_word[2] = rx_buffer[SHA204_BUFFER_POS_DATA+2]; + config_word[3] = rx_buffer[SHA204_BUFFER_POS_DATA+3]; + do_write = false; + } - // Update crc with CRC for the current word - crc = sha204.calculateAndUpdateCrc(4, config_word, crc); + // Update crc with CRC for the current word + crc = sha204.calculateAndUpdateCrc(4, config_word, crc); - // Write config word - if (do_write) - { - ret_code = sha204.sha204m_execute(SHA204_WRITE, SHA204_ZONE_CONFIG, - i >> 2, 4, config_word, 0, NULL, 0, NULL, - WRITE_COUNT_SHORT, tx_buffer, WRITE_RSP_SIZE, rx_buffer); - if (ret_code != SHA204_SUCCESS) - { - Serial.print(F("Failed to write config word at address ")); Serial.print(i); - Serial.print(F(". Response: ")); Serial.println(ret_code, HEX); - halt(); - } - } - } - return crc; + // Write config word + if (do_write) { + ret_code = sha204.sha204m_execute(SHA204_WRITE, SHA204_ZONE_CONFIG, + i >> 2, 4, config_word, 0, NULL, 0, NULL, + WRITE_COUNT_SHORT, tx_buffer, WRITE_RSP_SIZE, rx_buffer); + if (ret_code != SHA204_SUCCESS) { + Serial.print(F("Failed to write config word at address ")); + Serial.print(i); + Serial.print(F(". Response: ")); + Serial.println(ret_code, HEX); + halt(); + } + } + } + return crc; } /** @@ -364,991 +342,792 @@ uint16_t write_config_and_get_crc() */ void write_key(uint8_t* key) { - uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; - uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; - uint8_t ret_code; + uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; + uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; + uint8_t ret_code; - // Write key to slot 0 - ret_code = sha204.sha204m_execute(SHA204_WRITE, SHA204_ZONE_DATA | SHA204_ZONE_COUNT_FLAG, - 0, SHA204_ZONE_ACCESS_32, key, 0, NULL, 0, NULL, - WRITE_COUNT_LONG, tx_buffer, WRITE_RSP_SIZE, rx_buffer); - if (ret_code != SHA204_SUCCESS) - { - Serial.print(F("Failed to write key to slot 0. Response: ")); Serial.println(ret_code, HEX); - halt(); - } + // Write key to slot 0 + ret_code = sha204.sha204m_execute(SHA204_WRITE, SHA204_ZONE_DATA | SHA204_ZONE_COUNT_FLAG, + 0, SHA204_ZONE_ACCESS_32, key, 0, NULL, 0, NULL, + WRITE_COUNT_LONG, tx_buffer, WRITE_RSP_SIZE, rx_buffer); + if (ret_code != SHA204_SUCCESS) { + Serial.print(F("Failed to write key to slot 0. Response: ")); + Serial.println(ret_code, HEX); + halt(); + } } #endif // not USE_SOFT_SIGNING /** @brief Dump current configuration to UART */ void dump_configuration() { - uint8_t buffer[32]; + uint8_t buffer[32]; #ifndef USE_SOFT_SIGNING - Serial.println(F("EEPROM DATA:")); + Serial.println(F("EEPROM DATA:")); #endif - hwReadConfigBlock((void*)buffer, (void*)EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32); - Serial.print(F("SOFT_HMAC_KEY | ")); - for (int j=0; j<32; j++) - { - if (buffer[j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(buffer[j], HEX); - } - Serial.println(); - hwReadConfigBlock((void*)buffer, (void*)EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9); - Serial.print(F("SOFT_SERIAL | ")); - for (int j=0; j<9; j++) - { - if (buffer[j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(buffer[j], HEX); - } - Serial.println(); - hwReadConfigBlock((void*)buffer, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); - Serial.print(F("AES_KEY | ")); - for (int j=0; j<16; j++) - { - if (buffer[j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(buffer[j], HEX); - } - Serial.println(); + hwReadConfigBlock((void*)buffer, (void*)EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32); + Serial.print(F("SOFT_HMAC_KEY | ")); + for (int j=0; j<32; j++) { + if (buffer[j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(buffer[j], HEX); + } + Serial.println(); + hwReadConfigBlock((void*)buffer, (void*)EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9); + Serial.print(F("SOFT_SERIAL | ")); + for (int j=0; j<9; j++) { + if (buffer[j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(buffer[j], HEX); + } + Serial.println(); + hwReadConfigBlock((void*)buffer, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); + Serial.print(F("AES_KEY | ")); + for (int j=0; j<16; j++) { + if (buffer[j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(buffer[j], HEX); + } + Serial.println(); #ifndef USE_SOFT_SIGNING - uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; - uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; - uint8_t ret_code; - Serial.println(F("ATSHA204A DATA:")); - for (int i=0; i < 88; i += 4) - { - ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, i); - if (ret_code != SHA204_SUCCESS) - { - Serial.print(F("Failed to read config. Response: ")); Serial.println(ret_code, HEX); - halt(); - } - if (i == 0x00) - { - Serial.print(F(" SN[0:1] | SN[2:3] | ")); - for (int j=0; j<4; j++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - if (j == 1) - { - Serial.print(F(" | ")); - } - else - { - Serial.print(F(" ")); - } - } - Serial.println(); - } - else if (i == 0x04) - { - Serial.print(F(" Revnum | ")); - for (int j=0; j<4; j++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - Serial.print(F(" ")); - } - Serial.println(); - } - else if (i == 0x08) - { - Serial.print(F(" SN[4:7] | ")); - for (int j=0; j<4; j++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - Serial.print(F(" ")); - } - Serial.println(); - } - else if (i == 0x0C) - { - Serial.print(F(" SN[8] | Reserved13 | I2CEnable | Reserved15 | ")); - for (int j=0; j<4; j++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - if (j < 3) - { - Serial.print(F(" | ")); - } - else - { - Serial.print(F(" ")); - } - } - Serial.println(); - } - else if (i == 0x10) - { - Serial.print(F(" I2CAddress | TempOffset | OTPmode | SelectorMode | ")); - for (int j=0; j<4; j++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - if (j < 3) - { - Serial.print(F(" | ")); - } - else - { - Serial.print(F(" ")); - } - } - Serial.println(); - } - else if (i == 0x14) - { - Serial.print(F(" SlotConfig00 | SlotConfig01 | ")); - for (int j=0; j<4; j++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - if (j == 1) - { - Serial.print(F(" | ")); - } - else - { - Serial.print(F(" ")); - } - } - Serial.println(); - } - else if (i == 0x18) - { - Serial.print(F(" SlotConfig02 | SlotConfig03 | ")); - for (int j=0; j<4; j++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - if (j == 1) - { - Serial.print(F(" | ")); - } - else - { - Serial.print(F(" ")); - } - } - Serial.println(); - } - else if (i == 0x1C) - { - Serial.print(F(" SlotConfig04 | SlotConfig05 | ")); - for (int j=0; j<4; j++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - if (j == 1) - { - Serial.print(F(" | ")); - } - else - { - Serial.print(F(" ")); - } - } - Serial.println(); - } - else if (i == 0x20) - { - Serial.print(F(" SlotConfig06 | SlotConfig07 | ")); - for (int j=0; j<4; j++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - if (j == 1) - { - Serial.print(F(" | ")); - } - else - { - Serial.print(F(" ")); - } - } - Serial.println(); - } - else if (i == 0x24) - { - Serial.print(F(" SlotConfig08 | SlotConfig09 | ")); - for (int j=0; j<4; j++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - if (j == 1) - { - Serial.print(F(" | ")); - } - else - { - Serial.print(F(" ")); - } - } - Serial.println(); - } - else if (i == 0x28) - { - Serial.print(F(" SlotConfig0A | SlotConfig0B | ")); - for (int j=0; j<4; j++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - if (j == 1) - { - Serial.print(F(" | ")); - } - else - { - Serial.print(F(" ")); - } - } - Serial.println(); - } - else if (i == 0x2C) - { - Serial.print(F(" SlotConfig0C | SlotConfig0D | ")); - for (int j=0; j<4; j++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - if (j == 1) - { - Serial.print(F(" | ")); - } - else - { - Serial.print(F(" ")); - } - } - Serial.println(); - } - else if (i == 0x30) - { - Serial.print(F(" SlotConfig0E | SlotConfig0F | ")); - for (int j=0; j<4; j++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - if (j == 1) - { - Serial.print(F(" | ")); - } - else - { - Serial.print(F(" ")); - } - } - Serial.println(); - } - else if (i == 0x34) - { - Serial.print(F(" UseFlag00 | UpdateCount00 | UseFlag01 | UpdateCount01 | ")); - for (int j=0; j<4; j++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - if (j < 3) - { - Serial.print(F(" | ")); - } - else - { - Serial.print(F(" ")); - } - } - Serial.println(); - } - else if (i == 0x38) - { - Serial.print(F(" UseFlag02 | UpdateCount02 | UseFlag03 | UpdateCount03 | ")); - for (int j=0; j<4; j++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - if (j < 3) - { - Serial.print(F(" | ")); - } - else - { - Serial.print(F(" ")); - } - } - Serial.println(); - } - else if (i == 0x3C) - { - Serial.print(F(" UseFlag04 | UpdateCount04 | UseFlag05 | UpdateCount05 | ")); - for (int j=0; j<4; j++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - if (j < 3) - { - Serial.print(F(" | ")); - } - else - { - Serial.print(F(" ")); - } - } - Serial.println(); - } - else if (i == 0x40) - { - Serial.print(F(" UseFlag06 | UpdateCount06 | UseFlag07 | UpdateCount07 | ")); - for (int j=0; j<4; j++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - if (j < 3) - { - Serial.print(F(" | ")); - } - else - { - Serial.print(F(" ")); - } - } - Serial.println(); - } - else if (i == 0x44) - { - Serial.print(F(" LastKeyUse[0:3] | ")); - for (int j=0; j<4; j++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - Serial.print(F(" ")); - } - Serial.println(); - } - else if (i == 0x48) - { - Serial.print(F(" LastKeyUse[4:7] | ")); - for (int j=0; j<4; j++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - Serial.print(F(" ")); - } - Serial.println(); - } - else if (i == 0x4C) - { - Serial.print(F(" LastKeyUse[8:B] | ")); - for (int j=0; j<4; j++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - Serial.print(F(" ")); - } - Serial.println(); - } - else if (i == 0x50) - { - Serial.print(F(" LastKeyUse[C:F] | ")); - for (int j=0; j<4; j++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - Serial.print(F(" ")); - } - Serial.println(); - } - else if (i == 0x54) - { - Serial.print(F(" UserExtra | Selector | LockValue | LockConfig | ")); - for (int j=0; j<4; j++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); - if (j < 3) - { - Serial.print(F(" | ")); - } - else - { - Serial.print(F(" ")); - } - } - Serial.println(); - } - } + uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; + uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; + uint8_t ret_code; + Serial.println(F("ATSHA204A DATA:")); + for (int i=0; i < 88; i += 4) { + ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, i); + if (ret_code != SHA204_SUCCESS) { + Serial.print(F("Failed to read config. Response: ")); + Serial.println(ret_code, HEX); + halt(); + } + if (i == 0x00) { + Serial.print(F(" SN[0:1] | SN[2:3] | ")); + for (int j=0; j<4; j++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j == 1) { + Serial.print(F(" | ")); + } else { + Serial.print(F(" ")); + } + } + Serial.println(); + } else if (i == 0x04) { + Serial.print(F(" Revnum | ")); + for (int j=0; j<4; j++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + Serial.print(F(" ")); + } + Serial.println(); + } else if (i == 0x08) { + Serial.print(F(" SN[4:7] | ")); + for (int j=0; j<4; j++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + Serial.print(F(" ")); + } + Serial.println(); + } else if (i == 0x0C) { + Serial.print(F(" SN[8] | Reserved13 | I2CEnable | Reserved15 | ")); + for (int j=0; j<4; j++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j < 3) { + Serial.print(F(" | ")); + } else { + Serial.print(F(" ")); + } + } + Serial.println(); + } else if (i == 0x10) { + Serial.print(F(" I2CAddress | TempOffset | OTPmode | SelectorMode | ")); + for (int j=0; j<4; j++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j < 3) { + Serial.print(F(" | ")); + } else { + Serial.print(F(" ")); + } + } + Serial.println(); + } else if (i == 0x14) { + Serial.print(F(" SlotConfig00 | SlotConfig01 | ")); + for (int j=0; j<4; j++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j == 1) { + Serial.print(F(" | ")); + } else { + Serial.print(F(" ")); + } + } + Serial.println(); + } else if (i == 0x18) { + Serial.print(F(" SlotConfig02 | SlotConfig03 | ")); + for (int j=0; j<4; j++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j == 1) { + Serial.print(F(" | ")); + } else { + Serial.print(F(" ")); + } + } + Serial.println(); + } else if (i == 0x1C) { + Serial.print(F(" SlotConfig04 | SlotConfig05 | ")); + for (int j=0; j<4; j++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j == 1) { + Serial.print(F(" | ")); + } else { + Serial.print(F(" ")); + } + } + Serial.println(); + } else if (i == 0x20) { + Serial.print(F(" SlotConfig06 | SlotConfig07 | ")); + for (int j=0; j<4; j++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j == 1) { + Serial.print(F(" | ")); + } else { + Serial.print(F(" ")); + } + } + Serial.println(); + } else if (i == 0x24) { + Serial.print(F(" SlotConfig08 | SlotConfig09 | ")); + for (int j=0; j<4; j++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j == 1) { + Serial.print(F(" | ")); + } else { + Serial.print(F(" ")); + } + } + Serial.println(); + } else if (i == 0x28) { + Serial.print(F(" SlotConfig0A | SlotConfig0B | ")); + for (int j=0; j<4; j++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j == 1) { + Serial.print(F(" | ")); + } else { + Serial.print(F(" ")); + } + } + Serial.println(); + } else if (i == 0x2C) { + Serial.print(F(" SlotConfig0C | SlotConfig0D | ")); + for (int j=0; j<4; j++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j == 1) { + Serial.print(F(" | ")); + } else { + Serial.print(F(" ")); + } + } + Serial.println(); + } else if (i == 0x30) { + Serial.print(F(" SlotConfig0E | SlotConfig0F | ")); + for (int j=0; j<4; j++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j == 1) { + Serial.print(F(" | ")); + } else { + Serial.print(F(" ")); + } + } + Serial.println(); + } else if (i == 0x34) { + Serial.print(F(" UseFlag00 | UpdateCount00 | UseFlag01 | UpdateCount01 | ")); + for (int j=0; j<4; j++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j < 3) { + Serial.print(F(" | ")); + } else { + Serial.print(F(" ")); + } + } + Serial.println(); + } else if (i == 0x38) { + Serial.print(F(" UseFlag02 | UpdateCount02 | UseFlag03 | UpdateCount03 | ")); + for (int j=0; j<4; j++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j < 3) { + Serial.print(F(" | ")); + } else { + Serial.print(F(" ")); + } + } + Serial.println(); + } else if (i == 0x3C) { + Serial.print(F(" UseFlag04 | UpdateCount04 | UseFlag05 | UpdateCount05 | ")); + for (int j=0; j<4; j++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j < 3) { + Serial.print(F(" | ")); + } else { + Serial.print(F(" ")); + } + } + Serial.println(); + } else if (i == 0x40) { + Serial.print(F(" UseFlag06 | UpdateCount06 | UseFlag07 | UpdateCount07 | ")); + for (int j=0; j<4; j++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j < 3) { + Serial.print(F(" | ")); + } else { + Serial.print(F(" ")); + } + } + Serial.println(); + } else if (i == 0x44) { + Serial.print(F(" LastKeyUse[0:3] | ")); + for (int j=0; j<4; j++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + Serial.print(F(" ")); + } + Serial.println(); + } else if (i == 0x48) { + Serial.print(F(" LastKeyUse[4:7] | ")); + for (int j=0; j<4; j++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + Serial.print(F(" ")); + } + Serial.println(); + } else if (i == 0x4C) { + Serial.print(F(" LastKeyUse[8:B] | ")); + for (int j=0; j<4; j++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + Serial.print(F(" ")); + } + Serial.println(); + } else if (i == 0x50) { + Serial.print(F(" LastKeyUse[C:F] | ")); + for (int j=0; j<4; j++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + Serial.print(F(" ")); + } + Serial.println(); + } else if (i == 0x54) { + Serial.print(F(" UserExtra | Selector | LockValue | LockConfig | ")); + for (int j=0; j<4; j++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+j] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+j], HEX); + if (j < 3) { + Serial.print(F(" | ")); + } else { + Serial.print(F(" ")); + } + } + Serial.println(); + } + } #endif // not USE_SOFT_SIGNING } /** @brief Sketch setup code */ void setup() { - // Delay startup a bit for serial consoles to catch up - unsigned long enter = hwMillis(); - while (hwMillis() - enter < (unsigned long)500); + // Delay startup a bit for serial consoles to catch up + unsigned long enter = hwMillis(); + while (hwMillis() - enter < (unsigned long)500); #ifndef USE_SOFT_SIGNING - uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; - uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; - uint8_t ret_code; - uint8_t lockConfig = 0; - uint8_t lockValue = 0; - uint16_t crc; - (void)crc; + uint8_t tx_buffer[SHA204_CMD_SIZE_MAX]; + uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; + uint8_t ret_code; + uint8_t lockConfig = 0; + uint8_t lockValue = 0; + uint16_t crc; + (void)crc; #else - // initialize pseudo-RNG - randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)); + // initialize pseudo-RNG + randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)); #endif - uint8_t key[32]; - (void)key; + uint8_t key[32]; + (void)key; - Serial.begin(115200); - hwInit(); - Serial.println(F("Personalization sketch for MySensors usage.")); - Serial.println(F("-------------------------------------------")); + Serial.begin(115200); + hwInit(); + Serial.println(F("Personalization sketch for MySensors usage.")); + Serial.println(F("-------------------------------------------")); #ifndef USE_SOFT_SIGNING - // Wake device before starting operations - ret_code = sha204.sha204c_wakeup(rx_buffer); - if (ret_code != SHA204_SUCCESS) - { - Serial.print(F("Failed to wake device. Response: ")); Serial.println(ret_code, HEX); - halt(); - } - // Read out lock config bits to determine if locking is possible - ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, 0x15<<2); - if (ret_code != SHA204_SUCCESS) - { - Serial.print(F("Failed to determine device lock status. Response: ")); Serial.println(ret_code, HEX); - halt(); - } - else - { - lockConfig = rx_buffer[SHA204_BUFFER_POS_DATA+3]; - lockValue = rx_buffer[SHA204_BUFFER_POS_DATA+2]; - } + // Wake device before starting operations + ret_code = sha204.sha204c_wakeup(rx_buffer); + if (ret_code != SHA204_SUCCESS) { + Serial.print(F("Failed to wake device. Response: ")); + Serial.println(ret_code, HEX); + halt(); + } + // Read out lock config bits to determine if locking is possible + ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, 0x15<<2); + if (ret_code != SHA204_SUCCESS) { + Serial.print(F("Failed to determine device lock status. Response: ")); + Serial.println(ret_code, HEX); + halt(); + } else { + lockConfig = rx_buffer[SHA204_BUFFER_POS_DATA+3]; + lockValue = rx_buffer[SHA204_BUFFER_POS_DATA+2]; + } #endif #ifdef STORE_SOFT_KEY #ifdef USER_SOFT_KEY - memcpy(key, user_soft_key_data, 32); - Serial.println(F("Using this user supplied soft HMAC key:")); + memcpy(key, user_soft_key_data, 32); + Serial.println(F("Using this user supplied soft HMAC key:")); #else - // Retrieve random value to use as soft HMAC key + // Retrieve random value to use as soft HMAC key #ifdef USE_SOFT_SIGNING - for (int i = 0; i < 32; i++) { - key[i] = random(256) ^ micros(); - unsigned long enter = hwMillis(); - while (hwMillis() - enter < (unsigned long)2); - } - Serial.println(F("This value will be stored in EEPROM as soft HMAC key:")); + for (int i = 0; i < 32; i++) { + key[i] = random(256) ^ micros(); + unsigned long enter = hwMillis(); + while (hwMillis() - enter < (unsigned long)2); + } + Serial.println(F("This value will be stored in EEPROM as soft HMAC key:")); #else - ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE); - if (ret_code != SHA204_SUCCESS) - { - Serial.print(F("Random key generation failed. Response: ")); Serial.println(ret_code, HEX); - halt(); - } - else - { - memcpy(key, rx_buffer+SHA204_BUFFER_POS_DATA, 32); - } - if (lockConfig == 0x00) - { - Serial.println(F("This value will be stored in EEPROM as soft HMAC key:")); - } - else - { - Serial.println(F("Key is not randomized (configuration not locked):")); - } + ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE); + if (ret_code != SHA204_SUCCESS) { + Serial.print(F("Random key generation failed. Response: ")); + Serial.println(ret_code, HEX); + halt(); + } else { + memcpy(key, rx_buffer+SHA204_BUFFER_POS_DATA, 32); + } + if (lockConfig == 0x00) { + Serial.println(F("This value will be stored in EEPROM as soft HMAC key:")); + } else { + Serial.println(F("Key is not randomized (configuration not locked):")); + } #endif // not USE_SOFT_SIGNING #endif // not USER_SOFT_KEY - Serial.print("#define MY_SOFT_HMAC_KEY "); - for (int i=0; i<32; i++) - { - Serial.print("0x"); - if (key[i] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(key[i], HEX); - if (i < 31) Serial.print(','); - } - Serial.println(); - hwWriteConfigBlock((void*)key, (void*)EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32); + Serial.print("#define MY_SOFT_HMAC_KEY "); + for (int i=0; i<32; i++) { + Serial.print("0x"); + if (key[i] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(key[i], HEX); + if (i < 31) { + Serial.print(','); + } + } + Serial.println(); + hwWriteConfigBlock((void*)key, (void*)EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32); #endif // STORE_SOFT_KEY #ifdef STORE_SOFT_SERIAL #ifdef USER_SOFT_SERIAL - memcpy(key, user_soft_serial, 9); - Serial.println(F("Using this user supplied soft serial:")); + memcpy(key, user_soft_serial, 9); + Serial.println(F("Using this user supplied soft serial:")); #else - // Retrieve random value to use as serial + // Retrieve random value to use as serial #ifdef USE_SOFT_SIGNING - for (int i = 0; i < 9; i++) { - key[i] = random(256) ^ micros(); - unsigned long enter = hwMillis(); - while (hwMillis() - enter < (unsigned long)2); - } - Serial.println(F("This value will be stored in EEPROM as soft serial:")); + for (int i = 0; i < 9; i++) { + key[i] = random(256) ^ micros(); + unsigned long enter = hwMillis(); + while (hwMillis() - enter < (unsigned long)2); + } + Serial.println(F("This value will be stored in EEPROM as soft serial:")); #else - ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE); - if (ret_code != SHA204_SUCCESS) - { - Serial.print(F("Random serial generation failed. Response: ")); Serial.println(ret_code, HEX); - halt(); - } - else - { - memcpy(key, rx_buffer+SHA204_BUFFER_POS_DATA, 9); - } - if (lockConfig == 0x00) - { - Serial.println(F("This value will be stored in EEPROM as soft serial:")); - } - else - { - Serial.println(F("Serial is not randomized (configuration not locked):")); - } + ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE); + if (ret_code != SHA204_SUCCESS) { + Serial.print(F("Random serial generation failed. Response: ")); + Serial.println(ret_code, HEX); + halt(); + } else { + memcpy(key, rx_buffer+SHA204_BUFFER_POS_DATA, 9); + } + if (lockConfig == 0x00) { + Serial.println(F("This value will be stored in EEPROM as soft serial:")); + } else { + Serial.println(F("Serial is not randomized (configuration not locked):")); + } #endif // not USE_SOFT_SIGNING #endif // not USER_SOFT_SERIAL - Serial.print("#define MY_SOFT_SERIAL "); - for (int i=0; i<9; i++) - { - Serial.print("0x"); - if (key[i] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(key[i], HEX); - if (i < 8) Serial.print(','); - } - Serial.println(); - hwWriteConfigBlock((void*)key, (void*)EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9); + Serial.print("#define MY_SOFT_SERIAL "); + for (int i=0; i<9; i++) { + Serial.print("0x"); + if (key[i] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(key[i], HEX); + if (i < 8) { + Serial.print(','); + } + } + Serial.println(); + hwWriteConfigBlock((void*)key, (void*)EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9); #endif // STORE_SOFT_SERIAL #ifdef STORE_AES_KEY #ifdef USER_AES_KEY - memcpy(key, user_aes_key, 16); - Serial.println(F("Using this user supplied AES key:")); + memcpy(key, user_aes_key, 16); + Serial.println(F("Using this user supplied AES key:")); #else - // Retrieve random value to use as key + // Retrieve random value to use as key #ifdef USE_SOFT_SIGNING - for (int i = 0; i < 16; i++) { - key[i] = random(256) ^ micros(); - unsigned long enter = hwMillis(); - while (hwMillis() - enter < (unsigned long)2); - } - Serial.println(F("This key will be stored in EEPROM as AES key:")); + for (int i = 0; i < 16; i++) { + key[i] = random(256) ^ micros(); + unsigned long enter = hwMillis(); + while (hwMillis() - enter < (unsigned long)2); + } + Serial.println(F("This key will be stored in EEPROM as AES key:")); #else - ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE); - if (ret_code != SHA204_SUCCESS) - { - Serial.print(F("Random key generation failed. Response: ")); Serial.println(ret_code, HEX); - halt(); - } - else - { - memcpy(key, rx_buffer+SHA204_BUFFER_POS_DATA, 32); - } - if (lockConfig == 0x00) - { - Serial.println(F("This key will be stored in EEPROM as AES key:")); - } - else - { - Serial.println(F("Key is not randomized (configuration not locked):")); - } + ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE); + if (ret_code != SHA204_SUCCESS) { + Serial.print(F("Random key generation failed. Response: ")); + Serial.println(ret_code, HEX); + halt(); + } else { + memcpy(key, rx_buffer+SHA204_BUFFER_POS_DATA, 32); + } + if (lockConfig == 0x00) { + Serial.println(F("This key will be stored in EEPROM as AES key:")); + } else { + Serial.println(F("Key is not randomized (configuration not locked):")); + } #endif // not USE_SOFT_SIGNING #endif // not USER_AES_KEY - Serial.print("#define MY_AES_KEY "); - for (int i=0; i<16; i++) - { - Serial.print("0x"); - if (key[i] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(key[i], HEX); - if (i < 15) Serial.print(','); - } - Serial.println(); - hwWriteConfigBlock((void*)key, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); + Serial.print("#define MY_AES_KEY "); + for (int i=0; i<16; i++) { + Serial.print("0x"); + if (key[i] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(key[i], HEX); + if (i < 15) { + Serial.print(','); + } + } + Serial.println(); + hwWriteConfigBlock((void*)key, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); #endif // STORE_AES_KEY #ifdef USE_SOFT_SIGNING - Serial.println(F("EEPROM configuration:")); - dump_configuration(); + Serial.println(F("EEPROM configuration:")); + dump_configuration(); #else - // Output device revision on console - ret_code = sha204.sha204m_dev_rev(tx_buffer, rx_buffer); - if (ret_code != SHA204_SUCCESS) - { - Serial.print(F("Failed to determine device revision. Response: ")); Serial.println(ret_code, HEX); - halt(); - } - else - { - Serial.print(F("Device revision: ")); - for (int i=0; i<4; i++) - { - if (rx_buffer[SHA204_BUFFER_POS_DATA+i] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+i], HEX); - } - Serial.println(); - } + // Output device revision on console + ret_code = sha204.sha204m_dev_rev(tx_buffer, rx_buffer); + if (ret_code != SHA204_SUCCESS) { + Serial.print(F("Failed to determine device revision. Response: ")); + Serial.println(ret_code, HEX); + halt(); + } else { + Serial.print(F("Device revision: ")); + for (int i=0; i<4; i++) { + if (rx_buffer[SHA204_BUFFER_POS_DATA+i] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[SHA204_BUFFER_POS_DATA+i], HEX); + } + Serial.println(); + } - // Output serial number on console - ret_code = sha204.getSerialNumber(rx_buffer); - if (ret_code != SHA204_SUCCESS) - { - Serial.print(F("Failed to obtain device serial number. Response: ")); Serial.println(ret_code, HEX); - halt(); - } - else - { - Serial.print(F("Device serial: ")); - Serial.print('{'); - for (int i=0; i<9; i++) - { - Serial.print(F("0x")); - if (rx_buffer[i] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[i], HEX); - if (i < 8) Serial.print(','); - } - Serial.print('}'); - Serial.println(); - for (int i=0; i<9; i++) - { - if (rx_buffer[i] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[i], HEX); - } - Serial.println(); - } + // Output serial number on console + ret_code = sha204.getSerialNumber(rx_buffer); + if (ret_code != SHA204_SUCCESS) { + Serial.print(F("Failed to obtain device serial number. Response: ")); + Serial.println(ret_code, HEX); + halt(); + } else { + Serial.print(F("Device serial: ")); + Serial.print('{'); + for (int i=0; i<9; i++) { + Serial.print(F("0x")); + if (rx_buffer[i] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[i], HEX); + if (i < 8) { + Serial.print(','); + } + } + Serial.print('}'); + Serial.println(); + for (int i=0; i<9; i++) { + if (rx_buffer[i] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[i], HEX); + } + Serial.println(); + } - if (lockConfig != 0x00) - { - // Write config and get CRC for the updated config - crc = write_config_and_get_crc(); + if (lockConfig != 0x00) { + // Write config and get CRC for the updated config + crc = write_config_and_get_crc(); - // List current configuration before attempting to lock - Serial.println(F("Chip configuration:")); - dump_configuration(); + // List current configuration before attempting to lock + Serial.println(F("Chip configuration:")); + dump_configuration(); #ifdef LOCK_CONFIGURATION - // Purge serial input buffer + // Purge serial input buffer #ifndef SKIP_UART_CONFIRMATION - while (Serial.available()) - { - Serial.read(); - } - Serial.println(F("Send SPACE character now to lock the configuration...")); + while (Serial.available()) { + Serial.read(); + } + Serial.println(F("Send SPACE character now to lock the configuration...")); - while (Serial.available() == 0); - if (Serial.read() == ' ') + while (Serial.available() == 0); + if (Serial.read() == ' ') #endif //not SKIP_UART_CONFIRMATION - { - Serial.println(F("Locking configuration...")); + { + Serial.println(F("Locking configuration...")); - // Correct sequence, resync chip - ret_code = sha204.sha204c_resync(SHA204_RSP_SIZE_MAX, rx_buffer); - if (ret_code != SHA204_SUCCESS && ret_code != SHA204_RESYNC_WITH_WAKEUP) - { - Serial.print(F("Resync failed. Response: ")); Serial.println(ret_code, HEX); - halt(); - } + // Correct sequence, resync chip + ret_code = sha204.sha204c_resync(SHA204_RSP_SIZE_MAX, rx_buffer); + if (ret_code != SHA204_SUCCESS && ret_code != SHA204_RESYNC_WITH_WAKEUP) { + Serial.print(F("Resync failed. Response: ")); + Serial.println(ret_code, HEX); + halt(); + } - // Lock configuration zone - ret_code = sha204.sha204m_execute(SHA204_LOCK, SHA204_ZONE_CONFIG, - crc, 0, NULL, 0, NULL, 0, NULL, - LOCK_COUNT, tx_buffer, LOCK_RSP_SIZE, rx_buffer); - if (ret_code != SHA204_SUCCESS) - { - Serial.print(F("Configuration lock failed. Response: ")); Serial.println(ret_code, HEX); - halt(); - } - else - { - Serial.println(F("Configuration locked.")); + // Lock configuration zone + ret_code = sha204.sha204m_execute(SHA204_LOCK, SHA204_ZONE_CONFIG, + crc, 0, NULL, 0, NULL, 0, NULL, + LOCK_COUNT, tx_buffer, LOCK_RSP_SIZE, rx_buffer); + if (ret_code != SHA204_SUCCESS) { + Serial.print(F("Configuration lock failed. Response: ")); + Serial.println(ret_code, HEX); + halt(); + } else { + Serial.println(F("Configuration locked.")); - // Update lock flags after locking - ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, 0x15<<2); - if (ret_code != SHA204_SUCCESS) - { - Serial.print(F("Failed to determine device lock status. Response: ")); Serial.println(ret_code, HEX); - halt(); - } - else - { - lockConfig = rx_buffer[SHA204_BUFFER_POS_DATA+3]; - lockValue = rx_buffer[SHA204_BUFFER_POS_DATA+2]; - } - } - } + // Update lock flags after locking + ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, 0x15<<2); + if (ret_code != SHA204_SUCCESS) { + Serial.print(F("Failed to determine device lock status. Response: ")); + Serial.println(ret_code, HEX); + halt(); + } else { + lockConfig = rx_buffer[SHA204_BUFFER_POS_DATA+3]; + lockValue = rx_buffer[SHA204_BUFFER_POS_DATA+2]; + } + } + } #ifndef SKIP_UART_CONFIRMATION - else - { - Serial.println(F("Unexpected answer. Skipping lock.")); - } + else { + Serial.println(F("Unexpected answer. Skipping lock.")); + } #endif //not SKIP_UART_CONFIRMATION #else //LOCK_CONFIGURATION - Serial.println(F("Configuration not locked. Define LOCK_CONFIGURATION to lock for real.")); + Serial.println(F("Configuration not locked. Define LOCK_CONFIGURATION to lock for real.")); #endif - } - else - { - Serial.println(F("Skipping configuration write and lock (configuration already locked).")); - Serial.println(F("Chip configuration:")); - dump_configuration(); - } + } else { + Serial.println(F("Skipping configuration write and lock (configuration already locked).")); + Serial.println(F("Chip configuration:")); + dump_configuration(); + } #ifdef SKIP_KEY_STORAGE - Serial.println(F("Disable SKIP_KEY_STORAGE to store key.")); + Serial.println(F("Disable SKIP_KEY_STORAGE to store key.")); #else #ifdef USER_KEY - memcpy(key, user_key_data, 32); - Serial.println(F("Using this user supplied HMAC key:")); + memcpy(key, user_key_data, 32); + Serial.println(F("Using this user supplied HMAC key:")); #else - // Retrieve random value to use as key - ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE); - if (ret_code != SHA204_SUCCESS) - { - Serial.print(F("Random key generation failed. Response: ")); Serial.println(ret_code, HEX); - halt(); - } - else - { - memcpy(key, rx_buffer+SHA204_BUFFER_POS_DATA, 32); - } - if (lockConfig == 0x00) - { - Serial.println(F("Take note of this key, it will never be the shown again:")); - } - else - { - Serial.println(F("Key is not randomized (configuration not locked):")); - } + // Retrieve random value to use as key + ret_code = sha204.sha204m_random(tx_buffer, rx_buffer, RANDOM_SEED_UPDATE); + if (ret_code != SHA204_SUCCESS) { + Serial.print(F("Random key generation failed. Response: ")); + Serial.println(ret_code, HEX); + halt(); + } else { + memcpy(key, rx_buffer+SHA204_BUFFER_POS_DATA, 32); + } + if (lockConfig == 0x00) { + Serial.println(F("Take note of this key, it will never be the shown again:")); + } else { + Serial.println(F("Key is not randomized (configuration not locked):")); + } #endif - Serial.print("#define MY_HMAC_KEY "); - for (int i=0; i<32; i++) - { - Serial.print("0x"); - if (key[i] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(key[i], HEX); - if (i < 31) Serial.print(','); - if (i+1 == 16) Serial.print("\\\n "); - } - Serial.println(); + Serial.print("#define MY_HMAC_KEY "); + for (int i=0; i<32; i++) { + Serial.print("0x"); + if (key[i] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(key[i], HEX); + if (i < 31) { + Serial.print(','); + } + if (i+1 == 16) { + Serial.print("\\\n "); + } + } + Serial.println(); - // It will not be possible to write the key if the configuration zone is unlocked - if (lockConfig == 0x00) - { - // Write the key to the appropriate slot in the data zone - Serial.println(F("Writing key to slot 0...")); - write_key(key); - } - else - { - Serial.println(F("Skipping key storage (configuration not locked).")); - Serial.println(F("The configuration must be locked to be able to write a key.")); - } + // It will not be possible to write the key if the configuration zone is unlocked + if (lockConfig == 0x00) { + // Write the key to the appropriate slot in the data zone + Serial.println(F("Writing key to slot 0...")); + write_key(key); + } else { + Serial.println(F("Skipping key storage (configuration not locked).")); + Serial.println(F("The configuration must be locked to be able to write a key.")); + } #endif - if (lockValue != 0x00) - { + if (lockValue != 0x00) { #ifdef LOCK_DATA #ifndef SKIP_UART_CONFIRMATION - while (Serial.available()) - { - Serial.read(); - } - Serial.println(F("Send SPACE character to lock data...")); - while (Serial.available() == 0); - if (Serial.read() == ' ') + while (Serial.available()) { + Serial.read(); + } + Serial.println(F("Send SPACE character to lock data...")); + while (Serial.available() == 0); + if (Serial.read() == ' ') #endif //not SKIP_UART_CONFIRMATION - { - // Correct sequence, resync chip - ret_code = sha204.sha204c_resync(SHA204_RSP_SIZE_MAX, rx_buffer); - if (ret_code != SHA204_SUCCESS && ret_code != SHA204_RESYNC_WITH_WAKEUP) - { - Serial.print(F("Resync failed. Response: ")); Serial.println(ret_code, HEX); - halt(); - } + { + // Correct sequence, resync chip + ret_code = sha204.sha204c_resync(SHA204_RSP_SIZE_MAX, rx_buffer); + if (ret_code != SHA204_SUCCESS && ret_code != SHA204_RESYNC_WITH_WAKEUP) { + Serial.print(F("Resync failed. Response: ")); + Serial.println(ret_code, HEX); + halt(); + } - // If configuration is unlocked, key is not updated. Locking data in this case will cause - // slot 0 to contain an unknown (or factory default) key, and this is in practically any - // usecase not the desired behaviour, so ask for additional confirmation in this case. - if (lockConfig != 0x00) - { - while (Serial.available()) - { - Serial.read(); - } - Serial.println(F("*** ATTENTION ***")); - Serial.println(F("Configuration is not locked. Are you ABSULOUTELY SURE you want to lock data?")); - Serial.println(F("Locking data at this stage will cause slot 0 to contain a factory default key")); - Serial.println(F("which cannot be change after locking is done. This is in practically any usecase")); - Serial.println(F("NOT the desired behavour. Send SPACE character now to lock data anyway...")); - while (Serial.available() == 0); - if (Serial.read() != ' ') - { - Serial.println(F("Unexpected answer. Skipping lock.")); - halt(); - } - } + // If configuration is unlocked, key is not updated. Locking data in this case will cause + // slot 0 to contain an unknown (or factory default) key, and this is in practically any + // usecase not the desired behaviour, so ask for additional confirmation in this case. + if (lockConfig != 0x00) { + while (Serial.available()) { + Serial.read(); + } + Serial.println(F("*** ATTENTION ***")); + Serial.println(F("Configuration is not locked. Are you ABSULOUTELY SURE you want to lock data?")); + Serial.println(F("Locking data at this stage will cause slot 0 to contain a factory default key")); + Serial.println( + F("which cannot be change after locking is done. This is in practically any usecase")); + Serial.println(F("NOT the desired behavour. Send SPACE character now to lock data anyway...")); + while (Serial.available() == 0); + if (Serial.read() != ' ') { + Serial.println(F("Unexpected answer. Skipping lock.")); + halt(); + } + } - // Lock data zone - ret_code = sha204.sha204m_execute(SHA204_LOCK, SHA204_ZONE_DATA | LOCK_ZONE_NO_CRC, - 0x0000, 0, NULL, 0, NULL, 0, NULL, - LOCK_COUNT, tx_buffer, LOCK_RSP_SIZE, rx_buffer); - if (ret_code != SHA204_SUCCESS) - { - Serial.print(F("Data lock failed. Response: ")); Serial.println(ret_code, HEX); - halt(); - } - else - { - Serial.println(F("Data locked.")); + // Lock data zone + ret_code = sha204.sha204m_execute(SHA204_LOCK, SHA204_ZONE_DATA | LOCK_ZONE_NO_CRC, + 0x0000, 0, NULL, 0, NULL, 0, NULL, + LOCK_COUNT, tx_buffer, LOCK_RSP_SIZE, rx_buffer); + if (ret_code != SHA204_SUCCESS) { + Serial.print(F("Data lock failed. Response: ")); + Serial.println(ret_code, HEX); + halt(); + } else { + Serial.println(F("Data locked.")); - // Update lock flags after locking - ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, 0x15<<2); - if (ret_code != SHA204_SUCCESS) - { - Serial.print(F("Failed to determine device lock status. Response: ")); Serial.println(ret_code, HEX); - halt(); - } - else - { - lockConfig = rx_buffer[SHA204_BUFFER_POS_DATA+3]; - lockValue = rx_buffer[SHA204_BUFFER_POS_DATA+2]; - } - } - } + // Update lock flags after locking + ret_code = sha204.sha204m_read(tx_buffer, rx_buffer, SHA204_ZONE_CONFIG, 0x15<<2); + if (ret_code != SHA204_SUCCESS) { + Serial.print(F("Failed to determine device lock status. Response: ")); + Serial.println(ret_code, HEX); + halt(); + } else { + lockConfig = rx_buffer[SHA204_BUFFER_POS_DATA+3]; + lockValue = rx_buffer[SHA204_BUFFER_POS_DATA+2]; + } + } + } #ifndef SKIP_UART_CONFIRMATION - else - { - Serial.println(F("Unexpected answer. Skipping lock.")); - } + else { + Serial.println(F("Unexpected answer. Skipping lock.")); + } #endif //not SKIP_UART_CONFIRMATION #else //LOCK_DATA - Serial.println(F("Data not locked. Define LOCK_DATA to lock for real.")); + Serial.println(F("Data not locked. Define LOCK_DATA to lock for real.")); #endif - } - else - { - Serial.println(F("Skipping OTP/data zone lock (zone already locked).")); - } + } else { + Serial.println(F("Skipping OTP/data zone lock (zone already locked).")); + } #endif // not USE_SOFT_SIGNING - Serial.println(F("--------------------------------")); - Serial.println(F("Personalization is now complete.")); + Serial.println(F("--------------------------------")); + Serial.println(F("Personalization is now complete.")); #ifndef USE_SOFT_SIGNING - Serial.print(F("Configuration is ")); - if (lockConfig == 0x00) - { - Serial.println("LOCKED"); - } - else - { - Serial.println("UNLOCKED"); - } - Serial.print(F("Data is ")); - if (lockValue == 0x00) - { - Serial.println("LOCKED"); - } - else - { - Serial.println("UNLOCKED"); - } + Serial.print(F("Configuration is ")); + if (lockConfig == 0x00) { + Serial.println("LOCKED"); + } else { + Serial.println("UNLOCKED"); + } + Serial.print(F("Data is ")); + if (lockValue == 0x00) { + Serial.println("LOCKED"); + } else { + Serial.println("UNLOCKED"); + } #endif } diff --git a/examples/SecurityPersonalizer/sha204_library.cpp b/examples/SecurityPersonalizer/sha204_library.cpp index a747c4d15..a384fdabb 100644 --- a/examples/SecurityPersonalizer/sha204_library.cpp +++ b/examples/SecurityPersonalizer/sha204_library.cpp @@ -10,11 +10,11 @@ // For others it will only store the pin number which is used in subsequent functions atsha204Class::atsha204Class(uint8_t pin) -{ +{ #if defined(ARDUINO_ARCH_AVR) device_pin = digitalPinToBitMask(pin); // Find the bit value of the pin uint8_t port = digitalPinToPort(pin); // temoporarily used to get the next three registers - + // Point to data direction register port of pin device_port_DDR = portModeRegister(port); // Point to output register of pin @@ -26,472 +26,476 @@ atsha204Class::atsha204Class(uint8_t pin) #endif } -/* Puts a the ATSHA204's unique, 4-byte serial number in the response array +/* Puts a the ATSHA204's unique, 4-byte serial number in the response array returns an SHA204 Return code */ uint8_t atsha204Class::getSerialNumber(uint8_t * response) { uint8_t readCommand[READ_COUNT]; uint8_t readResponse[READ_4_RSP_SIZE]; - + /* read from bytes 0->3 of config zone */ uint8_t returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN03); - if (!returnCode) // should return 0 if successful - { - for (int i=0; i<4; i++) // store bytes 0-3 into respones array + if (!returnCode) { // should return 0 if successful + for (int i=0; i<4; i++) { // store bytes 0-3 into respones array response[i] = readResponse[SHA204_BUFFER_POS_DATA+i]; - + } + /* read from bytes 8->11 of config zone */ returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN47); - - for (int i=4; i<8; i++) // store bytes 4-7 of SN into response array + + for (int i=4; i<8; i++) { // store bytes 4-7 of SN into response array response[i] = readResponse[SHA204_BUFFER_POS_DATA+(i-4)]; - - if (!returnCode) - { /* Finally if last two reads were successful, read byte 8 of the SN */ + } + + if (!returnCode) { + /* Finally if last two reads were successful, read byte 8 of the SN */ returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN8); response[8] = readResponse[SHA204_BUFFER_POS_DATA]; // Byte 8 of SN should always be 0xEE } } - + return returnCode; } -/* Calculates CRC16 value of provided data (and optionally including provided existing CRC16 data) +/* Calculates CRC16 value of provided data (and optionally including provided existing CRC16 data) returns the calculated CRC16 value */ uint16_t atsha204Class::calculateAndUpdateCrc(uint8_t length, uint8_t *data, uint16_t current_crc) { - uint8_t counter; - uint16_t crc_register = current_crc; - uint16_t polynom = 0x8005; - uint8_t shift_register; - uint8_t data_bit, crc_bit; - - for (counter = 0; counter < length; counter++) - { - for (shift_register = 0x01; shift_register > 0x00; shift_register <<= 1) - { - data_bit = (data[counter] & shift_register) ? 1 : 0; - crc_bit = crc_register >> 15; - - // Shift CRC to the left by 1. - crc_register <<= 1; - - if ((data_bit ^ crc_bit) != 0) - crc_register ^= polynom; - } - } - return crc_register; + uint8_t counter; + uint16_t crc_register = current_crc; + uint16_t polynom = 0x8005; + uint8_t shift_register; + uint8_t data_bit, crc_bit; + + for (counter = 0; counter < length; counter++) { + for (shift_register = 0x01; shift_register > 0x00; shift_register <<= 1) { + data_bit = (data[counter] & shift_register) ? 1 : 0; + crc_bit = crc_register >> 15; + + // Shift CRC to the left by 1. + crc_register <<= 1; + + if ((data_bit ^ crc_bit) != 0) { + crc_register ^= polynom; + } + } + } + return crc_register; } /* SWI bit bang functions */ void atsha204Class::swi_set_signal_pin(uint8_t is_high) { - SHA204_SET_OUTPUT(); - if (is_high) { - SHA204_POUT_HIGH(); - } - else { - SHA204_POUT_LOW(); - } + SHA204_SET_OUTPUT(); + if (is_high) { + SHA204_POUT_HIGH(); + } else { + SHA204_POUT_LOW(); + } } uint8_t atsha204Class::swi_send_bytes(uint8_t count, uint8_t *buffer) { - uint8_t i, bit_mask; - - // Disable interrupts while sending. - noInterrupts(); //swi_disable_interrupts(); - - // Set signal pin as output. - SHA204_POUT_HIGH(); - SHA204_SET_OUTPUT(); - // Wait turn around time. - delayMicroseconds(RX_TX_DELAY); //RX_TX_DELAY; - - for (i = 0; i < count; i++) - { - for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1) - { - if (bit_mask & buffer[i]) - { - SHA204_POUT_LOW(); - delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; - SHA204_POUT_HIGH(); - delayMicroseconds(7*BIT_DELAY); //BIT_DELAY_7; - } - else - { - // Send a zero bit. - SHA204_POUT_LOW(); - delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; - SHA204_POUT_HIGH(); - delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; - SHA204_POUT_LOW(); - delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; - SHA204_POUT_HIGH(); - delayMicroseconds(5*BIT_DELAY); //BIT_DELAY_5; - } - } - } - interrupts(); //swi_enable_interrupts(); - return SWI_FUNCTION_RETCODE_SUCCESS; + uint8_t i, bit_mask; + + // Disable interrupts while sending. + noInterrupts(); //swi_disable_interrupts(); + + // Set signal pin as output. + SHA204_POUT_HIGH(); + SHA204_SET_OUTPUT(); + // Wait turn around time. + delayMicroseconds(RX_TX_DELAY); //RX_TX_DELAY; + + for (i = 0; i < count; i++) { + for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1) { + if (bit_mask & buffer[i]) { + SHA204_POUT_LOW(); + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + SHA204_POUT_HIGH(); + delayMicroseconds(7*BIT_DELAY); //BIT_DELAY_7; + } else { + // Send a zero bit. + SHA204_POUT_LOW(); + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + SHA204_POUT_HIGH(); + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + SHA204_POUT_LOW(); + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + SHA204_POUT_HIGH(); + delayMicroseconds(5*BIT_DELAY); //BIT_DELAY_5; + } + } + } + interrupts(); //swi_enable_interrupts(); + return SWI_FUNCTION_RETCODE_SUCCESS; } uint8_t atsha204Class::swi_send_byte(uint8_t value) { - return swi_send_bytes(1, &value); + return swi_send_bytes(1, &value); } -uint8_t atsha204Class::swi_receive_bytes(uint8_t count, uint8_t *buffer) +uint8_t atsha204Class::swi_receive_bytes(uint8_t count, uint8_t *buffer) { - uint8_t status = SWI_FUNCTION_RETCODE_SUCCESS; - uint8_t i; - uint8_t bit_mask; - uint8_t pulse_count; - uint8_t timeout_count; - - // Disable interrupts while receiving. - noInterrupts(); //swi_disable_interrupts(); - - // Configure signal pin as input - SHA204_SET_INPUT(); - - // Receive bits and store in buffer. - for (i = 0; i < count; i++) - { - for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1) - { - pulse_count = 0; - - // Make sure that the variable below is big enough. - // Change it to uint16_t if 255 is too small, but be aware that - // the loop resolution decreases on an 8-bit controller in that case. - timeout_count = START_PULSE_TIME_OUT; - - // Detect start bit. - while (--timeout_count > 0) - { - // Wait for falling edge. - if (SHA204_PIN_READ() == 0) - break; - } - - if (timeout_count == 0) - { - status = SWI_FUNCTION_RETCODE_TIMEOUT; - break; - } - - do - { - // Wait for rising edge. - if (SHA204_PIN_READ() != 0) - { - // For an Atmel microcontroller this might be faster than "pulse_count++". - pulse_count = 1; - break; - } - } while (--timeout_count > 0); - - if (pulse_count == 0) - { - status = SWI_FUNCTION_RETCODE_TIMEOUT; - break; - } - - // Trying to measure the time of start bit and calculating the timeout - // for zero bit detection is not accurate enough for an 8 MHz 8-bit CPU. - // So let's just wait the maximum time for the falling edge of a zero bit - // to arrive after we have detected the rising edge of the start bit. - timeout_count = ZERO_PULSE_TIME_OUT; - - // Detect possible edge indicating zero bit. - do - { - if (SHA204_PIN_READ() == 0) - { - // For an Atmel microcontroller this might be faster than "pulse_count++". - pulse_count = 2; - break; - } - } while (--timeout_count > 0); - - // Wait for rising edge of zero pulse before returning. Otherwise we might interpret - // its rising edge as the next start pulse. - if (pulse_count == 2) - { - do - { - if (SHA204_PIN_READ() != 0) - break; - } while (timeout_count-- > 0); - } - - // Update byte at current buffer index. - else - buffer[i] |= bit_mask; // received "one" bit - } - - if (status != SWI_FUNCTION_RETCODE_SUCCESS) - break; - } - interrupts(); //swi_enable_interrupts(); - - if (status == SWI_FUNCTION_RETCODE_TIMEOUT) - { - if (i > 0) - // Indicate that we timed out after having received at least one byte. - status = SWI_FUNCTION_RETCODE_RX_FAIL; - } - return status; + uint8_t status = SWI_FUNCTION_RETCODE_SUCCESS; + uint8_t i; + uint8_t bit_mask; + uint8_t pulse_count; + uint8_t timeout_count; + + // Disable interrupts while receiving. + noInterrupts(); //swi_disable_interrupts(); + + // Configure signal pin as input + SHA204_SET_INPUT(); + + // Receive bits and store in buffer. + for (i = 0; i < count; i++) { + for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1) { + pulse_count = 0; + + // Make sure that the variable below is big enough. + // Change it to uint16_t if 255 is too small, but be aware that + // the loop resolution decreases on an 8-bit controller in that case. + timeout_count = START_PULSE_TIME_OUT; + + // Detect start bit. + while (--timeout_count > 0) { + // Wait for falling edge. + if (SHA204_PIN_READ() == 0) { + break; + } + } + + if (timeout_count == 0) { + status = SWI_FUNCTION_RETCODE_TIMEOUT; + break; + } + + do { + // Wait for rising edge. + if (SHA204_PIN_READ() != 0) { + // For an Atmel microcontroller this might be faster than "pulse_count++". + pulse_count = 1; + break; + } + } while (--timeout_count > 0); + + if (pulse_count == 0) { + status = SWI_FUNCTION_RETCODE_TIMEOUT; + break; + } + + // Trying to measure the time of start bit and calculating the timeout + // for zero bit detection is not accurate enough for an 8 MHz 8-bit CPU. + // So let's just wait the maximum time for the falling edge of a zero bit + // to arrive after we have detected the rising edge of the start bit. + timeout_count = ZERO_PULSE_TIME_OUT; + + // Detect possible edge indicating zero bit. + do { + if (SHA204_PIN_READ() == 0) { + // For an Atmel microcontroller this might be faster than "pulse_count++". + pulse_count = 2; + break; + } + } while (--timeout_count > 0); + + // Wait for rising edge of zero pulse before returning. Otherwise we might interpret + // its rising edge as the next start pulse. + if (pulse_count == 2) { + do { + if (SHA204_PIN_READ() != 0) { + break; + } + } while (timeout_count-- > 0); + } + + // Update byte at current buffer index. + else { + buffer[i] |= bit_mask; // received "one" bit + } + } + + if (status != SWI_FUNCTION_RETCODE_SUCCESS) { + break; + } + } + interrupts(); //swi_enable_interrupts(); + + if (status == SWI_FUNCTION_RETCODE_TIMEOUT) { + if (i > 0) + // Indicate that we timed out after having received at least one byte. + { + status = SWI_FUNCTION_RETCODE_RX_FAIL; + } + } + return status; } /* Physical functions */ uint8_t atsha204Class::sha204p_wakeup() { - swi_set_signal_pin(0); - delayMicroseconds(10*SHA204_WAKEUP_PULSE_WIDTH); - swi_set_signal_pin(1); - delay(SHA204_WAKEUP_DELAY); + swi_set_signal_pin(0); + delayMicroseconds(10*SHA204_WAKEUP_PULSE_WIDTH); + swi_set_signal_pin(1); + delay(SHA204_WAKEUP_DELAY); - return SHA204_SUCCESS; + return SHA204_SUCCESS; } uint8_t atsha204Class::sha204p_sleep() { - return swi_send_byte(SHA204_SWI_FLAG_SLEEP); + return swi_send_byte(SHA204_SWI_FLAG_SLEEP); } uint8_t atsha204Class::sha204p_resync(uint8_t size, uint8_t *response) { - delay(SHA204_SYNC_TIMEOUT); - return sha204p_receive_response(size, response); + delay(SHA204_SYNC_TIMEOUT); + return sha204p_receive_response(size, response); } uint8_t atsha204Class::sha204p_receive_response(uint8_t size, uint8_t *response) { - uint8_t count_byte; - uint8_t i; - uint8_t ret_code; - - for (i = 0; i < size; i++) - response[i] = 0; - - (void) swi_send_byte(SHA204_SWI_FLAG_TX); - - ret_code = swi_receive_bytes(size, response); - if (ret_code == SWI_FUNCTION_RETCODE_SUCCESS || ret_code == SWI_FUNCTION_RETCODE_RX_FAIL) - { - count_byte = response[SHA204_BUFFER_POS_COUNT]; - if ((count_byte < SHA204_RSP_SIZE_MIN) || (count_byte > size)) - return SHA204_INVALID_SIZE; - - return SHA204_SUCCESS; - } - - // Translate error so that the Communication layer - // can distinguish between a real error or the - // device being busy executing a command. - if (ret_code == SWI_FUNCTION_RETCODE_TIMEOUT) - return SHA204_RX_NO_RESPONSE; - else - return SHA204_RX_FAIL; + uint8_t count_byte; + uint8_t i; + uint8_t ret_code; + + for (i = 0; i < size; i++) { + response[i] = 0; + } + + (void) swi_send_byte(SHA204_SWI_FLAG_TX); + + ret_code = swi_receive_bytes(size, response); + if (ret_code == SWI_FUNCTION_RETCODE_SUCCESS || ret_code == SWI_FUNCTION_RETCODE_RX_FAIL) { + count_byte = response[SHA204_BUFFER_POS_COUNT]; + if ((count_byte < SHA204_RSP_SIZE_MIN) || (count_byte > size)) { + return SHA204_INVALID_SIZE; + } + + return SHA204_SUCCESS; + } + + // Translate error so that the Communication layer + // can distinguish between a real error or the + // device being busy executing a command. + if (ret_code == SWI_FUNCTION_RETCODE_TIMEOUT) { + return SHA204_RX_NO_RESPONSE; + } else { + return SHA204_RX_FAIL; + } } uint8_t atsha204Class::sha204p_send_command(uint8_t count, uint8_t * command) { - uint8_t ret_code = swi_send_byte(SHA204_SWI_FLAG_CMD); - if (ret_code != SWI_FUNCTION_RETCODE_SUCCESS) - return SHA204_COMM_FAIL; + uint8_t ret_code = swi_send_byte(SHA204_SWI_FLAG_CMD); + if (ret_code != SWI_FUNCTION_RETCODE_SUCCESS) { + return SHA204_COMM_FAIL; + } - return swi_send_bytes(count, command); + return swi_send_bytes(count, command); } /* Communication functions */ uint8_t atsha204Class::sha204c_wakeup(uint8_t *response) { - uint8_t ret_code = sha204p_wakeup(); - if (ret_code != SHA204_SUCCESS) - return ret_code; - - ret_code = sha204p_receive_response(SHA204_RSP_SIZE_MIN, response); - if (ret_code != SHA204_SUCCESS) - return ret_code; - - // Verify status response. - if (response[SHA204_BUFFER_POS_COUNT] != SHA204_RSP_SIZE_MIN) - ret_code = SHA204_INVALID_SIZE; - else if (response[SHA204_BUFFER_POS_STATUS] != SHA204_STATUS_BYTE_WAKEUP) - ret_code = SHA204_COMM_FAIL; - else - { - if ((response[SHA204_RSP_SIZE_MIN - SHA204_CRC_SIZE] != 0x33) - || (response[SHA204_RSP_SIZE_MIN + 1 - SHA204_CRC_SIZE] != 0x43)) - ret_code = SHA204_BAD_CRC; - } - if (ret_code != SHA204_SUCCESS) - delay(SHA204_COMMAND_EXEC_MAX); - - return ret_code; + uint8_t ret_code = sha204p_wakeup(); + if (ret_code != SHA204_SUCCESS) { + return ret_code; + } + + ret_code = sha204p_receive_response(SHA204_RSP_SIZE_MIN, response); + if (ret_code != SHA204_SUCCESS) { + return ret_code; + } + + // Verify status response. + if (response[SHA204_BUFFER_POS_COUNT] != SHA204_RSP_SIZE_MIN) { + ret_code = SHA204_INVALID_SIZE; + } else if (response[SHA204_BUFFER_POS_STATUS] != SHA204_STATUS_BYTE_WAKEUP) { + ret_code = SHA204_COMM_FAIL; + } else { + if ((response[SHA204_RSP_SIZE_MIN - SHA204_CRC_SIZE] != 0x33) + || (response[SHA204_RSP_SIZE_MIN + 1 - SHA204_CRC_SIZE] != 0x43)) { + ret_code = SHA204_BAD_CRC; + } + } + if (ret_code != SHA204_SUCCESS) { + delay(SHA204_COMMAND_EXEC_MAX); + } + + return ret_code; } uint8_t atsha204Class::sha204c_resync(uint8_t size, uint8_t *response) { - // Try to re-synchronize without sending a Wake token - // (step 1 of the re-synchronization process). - uint8_t ret_code = sha204p_resync(size, response); - if (ret_code == SHA204_SUCCESS) - return ret_code; - - // We lost communication. Send a Wake pulse and try - // to receive a response (steps 2 and 3 of the - // re-synchronization process). - (void) sha204p_sleep(); - ret_code = sha204c_wakeup(response); - - // Translate a return value of success into one - // that indicates that the device had to be woken up - // and might have lost its TempKey. - return (ret_code == SHA204_SUCCESS ? SHA204_RESYNC_WITH_WAKEUP : ret_code); + // Try to re-synchronize without sending a Wake token + // (step 1 of the re-synchronization process). + uint8_t ret_code = sha204p_resync(size, response); + if (ret_code == SHA204_SUCCESS) { + return ret_code; + } + + // We lost communication. Send a Wake pulse and try + // to receive a response (steps 2 and 3 of the + // re-synchronization process). + (void) sha204p_sleep(); + ret_code = sha204c_wakeup(response); + + // Translate a return value of success into one + // that indicates that the device had to be woken up + // and might have lost its TempKey. + return (ret_code == SHA204_SUCCESS ? SHA204_RESYNC_WITH_WAKEUP : ret_code); } -uint8_t atsha204Class::sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout) +uint8_t atsha204Class::sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, + uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout) { - uint8_t ret_code = SHA204_FUNC_FAIL; - uint8_t ret_code_resync; - uint8_t n_retries_send; - uint8_t n_retries_receive; - uint8_t i; - uint8_t status_byte; - uint8_t count = tx_buffer[SHA204_BUFFER_POS_COUNT]; - uint8_t count_minus_crc = count - SHA204_CRC_SIZE; - uint16_t execution_timeout_us = (uint16_t) (execution_timeout * 1000) + SHA204_RESPONSE_TIMEOUT; - volatile uint16_t timeout_countdown; - - // Append CRC. - sha204c_calculate_crc(count_minus_crc, tx_buffer, tx_buffer + count_minus_crc); - - // Retry loop for sending a command and receiving a response. - n_retries_send = SHA204_RETRY_COUNT + 1; - - while ((n_retries_send-- > 0) && (ret_code != SHA204_SUCCESS)) - { - // Send command. - ret_code = sha204p_send_command(count, tx_buffer); - if (ret_code != SHA204_SUCCESS) - { - if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE) - return ret_code; // The device seems to be dead in the water. - else - continue; - } - - // Wait minimum command execution time and then start polling for a response. - delay(execution_delay); - - // Retry loop for receiving a response. - n_retries_receive = SHA204_RETRY_COUNT + 1; - while (n_retries_receive-- > 0) - { - // Reset response buffer. - for (i = 0; i < rx_size; i++) - rx_buffer[i] = 0; - - // Poll for response. - timeout_countdown = execution_timeout_us; - do - { - ret_code = sha204p_receive_response(rx_size, rx_buffer); - timeout_countdown -= SHA204_RESPONSE_TIMEOUT; - } - while ((timeout_countdown > SHA204_RESPONSE_TIMEOUT) && (ret_code == SHA204_RX_NO_RESPONSE)); - - if (ret_code == SHA204_RX_NO_RESPONSE) - { - // We did not receive a response. Re-synchronize and send command again. - if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE) - // The device seems to be dead in the water. - return ret_code; - else - break; - } - - // Check whether we received a valid response. - if (ret_code == SHA204_INVALID_SIZE) - { - // We see 0xFF for the count when communication got out of sync. - ret_code_resync = sha204c_resync(rx_size, rx_buffer); - if (ret_code_resync == SHA204_SUCCESS) - // We did not have to wake up the device. Try receiving response again. - continue; - if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP) - // We could re-synchronize, but only after waking up the device. - // Re-send command. - break; - else - // We failed to re-synchronize. - return ret_code; - } - - // We received a response of valid size. - // Check the consistency of the response. - ret_code = sha204c_check_crc(rx_buffer); - if (ret_code == SHA204_SUCCESS) - { - // Received valid response. - if (rx_buffer[SHA204_BUFFER_POS_COUNT] > SHA204_RSP_SIZE_MIN) - // Received non-status response. We are done. - return ret_code; - - // Received status response. - status_byte = rx_buffer[SHA204_BUFFER_POS_STATUS]; - - // Translate the three possible device status error codes - // into library return codes. - if (status_byte == SHA204_STATUS_BYTE_PARSE) - return SHA204_PARSE_ERROR; - if (status_byte == SHA204_STATUS_BYTE_EXEC) - return SHA204_CMD_FAIL; - if (status_byte == SHA204_STATUS_BYTE_COMM) - { - // In case of the device status byte indicating a communication - // error this function exits the retry loop for receiving a response - // and enters the overall retry loop - // (send command / receive response). - ret_code = SHA204_STATUS_CRC; - break; - } - - // Received status response from CheckMAC, DeriveKey, GenDig, - // Lock, Nonce, Pause, UpdateExtra, or Write command. - return ret_code; - } - - else - { - // Received response with incorrect CRC. - ret_code_resync = sha204c_resync(rx_size, rx_buffer); - if (ret_code_resync == SHA204_SUCCESS) - // We did not have to wake up the device. Try receiving response again. - continue; - if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP) - // We could re-synchronize, but only after waking up the device. - // Re-send command. - break; - else - // We failed to re-synchronize. - return ret_code; - } // block end of check response consistency - - } // block end of receive retry loop - - } // block end of send and receive retry loop - - return ret_code; + uint8_t ret_code = SHA204_FUNC_FAIL; + uint8_t ret_code_resync; + uint8_t n_retries_send; + uint8_t n_retries_receive; + uint8_t i; + uint8_t status_byte; + uint8_t count = tx_buffer[SHA204_BUFFER_POS_COUNT]; + uint8_t count_minus_crc = count - SHA204_CRC_SIZE; + uint16_t execution_timeout_us = (uint16_t) (execution_timeout * 1000) + SHA204_RESPONSE_TIMEOUT; + volatile uint16_t timeout_countdown; + + // Append CRC. + sha204c_calculate_crc(count_minus_crc, tx_buffer, tx_buffer + count_minus_crc); + + // Retry loop for sending a command and receiving a response. + n_retries_send = SHA204_RETRY_COUNT + 1; + + while ((n_retries_send-- > 0) && (ret_code != SHA204_SUCCESS)) { + // Send command. + ret_code = sha204p_send_command(count, tx_buffer); + if (ret_code != SHA204_SUCCESS) { + if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE) { + return ret_code; // The device seems to be dead in the water. + } else { + continue; + } + } + + // Wait minimum command execution time and then start polling for a response. + delay(execution_delay); + + // Retry loop for receiving a response. + n_retries_receive = SHA204_RETRY_COUNT + 1; + while (n_retries_receive-- > 0) { + // Reset response buffer. + for (i = 0; i < rx_size; i++) { + rx_buffer[i] = 0; + } + + // Poll for response. + timeout_countdown = execution_timeout_us; + do { + ret_code = sha204p_receive_response(rx_size, rx_buffer); + timeout_countdown -= SHA204_RESPONSE_TIMEOUT; + } while ((timeout_countdown > SHA204_RESPONSE_TIMEOUT) && (ret_code == SHA204_RX_NO_RESPONSE)); + + if (ret_code == SHA204_RX_NO_RESPONSE) { + // We did not receive a response. Re-synchronize and send command again. + if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE) + // The device seems to be dead in the water. + { + return ret_code; + } else { + break; + } + } + + // Check whether we received a valid response. + if (ret_code == SHA204_INVALID_SIZE) { + // We see 0xFF for the count when communication got out of sync. + ret_code_resync = sha204c_resync(rx_size, rx_buffer); + if (ret_code_resync == SHA204_SUCCESS) + // We did not have to wake up the device. Try receiving response again. + { + continue; + } + if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP) + // We could re-synchronize, but only after waking up the device. + // Re-send command. + { + break; + } else + // We failed to re-synchronize. + { + return ret_code; + } + } + + // We received a response of valid size. + // Check the consistency of the response. + ret_code = sha204c_check_crc(rx_buffer); + if (ret_code == SHA204_SUCCESS) { + // Received valid response. + if (rx_buffer[SHA204_BUFFER_POS_COUNT] > SHA204_RSP_SIZE_MIN) + // Received non-status response. We are done. + { + return ret_code; + } + + // Received status response. + status_byte = rx_buffer[SHA204_BUFFER_POS_STATUS]; + + // Translate the three possible device status error codes + // into library return codes. + if (status_byte == SHA204_STATUS_BYTE_PARSE) { + return SHA204_PARSE_ERROR; + } + if (status_byte == SHA204_STATUS_BYTE_EXEC) { + return SHA204_CMD_FAIL; + } + if (status_byte == SHA204_STATUS_BYTE_COMM) { + // In case of the device status byte indicating a communication + // error this function exits the retry loop for receiving a response + // and enters the overall retry loop + // (send command / receive response). + ret_code = SHA204_STATUS_CRC; + break; + } + + // Received status response from CheckMAC, DeriveKey, GenDig, + // Lock, Nonce, Pause, UpdateExtra, or Write command. + return ret_code; + } + + else { + // Received response with incorrect CRC. + ret_code_resync = sha204c_resync(rx_size, rx_buffer); + if (ret_code_resync == SHA204_SUCCESS) + // We did not have to wake up the device. Try receiving response again. + { + continue; + } + if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP) + // We could re-synchronize, but only after waking up the device. + // Re-send command. + { + break; + } else + // We failed to re-synchronize. + { + return ret_code; + } + } // block end of check response consistency + + } // block end of receive retry loop + + } // block end of send and receive retry loop + + return ret_code; } @@ -499,173 +503,178 @@ uint8_t atsha204Class::sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_s uint8_t atsha204Class::sha204m_random(uint8_t * tx_buffer, uint8_t * rx_buffer, uint8_t mode) { - if (!tx_buffer || !rx_buffer || (mode > RANDOM_NO_SEED_UPDATE)) - return SHA204_BAD_PARAM; + if (!tx_buffer || !rx_buffer || (mode > RANDOM_NO_SEED_UPDATE)) { + return SHA204_BAD_PARAM; + } - tx_buffer[SHA204_COUNT_IDX] = RANDOM_COUNT; - tx_buffer[SHA204_OPCODE_IDX] = SHA204_RANDOM; - tx_buffer[RANDOM_MODE_IDX] = mode & RANDOM_SEED_UPDATE; + tx_buffer[SHA204_COUNT_IDX] = RANDOM_COUNT; + tx_buffer[SHA204_OPCODE_IDX] = SHA204_RANDOM; + tx_buffer[RANDOM_MODE_IDX] = mode & RANDOM_SEED_UPDATE; - tx_buffer[RANDOM_PARAM2_IDX] = - tx_buffer[RANDOM_PARAM2_IDX + 1] = 0; + tx_buffer[RANDOM_PARAM2_IDX] = + tx_buffer[RANDOM_PARAM2_IDX + 1] = 0; - return sha204c_send_and_receive(&tx_buffer[0], RANDOM_RSP_SIZE, &rx_buffer[0], RANDOM_DELAY, RANDOM_EXEC_MAX - RANDOM_DELAY); + return sha204c_send_and_receive(&tx_buffer[0], RANDOM_RSP_SIZE, &rx_buffer[0], RANDOM_DELAY, + RANDOM_EXEC_MAX - RANDOM_DELAY); } uint8_t atsha204Class::sha204m_dev_rev(uint8_t *tx_buffer, uint8_t *rx_buffer) { - if (!tx_buffer || !rx_buffer) - return SHA204_BAD_PARAM; + if (!tx_buffer || !rx_buffer) { + return SHA204_BAD_PARAM; + } - tx_buffer[SHA204_COUNT_IDX] = DEVREV_COUNT; - tx_buffer[SHA204_OPCODE_IDX] = SHA204_DEVREV; + tx_buffer[SHA204_COUNT_IDX] = DEVREV_COUNT; + tx_buffer[SHA204_OPCODE_IDX] = SHA204_DEVREV; - // Parameters are 0. - tx_buffer[DEVREV_PARAM1_IDX] = - tx_buffer[DEVREV_PARAM2_IDX] = - tx_buffer[DEVREV_PARAM2_IDX + 1] = 0; + // Parameters are 0. + tx_buffer[DEVREV_PARAM1_IDX] = + tx_buffer[DEVREV_PARAM2_IDX] = + tx_buffer[DEVREV_PARAM2_IDX + 1] = 0; - return sha204c_send_and_receive(&tx_buffer[0], DEVREV_RSP_SIZE, &rx_buffer[0], - DEVREV_DELAY, DEVREV_EXEC_MAX - DEVREV_DELAY); + return sha204c_send_and_receive(&tx_buffer[0], DEVREV_RSP_SIZE, &rx_buffer[0], + DEVREV_DELAY, DEVREV_EXEC_MAX - DEVREV_DELAY); } -uint8_t atsha204Class::sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address) +uint8_t atsha204Class::sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, + uint16_t address) { - uint8_t rx_size; - - if (!tx_buffer || !rx_buffer || ((zone & ~READ_ZONE_MASK) != 0) - || ((zone & READ_ZONE_MODE_32_BYTES) && (zone == SHA204_ZONE_OTP))) - return SHA204_BAD_PARAM; - - address >>= 2; - if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_CONFIG) - { - if (address > SHA204_ADDRESS_MASK_CONFIG) - return SHA204_BAD_PARAM; - } - else if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_OTP) - { - if (address > SHA204_ADDRESS_MASK_OTP) - return SHA204_BAD_PARAM; - } - else if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_DATA) - { - if (address > SHA204_ADDRESS_MASK) - return SHA204_BAD_PARAM; - } - - tx_buffer[SHA204_COUNT_IDX] = READ_COUNT; - tx_buffer[SHA204_OPCODE_IDX] = SHA204_READ; - tx_buffer[READ_ZONE_IDX] = zone; - tx_buffer[READ_ADDR_IDX] = (uint8_t) (address & SHA204_ADDRESS_MASK); - tx_buffer[READ_ADDR_IDX + 1] = 0; - - rx_size = (zone & SHA204_ZONE_COUNT_FLAG) ? READ_32_RSP_SIZE : READ_4_RSP_SIZE; - - return sha204c_send_and_receive(&tx_buffer[0], rx_size, &rx_buffer[0], READ_DELAY, READ_EXEC_MAX - READ_DELAY); + uint8_t rx_size; + + if (!tx_buffer || !rx_buffer || ((zone & ~READ_ZONE_MASK) != 0) + || ((zone & READ_ZONE_MODE_32_BYTES) && (zone == SHA204_ZONE_OTP))) { + return SHA204_BAD_PARAM; + } + + address >>= 2; + if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_CONFIG) { + if (address > SHA204_ADDRESS_MASK_CONFIG) { + return SHA204_BAD_PARAM; + } + } else if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_OTP) { + if (address > SHA204_ADDRESS_MASK_OTP) { + return SHA204_BAD_PARAM; + } + } else if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_DATA) { + if (address > SHA204_ADDRESS_MASK) { + return SHA204_BAD_PARAM; + } + } + + tx_buffer[SHA204_COUNT_IDX] = READ_COUNT; + tx_buffer[SHA204_OPCODE_IDX] = SHA204_READ; + tx_buffer[READ_ZONE_IDX] = zone; + tx_buffer[READ_ADDR_IDX] = (uint8_t) (address & SHA204_ADDRESS_MASK); + tx_buffer[READ_ADDR_IDX + 1] = 0; + + rx_size = (zone & SHA204_ZONE_COUNT_FLAG) ? READ_32_RSP_SIZE : READ_4_RSP_SIZE; + + return sha204c_send_and_receive(&tx_buffer[0], rx_size, &rx_buffer[0], READ_DELAY, + READ_EXEC_MAX - READ_DELAY); } uint8_t atsha204Class::sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t param2, - uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3, - uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer) + uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, + uint8_t *data3, + uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer) { uint8_t poll_delay, poll_timeout, response_size; uint8_t *p_buffer; uint8_t len; uint8_t ret_code = sha204m_check_parameters(op_code, param1, param2, - datalen1, data1, datalen2, data2, datalen3, data3, - tx_size, tx_buffer, rx_size, rx_buffer); - if (ret_code != SHA204_SUCCESS) + datalen1, data1, datalen2, data2, datalen3, data3, + tx_size, tx_buffer, rx_size, rx_buffer); + if (ret_code != SHA204_SUCCESS) { return ret_code; + } // Supply delays and response size. - switch (op_code) - { - case SHA204_CHECKMAC: - poll_delay = CHECKMAC_DELAY; - poll_timeout = CHECKMAC_EXEC_MAX - CHECKMAC_DELAY; - response_size = CHECKMAC_RSP_SIZE; - break; - - case SHA204_DERIVE_KEY: - poll_delay = DERIVE_KEY_DELAY; - poll_timeout = DERIVE_KEY_EXEC_MAX - DERIVE_KEY_DELAY; - response_size = DERIVE_KEY_RSP_SIZE; - break; - - case SHA204_DEVREV: - poll_delay = DEVREV_DELAY; - poll_timeout = DEVREV_EXEC_MAX - DEVREV_DELAY; - response_size = DEVREV_RSP_SIZE; - break; - - case SHA204_GENDIG: - poll_delay = GENDIG_DELAY; - poll_timeout = GENDIG_EXEC_MAX - GENDIG_DELAY; - response_size = GENDIG_RSP_SIZE; - break; - - case SHA204_HMAC: - poll_delay = HMAC_DELAY; - poll_timeout = HMAC_EXEC_MAX - HMAC_DELAY; - response_size = HMAC_RSP_SIZE; - break; - - case SHA204_LOCK: - poll_delay = LOCK_DELAY; - poll_timeout = LOCK_EXEC_MAX - LOCK_DELAY; - response_size = LOCK_RSP_SIZE; - break; - - case SHA204_MAC: - poll_delay = MAC_DELAY; - poll_timeout = MAC_EXEC_MAX - MAC_DELAY; - response_size = MAC_RSP_SIZE; - break; - - case SHA204_NONCE: - poll_delay = NONCE_DELAY; - poll_timeout = NONCE_EXEC_MAX - NONCE_DELAY; - response_size = param1 == NONCE_MODE_PASSTHROUGH - ? NONCE_RSP_SIZE_SHORT : NONCE_RSP_SIZE_LONG; - break; - - case SHA204_PAUSE: - poll_delay = PAUSE_DELAY; - poll_timeout = PAUSE_EXEC_MAX - PAUSE_DELAY; - response_size = PAUSE_RSP_SIZE; - break; - - case SHA204_RANDOM: - poll_delay = RANDOM_DELAY; - poll_timeout = RANDOM_EXEC_MAX - RANDOM_DELAY; - response_size = RANDOM_RSP_SIZE; - break; - - case SHA204_READ: - poll_delay = READ_DELAY; - poll_timeout = READ_EXEC_MAX - READ_DELAY; - response_size = (param1 & SHA204_ZONE_COUNT_FLAG) - ? READ_32_RSP_SIZE : READ_4_RSP_SIZE; - break; - - case SHA204_UPDATE_EXTRA: - poll_delay = UPDATE_DELAY; - poll_timeout = UPDATE_EXEC_MAX - UPDATE_DELAY; - response_size = UPDATE_RSP_SIZE; - break; - - case SHA204_WRITE: - poll_delay = WRITE_DELAY; - poll_timeout = WRITE_EXEC_MAX - WRITE_DELAY; - response_size = WRITE_RSP_SIZE; - break; - - default: - poll_delay = 0; - poll_timeout = SHA204_COMMAND_EXEC_MAX; - response_size = rx_size; + switch (op_code) { + case SHA204_CHECKMAC: + poll_delay = CHECKMAC_DELAY; + poll_timeout = CHECKMAC_EXEC_MAX - CHECKMAC_DELAY; + response_size = CHECKMAC_RSP_SIZE; + break; + + case SHA204_DERIVE_KEY: + poll_delay = DERIVE_KEY_DELAY; + poll_timeout = DERIVE_KEY_EXEC_MAX - DERIVE_KEY_DELAY; + response_size = DERIVE_KEY_RSP_SIZE; + break; + + case SHA204_DEVREV: + poll_delay = DEVREV_DELAY; + poll_timeout = DEVREV_EXEC_MAX - DEVREV_DELAY; + response_size = DEVREV_RSP_SIZE; + break; + + case SHA204_GENDIG: + poll_delay = GENDIG_DELAY; + poll_timeout = GENDIG_EXEC_MAX - GENDIG_DELAY; + response_size = GENDIG_RSP_SIZE; + break; + + case SHA204_HMAC: + poll_delay = HMAC_DELAY; + poll_timeout = HMAC_EXEC_MAX - HMAC_DELAY; + response_size = HMAC_RSP_SIZE; + break; + + case SHA204_LOCK: + poll_delay = LOCK_DELAY; + poll_timeout = LOCK_EXEC_MAX - LOCK_DELAY; + response_size = LOCK_RSP_SIZE; + break; + + case SHA204_MAC: + poll_delay = MAC_DELAY; + poll_timeout = MAC_EXEC_MAX - MAC_DELAY; + response_size = MAC_RSP_SIZE; + break; + + case SHA204_NONCE: + poll_delay = NONCE_DELAY; + poll_timeout = NONCE_EXEC_MAX - NONCE_DELAY; + response_size = param1 == NONCE_MODE_PASSTHROUGH + ? NONCE_RSP_SIZE_SHORT : NONCE_RSP_SIZE_LONG; + break; + + case SHA204_PAUSE: + poll_delay = PAUSE_DELAY; + poll_timeout = PAUSE_EXEC_MAX - PAUSE_DELAY; + response_size = PAUSE_RSP_SIZE; + break; + + case SHA204_RANDOM: + poll_delay = RANDOM_DELAY; + poll_timeout = RANDOM_EXEC_MAX - RANDOM_DELAY; + response_size = RANDOM_RSP_SIZE; + break; + + case SHA204_READ: + poll_delay = READ_DELAY; + poll_timeout = READ_EXEC_MAX - READ_DELAY; + response_size = (param1 & SHA204_ZONE_COUNT_FLAG) + ? READ_32_RSP_SIZE : READ_4_RSP_SIZE; + break; + + case SHA204_UPDATE_EXTRA: + poll_delay = UPDATE_DELAY; + poll_timeout = UPDATE_EXEC_MAX - UPDATE_DELAY; + response_size = UPDATE_RSP_SIZE; + break; + + case SHA204_WRITE: + poll_delay = WRITE_DELAY; + poll_timeout = WRITE_EXEC_MAX - WRITE_DELAY; + response_size = WRITE_RSP_SIZE; + break; + + default: + poll_delay = 0; + poll_timeout = SHA204_COMMAND_EXEC_MAX; + response_size = rx_size; } // Assemble command. @@ -694,146 +703,159 @@ uint8_t atsha204Class::sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t // Send command and receive response. return sha204c_send_and_receive(&tx_buffer[0], response_size, - &rx_buffer[0], poll_delay, poll_timeout); + &rx_buffer[0], poll_delay, poll_timeout); } uint8_t atsha204Class::sha204m_check_parameters(uint8_t op_code, uint8_t param1, uint16_t param2, - uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3, - uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer) + uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, + uint8_t *data3, + uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer) { #ifdef SHA204_CHECK_PARAMETERS uint8_t len = datalen1 + datalen2 + datalen3 + SHA204_CMD_SIZE_MIN; - if (!tx_buffer || tx_size < len || rx_size < SHA204_RSP_SIZE_MIN || !rx_buffer) + if (!tx_buffer || tx_size < len || rx_size < SHA204_RSP_SIZE_MIN || !rx_buffer) { return SHA204_BAD_PARAM; + } - if ((datalen1 > 0 && !data1) || (datalen2 > 0 && !data2) || (datalen3 > 0 && !data3)) + if ((datalen1 > 0 && !data1) || (datalen2 > 0 && !data2) || (datalen3 > 0 && !data3)) { return SHA204_BAD_PARAM; + } // Check parameters depending on op-code. - switch (op_code) - { - case SHA204_CHECKMAC: - if ( - // no null pointers allowed - !data1 || !data2 - // No reserved bits should be set. - || (param1 | CHECKMAC_MODE_MASK) != CHECKMAC_MODE_MASK - // key_id > 15 not allowed - || param2 > SHA204_KEY_ID_MAX - ) - return SHA204_BAD_PARAM; - break; - - case SHA204_DERIVE_KEY: - if (param2 > SHA204_KEY_ID_MAX) - return SHA204_BAD_PARAM; - break; + switch (op_code) { + case SHA204_CHECKMAC: + if ( + // no null pointers allowed + !data1 || !data2 + // No reserved bits should be set. + || (param1 | CHECKMAC_MODE_MASK) != CHECKMAC_MODE_MASK + // key_id > 15 not allowed + || param2 > SHA204_KEY_ID_MAX + ) { + return SHA204_BAD_PARAM; + } + break; - case SHA204_DEVREV: - break; + case SHA204_DERIVE_KEY: + if (param2 > SHA204_KEY_ID_MAX) { + return SHA204_BAD_PARAM; + } + break; - case SHA204_GENDIG: - if ((param1 != GENDIG_ZONE_OTP) && (param1 != GENDIG_ZONE_DATA)) - return SHA204_BAD_PARAM; - break; + case SHA204_DEVREV: + break; - case SHA204_HMAC: - if ((param1 & ~HMAC_MODE_MASK) != 0) - return SHA204_BAD_PARAM; - break; + case SHA204_GENDIG: + if ((param1 != GENDIG_ZONE_OTP) && (param1 != GENDIG_ZONE_DATA)) { + return SHA204_BAD_PARAM; + } + break; - case SHA204_LOCK: - if (((param1 & ~LOCK_ZONE_MASK) != 0) - || ((param1 & LOCK_ZONE_NO_CRC) && (param2 != 0))) - return SHA204_BAD_PARAM; - break; + case SHA204_HMAC: + if ((param1 & ~HMAC_MODE_MASK) != 0) { + return SHA204_BAD_PARAM; + } + break; - case SHA204_MAC: - if (((param1 & ~MAC_MODE_MASK) != 0) - || (((param1 & MAC_MODE_BLOCK2_TEMPKEY) == 0) && !data1)) - return SHA204_BAD_PARAM; - break; + case SHA204_LOCK: + if (((param1 & ~LOCK_ZONE_MASK) != 0) + || ((param1 & LOCK_ZONE_NO_CRC) && (param2 != 0))) { + return SHA204_BAD_PARAM; + } + break; - case SHA204_NONCE: - if ( !data1 - || (param1 > NONCE_MODE_PASSTHROUGH) - || (param1 == NONCE_MODE_INVALID) - ) - return SHA204_BAD_PARAM; - break; + case SHA204_MAC: + if (((param1 & ~MAC_MODE_MASK) != 0) + || (((param1 & MAC_MODE_BLOCK2_TEMPKEY) == 0) && !data1)) { + return SHA204_BAD_PARAM; + } + break; - case SHA204_PAUSE: - break; + case SHA204_NONCE: + if ( !data1 + || (param1 > NONCE_MODE_PASSTHROUGH) + || (param1 == NONCE_MODE_INVALID) + ) { + return SHA204_BAD_PARAM; + } + break; - case SHA204_RANDOM: - if (param1 > RANDOM_NO_SEED_UPDATE) - return SHA204_BAD_PARAM; - break; + case SHA204_PAUSE: + break; - case SHA204_READ: - if (((param1 & ~READ_ZONE_MASK) != 0) - || ((param1 & READ_ZONE_MODE_32_BYTES) && (param1 == SHA204_ZONE_OTP))) - return SHA204_BAD_PARAM; - break; + case SHA204_RANDOM: + if (param1 > RANDOM_NO_SEED_UPDATE) { + return SHA204_BAD_PARAM; + } + break; - case SHA204_TEMPSENSE: - break; + case SHA204_READ: + if (((param1 & ~READ_ZONE_MASK) != 0) + || ((param1 & READ_ZONE_MODE_32_BYTES) && (param1 == SHA204_ZONE_OTP))) { + return SHA204_BAD_PARAM; + } + break; - case SHA204_UPDATE_EXTRA: - if (param1 > UPDATE_CONFIG_BYTE_86) - return SHA204_BAD_PARAM; - break; + case SHA204_TEMPSENSE: + break; - case SHA204_WRITE: - if (!data1 || ((param1 & ~WRITE_ZONE_MASK) != 0)) - return SHA204_BAD_PARAM; - break; + case SHA204_UPDATE_EXTRA: + if (param1 > UPDATE_CONFIG_BYTE_86) { + return SHA204_BAD_PARAM; + } + break; - default: - // unknown op-code + case SHA204_WRITE: + if (!data1 || ((param1 & ~WRITE_ZONE_MASK) != 0)) { return SHA204_BAD_PARAM; + } + break; + + default: + // unknown op-code + return SHA204_BAD_PARAM; } return SHA204_SUCCESS; #else - (void)rx_size; - (void)tx_size; - (void)tx_buffer; - (void)rx_buffer; - (void)param1; - (void)param2; - (void)data1; - (void)data2; - (void)data3; - (void)datalen1; - (void)datalen2; - (void)datalen3; - (void)op_code; + (void)rx_size; + (void)tx_size; + (void)tx_buffer; + (void)rx_buffer; + (void)param1; + (void)param2; + (void)data1; + (void)data2; + (void)data3; + (void)datalen1; + (void)datalen2; + (void)datalen3; + (void)op_code; return SHA204_SUCCESS; #endif } /* CRC Calculator and Checker */ -void atsha204Class::sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc) +void atsha204Class::sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc) { - uint16_t crc_register = 0; + uint16_t crc_register = 0; - crc_register = calculateAndUpdateCrc(length, data, crc_register); - crc[0] = (uint8_t) (crc_register & 0x00FF); - crc[1] = (uint8_t) (crc_register >> 8); + crc_register = calculateAndUpdateCrc(length, data, crc_register); + crc[0] = (uint8_t) (crc_register & 0x00FF); + crc[1] = (uint8_t) (crc_register >> 8); } uint8_t atsha204Class::sha204c_check_crc(uint8_t *response) { - uint8_t crc[SHA204_CRC_SIZE]; - uint8_t count = response[SHA204_BUFFER_POS_COUNT]; + uint8_t crc[SHA204_CRC_SIZE]; + uint8_t count = response[SHA204_BUFFER_POS_COUNT]; - count -= SHA204_CRC_SIZE; - sha204c_calculate_crc(count, response, crc); + count -= SHA204_CRC_SIZE; + sha204c_calculate_crc(count, response, crc); - return (crc[0] == response[count] && crc[1] == response[count + 1]) - ? SHA204_SUCCESS : SHA204_BAD_CRC; + return (crc[0] == response[count] && crc[1] == response[count + 1]) + ? SHA204_SUCCESS : SHA204_BAD_CRC; } diff --git a/examples/SecurityPersonalizer/sha204_library.h b/examples/SecurityPersonalizer/sha204_library.h index e9682bb46..fb0beb28a 100644 --- a/examples/SecurityPersonalizer/sha204_library.h +++ b/examples/SecurityPersonalizer/sha204_library.h @@ -260,7 +260,7 @@ #define SHA204_COMMAND_EXEC_MAX ((uint8_t) (69.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) //! maximum command delay #define SHA204_CMD_SIZE_MIN ((uint8_t) 7) //! minimum number of bytes in command (from count byte to second CRC byte) #ifndef SHA204_CMD_SIZE_MAX - #define SHA204_CMD_SIZE_MAX ((uint8_t) 84) //! maximum size of command packet (CheckMac) +#define SHA204_CMD_SIZE_MAX ((uint8_t) 84) //! maximum size of command packet (CheckMac) #endif #define SHA204_CRC_SIZE ((uint8_t) 2) //! number of CRC bytes #define SHA204_BUFFER_POS_STATUS (1) //! buffer index of status byte in status response @@ -284,17 +284,17 @@ /* Low level HW access macros */ /* function calls is not working, as it will have too much overhead */ #if !defined(ARDUINO_ARCH_AVR) // For everything else than AVR use pinMode / digitalWrite - #define SHA204_SET_OUTPUT() pinMode(device_pin, OUTPUT) - #define SHA204_SET_INPUT() pinMode(device_pin, INPUT) - #define SHA204_POUT_HIGH() digitalWrite(device_pin, HIGH) - #define SHA204_POUT_LOW() digitalWrite(device_pin, LOW) - #define SHA204_PIN_READ() digitalRead(device_pin) +#define SHA204_SET_OUTPUT() pinMode(device_pin, OUTPUT) +#define SHA204_SET_INPUT() pinMode(device_pin, INPUT) +#define SHA204_POUT_HIGH() digitalWrite(device_pin, HIGH) +#define SHA204_POUT_LOW() digitalWrite(device_pin, LOW) +#define SHA204_PIN_READ() digitalRead(device_pin) #else - #define SHA204_SET_INPUT() *device_port_DDR &= ~device_pin - #define SHA204_SET_OUTPUT() *device_port_DDR |= device_pin - #define SHA204_POUT_HIGH() *device_port_OUT |= device_pin - #define SHA204_POUT_LOW() *device_port_OUT &= ~device_pin - #define SHA204_PIN_READ() (*device_port_IN & device_pin) +#define SHA204_SET_INPUT() *device_port_DDR &= ~device_pin +#define SHA204_SET_OUTPUT() *device_port_DDR |= device_pin +#define SHA204_POUT_HIGH() *device_port_OUT |= device_pin +#define SHA204_POUT_LOW() *device_port_OUT &= ~device_pin +#define SHA204_PIN_READ() (*device_port_IN & device_pin) #endif /** diff --git a/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino b/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino index d5492f576..d7a57db43 100644 --- a/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino +++ b/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino @@ -1,40 +1,40 @@ - /** - * 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. - * - ******************************* - * - * DESCRIPTION - * The ArduinoGateway prints data received from sensors on the serial link. - * The gateway accepts input on seral which will be sent out on radio network. - * - * This GW code is designed for Sensebender GateWay / (Arduino Zero variant) - * - * Wire connections (OPTIONAL): - * - Inclusion button should be connected to SW2 - * - * LEDs on board (default assignments): - * - Orange: USB RX/TX - Blink when receiving / transmitting on USB CDC device - * - Yellow: RX - Blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved - * - Green : TX - Blink fast on radio message transmitted. In inclusion mode will blink slowly - * - Red : ERR - Fast blink on error during transmission error or recieve crc error - * - Blue : free - (use with LED_BLUE macro) - * - */ +/** +* 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. +* +******************************* +* +* DESCRIPTION +* The ArduinoGateway prints data received from sensors on the serial link. +* The gateway accepts input on seral which will be sent out on radio network. +* +* This GW code is designed for Sensebender GateWay / (Arduino Zero variant) +* +* Wire connections (OPTIONAL): +* - Inclusion button should be connected to SW2 +* +* LEDs on board (default assignments): +* - Orange: USB RX/TX - Blink when receiving / transmitting on USB CDC device +* - Yellow: RX - Blink fast on radio message recieved. In inclusion mode will blink fast only on presentation recieved +* - Green : TX - Blink fast on radio message transmitted. In inclusion mode will blink slowly +* - Red : ERR - Fast blink on error during transmission error or recieve crc error +* - Blue : free - (use with LED_BLUE macro) +* +*/ #define SKETCH_VERSION "0.2" // Enable debug prints to serial monitor @@ -92,177 +92,189 @@ Sd2Card card; static uint8_t num_of_leds = 5; static uint8_t leds[] = {LED_BLUE, LED_RED, LED_GREEN, LED_YELLOW, LED_ORANGE}; -void setup() { - // Setup locally attached sensors +void setup() +{ + // Setup locally attached sensors } -void presentation() { - // Present locally attached sensors +void presentation() +{ + // Present locally attached sensors } -void loop() { - // Send locally attached sensor data here +void loop() +{ + // Send locally attached sensor data here } -void preHwInit() { +void preHwInit() +{ - pinMode(MY_SWC1, INPUT_PULLUP); - pinMode(MY_SWC2, INPUT_PULLUP); - if (digitalRead(MY_SWC1) && digitalRead(MY_SWC2)) return; + pinMode(MY_SWC1, INPUT_PULLUP); + pinMode(MY_SWC2, INPUT_PULLUP); + if (digitalRead(MY_SWC1) && digitalRead(MY_SWC2)) { + return; + } - uint8_t tests = 0; + uint8_t tests = 0; - for (int i=0; i< num_of_leds; i++) { - pinMode(leds[i], OUTPUT); - } - uint8_t led_state = 0; - if (digitalRead(MY_SWC1)) { - while (!Serial) { - digitalWrite(LED_BLUE, led_state); - led_state ^= 0x01; - delay(500); - } // Wait for USB to be connected, before spewing out data. - } - digitalWrite(LED_BLUE, LOW); - if (Serial) { - Serial.println("Sensebender GateWay test routine"); - Serial.print("Mysensors core version : "); - Serial.println(MYSENSORS_LIBRARY_VERSION); - Serial.print("GateWay sketch version : "); - Serial.println(SKETCH_VERSION); - Serial.println("----------------------------------"); - Serial.println(); - } - if (testSha204()) { - digitalWrite(LED_GREEN, HIGH); - tests++; - } - if (testSDCard()) { - digitalWrite(LED_YELLOW, HIGH); - tests++; - } + for (int i=0; i< num_of_leds; i++) { + pinMode(leds[i], OUTPUT); + } + uint8_t led_state = 0; + if (digitalRead(MY_SWC1)) { + while (!Serial) { + digitalWrite(LED_BLUE, led_state); + led_state ^= 0x01; + delay(500); + } // Wait for USB to be connected, before spewing out data. + } + digitalWrite(LED_BLUE, LOW); + if (Serial) { + Serial.println("Sensebender GateWay test routine"); + Serial.print("Mysensors core version : "); + Serial.println(MYSENSORS_LIBRARY_VERSION); + Serial.print("GateWay sketch version : "); + Serial.println(SKETCH_VERSION); + Serial.println("----------------------------------"); + Serial.println(); + } + if (testSha204()) { + digitalWrite(LED_GREEN, HIGH); + tests++; + } + if (testSDCard()) { + digitalWrite(LED_YELLOW, HIGH); + tests++; + } - if (testEEProm()) { - digitalWrite(LED_ORANGE, HIGH); - tests++; - } - if (testAnalog()) { - digitalWrite(LED_BLUE, HIGH); - tests++; - } - if (tests == 4) { - while(1) { - for (int i=0; i SHA204 "); - atsha204_init(MY_SIGNING_ATSHA204_PIN); - ret_code = atsha204_wakeup(rx_buffer); +bool testSha204() +{ + uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; + uint8_t ret_code; + if (Serial) { + Serial.print("- > SHA204 "); + } + atsha204_init(MY_SIGNING_ATSHA204_PIN); + ret_code = atsha204_wakeup(rx_buffer); - if (ret_code == SHA204_SUCCESS) - { - ret_code = atsha204_getSerialNumber(rx_buffer); - if (ret_code != SHA204_SUCCESS) - { - if (Serial) Serial.println(F("Failed to obtain device serial number. Response: ")); Serial.println(ret_code, HEX); - } - else - { - if (Serial) { - Serial.print(F("Ok (serial : ")); - for (int i=0; i<9; i++) - { - if (rx_buffer[i] < 0x10) - { - Serial.print('0'); // Because Serial.print does not 0-pad HEX - } - Serial.print(rx_buffer[i], HEX); - } - Serial.println(")"); - } - return true; - } - } - else { - if (Serial) Serial.println(F("Failed to wakeup SHA204")); - } - return false; + if (ret_code == SHA204_SUCCESS) { + ret_code = atsha204_getSerialNumber(rx_buffer); + if (ret_code != SHA204_SUCCESS) { + if (Serial) { + Serial.println(F("Failed to obtain device serial number. Response: ")); + } + Serial.println(ret_code, HEX); + } else { + if (Serial) { + Serial.print(F("Ok (serial : ")); + for (int i=0; i<9; i++) { + if (rx_buffer[i] < 0x10) { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[i], HEX); + } + Serial.println(")"); + } + return true; + } + } else { + if (Serial) { + Serial.println(F("Failed to wakeup SHA204")); + } + } + return false; } -bool testSDCard() { - if (Serial) Serial.print("- > SD CARD "); - if (!card.init(SPI_HALF_SPEED, MY_SDCARD_CS)) { - if (Serial) Serial.println("SD CARD did not initialize!"); - } - else { - if (Serial) { - Serial.print("SD Card initialized correct! - "); - Serial.print("type detected : "); - switch(card.type()) { - case SD_CARD_TYPE_SD1: - Serial.println("SD1"); - break; - case SD_CARD_TYPE_SD2: - Serial.println("SD2"); - break; - case SD_CARD_TYPE_SDHC: - Serial.println("SDHC"); - break; - default: - Serial.println("Unknown"); - } - } - return true; - } - return false; +bool testSDCard() +{ + if (Serial) { + Serial.print("- > SD CARD "); + } + if (!card.init(SPI_HALF_SPEED, MY_SDCARD_CS)) { + if (Serial) { + Serial.println("SD CARD did not initialize!"); + } + } else { + if (Serial) { + Serial.print("SD Card initialized correct! - "); + Serial.print("type detected : "); + switch(card.type()) { + case SD_CARD_TYPE_SD1: + Serial.println("SD1"); + break; + case SD_CARD_TYPE_SD2: + Serial.println("SD2"); + break; + case SD_CARD_TYPE_SDHC: + Serial.println("SDHC"); + break; + default: + Serial.println("Unknown"); + } + } + return true; + } + return false; } -bool testEEProm() { - uint8_t eeprom_d1, eeprom_d2; - SerialUSB.print(" -> EEPROM "); - Wire.begin(); - eeprom_d1 = i2c_eeprom_read_byte(EEPROM_VERIFICATION_ADDRESS); - delay(500); - eeprom_d1 = ~eeprom_d1; // invert the bits - i2c_eeprom_write_byte(EEPROM_VERIFICATION_ADDRESS, eeprom_d1); - delay(500); - eeprom_d2 = i2c_eeprom_read_byte(EEPROM_VERIFICATION_ADDRESS); - if (eeprom_d1 == eeprom_d2) { - SerialUSB.println("PASSED"); - i2c_eeprom_write_byte(EEPROM_VERIFICATION_ADDRESS, ~eeprom_d1); - return true; - } - SerialUSB.println("FAILED!"); - return false; +bool testEEProm() +{ + uint8_t eeprom_d1, eeprom_d2; + SerialUSB.print(" -> EEPROM "); + Wire.begin(); + eeprom_d1 = i2c_eeprom_read_byte(EEPROM_VERIFICATION_ADDRESS); + delay(500); + eeprom_d1 = ~eeprom_d1; // invert the bits + i2c_eeprom_write_byte(EEPROM_VERIFICATION_ADDRESS, eeprom_d1); + delay(500); + eeprom_d2 = i2c_eeprom_read_byte(EEPROM_VERIFICATION_ADDRESS); + if (eeprom_d1 == eeprom_d2) { + SerialUSB.println("PASSED"); + i2c_eeprom_write_byte(EEPROM_VERIFICATION_ADDRESS, ~eeprom_d1); + return true; + } + SerialUSB.println("FAILED!"); + return false; } -bool testAnalog() { - int bat_detect = analogRead(MY_BAT_DETECT); - Serial.print("-> analog : "); - Serial.print(bat_detect); - if (bat_detect < 400 || bat_detect > 650) { - Serial.println(" Failed"); - return false; - } - Serial.println(" Passed"); - return true; +bool testAnalog() +{ + int bat_detect = analogRead(MY_BAT_DETECT); + Serial.print("-> analog : "); + Serial.print(bat_detect); + if (bat_detect < 400 || bat_detect > 650) { + Serial.println(" Failed"); + return false; + } + Serial.println(" Passed"); + return true; } diff --git a/examples/SoilMoistSensor/SoilMoistSensor.ino b/examples/SoilMoistSensor/SoilMoistSensor.ino index 0d45d080d..b43deb3ce 100644 --- a/examples/SoilMoistSensor/SoilMoistSensor.ino +++ b/examples/SoilMoistSensor/SoilMoistSensor.ino @@ -22,24 +22,24 @@ * * Arduino soil moisture based on gypsum sensor/resistive sensor to avoid electric catalyse in soil * Required to interface the sensor: 2 * 4.7kOhm + 2 * 1N4148 - * - * Gypsum sensor and calibration: + * + * Gypsum sensor and calibration: * DIY: See http://vanderleevineyard.com/1/category/vinduino/1.html - * Built: Davis / Watermark 200SS + * Built: Davis / Watermark 200SS * http://www.cooking-hacks.com/watermark-soil-moisture-sensor?_bksrc=item2item&_bkloc=product * http://www.irrometer.com/pdf/supportmaterial/sensors/voltage-WM-chart.pdf * cb (centibar) http://www.irrometer.com/basics.html - * 0-10 Saturated Soil. Occurs for a day or two after irrigation - * 10-20 Soil is adequately wet (except coarse sands which are drying out at this range) - * 30-60 Usual range to irrigate or water (except heavy clay soils). - * 60-100 Usual range to irrigate heavy clay soils - * 100-200 Soil is becoming dangerously dry for maximum production. Proceed with caution. - * + * 0-10 Saturated Soil. Occurs for a day or two after irrigation + * 10-20 Soil is adequately wet (except coarse sands which are drying out at this range) + * 30-60 Usual range to irrigate or water (except heavy clay soils). + * 60-100 Usual range to irrigate heavy clay soils + * 100-200 Soil is becoming dangerously dry for maximum production. Proceed with caution. + * * Connection: * D6, D7: alternative powering to avoid sensor degradation * A0, A1: alternative resistance mesuring * - * Based on: + * Based on: * "Vinduino" portable soil moisture sensor code V3.00 * Date December 31, 2012 * Reinier van der Lee and Theodore Kaskalis @@ -61,7 +61,7 @@ // GNU General Public License for more details. // Enable debug prints to serial monitor -#define MY_DEBUG +#define MY_DEBUG // Enable and select radio type attached #define MY_RADIO_NRF24 @@ -74,7 +74,7 @@ #define NUM_READS 10 // Number of sensor reads for filtering #define CHILD_ID 0 -MyMessage msg(CHILD_ID, V_LEVEL); +MyMessage msg(CHILD_ID, V_LEVEL); unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds) long buffer[NUM_READS]; @@ -82,8 +82,8 @@ int index; /// @brief Structure to be used in percentage and resistance values matrix to be filtered (have to be in pairs) typedef struct { - int moisture; //!< Moisture - long resistance; //!< Resistance + int moisture; //!< Moisture + long resistance; //!< Resistance } values; const long knownResistor = 4700; // Constant value of known resistor in Ohms @@ -95,24 +95,27 @@ values valueOf[NUM_READS]; // Calculated moisture percentages and resista int i; // Simple index variable -void setup() { - // initialize the digital pins as an output. - // Pin 6,7 is for sensor 1 - // initialize the digital pin as an output. - // Pin 6 is sense resistor voltage supply 1 - pinMode(6, OUTPUT); - - // initialize the digital pin as an output. - // Pin 7 is sense resistor voltage supply 2 - pinMode(7, OUTPUT); +void setup() +{ + // initialize the digital pins as an output. + // Pin 6,7 is for sensor 1 + // initialize the digital pin as an output. + // Pin 6 is sense resistor voltage supply 1 + pinMode(6, OUTPUT); + + // initialize the digital pin as an output. + // Pin 7 is sense resistor voltage supply 2 + pinMode(7, OUTPUT); } -void presentation() { - sendSketchInfo("Soil Moisture Sensor Reverse Polarity", "1.0"); - present(CHILD_ID, S_HUM); +void presentation() +{ + sendSketchInfo("Soil Moisture Sensor Reverse Polarity", "1.0"); + present(CHILD_ID, S_HUM); } -void loop() { +void loop() +{ measure(6,7,1); Serial.print ("\t"); @@ -131,59 +134,63 @@ void loop() { Serial.print ("sensor bias compensated value = "); Serial.println (sensor1); Serial.println (); - + //send back the values send(msg.set((long int)ceil(sensor1))); // delay until next measurement (msec) - sleep(SLEEP_TIME); + sleep(SLEEP_TIME); } void measure (int phase_b, int phase_a, int analog_input) { - // read sensor, filter, and calculate resistance value - // Noise filter: median filter - - for (i=0; i= NUM_READS) index = 0; +void addReading(long resistance) +{ + buffer[index] = resistance; + index++; + if (index >= NUM_READS) { + index = 0; + } } -long average(){ - long sum = 0; - for (int i = 0; i < NUM_READS; i++){ - sum += buffer[i]; - } - return (long)(sum / NUM_READS); +long average() +{ + long sum = 0; + for (int i = 0; i < NUM_READS; i++) { + sum += buffer[i]; + } + return (long)(sum / NUM_READS); } diff --git a/examples/UVSensor/UVSensor.ino b/examples/UVSensor/UVSensor.ino index e22451db5..0a6ea5246 100644 --- a/examples/UVSensor/UVSensor.ino +++ b/examples/UVSensor/UVSensor.ino @@ -21,29 +21,29 @@ * REVISION HISTORY * Version 1.0 - epierre * Contribution: bulldoglowell, gizmocuz - * + * * DESCRIPTION * Arduino UVM-30A * Index table taken from: http://www.elecrow.com/sensors-c-111/environment-c-111_112/uv-sensor-moduleuvm30a-p-716.html - * Because this table is pretty lineair, we can calculate a UVI with one decimal + * Because this table is pretty lineair, we can calculate a UVI with one decimal * * Connect sensor: * * + >>> 5V * - >>> GND - * out >>> A0 - * + * out >>> A0 + * * License: Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0) */ // Enable debug prints to serial monitor -#define MY_DEBUG +#define MY_DEBUG // Enable and select radio type attached #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include +#include #define UV_SENSOR_ANALOG_PIN 0 @@ -53,57 +53,57 @@ unsigned long SLEEP_TIME = 30*1000; // Sleep time between reads (in milliseconds MyMessage uvMsg(CHILD_ID_UV, V_UV); -unsigned long lastSend =0; +unsigned long lastSend =0; float uvIndex; float lastUV = -1; uint16_t uvIndexValue [12] = { 50, 227, 318, 408, 503, 606, 696, 795, 881, 976, 1079, 1170}; -void presentation() { - // Send the sketch version information to the gateway and Controller - sendSketchInfo("UV Sensor", "1.2"); +void presentation() +{ + // Send the sketch version information to the gateway and Controller + sendSketchInfo("UV Sensor", "1.2"); - // Register all sensors to gateway (they will be created as child devices) - present(CHILD_ID_UV, S_UV); + // Register all sensors to gateway (they will be created as child devices) + present(CHILD_ID_UV, S_UV); } -void loop() +void loop() { - unsigned long currentTime = millis(); - - uint16_t uv = analogRead(UV_SENSOR_ANALOG_PIN);// Get UV value - if (uv>1170) - uv=1170; - - //Serial.print("UV Analog reading: "); - //Serial.println(uv); - - int i; - for (i = 0; i < 12; i++) - { - if (uv <= uvIndexValue[i]) - { - uvIndex = i; - break; - } - } - - //calculate 1 decimal if possible - if (i>0) { - float vRange=uvIndexValue[i]-uvIndexValue[i-1]; - float vCalc=uv-uvIndexValue[i-1]; - uvIndex+=(1.0/vRange)*vCalc-1.0; - } - - //Serial.print("UVI: "); - //Serial.println(uvIndex,2); - - //Send value to gateway if changed, or at least every 5 minutes - if ((uvIndex != lastUV)||(currentTime-lastSend >= 5UL*60UL*1000UL)) { - lastSend=currentTime; - send(uvMsg.set(uvIndex,2)); - lastUV = uvIndex; - } - - sleep(SLEEP_TIME); + unsigned long currentTime = millis(); + + uint16_t uv = analogRead(UV_SENSOR_ANALOG_PIN);// Get UV value + if (uv>1170) { + uv=1170; + } + + //Serial.print("UV Analog reading: "); + //Serial.println(uv); + + int i; + for (i = 0; i < 12; i++) { + if (uv <= uvIndexValue[i]) { + uvIndex = i; + break; + } + } + + //calculate 1 decimal if possible + if (i>0) { + float vRange=uvIndexValue[i]-uvIndexValue[i-1]; + float vCalc=uv-uvIndexValue[i-1]; + uvIndex+=(1.0/vRange)*vCalc-1.0; + } + + //Serial.print("UVI: "); + //Serial.println(uvIndex,2); + + //Send value to gateway if changed, or at least every 5 minutes + if ((uvIndex != lastUV)||(currentTime-lastSend >= 5UL*60UL*1000UL)) { + lastSend=currentTime; + send(uvMsg.set(uvIndex,2)); + lastUV = uvIndex; + } + + sleep(SLEEP_TIME); } diff --git a/examples/VibrationSensor/VibrationSensor.ino b/examples/VibrationSensor/VibrationSensor.ino index eaefa5905..a07d7bde1 100644 --- a/examples/VibrationSensor/VibrationSensor.ino +++ b/examples/VibrationSensor/VibrationSensor.ino @@ -58,40 +58,42 @@ MyMessage vibrationMsg(CHILD_ID_VIBRATION, V_LEVEL); void setup() { - pinMode(VIBRATION_SENSOR_DIGITAL_PIN, INPUT); - attachInterrupt(digitalPinToInterrupt(VIBRATION_SENSOR_DIGITAL_PIN), blink, FALLING); // Trigger the blink function when the falling edge is detected - pinMode(SensorLED, OUTPUT); + pinMode(VIBRATION_SENSOR_DIGITAL_PIN, INPUT); + attachInterrupt(digitalPinToInterrupt(VIBRATION_SENSOR_DIGITAL_PIN), blink, + FALLING); // Trigger the blink function when the falling edge is detected + pinMode(SensorLED, OUTPUT); } -void presentation() { - // Send the sketch version information to the gateway and Controller - sendSketchInfo("VIBRATION Sensor", "1.0"); +void presentation() +{ + // Send the sketch version information to the gateway and Controller + sendSketchInfo("VIBRATION Sensor", "1.0"); - // Register all sensors to gateway (they will be created as child devices) - present(CHILD_ID_VIBRATION, S_VIBRATION); + // Register all sensors to gateway (they will be created as child devices) + present(CHILD_ID_VIBRATION, S_VIBRATION); } void loop() { - if(state>=40){ // basically below 40 so ignire basic level - send(vibrationMsg.set(int16_t(state))); - state = 0; - digitalWrite(SensorLED,HIGH); - } else { - state = 0; - digitalWrite(SensorLED,LOW); - } + if(state>=40) { // basically below 40 so ignire basic level + send(vibrationMsg.set(int16_t(state))); + state = 0; + digitalWrite(SensorLED,HIGH); + } else { + state = 0; + digitalWrite(SensorLED,LOW); + } - // Power down the radio. Note that the radio will get powered back up - // on the next write() call. - delay(1000); //delay to allow serial to fully print before sleep + // Power down the radio. Note that the radio will get powered back up + // on the next write() call. + delay(1000); //delay to allow serial to fully print before sleep - sleep(SLEEP_TIME); //sleep for: sleepTime + sleep(SLEEP_TIME); //sleep for: sleepTime } void blink()//Interrupts function { - state++; + state++; } diff --git a/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino b/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino index 2a0710530..fbf99e09e 100644 --- a/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino +++ b/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino @@ -21,27 +21,27 @@ * REVISION HISTORY * Version 1.0 - Henrik Ekblad * Version 1.1 - GizMoCuz - * + * * DESCRIPTION * Use this sensor to measure volume and flow of your house watermeter. * You need to set the correct pulsefactor of your meter (pulses per m3). * The sensor starts by fetching current volume reading from gateway (VAR 1). * Reports both volume and flow back to gateway. * - * Unfortunately millis() won't increment when the Arduino is in - * sleepmode. So we cannot make this sensor sleep if we also want + * Unfortunately millis() won't increment when the Arduino is in + * sleepmode. So we cannot make this sensor sleep if we also want * to calculate/report flow. * http://www.mysensors.org/build/pulse_water */ // Enable debug prints to serial monitor -#define MY_DEBUG +#define MY_DEBUG // Enable and select radio type attached #define MY_RADIO_NRF24 //#define MY_RADIO_RFM69 -#include +#include #define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your sensor. (Only 2 and 3 generates interrupt!) @@ -53,7 +53,8 @@ #define CHILD_ID 1 // Id of the sensor child -unsigned long SEND_FREQUENCY = 30000; // Minimum time between send (in milliseconds). We don't want to spam the gateway. +unsigned long SEND_FREQUENCY = + 30000; // Minimum time between send (in milliseconds). We don't want to spam the gateway. MyMessage flowMsg(CHILD_ID,V_FLOW); MyMessage volumeMsg(CHILD_ID,V_VOLUME); @@ -61,127 +62,126 @@ MyMessage lastCounterMsg(CHILD_ID,V_VAR1); double ppl = ((double)PULSE_FACTOR)/1000; // Pulses per liter -volatile unsigned long pulseCount = 0; +volatile unsigned long pulseCount = 0; volatile unsigned long lastBlink = 0; -volatile double flow = 0; +volatile double flow = 0; bool pcReceived = false; unsigned long oldPulseCount = 0; -unsigned long newBlink = 0; +unsigned long newBlink = 0; double oldflow = 0; -double volume =0; +double volume =0; double oldvolume =0; unsigned long lastSend =0; unsigned long lastPulse =0; -void setup() -{ - // initialize our digital pins internal pullup resistor so one pulse switches from high to low (less distortion) - pinMode(DIGITAL_INPUT_SENSOR, INPUT_PULLUP); - - pulseCount = oldPulseCount = 0; +void setup() +{ + // initialize our digital pins internal pullup resistor so one pulse switches from high to low (less distortion) + pinMode(DIGITAL_INPUT_SENSOR, INPUT_PULLUP); + + pulseCount = oldPulseCount = 0; - // Fetch last known pulse count value from gw - request(CHILD_ID, V_VAR1); + // Fetch last known pulse count value from gw + request(CHILD_ID, V_VAR1); - lastSend = lastPulse = millis(); + lastSend = lastPulse = millis(); - attachInterrupt(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR), onPulse, FALLING); + attachInterrupt(digitalPinToInterrupt(DIGITAL_INPUT_SENSOR), onPulse, FALLING); } -void presentation() { - // Send the sketch version information to the gateway and Controller - sendSketchInfo("Water Meter", "1.1"); +void presentation() +{ + // Send the sketch version information to the gateway and Controller + sendSketchInfo("Water Meter", "1.1"); - // Register this device as Waterflow sensor - present(CHILD_ID, S_WATER); + // Register this device as Waterflow sensor + present(CHILD_ID, S_WATER); } -void loop() -{ - unsigned long currentTime = millis(); - - // Only send values at a maximum frequency or woken up from sleep - if (SLEEP_MODE || (currentTime - lastSend > SEND_FREQUENCY)) - { - lastSend=currentTime; - - if (!pcReceived) { - //Last Pulsecount not yet received from controller, request it again - request(CHILD_ID, V_VAR1); - return; - } - - if (!SLEEP_MODE && flow != oldflow) { - oldflow = flow; - - Serial.print("l/min:"); - Serial.println(flow); - - // Check that we dont get unresonable large flow value. - // could hapen when long wraps or false interrupt triggered - if (flow<((unsigned long)MAX_FLOW)) { - send(flowMsg.set(flow, 2)); // Send flow value to gw - } - } - - // No Pulse count received in 2min - if(currentTime - lastPulse > 120000){ - flow = 0; - } - - // Pulse count has changed - if ((pulseCount != oldPulseCount)||(!SLEEP_MODE)) { - oldPulseCount = pulseCount; - - Serial.print("pulsecount:"); - Serial.println(pulseCount); - - send(lastCounterMsg.set(pulseCount)); // Send pulsecount value to gw in VAR1 - - double volume = ((double)pulseCount/((double)PULSE_FACTOR)); - if ((volume != oldvolume)||(!SLEEP_MODE)) { - oldvolume = volume; - - Serial.print("volume:"); - Serial.println(volume, 3); - - send(volumeMsg.set(volume, 3)); // Send volume value to gw - } - } - } - if (SLEEP_MODE) { - sleep(SEND_FREQUENCY); - } +void loop() +{ + unsigned long currentTime = millis(); + + // Only send values at a maximum frequency or woken up from sleep + if (SLEEP_MODE || (currentTime - lastSend > SEND_FREQUENCY)) { + lastSend=currentTime; + + if (!pcReceived) { + //Last Pulsecount not yet received from controller, request it again + request(CHILD_ID, V_VAR1); + return; + } + + if (!SLEEP_MODE && flow != oldflow) { + oldflow = flow; + + Serial.print("l/min:"); + Serial.println(flow); + + // Check that we dont get unresonable large flow value. + // could hapen when long wraps or false interrupt triggered + if (flow<((unsigned long)MAX_FLOW)) { + send(flowMsg.set(flow, 2)); // Send flow value to gw + } + } + + // No Pulse count received in 2min + if(currentTime - lastPulse > 120000) { + flow = 0; + } + + // Pulse count has changed + if ((pulseCount != oldPulseCount)||(!SLEEP_MODE)) { + oldPulseCount = pulseCount; + + Serial.print("pulsecount:"); + Serial.println(pulseCount); + + send(lastCounterMsg.set(pulseCount)); // Send pulsecount value to gw in VAR1 + + double volume = ((double)pulseCount/((double)PULSE_FACTOR)); + if ((volume != oldvolume)||(!SLEEP_MODE)) { + oldvolume = volume; + + Serial.print("volume:"); + Serial.println(volume, 3); + + send(volumeMsg.set(volume, 3)); // Send volume value to gw + } + } + } + if (SLEEP_MODE) { + sleep(SEND_FREQUENCY); + } } -void receive(const MyMessage &message) { - if (message.type==V_VAR1) { - unsigned long gwPulseCount=message.getULong(); - pulseCount += gwPulseCount; - flow=oldflow=0; - Serial.print("Received last pulse count from gw:"); - Serial.println(pulseCount); - pcReceived = true; - } +void receive(const MyMessage &message) +{ + if (message.type==V_VAR1) { + unsigned long gwPulseCount=message.getULong(); + pulseCount += gwPulseCount; + flow=oldflow=0; + Serial.print("Received last pulse count from gw:"); + Serial.println(pulseCount); + pcReceived = true; + } } -void onPulse() +void onPulse() { - if (!SLEEP_MODE) - { - unsigned long newBlink = micros(); - unsigned long interval = newBlink-lastBlink; - - if (interval!=0) - { - lastPulse = millis(); - if (interval<500000L) { - // Sometimes we get interrupt on RISING, 500000 = 0.5sek debounce ( max 120 l/min) - return; - } - flow = (60000000.0 /interval) / ppl; - } - lastBlink = newBlink; - } - pulseCount++; + if (!SLEEP_MODE) { + unsigned long newBlink = micros(); + unsigned long interval = newBlink-lastBlink; + + if (interval!=0) { + lastPulse = millis(); + if (interval<500000L) { + // Sometimes we get interrupt on RISING, 500000 = 0.5sek debounce ( max 120 l/min) + return; + } + flow = (60000000.0 /interval) / ppl; + } + lastBlink = newBlink; + } + pulseCount++; } diff --git a/examples_linux/mysgw.cpp b/examples_linux/mysgw.cpp index 7ada2f0b9..9812c4f55 100644 --- a/examples_linux/mysgw.cpp +++ b/examples_linux/mysgw.cpp @@ -16,7 +16,7 @@ * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. */ - + #include #include #include @@ -78,14 +78,17 @@ #undef ARDUINO -void setup() { +void setup() +{ // Setup locally attached sensors } -void presentation() { - // Present locally attached sensors here +void presentation() +{ + // Present locally attached sensors here } -void loop() { +void loop() +{ // Send locally attached sensors data here } diff --git a/projects/SublimeText/MySensors.sublime-project b/projects/SublimeText/MySensors.sublime-project index 8b2d26847..6817c1eea 100644 --- a/projects/SublimeText/MySensors.sublime-project +++ b/projects/SublimeText/MySensors.sublime-project @@ -28,11 +28,11 @@ // The coding style is documented here: https://www.mysensors.org/download/contributing "AStyleFormatter": { - "debug": true, - "autoformat_on_save": false, + "debug": false, + "autoformat_on_save": true, "options_c": { - "additional_options_file": "$project_path/../../.astylerc", + "additional_options_file": "$project_path/../../.tools/astyle/config/style.cfg", "use_only_additional_options": true }, "options_c++": diff --git a/tests/Arduino/sketches/serial_gateway_no_transport_full_debug/serial_gateway_no_transport_full_debug.ino b/tests/Arduino/sketches/serial_gateway_no_transport_full_debug/serial_gateway_no_transport_full_debug.ino index 4db3a7023..dcc685f0d 100644 --- a/tests/Arduino/sketches/serial_gateway_no_transport_full_debug/serial_gateway_no_transport_full_debug.ino +++ b/tests/Arduino/sketches/serial_gateway_no_transport_full_debug/serial_gateway_no_transport_full_debug.ino @@ -18,7 +18,7 @@ * ******************************* */ - + #define MY_DEBUG #define MY_GATEWAY_SERIAL #include \ No newline at end of file From 37881d56babf058e37713ae99c8065eba64e0235 Mon Sep 17 00:00:00 2001 From: Olivier Date: Sat, 10 Dec 2016 21:46:52 +0100 Subject: [PATCH 149/167] Fix Cppcheck warnings (#684) --- core/MyProtocolMySensors.cpp | 2 +- core/MySensorsCore.cpp | 6 ++++-- drivers/RFM69/RFM69.cpp | 7 ++----- drivers/RFM69/RFM69.h | 5 +++++ drivers/RFM95/RFM95.cpp | 10 +++++----- drivers/RFM95/RFM95.h | 2 +- 6 files changed, 18 insertions(+), 14 deletions(-) diff --git a/core/MyProtocolMySensors.cpp b/core/MyProtocolMySensors.cpp index a591891db..0c7308560 100755 --- a/core/MyProtocolMySensors.cpp +++ b/core/MyProtocolMySensors.cpp @@ -60,8 +60,8 @@ bool protocolParse(MyMessage &message, char *inputString) case 5: // Variable value if (command == C_STREAM) { blen = 0; - uint8_t val; while (*str) { + uint8_t val; val = protocolH2i(*str++) << 4; val += protocolH2i(*str++); bvalue[blen] = val; diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 934eeb137..82b64d4c5 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -426,11 +426,13 @@ bool _processInternalMessages(void) #if defined(MY_GATEWAY_FEATURE) // registeration requests are exclusively handled by GW/Controller #if !defined(MY_REGISTRATION_CONTROLLER) - // auto registration if version compatible - bool approveRegistration = true; + bool approveRegistration; #if defined(MY_CORE_COMPATIBILITY_CHECK) approveRegistration = (_msg.getByte() >= MY_CORE_MIN_VERSION); +#else + // auto registration if version compatible + approveRegistration = true; #endif #if (F_CPU>16000000) diff --git a/drivers/RFM69/RFM69.cpp b/drivers/RFM69/RFM69.cpp index bd3f3aac0..0e67ea5ad 100644 --- a/drivers/RFM69/RFM69.cpp +++ b/drivers/RFM69/RFM69.cpp @@ -256,10 +256,9 @@ void RFM69::send(uint8_t toAddress, const void* buffer, uint8_t bufferSize, bool bool RFM69::sendWithRetry(uint8_t toAddress, const void* buffer, uint8_t bufferSize, uint8_t retries, uint8_t retryWaitTime) { - uint32_t sentTime; for (uint8_t i = 0; i <= retries; i++) { send(toAddress, buffer, bufferSize, true); - sentTime = millis(); + uint32_t sentTime = millis(); while (millis() - sentTime < retryWaitTime) { if (ACKReceived(toAddress)) { //Serial.print(" ~ms:"); Serial.print(millis() - sentTime); @@ -574,8 +573,6 @@ void SerialPrint_P(PGM_P str, void (*f)(uint8_t) = SerialWrite ) void RFM69::readAllRegs() { - uint8_t regVal; - #if REGISTER_DETAIL int capVal; @@ -590,7 +587,7 @@ void RFM69::readAllRegs() for (uint8_t regAddr = 1; regAddr <= 0x4F; regAddr++) { select(); SPI.transfer(regAddr & 0x7F); // send address + r/w bit - regVal = SPI.transfer(0); + uint8_t regVal = SPI.transfer(0); unselect(); Serial.print(regAddr, HEX); diff --git a/drivers/RFM69/RFM69.h b/drivers/RFM69/RFM69.h index 682319b53..cb6c69791 100644 --- a/drivers/RFM69/RFM69.h +++ b/drivers/RFM69/RFM69.h @@ -111,6 +111,11 @@ class RFM69 _promiscuousMode = false; _powerLevel = 31; _isRFM69HW = isRFM69HW; + _address = RF69_BROADCAST_ADDR; +#if defined (SPCR) && defined (SPSR) + _SPCR = 0; + _SPSR = 0; +#endif } bool initialize(uint8_t freqBand, uint8_t ID, uint8_t networkID=1); //!< initialize diff --git a/drivers/RFM95/RFM95.cpp b/drivers/RFM95/RFM95.cpp index 1ce477300..7a0fc3d14 100644 --- a/drivers/RFM95/RFM95.cpp +++ b/drivers/RFM95/RFM95.cpp @@ -156,7 +156,7 @@ LOCAL bool RFM95_initialise(const float frequency) (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); const rfm95_modemConfig_t configuration = { MY_RFM95_MODEM_CONFIGRUATION }; - RFM95_setModemRegisters(configuration); + RFM95_setModemRegisters(&configuration); RFM95_setPreambleLength(RFM95_PREAMBLE_LENGTH); RFM95_setFrequency(frequency); // set power level @@ -331,11 +331,11 @@ LOCAL bool RFM95_setTxPower(uint8_t powerLevel) } // Sets registers from a canned modem configuration structure -LOCAL void RFM95_setModemRegisters(const rfm95_modemConfig_t config) +LOCAL void RFM95_setModemRegisters(const rfm95_modemConfig_t* config) { - RFM95_writeReg(RFM95_REG_1D_MODEM_CONFIG1, config.reg_1d); - RFM95_writeReg(RFM95_REG_1E_MODEM_CONFIG2, config.reg_1e); - RFM95_writeReg(RFM95_REG_26_MODEM_CONFIG3, config.reg_26); + RFM95_writeReg(RFM95_REG_1D_MODEM_CONFIG1, config->reg_1d); + RFM95_writeReg(RFM95_REG_1E_MODEM_CONFIG2, config->reg_1e); + RFM95_writeReg(RFM95_REG_26_MODEM_CONFIG3, config->reg_26); } LOCAL void RFM95_setPreambleLength(const uint16_t preambleLength) diff --git a/drivers/RFM95/RFM95.h b/drivers/RFM95/RFM95.h index 0a35f293c..110b165d8 100644 --- a/drivers/RFM95/RFM95.h +++ b/drivers/RFM95/RFM95.h @@ -291,7 +291,7 @@ LOCAL uint8_t RFM95_getAddress(void); * bandwidth, spreading factor etc. * @param config See modemConfig_t and references therein */ -LOCAL void RFM95_setModemRegisters(const rfm95_modemConfig_t config); +LOCAL void RFM95_setModemRegisters(const rfm95_modemConfig_t* config); /** * @brief Tests whether a new message is available * @return True if a new, complete, error-free uncollected message is available to be retreived by @ref RFM95_recv() From 28e0086291fd6ef399c37006833ef753ad323387 Mon Sep 17 00:00:00 2001 From: Bruce Lacey Date: Sun, 11 Dec 2016 00:40:32 -0800 Subject: [PATCH 150/167] Refactored tools structure & conventions for reuse (#685) 1. All common tools are hosted and managed in the tools directory (used for both local development and continuous integration) 2. Each tool comprises a directory, akin to a bundle, that encapsulates declarative command-line options, configuration files and a run script 3. A single bootstrap script configures a development environment 4. A lightweight runtime provides a common set of convenience functions and variables to all scripts References #672 --- .editorconfig | 2 +- .tools/.bundle_runtime.sh | 95 +++++++ .tools/README.md | 259 ++++++++++++++++++ .tools/astyle/options.sh | 5 + .tools/astyle/run.sh | 19 ++ .tools/bootstrap-dev.sh | 83 ++++++ .../cppcheck/config}/avr.xml | 0 .../cppcheck/config}/includes.cfg | 0 .../cppcheck/config}/suppressions.cfg | 0 .tools/cppcheck/options.sh | 12 + .tools/cppcheck/run.sh | 19 ++ .tools/hooks/pre-commit.sh | 33 +++ hooks/install-hooks.sh | 21 -- hooks/pre-commit.sh | 57 ---- 14 files changed, 526 insertions(+), 79 deletions(-) create mode 100755 .tools/.bundle_runtime.sh create mode 100644 .tools/README.md create mode 100755 .tools/astyle/options.sh create mode 100755 .tools/astyle/run.sh create mode 100755 .tools/bootstrap-dev.sh rename {tools/cppcheck => .tools/cppcheck/config}/avr.xml (100%) rename {tools/cppcheck => .tools/cppcheck/config}/includes.cfg (100%) rename {tools/cppcheck => .tools/cppcheck/config}/suppressions.cfg (100%) create mode 100755 .tools/cppcheck/options.sh create mode 100755 .tools/cppcheck/run.sh create mode 100755 .tools/hooks/pre-commit.sh delete mode 100755 hooks/install-hooks.sh delete mode 100755 hooks/pre-commit.sh diff --git a/.editorconfig b/.editorconfig index c2b4a9aa7..f74d4a187 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,7 +9,7 @@ end_of_line = lf charset = utf-8 # For all source code -[*.{c,cpp,h,ino}] +[*.{c,cpp,h,ino,sh}] insert_final_newline = true indent_style = tab indent_size = 2 diff --git a/.tools/.bundle_runtime.sh b/.tools/.bundle_runtime.sh new file mode 100755 index 000000000..f27f650a0 --- /dev/null +++ b/.tools/.bundle_runtime.sh @@ -0,0 +1,95 @@ +#!/bin/bash +### +# +# Tool runtime shim that provides a simple API for running +# tool bundles and convenience functions for other tool developers. +# +## +log() { IFS=" "; >&2 printf "%s\n" "$*"; } +warn() { IFS=" "; >&2 printf "\e[33m%s\e[m\n" "$*"; } +err() { IFS=" "; >&2 printf '\e[31m%s\e[m\n' "$*"; exit 1; } + +is_supported_os() +{ + [[ ${1} == darwin* ]] || [[ ${1} == linux-gnu ]] || [[ ${1} == freebsd ]] || [[ ${1} == msys ]] || [[ ${1} == cygwin ]] +} + +is_installed() +{ + which "${1}" > /dev/null 2>&1 +} + +tools_dir() +{ + git_config_tools_dir='git config mysensors.toolsdir' + + # Set mysensors.toolsdir in git config if it hasn't been set + if [ ! $($git_config_tools_dir) ]; then + $git_config_tools_dir "$( cd "$(dirname "${BASH_SOURCE[0]}")"; git rev-parse --show-prefix )" + git config alias.mystoolspath '![ -z "${GIT_PREFIX}" ] || cd ${GIT_PREFIX}; echo $(git rev-parse --show-cdup)$(git config mysensors.toolsdir)' + fi + + $git_config_tools_dir +} + +configure_git_tool_aliases() +{ + find "$(git mystoolspath)" -name run.sh -print0 | while IFS= read -r -d '' bundle; do + local tool="$(basename "$(dirname "${bundle}")")" + git config alias.${tool} '!f() { $(git mystoolspath)'${tool}'/run.sh $@; }; f' + done +} + +bootstrap_cksum() +{ + echo $(git ls-files -s -- $(git mystoolspath)bootstrap-dev.sh | cut -d' ' -f2) +} + +bootstrap_version() +{ + git_config_bootstrap_version='git config mysensors.bootstrap-cksum' + if [[ $1 == --set ]]; then + $git_config_bootstrap_version $(bootstrap_cksum) + else + echo $($git_config_bootstrap_version) + fi +} + +environment_outdated() +{ + [[ $(bootstrap_version) != $(bootstrap_cksum) ]] +} + +modifiedSourceFiles() +{ + against=$(git rev-parse --verify HEAD >/dev/null 2>&1 && echo HEAD || echo 4b825dc642cb6eb9a060e54bf8d69288fbee4904) + git diff $1 --diff-filter=AM --name-only $against | grep -E '.*\.(c|cpp|h|hpp|ino)$' +} + +stagedSourceFiles() +{ + modifiedSourceFiles '--cached' +} + +runBundle() +{ + local bundle="$(dirname "${0}")" + local tool=$(basename "${bundle}") + + local CMD_OPTIONS=$( TOOLCONFIG="${bundle}/config" "${bundle}/options.sh" ) + + $tool $CMD_OPTIONS "$@" +} + +### +# Common environment variables +# +$(git rev-parse --is-inside-work-tree --quiet >/dev/null 2>&1) || err "Working directory is not a git repository. aborting..." + +if environment_outdated && [[ $(basename "${0}") != *bootstrap* ]]; then + err "Your environment is out of date... Re-run $(git mystoolspath)bootstrap-dev.sh and try again" +fi + +GITREPO=$(git rev-parse --show-toplevel) +GITDIR=$(git rev-parse --git-dir) +TOOLSDIR="$(tools_dir)" diff --git a/.tools/README.md b/.tools/README.md new file mode 100644 index 000000000..694c4d349 --- /dev/null +++ b/.tools/README.md @@ -0,0 +1,259 @@ +# Development Tools + +### Overview + +This directory hosts MySensors development tools. The following +conventions are employed to facilitate consistent re-use/invocation +across modalitiies (e.g. local development, continuous integration, +editor linters, etc.) + +1. All common tools are hosted and managed in + the tools directory (used for both local development + and continuous integration) +2. Each tool comprises a directory, akin to a bundle, + that encapsulates declarative command-line options, + configuration files and a run script +3. A single bootstrap script configures a + development environment +4. A lightweight runtime provides a common set of + convenience functions and variables to all scripts +5. Support for all MySensors development environments + +### Usage + +The [boostrap-dev](bootstrap-dev.sh) script completely configures a +development environment. The boostrap-dev script validates development +pre-requisites such as verifying the git repo ```origin``` & +```upstream``` remotes, tools needed for the git client hooks, +installing local commit hooks, and creating git aliases, etc. + +```shell-script +$ cd MySensors # git repo +$ .tools/bootstrap-dev.sh +Checking operating system support: darwin16... +Checking github 'origin' & 'upstream' remotes... +Checking tool/utility pre-requisites... +Installing git client-side hooks... +Configuring git aliases for running mysensor tool bundles... +Successfully configured your repo for MySensors development... Thanks for your support! +$ +``` +**Note:** If the bootstrap can not find required command-line +utilities, you will be requested to install the required tools and +re-run bootstrap.sh. See [Installation instructions for pre-requisite +tools](#installtools). + +Once the bootstrapping process is complete, a git alias for each tool +is available to conveniently run the tool with the pre-configured +mysensors options and settings (no need to remember all those +command-line options or where the configuration files reside). +Furthermore, you can run the command against staged files, unstaged +modified files or a list of files common to most git commands. + +```shell-script +$ # Run cppcheck on an individual file +$ git cppcheck core/MyMessage.cpp +$ +$ # Run cppcheck on all changed files +$ git cppcheck +$ +$ # Run astyle on staged files +$ git astyle --cached +``` + +Available tool aliases: + +* git cppcheck [--cached] [files] +* git astyle [--cached] [files] + +Finally, to maintain code quality and a legible git revision history, +two git hooks are installed that will trigger whenever you commit +changes to your local repo. The hooks will examine your changes to +ensure they satisfy the [MySensors Code Contribution +Guidelines](https://www.mysensors.org/download/contributing) before +you push your changes to GitHub for merging by the core MySensors +team. Gitler will also enforce the coding guidelines so the hooks are +provided to reduce development cycle times by detecting standards +variances locally before pushing to GitHub. + +### Installation instructions for pre-requisite tools + +This first time you run the bootstrap script, it may inform you that +certain development tools are missing from your path or system: + +``` +Checking operating system support: darwin16... +Checking github 'origin' & 'upstream' remotes... +Checking tool/utility prerequisites... +astyle not installed or not in current path. +cppcheck not installed or not in current path. +One or more required tools not found. Install required tools and re-run .tools/bootstrap-dev.sh +``` + +To finish the bootstrap process, you will need to install the required +tools for your specific operating system as follows. Currently we use +Astyle 2.0.5 or later and Cppcheck 1.76 or later. Once you have +installed AStyle and Cppcheck, re-run bootstrap-dev.sh to finish +configuring your development environment. + +##### macOS + +```brew install astyle cppcheck``` + +#### Linux Xenial or later + +```apt-get install astyle cppcheck``` + +#### Linux Trusty or earlier + +##### Note: The apt versions are too old on Trusty so follow the [Linux - Build and Install from Source](#buildFromSource) instructions + +##### Windows - GitHub Git Shell + +###### *IMPORTANT: Be sure to launch PowerShell As Administrator* + +``` +### Install AStyle + +# Download +iwr 'https://sourceforge.net/projects/astyle/files/astyle/astyle%202.05.1/AStyle_2.05.1_windows.zip/download' -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox -OutFile astyle.2.05.zip + +# Unzip the filed & move the C:\Program Files +expand-archive astyle.2.05.zip +mv .\astyle.2.05 'C:\Program Files\AStyle\' + +# Add AStyle to your path +[Environment]::SetEnvironmentVariable("Path", $env:Path + ";C:\Program Files\AStyle\bin", [EnvironmentVariableTarget]::Machine) + +### Install Cppcheck (either 64-bit or 32-bit depending upon your version of Windows - pick one below) + +# 64-bit +iwr 'http://github.com/danmar/cppcheck/releases/download/1.76.1/cppcheck-1.76.1-x64-Setup.msi' -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox -OutFile cppcheck-1.76.1-Setup.msi + +# 32-bit +iwr 'http://github.com/danmar/cppcheck/releases/download/1.76.1/cppcheck-1.76.1-x86-Setup.msi' -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox -OutFile cppcheck-1.76.1-Setup.msi + +# Launch installer to install Cppcheck +& .\cppcheck-1.76.1-Setup.msi + +### Add Cppcheck to your path +[Environment]::SetEnvironmentVariable("Path", $env:Path + ";C:\Program Files\Cppcheck", [EnvironmentVariableTarget]::Machine) + +### At this point you need to reboot for the path changes to take effect +``` + +##### Windows - bash + +###### NOTE: At the time of this writing, the apt vresions of cppcheck and astyle are too old. Follow the [Linux - Build and Install from Source](#buildFromSource) instructions + +##### Windows - Cygwin +``` +Run Either Cygwin Setup-x86-64.exe or Setup-x86.exe depending upon your OS. Select and install astyle and cppcheck +``` + +##### Linux - Build and Install from Source + +``` +### Install AStyle + +# Download +curl -L 'https://sourceforge.net/projects/astyle/files/astyle/astyle%202.05.1/astyle_2.05.1_linux.tar.gz/download' | tar xvz + +# Compile and install +cd astyle/build/gcc && sudo make shared release shared static install + +### Install Cppcheck + +# Download +curl -L 'https://sourceforge.net/projects/cppcheck/files/cppcheck/1.76.1/cppcheck-1.76.1.tar.gz/download' | tar xvz + +# Compile and install +sudo apt-get install libpcre++-dev +sudo make SRCDIR=build CFGDIR=/usr/share/cppcheck HAVE_RULES=yes CXXFLAGS="-O2 -DNDEBUG -Wall -Wno-sign-compare -Wno-unused-function" install + +``` + +### Implementation Details + +*This section is intended for developers curious about the +implementation details or interested in extending the development +environment to support additional tools, aliases, etc.* + +A lightweight [runtime](.bundle_runtime.sh) (less than 70 lines of +code) provides a simple API to consistently run the MySensors toolset +across modalities including, but not limited to, local development and +continuous integration. The core concept is that each tool +encapsulates all runtime configuration settings in a simple, +stand-alone bundle, that can be executed by the bundle runtime. The +runtime provides an API to execute a tool bundle along with +convenience functions and environment variables common to all tools. + +Each tool bundle is laid out as follows: + +``` +${TOOLSDIR} [e.g. ${GITREPO}/.tools}] +.../tool [e.g. cppcheck, astyle] +....../run.sh [tool run script] +....../options.sh [command-line options] +....../config [supporting config files] +........./some.cfg +``` + +All bundle runtime dependencies are defined withing the namespace / +context of a git repo so users are free to rename or move repos or +even use multiple copies of the same repo without encountering +intra-repo tool settings/configuration conflicts. + +During the bootstrap process, certain keys and aliases are defined +that the runtime leverages. + +#####git config keys + +* mysensors.toolsdir = .tools (defined as a repo-relative path - location agnostic) +* mysensors.bootstrap-cksum = \ + +#####git aliases + +* mystoolspath = *returns the absolute path to the tools dir* +* \ = *(e.g. cppcheck) runs the tool bundle* + + NOTE: The \ aliases are auto-generated by enumerating the bundles located +in *mystoolspath*. + +While the ```git args``` API is designed to cover many the +common use cases, tool and hook authors may need to source the +[runtime](.bundle_runtime.sh) into their script context in order to +use the convenience functions and environment variables as follows: + +```shell-script +. "$(git config mystoolspath).bundle_runtime.sh" +``` + +The runtime shim will instantiate the following environment variables +and convenience functions in the script context for use within a tool +or script. + +``` +TOOLSDIR - absolute path to repo tools dir. Maintained in + a location-agnostic fashion (e.g. if the user + moves the repo, changes tools directory within + repo, etc. +GITREPO - absolute path to the git repo +GITDIR - absolute path to the repo .git directory + +runBundle() - Run a given tool / bundle +is_installed() - true if a given utility is installed +supported_os() - true if running on a supported os +log() - log a message in default color to console +warn() - log a message in yellow to console +err() - log a message in red and exit with non-zero status +``` + +Many of the aforementioned details can be safely ignored if you want +to add a new development tool to the toolset. Simply create a bundle +that follows the layout above, declare the tool command-line options +in the [bundle]/options.sh and any configuration files in +[bundle]/config/. While it should not be necessary to alter the +bundle execution behavior beyond declaring command-line options and +configuration files, you can override it by modifing the [bundle] +run.sh script. diff --git a/.tools/astyle/options.sh b/.tools/astyle/options.sh new file mode 100755 index 000000000..64f922d51 --- /dev/null +++ b/.tools/astyle/options.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +OPTIONS="--options="${TOOLCONFIG}"/style.cfg -n" + +echo $OPTIONS diff --git a/.tools/astyle/run.sh b/.tools/astyle/run.sh new file mode 100755 index 000000000..81d18f68e --- /dev/null +++ b/.tools/astyle/run.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Instantiate the bundle runtime shim +. "$(git mystoolspath).bundle_runtime.sh" + +# Astyle takes one or more files as an argument. +# --cached or for changed +if [[ $# = 0 ]]; then + for file in $(modifiedSourceFiles); do + runBundle $file + done +elif [[ $1 = '--cached' ]]; then + for file in $(stagedSourceFiles); do + runBundle $file + done +else + eval "set -- $(git rev-parse --sq --prefix "$GIT_PREFIX" "$@")" + runBundle "$@" +fi diff --git a/.tools/bootstrap-dev.sh b/.tools/bootstrap-dev.sh new file mode 100755 index 000000000..ce51abab4 --- /dev/null +++ b/.tools/bootstrap-dev.sh @@ -0,0 +1,83 @@ +#!/bin/bash +### +# OVERVIEW: +# This script bootstraps the MySensors development environment. +# +# USAGE: +# git clone https://github.com/mysensors/MySensors.git +# cd MySensors +# .tools/bootstrap-dev.sh +## + +## +# Import common utility functions and environment variables +. "$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd)/.bundle_runtime.sh" + +check_tool_prerequisites() +{ + local err=0 + for preReq in ${1}; do + if ! is_installed $preReq; then + warn "$preReq not installed or not in current path." + err=1 + fi + done + return $err +} + +check_git_remote() +{ + local url=$( git config --get remote.${1}.url ) + [[ $url == ${2} ]] +} + +install_hooks() +{ + for hook in "${1}"/*.sh; do + local hookname=$(basename $hook) + $(cd "${GITDIR}/hooks"; ln -s -f "../../${TOOLSDIR}hooks/${hookname}" "${hookname%.sh}") + done +} + +### +# Main entry +# +# 1. Check that we are bootstrapping a supported OS/environment +# 2. Validate github remotes include valid upstream and origin +# 3. Check for client commit hook pre-requisites +# 4. Install client commit hook pre-requisites +# 5. Define aliases for conveniently running tool bundles +## + +mysrepo="https://github.com/mysensors/MySensors.git" + +#1 +log "Checking operating system support: ${OSTYPE}..." +is_supported_os ${OSTYPE} || { + err "OS ${OSTYPE} is unknown/unsupported, won't install anything" +} + +#2 +log "Checking github 'origin' & 'upstream' remotes..." +check_git_remote "origin" "${mysrepo}" && warn "Git \"origin\" should point to your github fork, not the github MySensors repo ${mysrep}" + +check_git_remote "upstream" "${mysrepo}" || { + warn "Git \"upstream\" remote not found or incorrectly defined. Configuring remote upstream --> ${mysrepo}..." + git remote add upstream "${mysrepo}" || err "git remote add ${mysrep} failed due to error $?" +} + +#3 +log "Checking tool/utility prerequisites..." +check_tool_prerequisites "astyle cppcheck" || err "One or more required tools not found. Install required tools and re-run ${0}" + +#4 +log "Installing client-side git hooks..." +install_hooks "$(git mystoolspath)hooks" || err "Failed to install git hooks due to error $?..." + +#5 +log "Configuring git aliases for running mysensor tools..." +configure_git_tool_aliases || err "Failed to create git aliases due to error $?..." + +bootstrap_version "--set" + +log "Successfully configured your repo for MySensors development... Thanks for your support!" diff --git a/tools/cppcheck/avr.xml b/.tools/cppcheck/config/avr.xml similarity index 100% rename from tools/cppcheck/avr.xml rename to .tools/cppcheck/config/avr.xml diff --git a/tools/cppcheck/includes.cfg b/.tools/cppcheck/config/includes.cfg similarity index 100% rename from tools/cppcheck/includes.cfg rename to .tools/cppcheck/config/includes.cfg diff --git a/tools/cppcheck/suppressions.cfg b/.tools/cppcheck/config/suppressions.cfg similarity index 100% rename from tools/cppcheck/suppressions.cfg rename to .tools/cppcheck/config/suppressions.cfg diff --git a/.tools/cppcheck/options.sh b/.tools/cppcheck/options.sh new file mode 100755 index 000000000..5cc32d2b1 --- /dev/null +++ b/.tools/cppcheck/options.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +OPTIONS="--quiet \ + --error-exitcode=1 \ + --force \ + --enable=style,information \ + --library=avr \ + --platform="${TOOLCONFIG}"/avr.xml \ + --includes-file="${TOOLCONFIG}"/includes.cfg \ + --suppressions-list="${TOOLCONFIG}"/suppressions.cfg" + +echo $OPTIONS diff --git a/.tools/cppcheck/run.sh b/.tools/cppcheck/run.sh new file mode 100755 index 000000000..f674d4586 --- /dev/null +++ b/.tools/cppcheck/run.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Instantiate the tool runtime shim +. "$(git mystoolspath).bundle_runtime.sh" + +# cppcheck takes one or more files as an argument. +# --cached or for changed +if [[ $# = 0 ]]; then + for file in $(modifiedSourceFiles); do + runBundle $file + done +elif [[ $1 = '--cached' ]]; then + for file in $(stagedSourceFiles); do + runBundle $file + done +else + eval "set -- $(git rev-parse --sq --prefix "$GIT_PREFIX" "$@")" + runBundle "$@" +fi diff --git a/.tools/hooks/pre-commit.sh b/.tools/hooks/pre-commit.sh new file mode 100755 index 000000000..88b6f115b --- /dev/null +++ b/.tools/hooks/pre-commit.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# instantiate mysensors tool runtime shim +. "$(git mystoolspath).bundle_runtime.sh" + +### +# astyle +# +errorsDetected=0 +for file in $(stagedSourceFiles); do + git astyle $file >/dev/null + if ! git diff-files --quiet $file >&2; then + warn "$file has been updated to match the MySensors core coding style." + errorsDetected=1 + fi +done + +[ $errorsDetected == 1 ] && err "Styling updates applied. Review the changes and use 'git add' to update your staged files." + +### +# cppcheck +# +errorsDetected=0 +for file in $(stagedSourceFiles); do + if ! git cppcheck $file >/dev/null; then + warn "$file failed static analysis." + errorsDetected=1 + fi +done + +[ $errorsDetected == 1 ] && err "Correct the errors until cppcheck passees using 'git cppcheck --cached'." + +exit 0 diff --git a/hooks/install-hooks.sh b/hooks/install-hooks.sh deleted file mode 100755 index 3245cba7b..000000000 --- a/hooks/install-hooks.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -PRECOMMIT=hooks/pre-commit -GITROOT=$(git rev-parse --git-dir) -if [[ "$OSTYPE" == "linux-gnu" ]]; then - rm -f $GITROOT/$PRECOMMIT - ln -s ../../$PRECOMMIT.sh $GITROOT/$PRECOMMIT -elif [[ "$OSTYPE" == "darwin"* ]]; then - rm -f $GITROOT/$PRECOMMIT - ln -s ../../$PRECOMMIT.sh $GITROOT/$PRECOMMIT -elif [[ "$OSTYPE" == "cygwin" ]]; then - rm -f $GITROOT/$PRECOMMIT - cp $GITROOT/../$PRECOMMIT.sh $GITROOT/$PRECOMMIT -elif [[ "$OSTYPE" == "msys" ]]; then - rm -f $GITROOT/$PRECOMMIT - cp $GITROOT/../$PRECOMMIT.sh $GITROOT/$PRECOMMIT -elif [[ "$OSTYPE" == "freebsd"* ]]; then - rm -f $GITROOT/$PRECOMMIT - ln -s ../../$PRECOMMIT.sh $GITROOT/$PRECOMMIT -else - echo "Unknown/unsupported OS, won't install anything" -fi diff --git a/hooks/pre-commit.sh b/hooks/pre-commit.sh deleted file mode 100755 index e31904649..000000000 --- a/hooks/pre-commit.sh +++ /dev/null @@ -1,57 +0,0 @@ -#!/bin/sh -if git rev-parse --verify HEAD >/dev/null 2>&1 -then - against=HEAD -else - # Initial commit: diff against an empty tree object - against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 -fi - -OPTIONS="--options=.astylerc -n" -CPPCHECK_OPTIONS="--quiet --error-exitcode=1 --force --enable=style,information --library=avr --platform=tools/cppcheck/avr.xml --includes-file=tools/cppcheck/includes.cfg --suppressions-list=tools/cppcheck/suppressions.cfg" -FILES=$(git diff-index --cached $against | grep -E '[MA] .*\.(c|cpp|h|hpp|ino)$' | cut -d' ' -f 2) - -RETURN=0 -ASTYLE=$(which astyle >/dev/null) -if [ $? -ne 0 ]; then - echo "astyle not installed or not in current path. Unable to check source file format policy. Make sure you have a clean commit, or the CI system will reject your pull request." >&2 -else - ASTYLE=astyle - for FILE in $FILES; do - $ASTYLE $OPTIONS $FILE >/dev/null - $(git diff-files --quiet $FILE) >&2 - if [ $? -ne 0 ]; then - echo "[!] $FILE has been updated to match the MySensors core coding style." >&2 - RETURN=1 - fi - done - - if [ $RETURN -ne 0 ]; then - echo "" >&2 - echo "Styling updates applied. Review the changes and use 'git add' to update your staged data." >&2 - exit $RETURN - fi -fi - -RETURN=0 -CPPCHECK=$(which cppcheck >/dev/null) -if [ $? -ne 0 ]; then - echo "cppcheck not installed or not in current path. Unable to do static code analysis. Make sure you have a clean commit, or the CI system will reject your pull request." >&2 -else - CPPCHECK=cppcheck - for FILE in $FILES; do - $CPPCHECK $CPPCHECK_OPTIONS $FILE 2>&1 - if [ $? -eq 1 ]; then - echo "[!] $FILE has coding issues." >&2 - RETURN=1 - fi - done - - if [ $RETURN -ne 0 ]; then - echo "" >&2 - echo "Make sure you have run cppcheck 1.76.1 or newer cleanly with the following options:" >&2 - echo $CPPCHECK $CPPCHECK_OPTIONS $FILES >&2 - exit 1 - fi -fi -exit $RETURN From 68ce74d11a5f806c351c08497f09779193b328ef Mon Sep 17 00:00:00 2001 From: Bruce Lacey Date: Sun, 11 Dec 2016 13:08:14 -0800 Subject: [PATCH 151/167] Rename .tools to .mystools for Arduino IDE (#686) * The Arduino IDE considers the .tools directory special and warns if it finds .tools the repo References #672 --- {.tools => .mystools}/.bundle_runtime.sh | 2 +- {.tools => .mystools}/README.md | 9 +++++---- {.tools => .mystools}/astyle/config/style.cfg | 0 {.tools => .mystools}/astyle/options.sh | 0 {.tools => .mystools}/astyle/run.sh | 0 {.tools => .mystools}/bootstrap-dev.sh | 4 ++-- {.tools => .mystools}/cppcheck/config/avr.xml | 0 {.tools => .mystools}/cppcheck/config/includes.cfg | 0 {.tools => .mystools}/cppcheck/config/suppressions.cfg | 0 {.tools => .mystools}/cppcheck/options.sh | 0 {.tools => .mystools}/cppcheck/run.sh | 0 {.tools => .mystools}/hooks/pre-commit.sh | 0 12 files changed, 8 insertions(+), 7 deletions(-) rename {.tools => .mystools}/.bundle_runtime.sh (97%) rename {.tools => .mystools}/README.md (97%) rename {.tools => .mystools}/astyle/config/style.cfg (100%) rename {.tools => .mystools}/astyle/options.sh (100%) rename {.tools => .mystools}/astyle/run.sh (100%) rename {.tools => .mystools}/bootstrap-dev.sh (95%) rename {.tools => .mystools}/cppcheck/config/avr.xml (100%) rename {.tools => .mystools}/cppcheck/config/includes.cfg (100%) rename {.tools => .mystools}/cppcheck/config/suppressions.cfg (100%) rename {.tools => .mystools}/cppcheck/options.sh (100%) rename {.tools => .mystools}/cppcheck/run.sh (100%) rename {.tools => .mystools}/hooks/pre-commit.sh (100%) diff --git a/.tools/.bundle_runtime.sh b/.mystools/.bundle_runtime.sh similarity index 97% rename from .tools/.bundle_runtime.sh rename to .mystools/.bundle_runtime.sh index f27f650a0..744e9ba74 100755 --- a/.tools/.bundle_runtime.sh +++ b/.mystools/.bundle_runtime.sh @@ -24,7 +24,7 @@ tools_dir() git_config_tools_dir='git config mysensors.toolsdir' # Set mysensors.toolsdir in git config if it hasn't been set - if [ ! $($git_config_tools_dir) ]; then + if [ ! $($git_config_tools_dir) -o ! -d $($git_config_tools_dir) ]; then $git_config_tools_dir "$( cd "$(dirname "${BASH_SOURCE[0]}")"; git rev-parse --show-prefix )" git config alias.mystoolspath '![ -z "${GIT_PREFIX}" ] || cd ${GIT_PREFIX}; echo $(git rev-parse --show-cdup)$(git config mysensors.toolsdir)' fi diff --git a/.tools/README.md b/.mystools/README.md similarity index 97% rename from .tools/README.md rename to .mystools/README.md index 694c4d349..64dce0e2a 100644 --- a/.tools/README.md +++ b/.mystools/README.md @@ -23,7 +23,7 @@ editor linters, etc.) The [boostrap-dev](bootstrap-dev.sh) script completely configures a development environment. The boostrap-dev script validates development -pre-requisites such as verifying the git repo ```origin``` & +prerequisites such as verifying the git repo ```origin``` & ```upstream``` remotes, tools needed for the git client hooks, installing local commit hooks, and creating git aliases, etc. @@ -32,7 +32,7 @@ $ cd MySensors # git repo $ .tools/bootstrap-dev.sh Checking operating system support: darwin16... Checking github 'origin' & 'upstream' remotes... -Checking tool/utility pre-requisites... +Checking tool/utility prerequisites... Installing git client-side hooks... Configuring git aliases for running mysensor tool bundles... Successfully configured your repo for MySensors development... Thanks for your support! @@ -40,7 +40,7 @@ $ ``` **Note:** If the bootstrap can not find required command-line utilities, you will be requested to install the required tools and -re-run bootstrap.sh. See [Installation instructions for pre-requisite +re-run bootstrap.sh. See [Installation instructions for prerequisite tools](#installtools). Once the bootstrapping process is complete, a git alias for each tool @@ -76,7 +76,7 @@ team. Gitler will also enforce the coding guidelines so the hooks are provided to reduce development cycle times by detecting standards variances locally before pushing to GitHub. -### Installation instructions for pre-requisite tools +### Installation instructions for prerequisite tools This first time you run the bootstrap script, it may inform you that certain development tools are missing from your path or system: @@ -168,6 +168,7 @@ cd astyle/build/gcc && sudo make shared release shared static install curl -L 'https://sourceforge.net/projects/cppcheck/files/cppcheck/1.76.1/cppcheck-1.76.1.tar.gz/download' | tar xvz # Compile and install +cd cppcheck-1.76.1 sudo apt-get install libpcre++-dev sudo make SRCDIR=build CFGDIR=/usr/share/cppcheck HAVE_RULES=yes CXXFLAGS="-O2 -DNDEBUG -Wall -Wno-sign-compare -Wno-unused-function" install diff --git a/.tools/astyle/config/style.cfg b/.mystools/astyle/config/style.cfg similarity index 100% rename from .tools/astyle/config/style.cfg rename to .mystools/astyle/config/style.cfg diff --git a/.tools/astyle/options.sh b/.mystools/astyle/options.sh similarity index 100% rename from .tools/astyle/options.sh rename to .mystools/astyle/options.sh diff --git a/.tools/astyle/run.sh b/.mystools/astyle/run.sh similarity index 100% rename from .tools/astyle/run.sh rename to .mystools/astyle/run.sh diff --git a/.tools/bootstrap-dev.sh b/.mystools/bootstrap-dev.sh similarity index 95% rename from .tools/bootstrap-dev.sh rename to .mystools/bootstrap-dev.sh index ce51abab4..48e9d5542 100755 --- a/.tools/bootstrap-dev.sh +++ b/.mystools/bootstrap-dev.sh @@ -44,8 +44,8 @@ install_hooks() # # 1. Check that we are bootstrapping a supported OS/environment # 2. Validate github remotes include valid upstream and origin -# 3. Check for client commit hook pre-requisites -# 4. Install client commit hook pre-requisites +# 3. Check for client commit hook prerequisites +# 4. Install client commit hook prerequisites # 5. Define aliases for conveniently running tool bundles ## diff --git a/.tools/cppcheck/config/avr.xml b/.mystools/cppcheck/config/avr.xml similarity index 100% rename from .tools/cppcheck/config/avr.xml rename to .mystools/cppcheck/config/avr.xml diff --git a/.tools/cppcheck/config/includes.cfg b/.mystools/cppcheck/config/includes.cfg similarity index 100% rename from .tools/cppcheck/config/includes.cfg rename to .mystools/cppcheck/config/includes.cfg diff --git a/.tools/cppcheck/config/suppressions.cfg b/.mystools/cppcheck/config/suppressions.cfg similarity index 100% rename from .tools/cppcheck/config/suppressions.cfg rename to .mystools/cppcheck/config/suppressions.cfg diff --git a/.tools/cppcheck/options.sh b/.mystools/cppcheck/options.sh similarity index 100% rename from .tools/cppcheck/options.sh rename to .mystools/cppcheck/options.sh diff --git a/.tools/cppcheck/run.sh b/.mystools/cppcheck/run.sh similarity index 100% rename from .tools/cppcheck/run.sh rename to .mystools/cppcheck/run.sh diff --git a/.tools/hooks/pre-commit.sh b/.mystools/hooks/pre-commit.sh similarity index 100% rename from .tools/hooks/pre-commit.sh rename to .mystools/hooks/pre-commit.sh From 1e37f35dc6626a17e293c1cf8d197996bf87fa75 Mon Sep 17 00:00:00 2001 From: Bruce Lacey Date: Sun, 11 Dec 2016 13:28:37 -0800 Subject: [PATCH 152/167] Revert "Rename .tools to .mystools for Arduino IDE" (#687) --- {.mystools => .tools}/.bundle_runtime.sh | 2 +- {.mystools => .tools}/README.md | 9 ++++----- {.mystools => .tools}/astyle/config/style.cfg | 0 {.mystools => .tools}/astyle/options.sh | 0 {.mystools => .tools}/astyle/run.sh | 0 {.mystools => .tools}/bootstrap-dev.sh | 4 ++-- {.mystools => .tools}/cppcheck/config/avr.xml | 0 {.mystools => .tools}/cppcheck/config/includes.cfg | 0 {.mystools => .tools}/cppcheck/config/suppressions.cfg | 0 {.mystools => .tools}/cppcheck/options.sh | 0 {.mystools => .tools}/cppcheck/run.sh | 0 {.mystools => .tools}/hooks/pre-commit.sh | 0 12 files changed, 7 insertions(+), 8 deletions(-) rename {.mystools => .tools}/.bundle_runtime.sh (97%) rename {.mystools => .tools}/README.md (97%) rename {.mystools => .tools}/astyle/config/style.cfg (100%) rename {.mystools => .tools}/astyle/options.sh (100%) rename {.mystools => .tools}/astyle/run.sh (100%) rename {.mystools => .tools}/bootstrap-dev.sh (95%) rename {.mystools => .tools}/cppcheck/config/avr.xml (100%) rename {.mystools => .tools}/cppcheck/config/includes.cfg (100%) rename {.mystools => .tools}/cppcheck/config/suppressions.cfg (100%) rename {.mystools => .tools}/cppcheck/options.sh (100%) rename {.mystools => .tools}/cppcheck/run.sh (100%) rename {.mystools => .tools}/hooks/pre-commit.sh (100%) diff --git a/.mystools/.bundle_runtime.sh b/.tools/.bundle_runtime.sh similarity index 97% rename from .mystools/.bundle_runtime.sh rename to .tools/.bundle_runtime.sh index 744e9ba74..f27f650a0 100755 --- a/.mystools/.bundle_runtime.sh +++ b/.tools/.bundle_runtime.sh @@ -24,7 +24,7 @@ tools_dir() git_config_tools_dir='git config mysensors.toolsdir' # Set mysensors.toolsdir in git config if it hasn't been set - if [ ! $($git_config_tools_dir) -o ! -d $($git_config_tools_dir) ]; then + if [ ! $($git_config_tools_dir) ]; then $git_config_tools_dir "$( cd "$(dirname "${BASH_SOURCE[0]}")"; git rev-parse --show-prefix )" git config alias.mystoolspath '![ -z "${GIT_PREFIX}" ] || cd ${GIT_PREFIX}; echo $(git rev-parse --show-cdup)$(git config mysensors.toolsdir)' fi diff --git a/.mystools/README.md b/.tools/README.md similarity index 97% rename from .mystools/README.md rename to .tools/README.md index 64dce0e2a..694c4d349 100644 --- a/.mystools/README.md +++ b/.tools/README.md @@ -23,7 +23,7 @@ editor linters, etc.) The [boostrap-dev](bootstrap-dev.sh) script completely configures a development environment. The boostrap-dev script validates development -prerequisites such as verifying the git repo ```origin``` & +pre-requisites such as verifying the git repo ```origin``` & ```upstream``` remotes, tools needed for the git client hooks, installing local commit hooks, and creating git aliases, etc. @@ -32,7 +32,7 @@ $ cd MySensors # git repo $ .tools/bootstrap-dev.sh Checking operating system support: darwin16... Checking github 'origin' & 'upstream' remotes... -Checking tool/utility prerequisites... +Checking tool/utility pre-requisites... Installing git client-side hooks... Configuring git aliases for running mysensor tool bundles... Successfully configured your repo for MySensors development... Thanks for your support! @@ -40,7 +40,7 @@ $ ``` **Note:** If the bootstrap can not find required command-line utilities, you will be requested to install the required tools and -re-run bootstrap.sh. See [Installation instructions for prerequisite +re-run bootstrap.sh. See [Installation instructions for pre-requisite tools](#installtools). Once the bootstrapping process is complete, a git alias for each tool @@ -76,7 +76,7 @@ team. Gitler will also enforce the coding guidelines so the hooks are provided to reduce development cycle times by detecting standards variances locally before pushing to GitHub. -### Installation instructions for prerequisite tools +### Installation instructions for pre-requisite tools This first time you run the bootstrap script, it may inform you that certain development tools are missing from your path or system: @@ -168,7 +168,6 @@ cd astyle/build/gcc && sudo make shared release shared static install curl -L 'https://sourceforge.net/projects/cppcheck/files/cppcheck/1.76.1/cppcheck-1.76.1.tar.gz/download' | tar xvz # Compile and install -cd cppcheck-1.76.1 sudo apt-get install libpcre++-dev sudo make SRCDIR=build CFGDIR=/usr/share/cppcheck HAVE_RULES=yes CXXFLAGS="-O2 -DNDEBUG -Wall -Wno-sign-compare -Wno-unused-function" install diff --git a/.mystools/astyle/config/style.cfg b/.tools/astyle/config/style.cfg similarity index 100% rename from .mystools/astyle/config/style.cfg rename to .tools/astyle/config/style.cfg diff --git a/.mystools/astyle/options.sh b/.tools/astyle/options.sh similarity index 100% rename from .mystools/astyle/options.sh rename to .tools/astyle/options.sh diff --git a/.mystools/astyle/run.sh b/.tools/astyle/run.sh similarity index 100% rename from .mystools/astyle/run.sh rename to .tools/astyle/run.sh diff --git a/.mystools/bootstrap-dev.sh b/.tools/bootstrap-dev.sh similarity index 95% rename from .mystools/bootstrap-dev.sh rename to .tools/bootstrap-dev.sh index 48e9d5542..ce51abab4 100755 --- a/.mystools/bootstrap-dev.sh +++ b/.tools/bootstrap-dev.sh @@ -44,8 +44,8 @@ install_hooks() # # 1. Check that we are bootstrapping a supported OS/environment # 2. Validate github remotes include valid upstream and origin -# 3. Check for client commit hook prerequisites -# 4. Install client commit hook prerequisites +# 3. Check for client commit hook pre-requisites +# 4. Install client commit hook pre-requisites # 5. Define aliases for conveniently running tool bundles ## diff --git a/.mystools/cppcheck/config/avr.xml b/.tools/cppcheck/config/avr.xml similarity index 100% rename from .mystools/cppcheck/config/avr.xml rename to .tools/cppcheck/config/avr.xml diff --git a/.mystools/cppcheck/config/includes.cfg b/.tools/cppcheck/config/includes.cfg similarity index 100% rename from .mystools/cppcheck/config/includes.cfg rename to .tools/cppcheck/config/includes.cfg diff --git a/.mystools/cppcheck/config/suppressions.cfg b/.tools/cppcheck/config/suppressions.cfg similarity index 100% rename from .mystools/cppcheck/config/suppressions.cfg rename to .tools/cppcheck/config/suppressions.cfg diff --git a/.mystools/cppcheck/options.sh b/.tools/cppcheck/options.sh similarity index 100% rename from .mystools/cppcheck/options.sh rename to .tools/cppcheck/options.sh diff --git a/.mystools/cppcheck/run.sh b/.tools/cppcheck/run.sh similarity index 100% rename from .mystools/cppcheck/run.sh rename to .tools/cppcheck/run.sh diff --git a/.mystools/hooks/pre-commit.sh b/.tools/hooks/pre-commit.sh similarity index 100% rename from .mystools/hooks/pre-commit.sh rename to .tools/hooks/pre-commit.sh From 7e1aa82d6e4e6bfd333a498a4310fc9619722d95 Mon Sep 17 00:00:00 2001 From: Bruce Lacey Date: Sun, 11 Dec 2016 13:49:32 -0800 Subject: [PATCH 153/167] Rename .tools to .mystools for Arduino IDE 2 (#688) * The Arduino IDE considers the .tools directory special and warns if it finds .tools the repo * Added detection of .tools directory rename * Corrected README errata References #672 --- {.tools => .mystools}/.bundle_runtime.sh | 2 +- {.tools => .mystools}/README.md | 17 +++++++++-------- {.tools => .mystools}/astyle/config/style.cfg | 0 {.tools => .mystools}/astyle/options.sh | 0 {.tools => .mystools}/astyle/run.sh | 0 {.tools => .mystools}/bootstrap-dev.sh | 6 +++--- {.tools => .mystools}/cppcheck/config/avr.xml | 0 .../cppcheck/config/includes.cfg | 0 .../cppcheck/config/suppressions.cfg | 0 {.tools => .mystools}/cppcheck/options.sh | 0 {.tools => .mystools}/cppcheck/run.sh | 0 {.tools => .mystools}/hooks/pre-commit.sh | 0 12 files changed, 13 insertions(+), 12 deletions(-) rename {.tools => .mystools}/.bundle_runtime.sh (97%) rename {.tools => .mystools}/README.md (95%) rename {.tools => .mystools}/astyle/config/style.cfg (100%) rename {.tools => .mystools}/astyle/options.sh (100%) rename {.tools => .mystools}/astyle/run.sh (100%) rename {.tools => .mystools}/bootstrap-dev.sh (94%) rename {.tools => .mystools}/cppcheck/config/avr.xml (100%) rename {.tools => .mystools}/cppcheck/config/includes.cfg (100%) rename {.tools => .mystools}/cppcheck/config/suppressions.cfg (100%) rename {.tools => .mystools}/cppcheck/options.sh (100%) rename {.tools => .mystools}/cppcheck/run.sh (100%) rename {.tools => .mystools}/hooks/pre-commit.sh (100%) diff --git a/.tools/.bundle_runtime.sh b/.mystools/.bundle_runtime.sh similarity index 97% rename from .tools/.bundle_runtime.sh rename to .mystools/.bundle_runtime.sh index f27f650a0..744e9ba74 100755 --- a/.tools/.bundle_runtime.sh +++ b/.mystools/.bundle_runtime.sh @@ -24,7 +24,7 @@ tools_dir() git_config_tools_dir='git config mysensors.toolsdir' # Set mysensors.toolsdir in git config if it hasn't been set - if [ ! $($git_config_tools_dir) ]; then + if [ ! $($git_config_tools_dir) -o ! -d $($git_config_tools_dir) ]; then $git_config_tools_dir "$( cd "$(dirname "${BASH_SOURCE[0]}")"; git rev-parse --show-prefix )" git config alias.mystoolspath '![ -z "${GIT_PREFIX}" ] || cd ${GIT_PREFIX}; echo $(git rev-parse --show-cdup)$(git config mysensors.toolsdir)' fi diff --git a/.tools/README.md b/.mystools/README.md similarity index 95% rename from .tools/README.md rename to .mystools/README.md index 694c4d349..19a674251 100644 --- a/.tools/README.md +++ b/.mystools/README.md @@ -23,16 +23,16 @@ editor linters, etc.) The [boostrap-dev](bootstrap-dev.sh) script completely configures a development environment. The boostrap-dev script validates development -pre-requisites such as verifying the git repo ```origin``` & +prerequisites such as verifying the git repo ```origin``` & ```upstream``` remotes, tools needed for the git client hooks, installing local commit hooks, and creating git aliases, etc. ```shell-script $ cd MySensors # git repo -$ .tools/bootstrap-dev.sh +$ .mystools/bootstrap-dev.sh Checking operating system support: darwin16... Checking github 'origin' & 'upstream' remotes... -Checking tool/utility pre-requisites... +Checking tool/utility prerequisites... Installing git client-side hooks... Configuring git aliases for running mysensor tool bundles... Successfully configured your repo for MySensors development... Thanks for your support! @@ -40,7 +40,7 @@ $ ``` **Note:** If the bootstrap can not find required command-line utilities, you will be requested to install the required tools and -re-run bootstrap.sh. See [Installation instructions for pre-requisite +re-run bootstrap.sh. See [Installation instructions for prerequisite tools](#installtools). Once the bootstrapping process is complete, a git alias for each tool @@ -76,7 +76,7 @@ team. Gitler will also enforce the coding guidelines so the hooks are provided to reduce development cycle times by detecting standards variances locally before pushing to GitHub. -### Installation instructions for pre-requisite tools +### Installation instructions for prerequisite tools This first time you run the bootstrap script, it may inform you that certain development tools are missing from your path or system: @@ -87,7 +87,7 @@ Checking github 'origin' & 'upstream' remotes... Checking tool/utility prerequisites... astyle not installed or not in current path. cppcheck not installed or not in current path. -One or more required tools not found. Install required tools and re-run .tools/bootstrap-dev.sh +One or more required tools not found. Install required tools and re-run .mystools/bootstrap-dev.sh ``` To finish the bootstrap process, you will need to install the required @@ -168,6 +168,7 @@ cd astyle/build/gcc && sudo make shared release shared static install curl -L 'https://sourceforge.net/projects/cppcheck/files/cppcheck/1.76.1/cppcheck-1.76.1.tar.gz/download' | tar xvz # Compile and install +cd cppcheck-1.76.1 sudo apt-get install libpcre++-dev sudo make SRCDIR=build CFGDIR=/usr/share/cppcheck HAVE_RULES=yes CXXFLAGS="-O2 -DNDEBUG -Wall -Wno-sign-compare -Wno-unused-function" install @@ -191,7 +192,7 @@ convenience functions and environment variables common to all tools. Each tool bundle is laid out as follows: ``` -${TOOLSDIR} [e.g. ${GITREPO}/.tools}] +${TOOLSDIR} [e.g. ${GITREPO}/.mystools}] .../tool [e.g. cppcheck, astyle] ....../run.sh [tool run script] ....../options.sh [command-line options] @@ -209,7 +210,7 @@ that the runtime leverages. #####git config keys -* mysensors.toolsdir = .tools (defined as a repo-relative path - location agnostic) +* mysensors.toolsdir = .mystools (defined as a repo-relative path - location agnostic) * mysensors.bootstrap-cksum = \ #####git aliases diff --git a/.tools/astyle/config/style.cfg b/.mystools/astyle/config/style.cfg similarity index 100% rename from .tools/astyle/config/style.cfg rename to .mystools/astyle/config/style.cfg diff --git a/.tools/astyle/options.sh b/.mystools/astyle/options.sh similarity index 100% rename from .tools/astyle/options.sh rename to .mystools/astyle/options.sh diff --git a/.tools/astyle/run.sh b/.mystools/astyle/run.sh similarity index 100% rename from .tools/astyle/run.sh rename to .mystools/astyle/run.sh diff --git a/.tools/bootstrap-dev.sh b/.mystools/bootstrap-dev.sh similarity index 94% rename from .tools/bootstrap-dev.sh rename to .mystools/bootstrap-dev.sh index ce51abab4..e26467102 100755 --- a/.tools/bootstrap-dev.sh +++ b/.mystools/bootstrap-dev.sh @@ -6,7 +6,7 @@ # USAGE: # git clone https://github.com/mysensors/MySensors.git # cd MySensors -# .tools/bootstrap-dev.sh +# .mystools/bootstrap-dev.sh ## ## @@ -44,8 +44,8 @@ install_hooks() # # 1. Check that we are bootstrapping a supported OS/environment # 2. Validate github remotes include valid upstream and origin -# 3. Check for client commit hook pre-requisites -# 4. Install client commit hook pre-requisites +# 3. Check for client commit hook prerequisites +# 4. Install client commit hook prerequisites # 5. Define aliases for conveniently running tool bundles ## diff --git a/.tools/cppcheck/config/avr.xml b/.mystools/cppcheck/config/avr.xml similarity index 100% rename from .tools/cppcheck/config/avr.xml rename to .mystools/cppcheck/config/avr.xml diff --git a/.tools/cppcheck/config/includes.cfg b/.mystools/cppcheck/config/includes.cfg similarity index 100% rename from .tools/cppcheck/config/includes.cfg rename to .mystools/cppcheck/config/includes.cfg diff --git a/.tools/cppcheck/config/suppressions.cfg b/.mystools/cppcheck/config/suppressions.cfg similarity index 100% rename from .tools/cppcheck/config/suppressions.cfg rename to .mystools/cppcheck/config/suppressions.cfg diff --git a/.tools/cppcheck/options.sh b/.mystools/cppcheck/options.sh similarity index 100% rename from .tools/cppcheck/options.sh rename to .mystools/cppcheck/options.sh diff --git a/.tools/cppcheck/run.sh b/.mystools/cppcheck/run.sh similarity index 100% rename from .tools/cppcheck/run.sh rename to .mystools/cppcheck/run.sh diff --git a/.tools/hooks/pre-commit.sh b/.mystools/hooks/pre-commit.sh similarity index 100% rename from .tools/hooks/pre-commit.sh rename to .mystools/hooks/pre-commit.sh From 707442b257880f3c9e59212953e4f8db17310245 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Mon, 12 Dec 2016 19:23:19 -0200 Subject: [PATCH 154/167] RPi: Use logError when possible (#689) --- drivers/Linux/SoftEeprom.cpp | 28 +++++++++++++++++++++++++++- drivers/Linux/SoftEeprom.h | 9 +++++++++ drivers/RPi/rpi_util.cpp | 10 +++++----- 3 files changed, 41 insertions(+), 6 deletions(-) diff --git a/drivers/Linux/SoftEeprom.cpp b/drivers/Linux/SoftEeprom.cpp index 46e4b8158..8a07ee5d2 100644 --- a/drivers/Linux/SoftEeprom.cpp +++ b/drivers/Linux/SoftEeprom.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "log.h" #include "SoftEeprom.h" @@ -31,7 +32,7 @@ SoftEeprom::SoftEeprom(const char *fileName, size_t length) _fileName = strdup(fileName); if (_fileName == NULL) { - perror("Error: "); + logError("Error: %s\n", strerror(errno)); exit(1); } @@ -67,6 +68,17 @@ SoftEeprom::SoftEeprom(const char *fileName, size_t length) } } +SoftEeprom::SoftEeprom(const SoftEeprom& other) +{ + _fileName = strdup(other._fileName); + + _length = other._length; + _values = new uint8_t[_length]; + for (size_t i = 0; i < _length; ++i) { + _values[i] = other._values[i]; + } +} + SoftEeprom::~SoftEeprom() { delete[] _values; @@ -128,3 +140,17 @@ void SoftEeprom::writeByte(int addr, uint8_t value) writeBlock(&value, reinterpret_cast(addr), 1); } } + +SoftEeprom& SoftEeprom::operator=(const SoftEeprom& other) +{ + if (this != &other) { + _fileName = strdup(other._fileName); + + _length = other._length; + _values = new uint8_t[_length]; + for (size_t i = 0; i < _length; ++i) { + _values[i] = other._values[i]; + } + } + return *this; +} diff --git a/drivers/Linux/SoftEeprom.h b/drivers/Linux/SoftEeprom.h index 70ad72cb1..7b096e570 100644 --- a/drivers/Linux/SoftEeprom.h +++ b/drivers/Linux/SoftEeprom.h @@ -43,6 +43,10 @@ class SoftEeprom * @brief SoftEeprom constructor. */ SoftEeprom(const char *fileName, size_t length); + /** + * @brief SoftEeprom copy constructor. + */ + SoftEeprom(const SoftEeprom& other); /** * @brief SoftEeprom destructor. */ @@ -77,6 +81,11 @@ class SoftEeprom * @param value to write. */ void writeByte(int addr, uint8_t value); + /** + * @brief Overloaded assign operator. + * + */ + SoftEeprom& operator=(const SoftEeprom& other); }; #endif diff --git a/drivers/RPi/rpi_util.cpp b/drivers/RPi/rpi_util.cpp index 39815753d..5c24d8bdc 100644 --- a/drivers/RPi/rpi_util.cpp +++ b/drivers/RPi/rpi_util.cpp @@ -96,7 +96,7 @@ int get_gpio_number(uint8_t physPin, uint8_t *gpio) void *interruptHandler(void *args) { - int fd, ret; + int fd; struct pollfd polls; char c; struct ThreadArgs *arguments = (struct ThreadArgs *)args; @@ -117,7 +117,7 @@ void *interruptHandler(void *args) while (1) { // Wait for it ... - ret = poll(&polls, 1, -1); + int ret = poll(&polls, 1, -1); if (ret < 0) { logError("Error waiting for interrupt: %s\n", strerror(errno)); break; @@ -232,7 +232,7 @@ void rpi_util::attachInterrupt(uint8_t physPin, void (*func)(), uint8_t mode) snprintf(fName, sizeof(fName), "/sys/class/gpio/gpio%d/direction", gpioPin) ; if ((fd = fopen (fName, "w")) == NULL) { - fprintf (stderr, "attachInterrupt: Unable to open GPIO direction interface for pin %d: %s\n", + logError("attachInterrupt: Unable to open GPIO direction interface for pin %d: %s\n", physPin, strerror(errno)); exit(1) ; } @@ -241,7 +241,7 @@ 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) { - fprintf (stderr, "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", physPin, strerror(errno)); exit(1) ; } @@ -268,7 +268,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) { - fprintf (stderr, "Error reading pin %d: %s\n", physPin, strerror(errno)); + logError("Error reading pin %d: %s\n", physPin, strerror(errno)); exit(1); } } From 4753c1ec3d970eabde5bb55120a4333e31a9a15e Mon Sep 17 00:00:00 2001 From: Bruce Lacey Date: Mon, 12 Dec 2016 15:26:11 -0800 Subject: [PATCH 155/167] Override cppcheck library & platform options (#691) * Using LIBRARY=[avr|gnu] git cppcheck ... will set the command line library= to the value * Using PLATFORM=[avr.xml|unix32.xml] git cppcheck ... will set the command line platform= to the value * Corrected logical if error when bootstapping a pristine repo References #672 --- .mystools/.bundle_runtime.sh | 4 ++-- .mystools/cppcheck/config/unix32.xml | 17 +++++++++++++++++ .mystools/cppcheck/options.sh | 4 ++-- 3 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 .mystools/cppcheck/config/unix32.xml diff --git a/.mystools/.bundle_runtime.sh b/.mystools/.bundle_runtime.sh index 744e9ba74..0a1560df0 100755 --- a/.mystools/.bundle_runtime.sh +++ b/.mystools/.bundle_runtime.sh @@ -24,7 +24,7 @@ tools_dir() git_config_tools_dir='git config mysensors.toolsdir' # Set mysensors.toolsdir in git config if it hasn't been set - if [ ! $($git_config_tools_dir) -o ! -d $($git_config_tools_dir) ]; then + if [[ ! $($git_config_tools_dir) || ! -d "$($git_config_tools_dir)" ]]; then $git_config_tools_dir "$( cd "$(dirname "${BASH_SOURCE[0]}")"; git rev-parse --show-prefix )" git config alias.mystoolspath '![ -z "${GIT_PREFIX}" ] || cd ${GIT_PREFIX}; echo $(git rev-parse --show-cdup)$(git config mysensors.toolsdir)' fi @@ -86,7 +86,7 @@ runBundle() # $(git rev-parse --is-inside-work-tree --quiet >/dev/null 2>&1) || err "Working directory is not a git repository. aborting..." -if environment_outdated && [[ $(basename "${0}") != *bootstrap* ]]; then +if [[ $(basename "${0}") != *bootstrap* ]] && environment_outdated ; then err "Your environment is out of date... Re-run $(git mystoolspath)bootstrap-dev.sh and try again" fi diff --git a/.mystools/cppcheck/config/unix32.xml b/.mystools/cppcheck/config/unix32.xml new file mode 100644 index 000000000..bc4ca0e89 --- /dev/null +++ b/.mystools/cppcheck/config/unix32.xml @@ -0,0 +1,17 @@ + + + 8 + unsigned + + 2 + 4 + 4 + 8 + 4 + 8 + 12 + 4 + 4 + 2 + + diff --git a/.mystools/cppcheck/options.sh b/.mystools/cppcheck/options.sh index 5cc32d2b1..e6b40235c 100755 --- a/.mystools/cppcheck/options.sh +++ b/.mystools/cppcheck/options.sh @@ -4,8 +4,8 @@ OPTIONS="--quiet \ --error-exitcode=1 \ --force \ --enable=style,information \ - --library=avr \ - --platform="${TOOLCONFIG}"/avr.xml \ + --library=${LIBRARY:-avr} \ + --platform="${TOOLCONFIG}"/${PLATFORM:-avr.xml} \ --includes-file="${TOOLCONFIG}"/includes.cfg \ --suppressions-list="${TOOLCONFIG}"/suppressions.cfg" From 3be2516ef8e815f2ab5d891d6aa8977144112c63 Mon Sep 17 00:00:00 2001 From: Bruce Lacey Date: Sat, 17 Dec 2016 12:50:52 -0800 Subject: [PATCH 156/167] Update RFM69 to MYS coding standards (#694) --- drivers/RFM69/RFM69.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/RFM69/RFM69.cpp b/drivers/RFM69/RFM69.cpp index 0e67ea5ad..a9520a9c6 100644 --- a/drivers/RFM69/RFM69.cpp +++ b/drivers/RFM69/RFM69.cpp @@ -345,7 +345,8 @@ void RFM69::sendFrame(uint8_t toAddress, const void* buffer, uint8_t bufferSize, setMode(RF69_MODE_TX); uint32_t txStart = millis(); while (hwDigitalRead(_interruptPin) == 0 && - millis() - txStart < RF69_TX_LIMIT_MS) {} // wait for DIO0 to turn HIGH signalling transmission finish + millis() - txStart < + RF69_TX_LIMIT_MS) {} // wait for DIO0 to turn HIGH signalling transmission finish //while (readReg(REG_IRQFLAGS2) & RF_IRQFLAGS2_PACKETSENT == 0x00); // wait for ModeReady setMode(RF69_MODE_STANDBY); } @@ -364,7 +365,8 @@ void RFM69::interruptHandler() PAYLOADLEN = PAYLOADLEN > 66 ? 66 : PAYLOADLEN; // precaution TARGETID = SPI.transfer(0); if(!(_promiscuousMode || TARGETID == _address || - TARGETID == RF69_BROADCAST_ADDR) // match this node's address, or broadcast address or anything in promiscuous mode + TARGETID == + RF69_BROADCAST_ADDR) // match this node's address, or broadcast address or anything in promiscuous mode || PAYLOADLEN < 3) { // address situation could receive packets that are malformed and don't fit this libraries extra fields PAYLOADLEN = 0; From 6a68510d576e0213b3d63e65aa5efdbbd6212ce0 Mon Sep 17 00:00:00 2001 From: Bruce Lacey Date: Sun, 18 Dec 2016 02:57:59 -0800 Subject: [PATCH 157/167] Tool bundle updates (#693) * Pre-commit --cached vs. less-efficient iteration * During pre-commit, leverage the git cppcheck --cached form instead of iterating over the cached files and invoking git cppcheck on each to eliminate redundant static analysis * Add support for Debian Linux on ARM * Check prerequisite tool minimum versions * Bootstrapping will now confirm that each prerequisite tool satisfies the minimum version required --- .mystools/.bundle_runtime.sh | 7 ++++--- .mystools/bootstrap-dev.sh | 27 +++++++++++++++++---------- .mystools/hooks/pre-commit.sh | 10 +--------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.mystools/.bundle_runtime.sh b/.mystools/.bundle_runtime.sh index 0a1560df0..ebf09b7be 100755 --- a/.mystools/.bundle_runtime.sh +++ b/.mystools/.bundle_runtime.sh @@ -6,12 +6,13 @@ # ## log() { IFS=" "; >&2 printf "%s\n" "$*"; } -warn() { IFS=" "; >&2 printf "\e[33m%s\e[m\n" "$*"; } -err() { IFS=" "; >&2 printf '\e[31m%s\e[m\n' "$*"; exit 1; } +info() { IFS=" "; >&2 printf "\e[92m%s\e[m\n" "$*"; } +warn() { IFS=" "; >&2 printf "\e[93m%s\e[m\n" "$*"; } +err() { IFS=" "; >&2 printf "\e[91m%s\e[m\n" "$*"; exit 1; } is_supported_os() { - [[ ${1} == darwin* ]] || [[ ${1} == linux-gnu ]] || [[ ${1} == freebsd ]] || [[ ${1} == msys ]] || [[ ${1} == cygwin ]] + [[ ${1} == darwin* ]] || [[ ${1} == linux-gnu* ]] || [[ ${1} == freebsd ]] || [[ ${1} == msys ]] || [[ ${1} == cygwin ]] } is_installed() diff --git a/.mystools/bootstrap-dev.sh b/.mystools/bootstrap-dev.sh index e26467102..33c689dd7 100755 --- a/.mystools/bootstrap-dev.sh +++ b/.mystools/bootstrap-dev.sh @@ -13,16 +13,21 @@ # Import common utility functions and environment variables . "$(cd "$(dirname "${BASH_SOURCE[0]}")"; pwd)/.bundle_runtime.sh" -check_tool_prerequisites() +check_tool_prerequisite() { - local err=0 - for preReq in ${1}; do - if ! is_installed $preReq; then - warn "$preReq not installed or not in current path." - err=1 + function ver { printf "%03d%03d%03d%03d" $(echo "$1" | tr '.' ' '); } + + if is_installed ${1} ; then + #local version=$(${1} --version 2>&1 | sed -e 's/[[:alpha:]|(|[:space:]]//g') + local version=$(${1} --version 2>&1 | sed -ne 's/[^0-9]*\(\([0-9]\.\)\{0,4\}[0-9][^.]\).*/\1/p') + if [ $(ver ${version}) -lt $(ver ${2}) ]; then + warn "Found ${1} ${version} however, version ${2} or greater is required..." + return 1 fi - done - return $err + else + warn "${1} not installed or not in current path." + return 1 + fi } check_git_remote() @@ -68,7 +73,9 @@ check_git_remote "upstream" "${mysrepo}" || { #3 log "Checking tool/utility prerequisites..." -check_tool_prerequisites "astyle cppcheck" || err "One or more required tools not found. Install required tools and re-run ${0}" +check_tool_prerequisite "astyle" "2.0.5" || err "Install AStyle 2.0.5 or greater and re-run ${0}" +check_tool_prerequisite "cppcheck" "1.76" || err "Install Cppcheck 1.76 or greater and re-run ${0}" +check_tool_prerequisite "git" "2.0" || err "Install git 2.0 or greater and re-run ${0}" #4 log "Installing client-side git hooks..." @@ -80,4 +87,4 @@ configure_git_tool_aliases || err "Failed to create git aliases due to error $?. bootstrap_version "--set" -log "Successfully configured your repo for MySensors development... Thanks for your support!" +info "Successfully configured your repo for MySensors development... Thanks for your support!" diff --git a/.mystools/hooks/pre-commit.sh b/.mystools/hooks/pre-commit.sh index 88b6f115b..146d85f2d 100755 --- a/.mystools/hooks/pre-commit.sh +++ b/.mystools/hooks/pre-commit.sh @@ -20,14 +20,6 @@ done ### # cppcheck # -errorsDetected=0 -for file in $(stagedSourceFiles); do - if ! git cppcheck $file >/dev/null; then - warn "$file failed static analysis." - errorsDetected=1 - fi -done - -[ $errorsDetected == 1 ] && err "Correct the errors until cppcheck passees using 'git cppcheck --cached'." +git cppcheck --cached || err "Correct the errors until cppcheck passes using 'git cppcheck --cached'." exit 0 From 38013ce5acf7b5af23ce5e9dbc2920d38836a910 Mon Sep 17 00:00:00 2001 From: Olivier Date: Mon, 19 Dec 2016 22:31:33 +0100 Subject: [PATCH 158/167] Fix bug preventing msgs from GW-attached sensors (#698) --- core/MySensorsCore.cpp | 30 ++++++++++++++++++------------ core/MySensorsCore.h | 1 + 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 82b64d4c5..8e1a15041 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -223,29 +223,35 @@ void presentNode(void) uint8_t getNodeId(void) { -#if defined(MY_SENSOR_NETWORK) - return transportGetNodeId(); -#else - return 0xFF; + uint8_t result = VALUE_NOT_DEFINED; +#if defined(MY_GATEWAY_FEATURE) + result = GATEWAY_ADDRESS; +#elif defined(MY_SENSOR_NETWORK) + result = transportGetNodeId(); #endif + return result; } uint8_t getParentNodeId(void) { -#if defined(MY_SENSOR_NETWORK) - return transportGetParentNodeId(); -#else - return 0xFF; + uint8_t result = VALUE_NOT_DEFINED; +#if defined(MY_GATEWAY_FEATURE) + result = VALUE_NOT_DEFINED; // GW doesn't have a parent +#elif defined(MY_SENSOR_NETWORK) + result = transportGetParentNodeId(); #endif + return result; } uint8_t getDistanceGW(void) { -#if defined(MY_SENSOR_NETWORK) - return transportGetDistanceGW(); -#else - return 0xFF; + uint8_t result = VALUE_NOT_DEFINED; +#if defined(MY_GATEWAY_FEATURE) + result = 0; +#elif defined(MY_SENSOR_NETWORK) + result = transportGetDistanceGW(); #endif + return result; } controllerConfig_t getConfig(void) diff --git a/core/MySensorsCore.h b/core/MySensorsCore.h index 6ae969d43..f0234dcc7 100644 --- a/core/MySensorsCore.h +++ b/core/MySensorsCore.h @@ -83,6 +83,7 @@ #define MY_SLEEP_NOT_POSSIBLE ((int8_t)-2) //!< Sleeping not possible #define INTERRUPT_NOT_DEFINED ((uint8_t)255) //!< _sleep() param: no interrupt defined #define MODE_NOT_DEFINED ((uint8_t)255) //!< _sleep() param: no mode defined +#define VALUE_NOT_DEFINED ((uint8_t)255) //!< Value not defined #ifdef MY_DEBUG From d204929937c5b1eb72a22aae091e1caf25fd83e6 Mon Sep 17 00:00:00 2001 From: Olivier Date: Mon, 19 Dec 2016 23:27:10 +0100 Subject: [PATCH 159/167] Use RNG for randomSeed(), ADC_MODE() switch (#696) --- core/MyHwESP8266.cpp | 16 ++++++++++++++-- core/MyHwESP8266.h | 3 +-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/core/MyHwESP8266.cpp b/core/MyHwESP8266.cpp index 398576903..b296b9782 100644 --- a/core/MyHwESP8266.cpp +++ b/core/MyHwESP8266.cpp @@ -90,13 +90,25 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo return MY_SLEEP_NOT_POSSIBLE; } -#if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG) +#if defined(MY_SPECIAL_DEBUG) +// settings for getVcc() ADC_MODE(ADC_VCC); +#else +// [default] settings for analogRead(A0) +ADC_MODE(ADC_TOUT); +#endif + +#if defined(MY_DEBUG) || defined(MY_SPECIAL_DEBUG) uint16_t hwCPUVoltage() { - // in mV +#if defined(MY_SPECIAL_DEBUG) + // in mV, requires ADC_VCC set return ESP.getVcc(); +#else + // not possible + return 0; +#endif } uint16_t hwCPUFrequency() diff --git a/core/MyHwESP8266.h b/core/MyHwESP8266.h index 03f622510..0d009e5a8 100644 --- a/core/MyHwESP8266.h +++ b/core/MyHwESP8266.h @@ -32,7 +32,6 @@ #define EEPROM_size (1024) - // Define these as macros to save valuable space #define hwDigitalWrite(__pin, __value) digitalWrite(__pin, __value) #define hwDigitalRead(__pin) digitalRead(__pin) @@ -40,7 +39,7 @@ #define hwWatchdogReset() wdt_reset() #define hwReboot() ESP.restart() #define hwMillis() millis() -#define hwRandomNumberInit() randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)) +#define hwRandomNumberInit() randomSeed(RANDOM_REG32) void hwInit(void); void hwReadConfigBlock(void* buf, void* adr, size_t length); From 61e6cecb3f8c6730b0559c9333ec4ff91aa4e297 Mon Sep 17 00:00:00 2001 From: Olivier Date: Tue, 20 Dec 2016 23:15:11 +0100 Subject: [PATCH 160/167] Fix regression, adjust parameters, typos (#699) --- MyConfig.h | 8 ++++---- MySensors.h | 5 +++++ core/MySensorsCore.cpp | 4 ++-- core/MyTransport.cpp | 8 ++++---- core/MyTransport.h | 36 ++++++++++++++++++------------------ 5 files changed, 33 insertions(+), 28 deletions(-) diff --git a/MyConfig.h b/MyConfig.h index 1efd3970e..16f6da722 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -103,7 +103,7 @@ * @brief Interval to dump content of routing table to eeprom */ #ifndef MY_ROUTING_TABLE_SAVE_INTERVAL_MS -#define MY_ROUTING_TABLE_SAVE_INTERVAL_MS (10*60*1000ul) +#define MY_ROUTING_TABLE_SAVE_INTERVAL_MS (30*60*1000ul) #endif /** * @def MY_TRANSPORT_SANITY_CHECK @@ -114,17 +114,17 @@ /** * @def MY_TRANSPORT_SANITY_CHECK_INTERVAL_MS -* @brief Interval (in ms) of transport sanity checks +* @brief Interval (in ms) for transport sanity checks */ #ifndef MY_TRANSPORT_SANITY_CHECK_INTERVAL_MS -#define MY_TRANSPORT_SANITY_CHECK_INTERVAL_MS (60*1000ul) +#define MY_TRANSPORT_SANITY_CHECK_INTERVAL_MS (15*60*1000ul) #endif /** * @def MY_TRANSPORT_DISCOVERY_INTERVAL_MS * @brief This is a gateway-only feature: Interval (in ms) to issue network discovery checks */ #ifndef MY_TRANSPORT_DISCOVERY_INTERVAL_MS -#define MY_TRANSPORT_DISCOVERY_INTERVAL_MS (10*60*1000ul) +#define MY_TRANSPORT_DISCOVERY_INTERVAL_MS (20*60*1000ul) #endif /** diff --git a/MySensors.h b/MySensors.h index 6471f8a6e..9dd38acb0 100644 --- a/MySensors.h +++ b/MySensors.h @@ -239,6 +239,11 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs #endif #endif +#if defined(MY_REPEATER_FEATURE) +#define MY_TRANSPORT_SANITY_CHECK +#endif + + #if defined(MY_TRANSPORT_DONT_CARE_MODE) #error This directive is deprecated, set MY_TRANSPORT_WAIT_READY_MS instead! #endif diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 8e1a15041..3bf209fb5 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -40,9 +40,7 @@ void _callbackTransportReady(void) { if (!_coreConfig.presentationSent) { presentNode(); -#if !defined(MY_GATEWAY_FEATURE) _registerNode(); -#endif _coreConfig.presentationSent = true; } } @@ -153,6 +151,8 @@ void _begin(void) #if defined(MY_SENSOR_NETWORK) CORE_DEBUG(PSTR("MCO:BGN:INIT OK,TSP=%d\n"), isTransportReady()); #else + // no sensor network defined, call presentation & registration + _callbackTransportReady(); CORE_DEBUG(PSTR("MCO:BGN:INIT OK,TSP=NA\n")); #endif // reset wdt before handing over to loop diff --git a/core/MyTransport.cpp b/core/MyTransport.cpp index 969e2994c..cd041215f 100644 --- a/core/MyTransport.cpp +++ b/core/MyTransport.cpp @@ -625,13 +625,13 @@ void transportProcessMessage(void) // update routing table if msg not from parent #if defined(MY_REPEATER_FEATURE) #if !defined(MY_GATEWAY_FEATURE) - if (last != getParentNodeId()) { + if (last != _transportConfig.parentNodeId) { #else // GW doesn't have parent { #endif // Message is from one of the child nodes and not sent from this node. Add it to routing table. - if (sender != getNodeId()) + if (sender != _transportConfig.nodeId) { transportSetRoute(sender, last); } @@ -840,10 +840,10 @@ void transportProcessMessage(void) void transportInvokeSanityCheck(void) { if (!transportSanityCheck()) { - TRANSPORT_DEBUG(PSTR("!TSF:SNK:FAIL\n")); // sanity check fail + TRANSPORT_DEBUG(PSTR("!TSF:SAN:FAIL\n")); // sanity check fail transportSwitchSM(stFailure); } else { - TRANSPORT_DEBUG(PSTR("TSF:SNK:OK\n")); // sanity check ok + TRANSPORT_DEBUG(PSTR("TSF:SAN:OK\n")); // sanity check ok } } diff --git a/core/MyTransport.h b/core/MyTransport.h index 52cdd48b8..3355db081 100644 --- a/core/MyTransport.h +++ b/core/MyTransport.h @@ -38,17 +38,17 @@ * - TSM:READY from stReady Transport is ready and fully operational * - TSM:FAIL from stFailure Failure in transport link or transport HW * - Transport support function (TSF) -* - TSF:CHKUPL from @ref transportCheckUplink(), checks connection to GW -* - TSF:ASID from @ref transportAssignNodeID(), assigns node ID -* - TSF:PING from @ref transportPingNode(), pings a node +* - TSF:CKU from @ref transportCheckUplink(), checks connection to GW +* - TSF:SID from @ref transportAssignNodeID(), assigns node ID +* - TSF:PNG from @ref transportPingNode(), pings a node * - TSF:WUR from @ref transportWaitUntilReady(), waits until transport is ready * - TSF:CRT from @ref transportClearRoutingTable(), clears routing table stored in EEPROM * - TSF:LRT from @ref transportLoadRoutingTable(), loads RAM routing table from EEPROM (only GW/repeaters) * - TSF:SRT from @ref transportSaveRoutingTable(), saves RAM routing table to EEPROM (only GW/repeaters) * - TSF:MSG from @ref transportProcessMessage(), processes incoming message -* - TSF:SANCHK from @ref transportInvokeSanityCheck(), calls transport-specific sanity check -* - TSF:ROUTE from @ref transportRouteMessage(), sends message -* - TSF:SEND from @ref transportSendRoute(), sends message if transport is ready (exposed) +* - TSF:SAN from @ref transportInvokeSanityCheck(), calls transport-specific sanity check +* - TSF:RTE from @ref transportRouteMessage(), sends message +* - TSF:SND from @ref transportSendRoute(), sends message if transport is ready (exposed) * * Transport debug log messages: @@ -80,13 +80,13 @@ * | | TSM | FAIL | CNT=%%d | Transition to stFailure state, consecutive failure counter (CNT) * | | TSM | FAIL | PDT | Power-down transport * | | TSM | FAIL | RE-INIT | Attempt to re-initialize transport -* | | TSF | CHKUPL | OK | Uplink OK -* | | TSF | CHKUPL | OK,FCTRL | Uplink OK, flood control prevents pinging GW in too short intervals -* | | TSF | CHKUPL | DGWC,O=%%d,N=%%d | Uplink check revealed changed network topology, old distance (O), new distance (N) -* | | TSF | CHKUPL | FAIL | No reply received when checking uplink -* | | TSF | ASID | OK,ID=%%d | Node ID assigned -* |!| TSF | ASID | FAIL,ID=%%d | Assigned ID is invalid -* | | TSF | PING | SEND,TO=%%d | Send ping to destination (TO) +* | | TSF | CKU | OK | Uplink OK +* | | TSF | CKU | OK,FCTRL | Uplink OK, flood control prevents pinging GW in too short intervals +* | | TSF | CKU | DGWC,O=%%d,N=%%d | Uplink check revealed changed network topology, old distance (O), new distance (N) +* | | TSF | CKU | FAIL | No reply received when checking uplink +* | | TSF | SID | OK,ID=%%d | Node ID assigned +* |!| TSF | SID | FAIL,ID=%%d | Assigned ID is invalid +* | | TSF | PNG | SEND,TO=%%d | Send ping to destination (TO) * | | TSF | WUR | MS=%%lu | Wait until transport ready, timeout (MS) * | | TSF | MSG | ACK REQ | ACK message requested * | | TSF | MSG | ACK | ACK message, do not proceed but forward to callback @@ -108,14 +108,14 @@ * |!| TSF | MSG | REL MSG,NORP | Node received a message for relaying, but node is not a repeater, message skipped * |!| TSF | MSG | SIGN FAIL | Signing message failed * |!| TSF | MSG | GWL FAIL | GW uplink failed -* | | TSF | SANCHK | OK | Sanity check passed -* |!| TSF | SANCHK | FAIL | Sanity check failed, attempt to re-initialize radio +* | | TSF | SAN | OK | Sanity check passed +* |!| TSF | SAN | FAIL | Sanity check failed, attempt to re-initialize radio * | | TSF | CRT | OK | Clearing routing table successful * | | TSF | LRT | OK | Loading routing table successful * | | TSF | SRT | OK | Saving routing table successful -* |!| TSF | ROUTE | FPAR ACTIVE | Finding parent active, message not sent -* |!| TSF | ROUTE | DST %%d UNKNOWN | Routing for destination (DST) unknown, send message to parent -* |!| TSF | SEND | TNR | Transport not ready, message cannot be sent +* |!| TSF | RTE | FPAR ACTIVE | Finding parent active, message not sent +* |!| TSF | RTE | DST %%d UNKNOWN | Routing for destination (DST) unknown, send message to parent +* |!| TSF | SND | TNR | Transport not ready, message cannot be sent * * Incoming / outgoing messages: * From 1040fbebc58e16838b33bb67436aeaddacc9ae23 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sun, 25 Dec 2016 16:12:40 +0100 Subject: [PATCH 161/167] Refactor signing backend (#690) Cleaned up the AES driver and removed some cppcheck isues in the process. --- core/MySigning.cpp | 533 +- core/MySigning.h | 8 - core/MySigningAtsha204.cpp | 3 + core/MySigningAtsha204Soft.cpp | 27 +- drivers/AES/AES.cpp | 7 +- drivers/AES/AES.h | 36 - drivers/AES/Doxyfile | 2372 -------- drivers/AES/Makefile | 62 - drivers/AES/examples/aes/aes.pde | 63 - drivers/AES/examples/test_vectors/RESOURCES | 16 - .../examples/test_vectors/known_answers.txt | 5321 ----------------- .../examples/test_vectors/test_vectors.pde | 191 - drivers/AES/examples_Rpi/Makefile | 39 - drivers/AES/examples_Rpi/RESOURCES | 16 - drivers/AES/examples_Rpi/aes.cpp | 47 - drivers/AES/examples_Rpi/known_answers.txt | 5321 ----------------- drivers/AES/examples_Rpi/test_vectors.cpp | 182 - drivers/AES/printf.h | 59 - drivers/ATSHA204/ATSHA204.cpp | 2 +- drivers/ATSHA204/sha256.cpp | 10 + drivers/ATSHA204/sha256.h | 1 + examples/SecureActuator/SecureActuator.ino | 2 +- .../SecurityPersonalizer/sha204_library.cpp | 2 +- .../SecurityPersonalizer/sha204_library.h | 2 +- .../SublimeText/MySensors.sublime-project | 6 +- ...t_hard_signing_whitelisting_full_debug.ino | 37 + ...t_soft_signing_whitelisting_full_debug.ino | 37 + 27 files changed, 398 insertions(+), 14004 deletions(-) delete mode 100644 drivers/AES/Doxyfile delete mode 100644 drivers/AES/Makefile delete mode 100644 drivers/AES/examples/aes/aes.pde delete mode 100644 drivers/AES/examples/test_vectors/RESOURCES delete mode 100644 drivers/AES/examples/test_vectors/known_answers.txt delete mode 100644 drivers/AES/examples/test_vectors/test_vectors.pde delete mode 100644 drivers/AES/examples_Rpi/Makefile delete mode 100644 drivers/AES/examples_Rpi/RESOURCES delete mode 100644 drivers/AES/examples_Rpi/aes.cpp delete mode 100644 drivers/AES/examples_Rpi/known_answers.txt delete mode 100644 drivers/AES/examples_Rpi/test_vectors.cpp delete mode 100644 drivers/AES/printf.h create mode 100644 tests/Arduino/sketches/serial_gateway_no_transport_hard_signing_whitelisting_full_debug/serial_gateway_no_transport_hard_signing_whitelisting_full_debug.ino create mode 100644 tests/Arduino/sketches/serial_gateway_no_transport_soft_signing_whitelisting_full_debug/serial_gateway_no_transport_soft_signing_whitelisting_full_debug.ino diff --git a/core/MySigning.cpp b/core/MySigning.cpp index 872cb4b67..35c2ff550 100644 --- a/core/MySigning.cpp +++ b/core/MySigning.cpp @@ -36,6 +36,9 @@ #if defined(MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL) && !defined(MY_SIGNING_REQUEST_SIGNATURES) #error You have to require signatures if you want to require signatures from all (also enable MY_SIGNING_REQUEST_SIGNATURES in your gateway) #endif +#if defined(MY_SIGNING_SOFT) && defined(MY_SIGNING_ATSHA204) +#error You have to pick one and only one signing backend +#endif #ifdef MY_SIGNING_FEATURE uint8_t _doSign[32]; // Bitfield indicating which sensors require signed communication uint8_t _doWhitelist[32]; // Bitfield indicating which sensors require serial salted signatures @@ -47,23 +50,17 @@ static uint8_t nof_nonce_requests = 0; static uint8_t nof_failed_verifications = 0; #endif -// Status when waiting for signing nonce in signerProcessInternal +// Status when waiting for signing nonce in signerSignMsg enum { SIGN_WAITING_FOR_NONCE = 0, SIGN_OK = 1 }; -// Macros for manipulating signing requirement table +// Macros for manipulating signing requirement tables #define DO_SIGN(node) (~_doSign[node>>3]&(1<>3]&=~(1<>3]|=(1<>3]&(1<>3]&=~(1<>3]|=(1<= MY_NODE_LOCK_COUNTER_MAX) { - _nodeLock("TMNR"); //Too many nonces requested - } -#endif -#if defined(MY_SIGNING_SOFT) - if (signerAtsha204SoftGetNonce(msg)) { -#endif -#if defined(MY_SIGNING_ATSHA204) - if (signerAtsha204GetNonce(msg)) { -#endif - if (!_sendRoute(build(msg, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_NONCE_RESPONSE))) { - SIGN_DEBUG(PSTR("Failed to transmit nonce!\n")); - } else { - SIGN_DEBUG(PSTR("Transmitted nonce\n")); - } - } else { - SIGN_DEBUG(PSTR("Failed to generate nonce!\n")); - } - return true; // No need to further process I_NONCE_REQUEST - } else if (msg.type == I_SIGNING_PRESENTATION) { - if (msg.data[0] != SIGNING_PRESENTATION_VERSION_1) { - SIGN_DEBUG(PSTR("Unsupported signing presentation version (%d)!\n"), msg.data[0]); - return true; // Just drop this presentation message - } - // 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); - } 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); - } - 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); - } 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); - } - - // Save updated tables - hwWriteConfigBlock((void*)_doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, - sizeof(_doSign)); - hwWriteConfigBlock((void*)_doWhitelist, (void*)EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS, - sizeof(_doWhitelist)); - - // 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 - // We do not want a gateway to require signing from all nodes in a network just because it wants one node - // to sign it's messages unless we explicitly configure it to -#if defined(MY_GATEWAY_FEATURE) - prepareSigningPresentation(msg, sender); -#if defined(MY_SIGNING_REQUEST_SIGNATURES) - if (DO_SIGN(sender)) { - msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES; - } -#if defined(MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL) - msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES; -#endif -#endif -#if defined(MY_SIGNING_NODE_WHITELISTING) - if (DO_WHITELIST(sender)) { - msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING; - } -#if defined(MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL) - msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING; -#endif -#endif - if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_SIGNATURES) { - 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"), sender); - } - if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_WHITELISTING) { - 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"), sender); - } - if (!_sendRoute(msg)) { - SIGN_DEBUG(PSTR("Failed to transmit signing presentation!\n")); - } -#endif // MY_GATEWAY_FEATURE - return true; // No need to further process I_SIGNING_PRESENTATION - } else if (msg.type == I_NONCE_RESPONSE) { - // Proceed with signing if nonce has been received - SIGN_DEBUG(PSTR("Nonce received from %d. Proceeding with signing...\n"), sender); - if (sender != _msgSign.destination) { - SIGN_DEBUG(PSTR("Nonce did not come from the destination (%d) of the message to be signed! " - "It came from %d.\n"), _msgSign.destination, sender); - SIGN_DEBUG(PSTR("Silently discarding this nonce\n")); - return true; // No need to further process I_NONCE_RESPONSE - } -#if defined(MY_SIGNING_SOFT) - signerAtsha204SoftPutNonce(msg); -#endif -#if defined(MY_SIGNING_ATSHA204) - signerAtsha204PutNonce(msg); -#endif -#if defined(MY_SIGNING_SOFT) - if (!signerAtsha204SoftSignMsg(_msgSign)) { -#endif -#if defined(MY_SIGNING_ATSHA204) - if (!signerAtsha204SignMsg(_msgSign)) { -#endif - SIGN_DEBUG(PSTR("Failed to sign message!\n")); - } else { - SIGN_DEBUG(PSTR("Message signed\n")); - _signingNonceStatus = SIGN_OK; // _msgSign now contains the signed message pending transmission - } - return true; // No need to further process I_NONCE_RESPONSE - } -#endif // MY_SIGNING_FEATURE - return false; + return ret; } -bool signerCheckTimer(void) { -#if defined(MY_SIGNING_SOFT) - return signerAtsha204SoftCheckTimer(); -#elif defined(MY_SIGNING_ATSHA204) - return signerAtsha204CheckTimer(); -#else - return true; // Without a configured backend, we always give "positive" results -#endif +bool signerCheckTimer(void) +{ + return signerBackendCheckTimer(); } -bool signerSignMsg(MyMessage &msg) { +bool signerSignMsg(MyMessage &msg) +{ + bool ret; #if defined(MY_SIGNING_FEATURE) // If destination is known to require signed messages and we are the sender, - // sign this message unless it is a handshake message + // sign this message unless it is identified as an exception if (DO_SIGN(msg.destination) && msg.sender == getNodeId()) { if (skipSign(msg)) { - return true; + ret = true; } else { // Send nonce-request _signingNonceStatus=SIGN_WAITING_FOR_NONCE; if (!_sendRoute(build(_msgSign, msg.destination, msg.sensor, C_INTERNAL, I_NONCE_REQUEST).set(""))) { SIGN_DEBUG(PSTR("Failed to transmit nonce request!\n")); - return false; - } - SIGN_DEBUG(PSTR("Nonce requested from %d. Waiting...\n"), msg.destination); - // We have to wait for the nonce to arrive before we can sign our original message - // Other messages could come in-between. We trust _process() takes care of them - unsigned long enter = hwMillis(); - _msgSign = msg; // Copy the message to sign since message buffer might be touched in _process() - while (hwMillis() - enter < MY_VERIFICATION_TIMEOUT_MS && - _signingNonceStatus==SIGN_WAITING_FOR_NONCE) { - _process(); - } - if (hwMillis() - enter > MY_VERIFICATION_TIMEOUT_MS) { - SIGN_DEBUG(PSTR("Timeout waiting for nonce!\n")); - return false; - } - if (_signingNonceStatus == SIGN_OK) { - // process() received a nonce and signerProcessInternal successfully signed the message - msg = _msgSign; // Write the signed message back - SIGN_DEBUG(PSTR("Message to send has been signed\n")); + ret = false; } else { - SIGN_DEBUG(PSTR("Message to send could not be signed!\n")); - return false; + SIGN_DEBUG(PSTR("Nonce requested from %d. Waiting...\n"), msg.destination); + // We have to wait for the nonce to arrive before we can sign our original message + // Other messages could come in-between. We trust _process() takes care of them + unsigned long enter = hwMillis(); + _msgSign = msg; // Copy the message to sign since message buffer might be touched in _process() + while (hwMillis() - enter < MY_VERIFICATION_TIMEOUT_MS && + _signingNonceStatus==SIGN_WAITING_FOR_NONCE) { + _process(); + } + if (hwMillis() - enter > MY_VERIFICATION_TIMEOUT_MS) { + SIGN_DEBUG(PSTR("Timeout waiting for nonce!\n")); + ret = false; + } else { + if (_signingNonceStatus == SIGN_OK) { + // process() received a nonce and signerProcessInternal successfully signed the message + msg = _msgSign; // Write the signed message back + SIGN_DEBUG(PSTR("Message to send has been signed\n")); + ret = true; + // After this point, only the 'last' member of the message structure is allowed to be altered if the + // message has been signed, or signature will become invalid and the message rejected by the receiver + } else { + SIGN_DEBUG(PSTR("Message to send could not be signed!\n")); + ret = false; + } + } } - // After this point, only the 'last' member of the message structure is allowed to be altered if the - // message has been signed, or signature will become invalid and the message rejected by the receiver } } else if (getNodeId() == msg.sender) { mSetSigned(msg, 0); // Message is not supposed to be signed, make sure it is marked unsigned + SIGN_DEBUG(PSTR("Will not sign message for destination %d as it does not require it\n"), + msg.destination); + ret = true; + } else { + SIGN_DEBUG(PSTR("Will not sign message since it was from %d and we are %d\n"), msg.sender, + getNodeId()); + ret = true; } #else (void)msg; + ret = true; #endif // MY_SIGNING_FEATURE - return true; + return ret; } -bool signerVerifyMsg(MyMessage &msg) { +bool signerVerifyMsg(MyMessage &msg) +{ bool verificationResult = true; // Before processing message, reject unsigned messages if signing is required and check signature // (if it is signed and addressed to us) @@ -390,14 +243,9 @@ bool signerVerifyMsg(MyMessage &msg) { SIGN_DEBUG(PSTR("Message is not signed, but it should have been!\n")); verificationResult = false; } else { -#if defined(MY_SIGNING_SOFT) - verificationResult = signerAtsha204SoftVerifyMsg(msg); -#endif -#if defined(MY_SIGNING_ATSHA204) - verificationResult = signerAtsha204VerifyMsg(msg); -#endif - if (!verificationResult) { + if (!signerBackendVerifyMsg(msg)) { SIGN_DEBUG(PSTR("Signature verification failed!\n")); + verificationResult = false; } #if defined(MY_NODE_LOCK_FEATURE) if (verificationResult) { @@ -425,23 +273,27 @@ bool signerVerifyMsg(MyMessage &msg) { static uint8_t sha256_hash[32]; Sha256Class _soft_sha256; -void signerSha256Init(void) { +void signerSha256Init(void) +{ memset(sha256_hash, 0, 32); _soft_sha256.init(); } -void signerSha256Update(const uint8_t* data, size_t sz) { +void signerSha256Update(const uint8_t* data, size_t sz) +{ for (size_t i = 0; i < sz; i++) { _soft_sha256.write(data[i]); } } -uint8_t* signerSha256Final(void) { +uint8_t* signerSha256Final(void) +{ memcpy(sha256_hash, _soft_sha256.result(), 32); return sha256_hash; } -int signerMemcmp(const void* a, const void* b, size_t sz) { +int signerMemcmp(const void* a, const void* b, size_t sz) +{ int retVal; size_t i; int done = 0; @@ -469,3 +321,190 @@ int signerMemcmp(const void* a, const void* b, size_t sz) { } return retVal; } + +#if defined(MY_SIGNING_FEATURE) +// Helper function to centralize signing/verification exceptions +static bool skipSign(MyMessage &msg) +{ + bool ret; + if (mGetAck(msg)) { + SIGN_DEBUG(PSTR("Skipping security for ACK on command %d type %d\n"), mGetCommand(msg), msg.type); + ret = true; + } else if (mGetCommand(msg) == C_INTERNAL && + (msg.type == I_NONCE_REQUEST || msg.type == I_NONCE_RESPONSE || + msg.type == I_SIGNING_PRESENTATION || + msg.type == I_ID_REQUEST || msg.type == I_ID_RESPONSE || + 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 )) { + SIGN_DEBUG(PSTR("Skipping security for command %d type %d\n"), mGetCommand(msg), msg.type); + ret = true; + } else if (mGetCommand(msg) == C_STREAM && + (msg.type == ST_FIRMWARE_REQUEST || msg.type == ST_FIRMWARE_RESPONSE || + msg.type == ST_SOUND || msg.type == ST_IMAGE)) { + SIGN_DEBUG(PSTR("Skipping security for command %d type %d\n"), mGetCommand(msg), msg.type); + ret = true; + } else { + ret = false; + } + return ret; +} +#endif + +// Helper to prepare a signing presentation message +static void prepareSigningPresentation(MyMessage &msg, uint8_t destination) +{ + // Only supports version 1 for now + (void)build(msg, destination, NODE_SENSOR_ID, C_INTERNAL, I_SIGNING_PRESENTATION).set(""); + mSetLength(msg, 2); + mSetPayloadType(msg, P_CUSTOM); // displayed as hex + msg.data[0] = SIGNING_PRESENTATION_VERSION_1; + msg.data[1] = 0; +} + +// Helper to process presentation mesages +static bool signerInternalProcessPresentation(MyMessage &msg) +{ +#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]); + return true; // Just drop this presentation message + } + // 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); + } 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); + } + 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); + } 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); + } + + // Save updated tables + hwWriteConfigBlock((void*)_doSign, (void*)EEPROM_SIGNING_REQUIREMENT_TABLE_ADDRESS, + sizeof(_doSign)); + hwWriteConfigBlock((void*)_doWhitelist, (void*)EEPROM_WHITELIST_REQUIREMENT_TABLE_ADDRESS, + sizeof(_doWhitelist)); + + // 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); +#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)) { + msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_SIGNATURES; + } +#endif +#endif // MY_SIGNING_REQUEST_SIGNATURES +#if defined(MY_SIGNING_NODE_WHITELISTING) +#if defined(MY_SIGNING_GW_REQUEST_SIGNATURES_FROM_ALL) + msg.data[1] |= SIGNING_PRESENTATION_REQUIRE_WHITELISTING; +#else + if (DO_WHITELIST(msg.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); + } else { + SIGN_DEBUG(PSTR("Informing node %d that we do not require signatures\n"), msg.sender); + } + if (msg.data[1] & SIGNING_PRESENTATION_REQUIRE_WHITELISTING) { + SIGN_DEBUG(PSTR("Informing node %d that we require whitelisting\n"), msg.sender); + } else { + SIGN_DEBUG(PSTR("Informing node %d that we do not require whitelisting\n"), msg.sender); + } + if (!_sendRoute(msg)) { + SIGN_DEBUG(PSTR("Failed to transmit signing presentation!\n")); + } +#endif // MY_GATEWAY_FEATURE +#else // not MY_SIGNING_FEATURE +#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); + SIGN_DEBUG( + PSTR("Informing node %d that we do not require signatures because we do not support it\n"), + msg.sender); + if (!_sendRoute(msg)) { + SIGN_DEBUG(PSTR("Failed to transmit signing presentation!\n")); + } +#else // not MY_GATEWAY_FEATURE + // 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; + SIGN_DEBUG(PSTR("Received signing presentation, but signing is not supported (message ignored)\n")); +#endif // not MY_GATEWAY_FEATURE +#endif // not MY_SIGNING_FEATURE + return true; // No need to further process I_SIGNING_PRESENTATION +} + +// Helper to process nonce request mesages +static bool signerInternalProcessNonceRequest(MyMessage &msg) +{ +#if defined(MY_SIGNING_FEATURE) +#if defined(MY_NODE_LOCK_FEATURE) + nof_nonce_requests++; + SIGN_DEBUG(PSTR("Nonce requests left until lockdown: %d\n"), + MY_NODE_LOCK_COUNTER_MAX-nof_nonce_requests); + if (nof_nonce_requests >= MY_NODE_LOCK_COUNTER_MAX) { + _nodeLock("TMNR"); //Too many nonces requested + } +#endif // MY_NODE_LOCK_FEATURE + if (signerBackendGetNonce(msg)) { + if (!_sendRoute(build(msg, msg.sender, NODE_SENSOR_ID, C_INTERNAL, I_NONCE_RESPONSE))) { + SIGN_DEBUG(PSTR("Failed to transmit nonce!\n")); + } else { + SIGN_DEBUG(PSTR("Transmitted nonce\n")); + } + } else { + SIGN_DEBUG(PSTR("Failed to generate nonce!\n")); + } +#else // not MY_SIGNING_FEATURE + (void)msg; + SIGN_DEBUG(PSTR("Received nonce request, but signing is not supported (message ignored)\n")); +#endif // MY_SIGNING_FEATURE + return true; // No need to further process I_NONCE_REQUEST +} + +// Helper to process nonce response mesages +static bool signerInternalProcessNonceResponse(MyMessage &msg) +{ +#if defined(MY_SIGNING_FEATURE) + // Proceed with signing if nonce has been received + SIGN_DEBUG(PSTR("Nonce received from %d.\n"), msg.sender); + if (msg.sender != _msgSign.destination) { + SIGN_DEBUG(PSTR("Nonce did not come from the destination (%d) of the message to be signed! " + "It came from %d.\n"), _msgSign.destination, msg.sender); + SIGN_DEBUG(PSTR("Silently discarding this nonce\n")); + } else { + SIGN_DEBUG(PSTR("Proceeding with signing...\n")); + signerBackendPutNonce(msg); + if (!signerBackendSignMsg(_msgSign)) { + SIGN_DEBUG(PSTR("Failed to sign message!\n")); + } else { + SIGN_DEBUG(PSTR("Message signed\n")); + _signingNonceStatus = SIGN_OK; // _msgSign now contains the signed message pending transmission + } + } +#else + (void)msg; + SIGN_DEBUG(PSTR("Received nonce response, but signing is not supported (message ignored)\n")); +#endif + return true; // No need to further process I_NONCE_RESPONSE +} diff --git a/core/MySigning.h b/core/MySigning.h index 4efacf7b8..386d60386 100644 --- a/core/MySigning.h +++ b/core/MySigning.h @@ -490,14 +490,6 @@ typedef struct { /** @brief Helper macro to determine the number of elements in a array */ #define NUM_OF(x) (sizeof(x)/sizeof(x[0])) -/** @brief Helper macro to determine if node require serial salted signatures */ -#define DO_WHITELIST(node) (~_doWhitelist[node>>3]&(1<>3]&=~(1<>3]|=(1<> 4); - printBuffer[(i * 2) + 1] = i2h(buf[i]); - } - printBuffer[sz * 2] = '\0'; - debug(str); - if (sz > 0) { - debug(printBuffer); - } -} -#else static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, uint8_t sz) { static char printBuffer[300]; -#ifdef MY_GATEWAY_FEATURE + if (NULL == buf) { + return; + } +#if defined(MY_GATEWAY_FEATURE) && !defined(__linux__) // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) snprintf_P(printBuffer, 299, PSTR("0;255;%d;0;%d;"), C_INTERNAL, I_LOG_MESSAGE); MY_SERIALDEVICE.print(printBuffer); @@ -92,7 +84,7 @@ static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, printBuffer[(i * 2) + 1] = i2h(buf[i]); } printBuffer[sz * 2] = '\0'; -#ifdef MY_GATEWAY_FEATURE +#if defined(MY_GATEWAY_FEATURE) && !defined(__linux__) // Truncate message if this is gateway node printBuffer[MY_GATEWAY_MAX_SEND_LENGTH-1-strlen_P((const char*)str)] = '\0'; #endif @@ -100,9 +92,10 @@ static void DEBUG_SIGNING_PRINTBUF(const __FlashStringHelper* str, uint8_t* buf, if (sz > 0) { MY_SERIALDEVICE.print(printBuffer); } +#if !defined(__linux__) MY_SERIALDEVICE.println(""); +#endif } -#endif /* __linux__ */ #else #define DEBUG_SIGNING_PRINTBUF(str, buf, sz) #endif diff --git a/drivers/AES/AES.cpp b/drivers/AES/AES.cpp index 06af427d0..d62589f69 100644 --- a/drivers/AES/AES.cpp +++ b/drivers/AES/AES.cpp @@ -104,7 +104,7 @@ const static byte s_inv [0x100] PROGMEM = { } ; // times 2 in the GF(2^8) -#define f2(x) ((x) & 0x80 ? (x << 1) ^ WPOLY : x << 1) +#define f2(x) (((x) & 0x80) ? (x << 1) ^ WPOLY : x << 1) #define d2(x) (((x) >> 1) ^ ((x) & 1 ? DPOLY : 0)) static byte s_box (byte x) @@ -248,6 +248,11 @@ static void inv_mix_sub_columns (byte dt[N_BLOCK], byte st[N_BLOCK]) AES::AES() { byte ar_iv[8] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 }; + IVC = 0x01; + round = 0; + pad = 0; + size = 0; + memset(key_sched, 0, KEY_SCHEDULE_BYTES); memcpy(iv,ar_iv,8); memcpy(iv+8,ar_iv,8); arr_pad[0] = 0x01; diff --git a/drivers/AES/AES.h b/drivers/AES/AES.h index 7ba5731c6..3c49f4e0e 100644 --- a/drivers/AES/AES.h +++ b/drivers/AES/AES.h @@ -312,42 +312,6 @@ class AES #endif -/** - * @example aes.pde - * For Arduino
- * Updated: spaniakos 2015
- * - * This is an example of how to use AES in CBC mode easily. - * The text and keys can be either in HEX or String format.
- */ - -/** -* @example aes.cpp -* For Rasberry pi
-* Updated: spaniakos 2015
-* -* This is an example of how to use AES in CBC mode easily. -* The text and keys can be either in HEX or String format.
-*/ - -/** -* @example test_vectors.pde -* For Arduino
-* Updated: spaniakos 2015
-* -* This is an example of monte carlo test vectors, in order to justify the effectiveness of the algorithm.
-* plus is a classical approach to the AES encryption library with out the easy to use add-on modifications. -*/ - -/** -* @example test_vectors.cpp -* For Rasberry pi
-* Updated: spaniakos 2015
-* -* This is an example of monte carlo test vectors, in order to justify the effectiveness of the algorithm.
-* plus is a classical approach to the AES encryption library with out the easy to use add-on modifications. -*/ - /** * @defgroup aeslib AES library for Arduino and Raspberry pi * @ingroup internals diff --git a/drivers/AES/Doxyfile b/drivers/AES/Doxyfile deleted file mode 100644 index 79cf3b7dc..000000000 --- a/drivers/AES/Doxyfile +++ /dev/null @@ -1,2372 +0,0 @@ -# Doxyfile 1.8.6 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project. -# -# All text after a double hash (##) is considered a comment and is placed in -# front of the TAG it is preceding. -# -# All text after a single hash (#) is considered a comment and will be ignored. -# The format is: -# TAG = value [value, ...] -# For lists, items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (\" \"). - -#--------------------------------------------------------------------------- -# Project related configuration options -#--------------------------------------------------------------------------- - -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all text -# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv -# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv -# for the list of possible encodings. -# The default value is: UTF-8. - -DOXYFILE_ENCODING = UTF-8 - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by -# double-quotes, unless you are using Doxywizard) that should identify the -# project for which the documentation is generated. This name is used in the -# title of most generated pages and in a few other places. -# The default value is: My Project. - -PROJECT_NAME = "AES Encryption Library for Arduino and Raspberry Pi" - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. This -# could be handy for archiving the generated documentation or if some version -# control system is used. - -PROJECT_NUMBER = - -# Using the PROJECT_BRIEF tag one can provide an optional one line description -# for a project that appears at the top of each page and should give viewer a -# quick idea about the purpose of the project. Keep the description short. - -PROJECT_BRIEF = "Spaniakos - AES Encryption Library for Arduino and Raspberry Pi" - -# With the PROJECT_LOGO tag one can specify an logo or icon that is included in -# the documentation. The maximum height of the logo should not exceed 55 pixels -# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo -# to the output directory. - -PROJECT_LOGO = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path -# into which the generated documentation will be written. If a relative path is -# entered, it will be relative to the location where doxygen was started. If -# left blank the current directory will be used. - -OUTPUT_DIRECTORY = "../Documentations/AES" - -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this -# option can be useful when feeding doxygen a huge amount of source files, where -# putting all generated files in the same directory would otherwise causes -# performance problems for the file system. -# The default value is: NO. - -CREATE_SUBDIRS = NO - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. -# The default value is: English. - -OUTPUT_LANGUAGE = English - -# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member -# descriptions after the members that are listed in the file and class -# documentation (similar to Javadoc). Set to NO to disable this. -# The default value is: YES. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief -# description of a member or function before the detailed description -# -# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. -# The default value is: YES. - -REPEAT_BRIEF = YES - -# This tag implements a quasi-intelligent brief description abbreviator that is -# used to form the text in various listings. Each string in this list, if found -# as the leading text of the brief description, will be stripped from the text -# and the result, after processing the whole list, is used as the annotated -# text. Otherwise, the brief description is used as-is. If left blank, the -# following values are used ($name is automatically replaced with the name of -# the entity):The $name class, The $name widget, The $name file, is, provides, -# specifies, contains, represents, a, an and the. - -ABBREVIATE_BRIEF = "The $name class" \ - "The $name widget" \ - "The $name file" \ - is \ - provides \ - specifies \ - contains \ - represents \ - a \ - an \ - the - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# doxygen will generate a detailed section even if there is only a brief -# description. -# The default value is: NO. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment -# operators of the base classes will not be shown. -# The default value is: NO. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path -# before files name in the file list and in the header files. If set to NO the -# shortest path that makes the file name unique will be used -# The default value is: YES. - -FULL_PATH_NAMES = YES - -# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path. -# Stripping is only done if one of the specified strings matches the left-hand -# part of the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the path to -# strip. -# -# Note that you can specify absolute paths here, but also relative paths, which -# will be relative from the directory where doxygen is started. -# This tag requires that the tag FULL_PATH_NAMES is set to YES. - -STRIP_FROM_PATH = - -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the -# path mentioned in the documentation of a class, which tells the reader which -# header file to include in order to use a class. If left blank only the name of -# the header file containing the class definition is used. Otherwise one should -# specify the list of include paths that are normally passed to the compiler -# using the -I flag. - -STRIP_FROM_INC_PATH = - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but -# less readable) file names. This can be useful is your file systems doesn't -# support long names like on DOS, Mac, or CD-ROM. -# The default value is: NO. - -SHORT_NAMES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the -# first line (until the first dot) of a Javadoc-style comment as the brief -# description. If set to NO, the Javadoc-style will behave just like regular Qt- -# style comments (thus requiring an explicit @brief command for a brief -# description.) -# The default value is: NO. - -JAVADOC_AUTOBRIEF = NO - -# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first -# line (until the first dot) of a Qt-style comment as the brief description. If -# set to NO, the Qt-style will behave just like regular Qt-style comments (thus -# requiring an explicit \brief command for a brief description.) -# The default value is: NO. - -QT_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a -# multi-line C++ special comment block (i.e. a block of //! or /// comments) as -# a brief description. This used to be the default behavior. The new default is -# to treat a multi-line C++ comment block as a detailed description. Set this -# tag to YES if you prefer the old behavior instead. -# -# Note that setting this tag to YES also means that rational rose comments are -# not recognized any more. -# The default value is: NO. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the -# documentation from any documented member that it re-implements. -# The default value is: YES. - -INHERIT_DOCS = YES - -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a -# new page for each member. If set to NO, the documentation of a member will be -# part of the file/class/namespace that contains it. -# The default value is: NO. - -SEPARATE_MEMBER_PAGES = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen -# uses this value to replace tabs by spaces in code fragments. -# Minimum value: 1, maximum value: 16, default value: 4. - -TAB_SIZE = 4 - -# This tag can be used to specify a number of aliases that act as commands in -# the documentation. An alias has the form: -# name=value -# For example adding -# "sideeffect=@par Side Effects:\n" -# will allow you to put the command \sideeffect (or @sideeffect) in the -# documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines. - -ALIASES = - -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources -# only. Doxygen will then generate output that is more tailored for C. For -# instance, some of the names that are used will be different. The list of all -# members will be omitted, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_FOR_C = NO - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or -# Python sources only. Doxygen will then generate output that is more tailored -# for that language. For instance, namespaces will be presented as packages, -# qualified scopes will look different, etc. -# The default value is: NO. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran -# sources. Doxygen will then generate output that is tailored for Fortran. -# The default value is: NO. - -OPTIMIZE_FOR_FORTRAN = NO - -# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL -# sources. Doxygen will then generate output that is tailored for VHDL. -# The default value is: NO. - -OPTIMIZE_OUTPUT_VHDL = NO - -# Doxygen selects the parser to use depending on the extension of the files it -# parses. With this tag you can assign which parser to use for a given -# extension. Doxygen has a built-in mapping, but you can override or extend it -# using this tag. The format is ext=language, where ext is a file extension, and -# language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL. For instance to make -# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C -# (default is Fortran), use: inc=Fortran f=C. -# -# Note For files without extension you can use no_extension as a placeholder. -# -# Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. - -EXTENSION_MAPPING = ino=c \ - pde=c - -# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments -# according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. -# The output of markdown processing is further processed by doxygen, so you can -# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in -# case of backward compatibilities issues. -# The default value is: YES. - -MARKDOWN_SUPPORT = YES - -# When enabled doxygen tries to link words that correspond to documented -# classes, or namespaces to their corresponding documentation. Such a link can -# be prevented in individual cases by by putting a % sign in front of the word -# or globally by setting AUTOLINK_SUPPORT to NO. -# The default value is: YES. - -AUTOLINK_SUPPORT = YES - -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want -# to include (a tag file for) the STL sources as input, then you should set this -# tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); -# versus func(std::string) {}). This also make the inheritance and collaboration -# diagrams that involve STL classes more complete and accurate. -# The default value is: NO. - -BUILTIN_STL_SUPPORT = NO - -# If you use Microsoft's C++/CLI language, you should set this option to YES to -# enable parsing support. -# The default value is: NO. - -CPP_CLI_SUPPORT = NO - -# Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen -# will parse them like normal C++ but will assume all classes use public instead -# of private inheritance when no explicit protection keyword is present. -# The default value is: NO. - -SIP_SUPPORT = NO - -# For Microsoft's IDL there are propget and propput attributes to indicate -# getter and setter methods for a property. Setting this option to YES will make -# doxygen to replace the get and set methods by a property in the documentation. -# This will only work if the methods are indeed getting or setting a simple -# type. If this is not the case, or you want to show the methods anyway, you -# should set this option to NO. -# The default value is: YES. - -IDL_PROPERTY_SUPPORT = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. -# The default value is: NO. - -DISTRIBUTE_GROUP_DOC = NO - -# Set the SUBGROUPING tag to YES to allow class member groups of the same type -# (for instance a group of public functions) to be put as a subgroup of that -# type (e.g. under the Public Functions section). Set it to NO to prevent -# subgrouping. Alternatively, this can be done per class using the -# \nosubgrouping command. -# The default value is: YES. - -SUBGROUPING = YES - -# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions -# are shown inside the group in which they are included (e.g. using \ingroup) -# instead of on a separate page (for HTML and Man pages) or section (for LaTeX -# and RTF). -# -# Note that this feature does not work in combination with -# SEPARATE_MEMBER_PAGES. -# The default value is: NO. - -INLINE_GROUPED_CLASSES = NO - -# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions -# with only public data fields or simple typedef fields will be shown inline in -# the documentation of the scope in which they are defined (i.e. file, -# namespace, or group documentation), provided this scope is documented. If set -# to NO, structs, classes, and unions are shown on a separate page (for HTML and -# Man pages) or section (for LaTeX and RTF). -# The default value is: NO. - -INLINE_SIMPLE_STRUCTS = NO - -# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or -# enum is documented as struct, union, or enum with the name of the typedef. So -# typedef struct TypeS {} TypeT, will appear in the documentation as a struct -# with name TypeT. When disabled the typedef will appear as a member of a file, -# namespace, or class. And the struct will be named TypeS. This can typically be -# useful for C code in case the coding convention dictates that all compound -# types are typedef'ed and only the typedef is referenced, never the tag name. -# The default value is: NO. - -TYPEDEF_HIDES_STRUCT = NO - -# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This -# cache is used to resolve symbols given their name and scope. Since this can be -# an expensive process and often the same symbol appears multiple times in the -# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small -# doxygen will become slower. If the cache is too large, memory is wasted. The -# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range -# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536 -# symbols. At the end of a run doxygen will report the cache usage and suggest -# the optimal cache size from a speed point of view. -# Minimum value: 0, maximum value: 9, default value: 0. - -LOOKUP_CACHE_SIZE = 0 - -#--------------------------------------------------------------------------- -# Build related configuration options -#--------------------------------------------------------------------------- - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. Private -# class members and static file members will be hidden unless the -# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES. -# Note: This will also disable the warnings about undocumented members that are -# normally produced when WARNINGS is set to YES. -# The default value is: NO. - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will -# be included in the documentation. -# The default value is: NO. - -EXTRACT_PRIVATE = YES - -# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal -# scope will be included in the documentation. -# The default value is: NO. - -EXTRACT_PACKAGE = YES - -# If the EXTRACT_STATIC tag is set to YES all static members of a file will be -# included in the documentation. -# The default value is: NO. - -EXTRACT_STATIC = YES - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined -# locally in source files will be included in the documentation. If set to NO -# only classes defined in header files are included. Does not have any effect -# for Java sources. -# The default value is: YES. - -EXTRACT_LOCAL_CLASSES = YES - -# This flag is only useful for Objective-C code. When set to YES local methods, -# which are defined in the implementation section but not in the interface are -# included in the documentation. If set to NO only methods in the interface are -# included. -# The default value is: NO. - -EXTRACT_LOCAL_METHODS = YES - -# If this flag is set to YES, the members of anonymous namespaces will be -# extracted and appear in the documentation as a namespace called -# 'anonymous_namespace{file}', where file will be replaced with the base name of -# the file that contains the anonymous namespace. By default anonymous namespace -# are hidden. -# The default value is: NO. - -EXTRACT_ANON_NSPACES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all -# undocumented members inside documented classes or files. If set to NO these -# members will be included in the various overviews, but no documentation -# section is generated. This option has no effect if EXTRACT_ALL is enabled. -# The default value is: NO. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. If set -# to NO these classes will be included in the various overviews. This option has -# no effect if EXTRACT_ALL is enabled. -# The default value is: NO. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend -# (class|struct|union) declarations. If set to NO these declarations will be -# included in the documentation. -# The default value is: NO. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any -# documentation blocks found inside the body of a function. If set to NO these -# blocks will be appended to the function's detailed documentation block. -# The default value is: NO. - -HIDE_IN_BODY_DOCS = NO - -# The INTERNAL_DOCS tag determines if documentation that is typed after a -# \internal command is included. If the tag is set to NO then the documentation -# will be excluded. Set it to YES to include the internal documentation. -# The default value is: NO. - -INTERNAL_DOCS = NO - -# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. -# The default value is: system dependent. - -CASE_SENSE_NAMES = YES - -# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with -# their full class and namespace scopes in the documentation. If set to YES the -# scope will be hidden. -# The default value is: NO. - -HIDE_SCOPE_NAMES = NO - -# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of -# the files that are included by a file in the documentation of that file. -# The default value is: YES. - -SHOW_INCLUDE_FILES = YES - - -SHOW_GROUPED_MEMB_INC = NO - -# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include -# files with double quotes in the documentation rather than with sharp brackets. -# The default value is: NO. - -FORCE_LOCAL_INCLUDES = NO - -# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the -# documentation for inline members. -# The default value is: YES. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the -# (detailed) documentation of file and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. -# The default value is: YES. - -SORT_MEMBER_DOCS = NO - -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief -# descriptions of file, namespace and class members alphabetically by member -# name. If set to NO the members will appear in declaration order. Note that -# this will also influence the order of the classes in the class list. -# The default value is: NO. - -SORT_BRIEF_DOCS = NO - -# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the -# (brief and detailed) documentation of class members so that constructors and -# destructors are listed first. If set to NO the constructors will appear in the -# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS. -# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief -# member documentation. -# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting -# detailed member documentation. -# The default value is: NO. - -SORT_MEMBERS_CTORS_1ST = NO - -# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy -# of group names into alphabetical order. If set to NO the group names will -# appear in their defined order. -# The default value is: NO. - -SORT_GROUP_NAMES = NO - -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by -# fully-qualified names, including namespaces. If set to NO, the class list will -# be sorted only by class name, not including the namespace part. -# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the alphabetical -# list. -# The default value is: NO. - -SORT_BY_SCOPE_NAME = YES - -# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper -# type resolution of all parameters of a function it will reject a match between -# the prototype and the implementation of a member function even if there is -# only one candidate or it is obvious which candidate to choose by doing a -# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still -# accept a match between prototype and implementation in such cases. -# The default value is: NO. - -STRICT_PROTO_MATCHING = NO - -# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the -# todo list. This list is created by putting \todo commands in the -# documentation. -# The default value is: YES. - -GENERATE_TODOLIST = NO - -# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the -# test list. This list is created by putting \test commands in the -# documentation. -# The default value is: YES. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug -# list. This list is created by putting \bug commands in the documentation. -# The default value is: YES. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO) -# the deprecated list. This list is created by putting \deprecated commands in -# the documentation. -# The default value is: YES. - -GENERATE_DEPRECATEDLIST= YES - -# The ENABLED_SECTIONS tag can be used to enable conditional documentation -# sections, marked by \if ... \endif and \cond -# ... \endcond blocks. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the -# initial value of a variable or macro / define can have for it to appear in the -# documentation. If the initializer consists of more lines than specified here -# it will be hidden. Use a value of 0 to hide initializers completely. The -# appearance of the value of individual variables and macros / defines can be -# controlled using \showinitializer or \hideinitializer command in the -# documentation regardless of this setting. -# Minimum value: 0, maximum value: 10000, default value: 30. - -MAX_INITIALIZER_LINES = 30 - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at -# the bottom of the documentation of classes and structs. If set to YES the list -# will mention the files that were used to generate the documentation. -# The default value is: YES. - -SHOW_USED_FILES = NO - -# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This -# will remove the Files entry from the Quick Index and from the Folder Tree View -# (if specified). -# The default value is: YES. - -SHOW_FILES = NO - -# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces -# page. This will remove the Namespaces entry from the Quick Index and from the -# Folder Tree View (if specified). -# The default value is: YES. - -SHOW_NAMESPACES = NO - -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from -# the version control system). Doxygen will invoke the program by executing (via -# popen()) the command command input-file, where command is the value of the -# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided -# by doxygen. Whatever the program writes to standard output is used as the file -# version. For an example see the documentation. - -FILE_VERSION_FILTER = - -# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed -# by doxygen. The layout file controls the global structure of the generated -# output files in an output format independent way. To create the layout file -# that represents doxygen's defaults, run doxygen with the -l option. You can -# optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. -# -# Note that if you run doxygen from a directory containing a file called -# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE -# tag is left empty. - -LAYOUT_FILE = - -# The CITE_BIB_FILES tag can be used to specify one or more bib files containing -# the reference definitions. This must be a list of .bib files. The .bib -# extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. -# For LaTeX the style of the bibliography can be controlled using -# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the -# search path. Do not use file names with spaces, bibtex cannot handle them. See -# also \cite for info how to create references. - -CITE_BIB_FILES = - -#--------------------------------------------------------------------------- -# Configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated to -# standard output by doxygen. If QUIET is set to YES this implies that the -# messages are off. -# The default value is: NO. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES -# this implies that the warnings are on. -# -# Tip: Turn warnings on while writing the documentation. -# The default value is: YES. - -WARNINGS = YES - -# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate -# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag -# will automatically be disabled. -# The default value is: YES. - -WARN_IF_UNDOCUMENTED = YES - -# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. -# The default value is: YES. - -WARN_IF_DOC_ERROR = YES - -# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that -# are documented, but have no documentation for their parameters or return -# value. If set to NO doxygen will only warn about wrong or incomplete parameter -# documentation, but not about the absence of documentation. -# The default value is: NO. - -WARN_NO_PARAMDOC = NO - -# The WARN_FORMAT tag determines the format of the warning messages that doxygen -# can produce. The string should contain the $file, $line, and $text tags, which -# will be replaced by the file and line number from which the warning originated -# and the warning text. Optionally the format may contain $version, which will -# be replaced by the version of the file (if it could be obtained via -# FILE_VERSION_FILTER) -# The default value is: $file:$line: $text. - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning and error -# messages should be written. If left blank the output is written to standard -# error (stderr). - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# Configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag is used to specify the files and/or directories that contain -# documented source files. You may enter file names like myfile.cpp or -# directories like /usr/src/myproject. Separate the files or directories with -# spaces. -# Note: If this tag is empty the current directory is searched. - -INPUT = ./ - -# This tag can be used to specify the character encoding of the source files -# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses -# libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: http://www.gnu.org/software/libiconv) for the list of -# possible encodings. -# The default value is: UTF-8. - -INPUT_ENCODING = UTF-8 - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank the -# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, -# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, -# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, -# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, -# *.qsf, *.as and *.js. - -FILE_PATTERNS = *.c \ - *.cc \ - *.cxx \ - *.cpp \ - *.c++ \ - *.java \ - *.ii \ - *.ixx \ - *.ipp \ - *.i++ \ - *.inl \ - *.idl \ - *.ddl \ - *.odl \ - *.h \ - *.hh \ - *.hxx \ - *.hpp \ - *.h++ \ - *.cs \ - *.d \ - *.php \ - *.php4 \ - *.php5 \ - *.phtml \ - *.inc \ - *.m \ - *.markdown \ - *.md \ - *.mm \ - *.dox \ - *.py \ - *.f90 \ - *.f \ - *.for \ - *.tcl \ - *.vhd \ - *.vhdl \ - *.ucf \ - *.qsf \ - *.as \ - *.js - -# The RECURSIVE tag can be used to specify whether or not subdirectories should -# be searched for input files as well. -# The default value is: NO. - -RECURSIVE = YES - -# The EXCLUDE tag can be used to specify files and/or directories that should be -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. -# -# Note that relative paths are relative to the directory from which doxygen is -# run. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or -# directories that are symbolic links (a Unix file system feature) are excluded -# from the input. -# The default value is: NO. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories for example use the pattern */test/* - -EXCLUDE_PATTERNS = - -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the -# output. The symbol name can be a fully qualified name, a word, or if the -# wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* - -EXCLUDE_SYMBOLS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or directories -# that contain example code fragments that are included (see the \include -# command). - -EXAMPLE_PATH = examples \ - examples_RPi \ - examples_Rpi - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank all -# files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude commands -# irrespective of the value of the RECURSIVE tag. -# The default value is: NO. - -EXAMPLE_RECURSIVE = YES - -# The IMAGE_PATH tag can be used to specify one or more files or directories -# that contain images that are to be included in the documentation (see the -# \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command: -# -# -# -# where is the value of the INPUT_FILTER tag, and is the -# name of an input file. Doxygen will then use the output that the filter -# program writes to standard output. If FILTER_PATTERNS is specified, this tag -# will be ignored. -# -# Note that the filter must not add or remove lines; it is applied before the -# code is scanned, but not when the output code is generated. If lines are added -# or removed, the anchors will not be placed correctly. - -INPUT_FILTER = - -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: pattern=filter -# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how -# filters are used. If the FILTER_PATTERNS tag is empty or if none of the -# patterns match the file name, INPUT_FILTER is applied. - -FILTER_PATTERNS = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER ) will also be used to filter the input files that are used for -# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES). -# The default value is: NO. - -FILTER_SOURCE_FILES = NO - -# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file -# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and -# it is also possible to disable source filtering for a specific pattern using -# *.ext= (so without naming a filter). -# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. - -FILTER_SOURCE_PATTERNS = - -# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that -# is part of the input, its contents will be placed on the main page -# (index.html). This can be useful if you have a project on for instance GitHub -# and want to reuse the introduction page also for the doxygen output. - -USE_MDFILE_AS_MAINPAGE = - -#--------------------------------------------------------------------------- -# Configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will be -# generated. Documented entities will be cross-referenced with these sources. -# -# Note: To get rid of all source code in the generated output, make sure that -# also VERBATIM_HEADERS is set to NO. -# The default value is: NO. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body of functions, -# classes and enums directly into the documentation. -# The default value is: NO. - -INLINE_SOURCES = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any -# special comment blocks from generated source code fragments. Normal C, C++ and -# Fortran comments will always remain visible. -# The default value is: YES. - -STRIP_CODE_COMMENTS = YES - -# If the REFERENCED_BY_RELATION tag is set to YES then for each documented -# function all documented functions referencing it will be listed. -# The default value is: NO. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES then for each documented function -# all documented entities called/used by that function will be listed. -# The default value is: NO. - -REFERENCES_RELATION = NO - -# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set -# to YES, then the hyperlinks from functions in REFERENCES_RELATION and -# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will -# link to the documentation. -# The default value is: YES. - -REFERENCES_LINK_SOURCE = YES - -# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the -# source code will show a tooltip with additional information such as prototype, -# brief description and links to the definition and documentation. Since this -# will make the HTML file larger and loading of large files a bit slower, you -# can opt to disable this feature. -# The default value is: YES. -# This tag requires that the tag SOURCE_BROWSER is set to YES. - -SOURCE_TOOLTIPS = YES - -# If the USE_HTAGS tag is set to YES then the references to source code will -# point to the HTML generated by the htags(1) tool instead of doxygen built-in -# source browser. The htags tool is part of GNU's global source tagging system -# (see http://www.gnu.org/software/global/global.html). You will need version -# 4.8.6 or higher. -# -# To use it do the following: -# - Install the latest version of global -# - Enable SOURCE_BROWSER and USE_HTAGS in the config file -# - Make sure the INPUT points to the root of the source tree -# - Run doxygen as normal -# -# Doxygen will invoke htags (and that will in turn invoke gtags), so these -# tools must be available from the command line (i.e. in the search path). -# -# The result: instead of the source browser generated by doxygen, the links to -# source code will now point to the output of htags. -# The default value is: NO. -# This tag requires that the tag SOURCE_BROWSER is set to YES. - -USE_HTAGS = NO - -# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a -# verbatim copy of the header file for each class for which an include is -# specified. Set to NO to disable this. -# See also: Section \class. -# The default value is: YES. - -VERBATIM_HEADERS = YES - -# If the CLANG_ASSISTED_PARSING tag is set to YES, then doxygen will use the -# clang parser (see: http://clang.llvm.org/) for more acurate parsing at the -# cost of reduced performance. This can be particularly helpful with template -# rich C++ code for which doxygen's built-in parser lacks the necessary type -# information. -# Note: The availability of this option depends on whether or not doxygen was -# compiled with the --with-libclang option. -# The default value is: NO. - -CLANG_ASSISTED_PARSING = NO - -# If clang assisted parsing is enabled you can provide the compiler with command -# line options that you would normally use when invoking the compiler. Note that -# the include paths will already be set by doxygen for the files and directories -# specified with INPUT and INCLUDE_PATH. -# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. - -CLANG_OPTIONS = - -#--------------------------------------------------------------------------- -# Configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all -# compounds will be generated. Enable this if the project contains a lot of -# classes, structs, unions or interfaces. -# The default value is: YES. - -ALPHABETICAL_INDEX = YES - -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index list will be split. -# Minimum value: 1, maximum value: 20, default value: 5. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -COLS_IN_ALPHA_INDEX = 10 - -# In case all classes in a project start with a common prefix, all classes will -# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag -# can be used to specify a prefix (or a list of prefixes) that should be ignored -# while generating the index headers. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# Configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output -# The default value is: YES. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a -# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of -# it. -# The default directory is: html. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_OUTPUT = html - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each -# generated HTML page (for example: .htm, .php, .asp). -# The default value is: .html. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a user-defined HTML header file for -# each generated HTML page. If the tag is left blank doxygen will generate a -# standard header. -# -# To get valid HTML the header file that includes any scripts and style sheets -# that doxygen needs, which is dependent on the configuration options used (e.g. -# the setting GENERATE_TREEVIEW). It is highly recommended to start with a -# default header using -# doxygen -w html new_header.html new_footer.html new_stylesheet.css -# YourConfigFile -# and then modify the file new_header.html. See also section "Doxygen usage" -# for information on how to generate the default header that doxygen normally -# uses. -# Note: The header is subject to change so you typically have to regenerate the -# default header when upgrading to a newer version of doxygen. For a description -# of the possible markers and block names see the documentation. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each -# generated HTML page. If the tag is left blank doxygen will generate a standard -# footer. See HTML_HEADER for more information on how to generate a default -# footer and what special commands can be used inside the footer. See also -# section "Doxygen usage" for information on how to generate the default footer -# that doxygen normally uses. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style -# sheet that is used by each HTML page. It can be used to fine-tune the look of -# the HTML output. If left blank doxygen will generate a default style sheet. -# See also section "Doxygen usage" for information on how to generate the style -# sheet that doxygen normally uses. -# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as -# it is more robust and this tag (HTML_STYLESHEET) will in the future become -# obsolete. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_STYLESHEET = - -# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user- -# defined cascading style sheet that is included after the standard style sheets -# created by doxygen. Using this option one can overrule certain style aspects. -# This is preferred over using HTML_STYLESHEET since it does not replace the -# standard style sheet and is therefor more robust against future updates. -# Doxygen will copy the style sheet file to the output directory. For an example -# see the documentation. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_EXTRA_STYLESHEET = doxygen-custom.css - -# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or -# other source files which should be copied to the HTML output directory. Note -# that these files will be copied to the base HTML output directory. Use the -# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these -# files. In the HTML_STYLESHEET file, use the file name only. Also note that the -# files will be copied as-is; there are no commands or markers available. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_EXTRA_FILES = - -# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen -# will adjust the colors in the stylesheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see -# http://en.wikipedia.org/wiki/Hue for more information. For instance the value -# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 -# purple, and 360 is red again. -# Minimum value: 0, maximum value: 359, default value: 220. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_HUE = 220 - -# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A -# value of 255 will produce the most vivid colors. -# Minimum value: 0, maximum value: 255, default value: 100. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_SAT = 100 - -# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the -# luminance component of the colors in the HTML output. Values below 100 -# gradually make the output lighter, whereas values above 100 make the output -# darker. The value divided by 100 is the actual gamma applied, so 80 represents -# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not -# change the gamma. -# Minimum value: 40, maximum value: 240, default value: 80. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_COLORSTYLE_GAMMA = 80 - -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_TIMESTAMP = YES - -# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML -# documentation will contain sections that can be hidden and shown after the -# page has loaded. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_DYNAMIC_SECTIONS = YES - -# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries -# shown in the various tree structured indices initially; the user can expand -# and collapse entries dynamically later on. Doxygen will expand the tree to -# such a level that at most the specified number of entries are visible (unless -# a fully collapsed tree already exceeds this amount). So setting the number of -# entries 1 will produce a full collapsed tree by default. 0 is a special value -# representing an infinite number of entries and will result in a full expanded -# tree by default. -# Minimum value: 0, maximum value: 9999, default value: 100. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_INDEX_NUM_ENTRIES = 100 - -# If the GENERATE_DOCSET tag is set to YES, additional index files will be -# generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: http://developer.apple.com/tools/xcode/), introduced with -# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a -# Makefile in the HTML output directory. Running make will produce the docset in -# that directory and running make install will install the docset in -# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at -# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_DOCSET = NO - -# This tag determines the name of the docset feed. A documentation feed provides -# an umbrella under which multiple documentation sets from a single provider -# (such as a company or product suite) can be grouped. -# The default value is: Doxygen generated docs. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_FEEDNAME = "Doxygen generated docs" - -# This tag specifies a string that should uniquely identify the documentation -# set bundle. This should be a reverse domain-name style string, e.g. -# com.mycompany.MyDocSet. Doxygen will append .docset to the name. -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_BUNDLE_ID = org.doxygen.Project - -# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify -# the documentation publisher. This should be a reverse domain-name style -# string, e.g. com.mycompany.MyDocSet.documentation. -# The default value is: org.doxygen.Publisher. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_PUBLISHER_ID = org.doxygen.Publisher - -# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. -# The default value is: Publisher. -# This tag requires that the tag GENERATE_DOCSET is set to YES. - -DOCSET_PUBLISHER_NAME = Publisher - -# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three -# additional HTML index files: index.hhp, index.hhc, and index.hhk. The -# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on -# Windows. -# -# The HTML Help Workshop contains a compiler that can convert all HTML output -# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML -# files are now used as the Windows 98 help format, and will replace the old -# Windows help format (.hlp) on all Windows platforms in the future. Compressed -# HTML files also contain an index, a table of contents, and you can search for -# words in the documentation. The HTML workshop also contains a viewer for -# compressed HTML files. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_HTMLHELP = NO - -# The CHM_FILE tag can be used to specify the file name of the resulting .chm -# file. You can add a path in front of the file if the result should not be -# written to the html output directory. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -CHM_FILE = - -# The HHC_LOCATION tag can be used to specify the location (absolute path -# including file name) of the HTML help compiler ( hhc.exe). If non-empty -# doxygen will try to run the HTML help compiler on the generated index.hhp. -# The file has to be specified with full path. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -HHC_LOCATION = - -# The GENERATE_CHI flag controls if a separate .chi index file is generated ( -# YES) or that it should be included in the master .chm file ( NO). -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -GENERATE_CHI = NO - -# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc) -# and project file content. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -CHM_INDEX_ENCODING = - -# The BINARY_TOC flag controls whether a binary table of contents is generated ( -# YES) or a normal table of contents ( NO) in the .chm file. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members to -# the table of contents of the HTML help documentation and to the tree view. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTMLHELP is set to YES. - -TOC_EXPAND = NO - -# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and -# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that -# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help -# (.qch) of the generated HTML documentation. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_QHP = NO - -# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify -# the file name of the resulting .qch file. The path specified is relative to -# the HTML output folder. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QCH_FILE = - -# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help -# Project output. For more information please see Qt Help Project / Namespace -# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_NAMESPACE = org.doxygen.Project - -# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt -# Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- -# folders). -# The default value is: doc. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_VIRTUAL_FOLDER = doc - -# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom -# filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_CUST_FILTER_NAME = - -# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the -# custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- -# filters). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_CUST_FILTER_ATTRS = - -# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this -# project's filter section matches. Qt Help Project / Filter Attributes (see: -# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHP_SECT_FILTER_ATTRS = - -# The QHG_LOCATION tag can be used to specify the location of Qt's -# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the -# generated .qhp file. -# This tag requires that the tag GENERATE_QHP is set to YES. - -QHG_LOCATION = - -# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be -# generated, together with the HTML files, they form an Eclipse help plugin. To -# install this plugin and make it available under the help contents menu in -# Eclipse, the contents of the directory containing the HTML and XML files needs -# to be copied into the plugins directory of eclipse. The name of the directory -# within the plugins directory should be the same as the ECLIPSE_DOC_ID value. -# After copying Eclipse needs to be restarted before the help appears. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_ECLIPSEHELP = NO - -# A unique identifier for the Eclipse help plugin. When installing the plugin -# the directory name containing the HTML and XML files should also have this -# name. Each documentation set should have its own identifier. -# The default value is: org.doxygen.Project. -# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES. - -ECLIPSE_DOC_ID = org.doxygen.Project - -# If you want full control over the layout of the generated HTML pages it might -# be necessary to disable the index and replace it with your own. The -# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top -# of each HTML page. A value of NO enables the index and the value YES disables -# it. Since the tabs in the index contain the same information as the navigation -# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -DISABLE_INDEX = NO - -# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index -# structure should be generated to display hierarchical information. If the tag -# value is set to YES, a side panel will be generated containing a tree-like -# index structure (just like the one that is generated for HTML Help). For this -# to work a browser that supports JavaScript, DHTML, CSS and frames is required -# (i.e. any modern browser). Windows users are probably better off using the -# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -GENERATE_TREEVIEW = NO - -# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that -# doxygen will group on one line in the generated HTML documentation. -# -# Note that a value of 0 will completely suppress the enum values from appearing -# in the overview section. -# Minimum value: 0, maximum value: 20, default value: 4. -# This tag requires that the tag GENERATE_HTML is set to YES. - -ENUM_VALUES_PER_LINE = 4 - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used -# to set the initial width (in pixels) of the frame in which the tree is shown. -# Minimum value: 0, maximum value: 1500, default value: 250. -# This tag requires that the tag GENERATE_HTML is set to YES. - -TREEVIEW_WIDTH = 250 - -# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to -# external symbols imported via tag files in a separate window. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -EXT_LINKS_IN_WINDOW = NO - -# Use this tag to change the font size of LaTeX formulas included as images in -# the HTML documentation. When you change the font size after a successful -# doxygen run you need to manually remove any form_*.png images from the HTML -# output directory to force them to be regenerated. -# Minimum value: 8, maximum value: 50, default value: 10. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_FONTSIZE = 10 - -# Use the FORMULA_TRANPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_TRANSPARENT = YES - -# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# http://www.mathjax.org) which uses client side Javascript for the rendering -# instead of using prerendered bitmaps. Use this if you do not have LaTeX -# installed or if you want to formulas look prettier in the HTML output. When -# enabled you may also need to install MathJax separately and configure the path -# to it using the MATHJAX_RELPATH option. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -USE_MATHJAX = NO - -# When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. -# Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. -# The default value is: HTML-CSS. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_FORMAT = HTML-CSS - -# When MathJax is enabled you need to specify the location relative to the HTML -# output directory using the MATHJAX_RELPATH option. The destination directory -# should contain the MathJax.js script. For instance, if the mathjax directory -# is located at the same level as the HTML output directory, then -# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax -# Content Delivery Network so you can quickly see the result without installing -# MathJax. However, it is strongly recommended to install a local copy of -# MathJax from http://www.mathjax.org before deployment. -# The default value is: http://cdn.mathjax.org/mathjax/latest. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest - -# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax -# extension names that should be enabled during MathJax rendering. For example -# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_EXTENSIONS = - -# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces -# of code that will be used on startup of the MathJax code. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an -# example see the documentation. -# This tag requires that the tag USE_MATHJAX is set to YES. - -MATHJAX_CODEFILE = - -# When the SEARCHENGINE tag is enabled doxygen will generate a search box for -# the HTML output. The underlying search engine uses javascript and DHTML and -# should work on any modern browser. Note that when using HTML help -# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET) -# there is already a search function so this one should typically be disabled. -# For large projects the javascript based search engine can be slow, then -# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to -# search using the keyboard; to jump to the search box use + S -# (what the is depends on the OS and browser, but it is typically -# , /