From 52ac498edae9f223458e3d9764285c17afbe9c89 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Thu, 25 Jan 2018 22:52:57 +0100 Subject: [PATCH 01/60] Development version 2.2.1-alpha (#1043) --- README.md | 2 +- core/Version.h | 6 +++--- library.json | 2 +- library.properties | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2c49716..b86fa20 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -MySensors Library v2.2.0 +MySensors Library v2.2.1-alpha Please visit www.mysensors.org for more information diff --git a/core/Version.h b/core/Version.h index 5cffbec..12b135b 100644 --- a/core/Version.h +++ b/core/Version.h @@ -48,9 +48,9 @@ #define MYSENSORS_LIBRARY_VERSION_MAJOR 2 //!< Major release version #define MYSENSORS_LIBRARY_VERSION_MINOR 2 //!< Minor release version -#define MYSENSORS_LIBRARY_VERSION_PATCH 0 //!< Patch version -#define MYSENSORS_LIBRARY_VERSION_PRERELEASE "" //!< Pre-release suffix, i.e. alpha, beta, rc.1, etc -#define MYSENSORS_LIBRARY_VERSION_PRERELEASE_NUMBER 0xFF //!< incremental counter, starting at 0x00. 0xFF for final release +#define MYSENSORS_LIBRARY_VERSION_PATCH 1 //!< Patch version +#define MYSENSORS_LIBRARY_VERSION_PRERELEASE "alpha" //!< Pre-release suffix, i.e. alpha, beta, rc.1, etc +#define MYSENSORS_LIBRARY_VERSION_PRERELEASE_NUMBER 0x00 //!< incremental counter, starting at 0x00. 0xFF for final release #if (MYSENSORS_LIBRARY_VERSION_PRERELEASE_NUMBER != 0xFF) diff --git a/library.json b/library.json index 9ada90e..0f1bdb9 100644 --- a/library.json +++ b/library.json @@ -7,7 +7,7 @@ "type": "git", "url": "https://github.com/mysensors/MySensors.git" }, - "version": "2.2.0", + "version": "2.2.1-alpha", "frameworks": "arduino", "platforms": [ "atmelavr", diff --git a/library.properties b/library.properties index 6a61a5b..6f210d4 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=MySensors -version=2.2.0 +version=2.2.1-alpha author=The MySensors Team maintainer=The MySensors Team sentence=Home Automation Framework From 06269dd94908c35b67ec206339b7cac36eb3352b Mon Sep 17 00:00:00 2001 From: Mikael Falkvidd Date: Sun, 28 Jan 2018 09:31:19 +0100 Subject: [PATCH 02/60] Fix cppcheck issues (#1036) Fixes the following cppcheck issues: examples/SecretKnockSensor/SecretKnockSensor.ino 305 variableScope 398 style The scope of the variable 'timeDiff' can be reduced. examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino 127 variableScope 398 style The scope of the variable 'led_state' can be reduced. --- examples/SecretKnockSensor/SecretKnockSensor.ino | 3 +-- examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/SecretKnockSensor/SecretKnockSensor.ino b/examples/SecretKnockSensor/SecretKnockSensor.ino index b473937..2bdf79c 100644 --- a/examples/SecretKnockSensor/SecretKnockSensor.ino +++ b/examples/SecretKnockSensor/SecretKnockSensor.ino @@ -302,8 +302,7 @@ bool validateKnock() 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 + for (int timeDiff = 0, 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 > diff --git a/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino b/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino index 1a62255..d0a9637 100644 --- a/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino +++ b/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino @@ -124,8 +124,8 @@ void preHwInit() for (int i=0; i< num_of_leds; i++) { pinMode(leds[i], OUTPUT); } - uint8_t led_state = 0; if (digitalRead(MY_SWC1)) { + uint8_t led_state = 0; while (!Serial) { digitalWrite(LED_BLUE, led_state); led_state ^= 0x01; From eff11367333162a772837471acadb5867ea22360 Mon Sep 17 00:00:00 2001 From: tekka Date: Sun, 28 Jan 2018 14:41:03 +0100 Subject: [PATCH 03/60] RFM69: Fix compiler warning (#1046) --- hal/transport/MyTransportRFM69.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hal/transport/MyTransportRFM69.cpp b/hal/transport/MyTransportRFM69.cpp index 39c5562..31501bf 100644 --- a/hal/transport/MyTransportRFM69.cpp +++ b/hal/transport/MyTransportRFM69.cpp @@ -26,8 +26,10 @@ bool transportInit(void) { const bool result = RFM69_initialise(MY_RFM69_FREQUENCY); -#if !defined(MY_GATEWAY_FEATURE) && !defined(MY_RFM69_ATC_MODE_DISABLED) - // only enable ATC mode nodes +#if defined(MY_GATEWAY_FEATURE) || defined(MY_RFM69_ATC_MODE_DISABLED) + // ATC mode disabled on GW + RFM69_ATCmode(false); +#else RFM69_ATCmode(true, MY_RFM69_ATC_TARGET_RSSI_DBM); #endif From 8fbdca445280ac41de0c62b333507595c518533b Mon Sep 17 00:00:00 2001 From: Mikael Falkvidd Date: Tue, 30 Jan 2018 20:47:11 +0100 Subject: [PATCH 04/60] Doxygenize MyMessage / Message manipulation (#1035) * Fix cppcheck issues Fixes the following cppcheck issues: examples/SecretKnockSensor/SecretKnockSensor.ino 305 variableScope 398 style The scope of the variable 'timeDiff' can be reduced. examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino 127 variableScope 398 style The scope of the variable 'led_state' can be reduced. * Doxygenize MyMessage / Message manipulation This should replace the static documentation at http://korturl.nu/stupid I have enabled existing comments and added new comments where necessary. Feedback on syntax and contents is welcome. --- core/MyMessage.cpp | 1 - core/MyMessage.h | 217 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 179 insertions(+), 39 deletions(-) diff --git a/core/MyMessage.cpp b/core/MyMessage.cpp index 1cea592..8382725 100644 --- a/core/MyMessage.cpp +++ b/core/MyMessage.cpp @@ -76,7 +76,6 @@ const char* MyMessage::getString() const } } -// handles single character hex (0 - 15) char MyMessage::i2h(uint8_t i) const { uint8_t k = i & 0x0F; diff --git a/core/MyMessage.h b/core/MyMessage.h index 91c08cb..ad10e34 100644 --- a/core/MyMessage.h +++ b/core/MyMessage.h @@ -50,6 +50,7 @@ typedef enum { C_STREAM = 4 //!< For firmware and other larger chunks of data that need to be divided into pieces. } mysensor_command; +#if !DOXYGEN // Hide until we migrate /// @brief Type of sensor (used when presenting sensors) typedef enum { S_DOOR = 0, //!< Door sensor, V_TRIPPED, V_ARMED @@ -158,6 +159,7 @@ typedef enum { 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; +#endif /// @brief Type of internal messages (for internal messages) @@ -275,23 +277,37 @@ typedef enum { #define miGetPayloadType() (uint8_t)BF_GET(command_ack_payload, 5, 3) //!< Internal getter for payload type field -#if !DOXYGEN -#ifdef __cplusplus +#if defined(__cplusplus) || defined(DOXYGEN) +/** + * @brief MyMessage is used to create, manipulate, send and read MySensors messages + */ class MyMessage { private: char* getCustomString(char *buffer) const; public: - // Constructors + /** + * Default constructor + */ MyMessage(); + /** + * Constructor + * @param sensor id of the child sensor for this message + * @param type see http://korturl.nu/stupidurl + */ MyMessage(uint8_t sensor, uint8_t type); + /** + * Single character hex (0 - 15) conversion + * @param i byte (only lower 4 bits will be considered) + * @return single char with the hex representation (0 to F) of the parameter + */ char i2h(uint8_t i) const; /** - * Clear message contents. + * @brief Clear message contents. */ void clear(); @@ -299,42 +315,158 @@ public: * 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 * 2*MAX_PAYLOAD+1. This is to be able to fit hex-conversion of a full binary payload. + * @param buffer pointer to a buffer that's at least 2*MAX_PAYLOAD+1 bytes large */ char* getStream(char *buffer) const; + + /** + * @brief Copy the payload into the supplied buffer + */ char* getString(char *buffer) const; + + /** + * @brief Get payload as string + * @return pointer to a char array storing the string + */ const char* getString() const; + + /** + * @brief Get custom payload + * @return pointer to the raw payload + */ void* getCustom() const; + + /** + * @brief Get bool payload + * @return a bool with the value of the payload (true/false) + */ bool getBool() const; + + /** + * @brief Get unsigned 8-bit integer payload + * @return the value of the payload, 0 to 255 + */ uint8_t getByte() const; + + /** + * @brief Get float payload + * @return the floating-point value of the payload + */ float getFloat() const; + + /** + * @brief Get signed 16-bit integer payload + * @return the value of the payload, –32768 to 32767 + */ int16_t getInt() const; + + /** + * @brief Get unsigned 16-bit integer payload + * @return the value of the payload, 0 to 65535 + */ uint16_t getUInt() const; + + /** + * @brief Get signed 32-bit integer payload + * @return the value of the payload, –2147483648 to 2147483647 + */ int32_t getLong() const; + + /** + * @brief Get unsigned 32-bit integer payload + * @return the value of the payload, 0 to 4294967295 + */ uint32_t getULong() const; - // Getter for command type + /** + * @brief Getter for command type + * @return #mysensor_command + */ uint8_t getCommand() const; - // Getter for ack-flag. True if this is an ack message. + /** + * @brief Getter for ack-flag. + * @return true if this is an ack message + */ bool isAck() const; - // Setters for building message "on the fly" + /** + * @brief Set message type + * @param type see http://korturl.nu/stupidurl + */ MyMessage& setType(uint8_t type); + + /** + * @brief Set which child sensor this message belongs to + */ MyMessage& setSensor(uint8_t sensor); + + /** + * @brief Set final destination node id for this message + */ MyMessage& setDestination(uint8_t destination); - // Setters for payload + /** + * @brief Set entire payload + * @param payload pointer to the buffer where the payload is stored + * @param length of the payload + */ MyMessage& set(void* payload, uint8_t length); + + /** + * @brief Set payload to character array + * @param value pointer to the character array. The array must be null-terminated. + */ MyMessage& set(const char* value); #if !defined(__linux__) + /** + * @brief Set payload to character array from flash + * @param value pointer to the character array. The array must be null-terminated. + */ MyMessage& set(const __FlashStringHelper* value); #endif + + /** + * @brief Set payload to decimal number + * @param value float + * @param decimals number of decimals to include + */ MyMessage& set(float value, uint8_t decimals); + + /** + * @brief Set payload to bool value + * @param value true or false + */ MyMessage& set(bool value); + + /** + * @brief Set payload to unsigned 8-bit integer value + * @param value (0 to 255) + */ MyMessage& set(uint8_t value); + + /** + * @brief Set payload to unsigned 32-bit integer value + * @param value (0 to 4294967295) + */ MyMessage& set(uint32_t value); + + /** + * @brief Set payload to signed 32-bit integer value + * @param value (–2147483648 to 2147483647) + */ MyMessage& set(int32_t value); + + /** + * @brief Set payload to unsigned 16-bit integer value + * @param value (0 to 65535) + */ MyMessage& set(uint16_t value); + + /** + * @brief Set payload to signed 16-bit integer value + * @param value (–32768 to 32767) + */ MyMessage& set(int16_t value); #else @@ -343,47 +475,56 @@ typedef union { struct { #endif - uint8_t last; // 8 bit - Id of last node this message passed - uint8_t sender; // 8 bit - Id of sender node (origin) - uint8_t destination; // 8 bit - Id of destination node + uint8_t last; ///< 8 bit - Id of last node this message passed + uint8_t sender; ///< 8 bit - Id of sender node (origin) + 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 - 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 message - 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. + /** + * 2 bit - Protocol version
+ * 1 bit - Signed flag
+ * 5 bit - Length of payload + */ + uint8_t version_length; - // Each message can transfer a payload. We add one extra byte for string - // terminator \0 to be "printable" this is not transferred OTA - // This union is used to simplify the construction of the binary data types transferred. + /** + * 3 bit - Command type
+ * 1 bit - Request an ack - Indicator that receiver should send an ack back
+ * 1 bit - Is ack message - Indicator that this is the actual ack message
+ * 3 bit - Payload data type + */ + uint8_t command_ack_payload; + + uint8_t type; ///< 8 bit - Type varies depending on command + uint8_t sensor; ///< 8 bit - Id of sensor that this message concerns. + + /* + * Each message can transfer a payload. We add one extra byte for string + * terminator \0 to be "printable" this is not transferred OTA + * This union is used to simplify the construction of the binary data types transferred. + */ union { - uint8_t bValue; - uint16_t uiValue; - int16_t iValue; - uint32_t ulValue; - int32_t lValue; - struct { // Float messages + uint8_t bValue; ///< unsigned byte value (8-bit) + uint16_t uiValue; ///< unsigned integer value (16-bit) + int16_t iValue; ///< signed integer value (16-bit) + uint32_t ulValue; ///< unsigned long value (32-bit) + int32_t lValue; ///< signed long value (32-bit) + struct { //< Float messages float fValue; - uint8_t fPrecision; // Number of decimals when serializing + uint8_t fPrecision; ///< Number of decimals when serializing }; - struct { // Presentation messages - uint8_t version; // Library version - uint8_t sensorType; // Sensor type hint for controller, see table above + struct { //< Presentation messages + uint8_t version; ///< Library version + uint8_t sensorType; ///< Sensor type hint for controller, see table above }; - char data[MAX_PAYLOAD + 1]; - } __attribute__((packed)); -#ifdef __cplusplus + char data[MAX_PAYLOAD + 1]; ///< Buffer for raw payload data + } __attribute__((packed)); ///< Doxygen will complain without this comment +#if defined(__cplusplus) || defined(DOXYGEN) } __attribute__((packed)); #else }; -uint8_t array[HEADER_SIZE + MAX_PAYLOAD + 1]; +uint8_t array[HEADER_SIZE + MAX_PAYLOAD + 1]; ///< buffer for entire message } __attribute__((packed)) MyMessage; #endif -#endif #endif /** @}*/ From 14d8accf37169191af8f26b9e18db345105bae15 Mon Sep 17 00:00:00 2001 From: Kartik Arora Date: Wed, 31 Jan 2018 01:34:37 +0530 Subject: [PATCH 05/60] Add URL option for MQTT broker in example sketch (#1033) --- examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino b/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino index 0cc91ca..4fe945f 100644 --- a/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino +++ b/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino @@ -100,6 +100,9 @@ // MQTT broker ip address. #define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 68 +//MQTT broker if using URL instead of ip address. +// #define MY_CONTROLLER_URL_ADDRESS "test.mosquitto.org" + // The MQTT broker port to to open #define MY_PORT 1883 From 7ed54423fbee959d7f0edaa1c8287154957ac8d7 Mon Sep 17 00:00:00 2001 From: Miloslav Kazda Date: Fri, 2 Feb 2018 12:37:53 +0100 Subject: [PATCH 06/60] RFM69 - add keyword MY_RFM69_IRQ_PIN (#1052) * Add MY_RFM69_IRQ_PIN keyword Add MY_RFM69_IRQ_PIN into keywords.txt --- keywords.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/keywords.txt b/keywords.txt index 11951d6..15fa12a 100644 --- a/keywords.txt +++ b/keywords.txt @@ -160,6 +160,7 @@ MY_RFM69_MAX_POWER_LEVEL_DBM LITERAL1 MY_RFM69_NETWORKID LITERAL1 MY_RFM69_RST_PIN LITERAL1 MY_RFM69_IRQ_PIN LITERAL1 +MY_RFM69_IRQ_NUM LITERAL1 MY_RFM69_CS_PIN LITERAL1 MY_RFM69_ENABLE_ENCRYPTION LITERAL1 MY_RFM69_ENABLE_LISTENMODE LITERAL1 From dea0fd50ca2a9c729462523b054b9e8141a5ddce Mon Sep 17 00:00:00 2001 From: tekka Date: Sat, 10 Feb 2018 18:49:31 +0100 Subject: [PATCH 07/60] Fix smartSleep() (#1060) --- core/MySensorsCore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index c971579..5412e87 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -585,7 +585,7 @@ int8_t _sleep(const uint32_t sleepingMS, const bool smartSleep, const uint8_t in #endif // MY_OTA_FIRMWARE_FEATURE if (smartSleep) { // sleeping time left? - if (sleepingTimeMS < ((uint32_t)MY_SMART_SLEEP_WAIT_DURATION_MS)) { + if (sleepingTimeMS > 0 && sleepingTimeMS < ((uint32_t)MY_SMART_SLEEP_WAIT_DURATION_MS)) { wait(sleepingMS); CORE_DEBUG(PSTR("!MCO:SLP:NTL\n")); // sleeping not possible, no time left return MY_SLEEP_NOT_POSSIBLE; From 72b71c8fc810c891043a34ceb8b77f216118b147 Mon Sep 17 00:00:00 2001 From: tekka Date: Sat, 10 Feb 2018 18:58:20 +0100 Subject: [PATCH 08/60] AVR: Harmonize code (#1059) --- hal/architecture/AVR/MyHwAVR.cpp | 55 +++++++++++++++++++------------- hal/architecture/AVR/MyHwAVR.h | 4 +-- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/hal/architecture/AVR/MyHwAVR.cpp b/hal/architecture/AVR/MyHwAVR.cpp index 8a3bf22..07f50ea 100644 --- a/hal/architecture/AVR/MyHwAVR.cpp +++ b/hal/architecture/AVR/MyHwAVR.cpp @@ -38,7 +38,7 @@ volatile uint8_t _wakeUp1Interrupt = volatile uint8_t _wakeUp2Interrupt = INVALID_INTERRUPT_NUM; // Interrupt number for wakeUp2-callback. -void wakeUp1() +void wakeUp1(void) { // Disable sleep. When an interrupt occurs after attachInterrupt, // but before sleeping the CPU would not wake up. @@ -50,7 +50,7 @@ void wakeUp1() _wokeUpByInterrupt = _wakeUp1Interrupt; } } -void wakeUp2() +void wakeUp2(void) { sleep_disable(); detachInterrupt(_wakeUp2Interrupt); @@ -60,7 +60,7 @@ void wakeUp2() } } -inline bool interruptWakeUp() +inline bool interruptWakeUp(void) { return _wokeUpByInterrupt != INVALID_INTERRUPT_NUM; } @@ -86,7 +86,7 @@ void hwPowerDown(const uint8_t wdto) // disable ADC for power saving ADCSRA &= ~(1 << ADEN); // save WDT settings - uint8_t WDTsave = WDTCSR; + const uint8_t WDTsave = WDTCSR; if (wdto != WDTO_SLEEP_FOREVER) { wdt_enable(wdto); // enable WDT interrupt before system reset @@ -98,7 +98,7 @@ void hwPowerDown(const uint8_t wdto) set_sleep_mode(SLEEP_MODE_PWR_DOWN); cli(); sleep_enable(); -#if defined __AVR_ATmega328P__ +#if defined(__AVR_ATmega328P__) sleep_bod_disable(); #endif // Enable interrupts & sleep until WDT or ext. interrupt @@ -144,12 +144,13 @@ int8_t hwSleep(uint32_t ms) return MY_WAKE_UP_BY_TIMER; } -int8_t hwSleep(uint8_t interrupt, uint8_t mode, uint32_t ms) +int8_t hwSleep(const uint8_t interrupt, const uint8_t mode, uint32_t ms) { - return hwSleep(interrupt,mode,INVALID_INTERRUPT_NUM,0u,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, +int8_t hwSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, + const uint8_t mode2, uint32_t ms) { // ATMega328P supports following modes to wake from sleep: LOW, CHANGE, RISING, FALLING @@ -203,14 +204,13 @@ int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mo return ret; } -inline void hwRandomNumberInit() +inline void hwRandomNumberInit(void) { // This function initializes the random number generator with a seed // of 32 bits. This method is good enough to earn FIPS 140-2 conform // random data. This should reach to generate 32 Bit for randomSeed(). uint32_t seed = 0; - uint32_t start = millis(); - uint32_t timeout = start + 20; + uint32_t timeout = millis() + 20; // Trigger floating effect of an unconnected pin pinMode(MY_SIGNING_SOFT_RANDOMSEED_PIN, INPUT_PULLUP); @@ -219,7 +219,7 @@ inline void hwRandomNumberInit() // Generate 32 bits of datas for (uint8_t i=0; i<32; i++) { - int pinValue = analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN); + const int pinValue = analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN); // Wait until the analog value has changed while ((pinValue == analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)) && (timeout>=millis())) { seed ^= (millis() << i); @@ -230,11 +230,10 @@ inline void hwRandomNumberInit() pinMode(MY_SIGNING_SOFT_RANDOMSEED_PIN, INPUT); // Pause a short while delay(seed % 10); - timeout = millis()+20; + timeout = millis() + 20; } } } - randomSeed(seed); } @@ -247,14 +246,18 @@ bool hwUniqueID(unique_id_t* uniqueID) *((uint8_t*)uniqueID + 1) = boot_signature_byte_get(0x02); *((uint8_t*)uniqueID + 2) = boot_signature_byte_get(0x04); *((uint8_t*)uniqueID + 3) = boot_signature_byte_get(0x01); //OSCCAL +#if defined(__AVR_ATmega328PB__) // ATMEGA328PB specifics, has unique ID - //for(uint8_t idx = 0; idx < 10; idx++) { - // *((uint8_t*)uniqueID + 4 + idx) = boot_signature_byte_get(0xE + idx); - //} - return false; // false, since no unique ID returned + for(uint8_t idx = 0; idx < 10; idx++) { + *((uint8_t*)uniqueID + 4 + idx) = boot_signature_byte_get(0xE + idx); + } + return true; // unique ID returned +#else + return false; // no unique ID returned +#endif } -uint16_t hwCPUVoltage() +uint16_t hwCPUVoltage(void) { // Measure Vcc against 1.1V Vref #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) @@ -275,16 +278,19 @@ uint16_t hwCPUVoltage() return (1125300UL) / ADC; } -uint16_t hwCPUFrequency() +uint16_t hwCPUFrequency(void) { cli(); + // save WDT & timer settings + const uint8_t WDTsave = WDTCSR; + const uint8_t TCCR1Asave = TCCR1A; + const uint8_t TCCR1Csave = TCCR1C; // setup timer1 TIFR1 = 0xFF; TCNT1 = 0; TCCR1A = 0; TCCR1C = 0; - // save WDT settings - uint8_t WDTsave = WDTCSR; + // set wdt wdt_enable(WDTO_500MS); // enable WDT interrupt mode => first timeout WDIF, 2nd timeout reset WDTCSR |= (1 << WDIE); @@ -300,11 +306,14 @@ uint16_t hwCPUFrequency() WDTCSR |= (1 << WDCE) | (1 << WDE); WDTCSR = WDTsave; sei(); + // restore timer settings + TCCR1A = TCCR1Asave; + TCCR1C = TCCR1Csave; // return frequency in 1/10MHz (accuracy +- 10%) return TCNT1 * 2048UL / 100000UL; } -uint16_t hwFreeMem() +uint16_t hwFreeMem(void) { extern int __heap_start, *__brkval; int v; diff --git a/hal/architecture/AVR/MyHwAVR.h b/hal/architecture/AVR/MyHwAVR.h index a189f70..863ed64 100644 --- a/hal/architecture/AVR/MyHwAVR.h +++ b/hal/architecture/AVR/MyHwAVR.h @@ -55,8 +55,8 @@ bool hwInit(void); #define hwReadConfigBlock(__buf, __pos, __length) eeprom_read_block((void*)(__buf), (void*)(__pos), (__length)) #define hwWriteConfigBlock(__buf, __pos, __length) eeprom_update_block((void*)(__buf), (void*)(__pos), (__length)) -inline void hwRandomNumberInit(); -void hwInternalSleep(unsigned long ms); +inline void hwRandomNumberInit(void); +void hwInternalSleep(uint32_t ms); #ifndef DOXYGEN #define MY_CRITICAL_SECTION ATOMIC_BLOCK(ATOMIC_RESTORESTATE) From 968b2daff731873645986d27423892062db19cd8 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sat, 10 Feb 2018 20:43:18 +0100 Subject: [PATCH 09/60] Various CI-pipeline fixes (#1042) * Let Gitler produce a changelog for release builds * Fix bug in publishing release documentation * Fix bug in labeling documentation (now uses tag data for better tracability) * Update copyright in documentation --- .ci/doxygen.groovy | 2 +- .ci/gitler.groovy | 34 ++++++++++++++++++++++++++++++++++ Documentation/doxygen.sh | 8 +------- Documentation/mainpage.dox | 2 +- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/.ci/doxygen.groovy b/.ci/doxygen.groovy index efab023..5c69ae9 100644 --- a/.ci/doxygen.groovy +++ b/.ci/doxygen.groovy @@ -19,7 +19,7 @@ def call(config) { // Publish docs to API server if (env.BRANCH_NAME == 'master') { sh """#!/bin/bash - scp -r ${config.repository_root}Documentation/html docs@direct.openhardware.io""" + scp -r ${config.repository_root}Documentation/html docs@direct.openhardware.io:""" } else if (env.BRANCH_NAME == 'development') { sh """#!/bin/bash scp -r ${config.repository_root}Documentation/html docs@direct.openhardware.io:beta""" diff --git a/.ci/gitler.groovy b/.ci/gitler.groovy index 5200411..00e4e79 100644 --- a/.ci/gitler.groovy +++ b/.ci/gitler.groovy @@ -15,7 +15,41 @@ def call(config) { else if (env.CHANGE_TARGET == 'master') { echo env.CHANGE_AUTHOR + ' is a valid author for targeting master branch, skipping further validation' + dir(config.repository_root) { + step([$class: 'GitChangelogRecorder', config: [configFile: 'git-changelog-settings.json', + createFileTemplateContent: ''' +# Changelog +{{#commits}} +### {{{messageTitle}}} +{{{messageBody}}} +[{{hash}}](https://github.com/mysensors/MySensors/commit/{{hash}}) by {{authorName}} at *{{commitTime}}* +{{/commits}} +''', + createFileTemplateFile: '', createFileUseTemplateContent: true, + createFileUseTemplateFile: false, customIssues: [[link: '', name: '', pattern: '', title: ''], + [link: '', name: '', pattern: '', title: '']], dateFormat: 'YYYY-MM-dd HH:mm:ss', + file: 'ReleaseNotes.md', fromReference: env.CHANGE_TARGET, fromType: 'ref', gitHubApi: '', + gitHubApiTokenCredentialsId: '', gitHubIssuePattern: '#([0-9]+)', gitHubToken: '', + gitLabApiTokenCredentialsId: '', gitLabProjectName: '', gitLabServer: '', gitLabToken: '', + ignoreCommitsIfMessageMatches: '^Merge.*', + ignoreCommitsWithoutIssue: false, ignoreTagsIfNameMatches: '', + jiraIssuePattern: '\\b[a-zA-Z]([a-zA-Z]+)-([0-9]+)\\b', jiraPassword: '', jiraServer: '', + jiraUsername: '', jiraUsernamePasswordCredentialsId: '', mediaWikiPassword: '', + mediaWikiTemplateContent: '', mediaWikiTemplateFile: '', mediaWikiTitle: '', mediaWikiUrl: '', + mediaWikiUseTemplateContent: false, mediaWikiUseTemplateFile: false, mediaWikiUsername: '', + noIssueName: 'No issue', readableTagName: '/([^/]+?)$', showSummary: false, + showSummaryTemplateContent: '', showSummaryTemplateFile: '', showSummaryUseTemplateContent: false, + showSummaryUseTemplateFile: false, subDirectory: '', timeZone: 'UTC', + toReference: config.git_sha, toType: 'commit', untaggedName: 'Unreleased', + useConfigFile: false, useFile: true, useGitHub: true, useGitHubApiTokenCredentials: false, + useGitLab: false, useGitLabApiTokenCredentials: false, useIgnoreTagsIfNameMatches: false, + useJira: false, useJiraUsernamePasswordCredentialsId: false, useMediaWiki: false, + useReadableTagName: false, useSubDirectory: false] + ]) + } + config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Gitler)', 'Pass', '') + config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Release changelog)', '', '${BUILD_URL}execution/node/3/ws/MySensors/ReleaseNotes.md/*view*/') return } diff --git a/Documentation/doxygen.sh b/Documentation/doxygen.sh index a724bd1..36bf079 100755 --- a/Documentation/doxygen.sh +++ b/Documentation/doxygen.sh @@ -7,13 +7,7 @@ echo -e "/**\n * @defgroup RaspberryPiGateway Raspberry Pi Gateway\n * @ingroup echo -e "@endverbatim\n@}*/\n" >> configure.h # Generate version information -export PROJECTNUMBER=$( - if [[ $(git rev-parse --abbrev-ref HEAD) == "master" ]]; then - git describe --tags ; - else - git rev-parse --short HEAD ; - fi -) +export PROJECTNUMBER=$(git fetch --tags; git describe --tags;) # Generate any UML diagrams in the code tree that has the proper tags export PLANTUML_JAR_PATH=Documentation/plantuml.jar diff --git a/Documentation/mainpage.dox b/Documentation/mainpage.dox index 273f2cb..7d16379 100644 --- a/Documentation/mainpage.dox +++ b/Documentation/mainpage.dox @@ -5,7 +5,7 @@ Are you a sketch developer/user, see @ref publics Are you a core/library developer, see @ref internals -@copyright (C) 2013-2017 Sensnology AB +@copyright (C) 2013-2018 Sensnology AB Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors */ From 8a1f5f4cf9d4a5ccecd087c5b5a0de4f29aea728 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sun, 11 Feb 2018 11:22:48 +0100 Subject: [PATCH 10/60] Revamp the simple password flag and rPi fixes (#1056) MY_SIGNING_SIMPLE_PASSWD is now called MY_SECURITY_SIMPLE_PASSWD. MY_SIGNING_SIMPLE_PASSWD only affects signing, and a new flag, MY_ENCRYPTION_SIMPLE_PASSWD only affects encryption. MY_SECURITY_SIMPLE_PASSWD enable both these flags. The rPi port has been improved to support more security settings and it is now also possible to enable encryption for RFM69 transport. Documentation has been improved to provide a "Security" section under "Library customisation" which has a table that summarize all security related configuration flags, and the corresponding rPi configuration flags. The signing personalization documentation has been updated to include the procedure for rPi. Fixes #1055 --- MyConfig.h | 99 +++++++++++++++++++++++--- configure | 47 +++++++++--- core/MySigning.h | 13 +++- hal/architecture/Linux/MyMainLinux.cpp | 6 +- hal/transport/MyTransportNRF5_ESB.cpp | 4 +- hal/transport/MyTransportRF24.cpp | 4 +- hal/transport/MyTransportRFM69.cpp | 8 +-- keywords.txt | 2 + 8 files changed, 151 insertions(+), 32 deletions(-) diff --git a/MyConfig.h b/MyConfig.h index 598b686..865f44d 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -1476,12 +1476,44 @@ * @ingroup MyConfigGrp * @brief These options control security related configurations. * - * Note that some encryption configurations are on a per-radio basis as these are specific to each - * radio. + * Overview over all security related settings and how/where to apply them: + * | Setting | Description | Arduino | Raspberry PI @c configure argument + * |--------------------------|-------------|---------|------------- + * | @ref MY_SECURITY_SIMPLE_PASSWD | Enables security (signing and encryption) without the need for @ref personalization | "#define" in the top of your sketch | Not supported (use the other two "simple" options) + * | @ref MY_SIGNING_SIMPLE_PASSWD | Enables signing without the need for @ref personalization | "#define" in the top of your sketch | @verbatim --my-signing=password --my-security-password= @endverbatim + * | @ref MY_ENCRYPTION_SIMPLE_PASSWD | Enables encryption without the need for @ref personalization | "#define" in the top of your sketch | @verbatim --my-security-password= @endverbatim and encryption enabled on the chosen transport + * | @ref MY_DEBUG_VERBOSE_SIGNING | Enables verbose signing debugging | "#define" in the top of your sketch | @verbatim --my-signing-debug @endverbatim + * | @ref MY_SIGNING_ATSHA204 | Enables support to sign messages backed by ATSHA204A hardware | "#define" in the top of your sketch | Not supported + * | @ref MY_SIGNING_SOFT | Enables support to sign messages backed by software | "#define" in the top of your sketch | @verbatim --my-signing=software @endverbatim + * | @ref MY_SIGNING_REQUEST_SIGNATURES | Enables node/gw to require signed messages | "#define" in the top of your sketch | @verbatim --my-signing-request-signatures @endverbatim + * | @ref MY_SIGNING_WEAK_SECURITY | Weakens signing security, useful for testing before deploying signing "globally" | "#define" in the top of your sketch | @verbatim --my-signing-weak_security @endverbatim + * | @ref MY_VERIFICATION_TIMEOUT_MS | Change default signing timeout | "#define" in the top of your sketch | @verbatim --my-signing-verification-timeout-ms= @endverbatim + * | @ref MY_SIGNING_NODE_WHITELISTING | Defines a whitelist of trusted nodes | "#define" in the top of your sketch | @verbatim --my-signing-whitelist="" @endverbatim + * | @ref MY_SIGNING_ATSHA204_PIN | Change default ATSHA204A communication pin | "#define" in the top of your sketch | Not supported + * | @ref MY_SIGNING_SOFT_RANDOMSEED_PIN | Change default software RNG seed pin | "#define" in the top of your sketch | Not supported + * | @ref MY_RF24_ENABLE_ENCRYPTION | Enables encryption on RF24 radios | "#define" in the top of your sketch | @verbatim --my-rf24-encryption-enabled @endverbatim + * | @ref MY_RFM69_ENABLE_ENCRYPTION | Enables encryption on %RFM69 radios | "#define" in the top of your sketch | @verbatim --my-rfm69-encryption-enabled @endverbatim + * | @ref MY_NRF5_ESB_ENABLE_ENCRYPTION | Enables encryption on nRF5 radios | "#define" in the top of your sketch | Not supported + * | @ref MY_NODE_LOCK_FEATURE | Enables the node locking feature | "#define" in the top of your sketch | Not supported + * | @ref MY_NODE_UNLOCK_PIN | Change default unlock pin | "#define" in the top of your sketch | Not supported + * | @ref MY_NODE_LOCK_COUNTER_MAX | Change default "malicious activity" counter max value | "#define" in the top of your sketch | Not supported * - * @see MY_RF24_ENABLE_ENCRYPTION, MY_RFM69_ENABLE_ENCRYPTION, MY_NRF5_ESB_ENABLE_ENCRYPTION * @{ */ +/** + * @def MY_SECURITY_SIMPLE_PASSWD + * @brief Enables SW backed signing functionality and encryption functionality in library and uses + * provided password as key. + * + * For details on the effects, see the references. + * @see MY_SIGNING_SIMPLE_PASSWD, MY_ENCRYPTION_SIMPLE_PASSWD + */ +//#define MY_SECURITY_SIMPLE_PASSWD "MyInsecurePassword" +#if defined(MY_SECURITY_SIMPLE_PASSWD) +#define MY_SIGNING_SIMPLE_PASSWD MY_SECURITY_SIMPLE_PASSWD +#define MY_ENCRYPTION_SIMPLE_PASSWD MY_SECURITY_SIMPLE_PASSWD +#endif + /** * @defgroup SigningSettingGrpPub Signing * @ingroup SecuritySettingGrpPub @@ -1500,8 +1532,10 @@ * @def MY_SIGNING_SIMPLE_PASSWD * @brief Enables SW backed signing functionality in library and uses provided password as key. * - * This flag will enable signing, signature requests and encryption. It has to be identical on ALL - * nodes in the network. + * This flag is automatically set if @ref MY_SECURITY_SIMPLE_PASSWD is used. + * + * This flag will enable signing and signature requests. It has to be identical on ALL nodes in the + * network. * * Whitelisting is supported and serial will be the first 8 characters of the password, the ninth * character will be the node ID (to make each node have a unique serial). @@ -1509,22 +1543,22 @@ * As with the regular signing modes, whitelisting is only activated if a whitelist is specified in * the sketch. * - * No personalization is required for this mode. + * No @ref personalization is required for this mode. * * It is allowed to set @ref MY_SIGNING_WEAK_SECURITY for deployment purposes in this mode as it is * with the regular software and ATSHA204A based modes. * - * If the provided password is shorter than the size of the HMAC or %AES key, it will be null-padded + * If the provided password is shorter than the size of the HMAC key, it will be null-padded * to accommodate the key size in question. A 32 character password is the maximum length. Any * password longer than that will be truncated. + * + * @see MY_SECURITY_SIMPLE_PASSWD + * */ //#define MY_SIGNING_SIMPLE_PASSWD "MyInsecurePassword" #if defined(MY_SIGNING_SIMPLE_PASSWD) #define MY_SIGNING_SOFT #define MY_SIGNING_REQUEST_SIGNATURES -#define MY_RF24_ENABLE_ENCRYPTION -#define MY_RFM69_ENABLE_ENCRYPTION -#define MY_NRF5_ESB_ENABLE_ENCRYPTION #endif /** @@ -1624,6 +1658,47 @@ #if defined(MY_SIGNING_ATSHA204) || defined(MY_SIGNING_SOFT) #define MY_SIGNING_FEATURE #endif +/** @}*/ // End of SigningSettingGrpPub group + +/** + * @defgroup EncryptionSettingGrpPub Encryption + * @ingroup SecuritySettingGrpPub + * @brief These options control encryption related configurations. + * + * Note that encryption is toggled on a per-radio basis. + * @see MY_RF24_ENABLE_ENCRYPTION, MY_RFM69_ENABLE_ENCRYPTION, MY_NRF5_ESB_ENABLE_ENCRYPTION + * @{ + */ + +/** + * @def MY_ENCRYPTION_SIMPLE_PASSWD + * @brief Enables encryption on all radio transports that supports it and uses provided password as key. + * + * This flag is automatically set if @ref MY_SECURITY_SIMPLE_PASSWD is used. + * + * This flag will enable encryption. It has to be identical on ALL nodes in the network. + * + * No @ref personalization is required for this mode. + * + * If the provided password is shorter than the size of the %AES key, it will be null-padded + * to accommodate the key size in question. A 16 character password is the maximum length. Any + * password longer than that will be truncated. + * + * @see MY_SECURITY_SIMPLE_PASSWD + */ +//#define MY_ENCRYPTION_SIMPLE_PASSWD "MyInsecurePassword" +#if defined(MY_ENCRYPTION_SIMPLE_PASSWD) +#ifndef MY_RF24_ENABLE_ENCRYPTION +#define MY_RF24_ENABLE_ENCRYPTION +#endif +#ifndef MY_RFM69_ENABLE_ENCRYPTION +#define MY_RFM69_ENABLE_ENCRYPTION +#endif +#ifndef MY_NRF5_ESB_ENABLE_ENCRYPTION +#define MY_NRF5_ESB_ENABLE_ENCRYPTION +#endif +#endif + /** * @def MY_ENCRYPTION_FEATURE * @ingroup internals @@ -1632,7 +1707,7 @@ #if defined(MY_RF24_ENABLE_ENCRYPTION) || defined(MY_RFM69_ENABLE_ENCRYPTION) || defined(MY_NRF5_ESB_ENABLE_ENCRYPTION) #define MY_ENCRYPTION_FEATURE #endif -/** @}*/ // End of SigningSettingGrpPub group +/** @}*/ // End of EncryptionSettingGrpPub group /** * @defgroup MyLockgrppub Node locking @@ -1949,7 +2024,9 @@ #define MY_DEFAULT_TX_LED_PIN #define MY_DEFAULT_RX_LED_PIN // signing +#define MY_SECURITY_SIMPLE_PASSWD "MyInsecurePassword" #define MY_SIGNING_SIMPLE_PASSWD "MyInsecurePassword" +#define MY_ENCRYPTION_SIMPLE_PASSWD "MyInsecurePassword" #define MY_SIGNING_ATSHA204 #define MY_SIGNING_SOFT #define MY_SIGNING_REQUEST_SIGNATURES diff --git a/configure b/configure index 8618eef..81c6efd 100755 --- a/configure +++ b/configure @@ -72,7 +72,7 @@ MySensors options: --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 + personalized with the same AES key. --my-rx-message-buffer-size= Buffer size for incoming messages when using rf24 interrupts. [20] --my-rfm69-frequency=[315|433|868|915] @@ -80,6 +80,10 @@ MySensors options: --my-is-rfm69hw Enable high-powered rfm69hw. --my-rfm69-irq-pin= Pin number connected to RFM69 IRQ pin. --my-rfm69-cs-pin= Pin number to use for RFM69 Chip-Select. + --my-rfm69-encryption-enabled + Enables RFM69 encryption. + All nodes and gateway must have this enabled, and all must be + personalized with the same AES key. --my-rs485-serial-port= RS485 serial port. You must provide a port. --my-rs485-baudrate= RS485 baudrate. [9600] @@ -98,8 +102,13 @@ MySensors options: gateway signature. --my-signing-weak_security Enable this to permit downgrade of security preferences and relaxed gateway signing requirements. - --my-signing-password= - If you are using password as the signature type, set your password here. + --my-signing-whitelist= + If you want to use a whitelist, provide it here, make sure to avoid + spaces in the expression. + --my-signing-verification-timeout-ms= + Signing timeout. [5000] + --my-security-password= + If you are using password for signing/encryption, set your password here. EOF } @@ -258,6 +267,7 @@ gateway_type=ethernet transport_type=nrf24 signing=none signing_request_signatures=false +encryption=false params="SOC CFLAGS CXXFLAGS CPPFLAGS LDFLAGS PREFIX CC CXX ARDUINO_LIB_DIR BUILDDIR BINDIR GATEWAY_DIR INIT_SYSTEM SPI_DRIVER" @@ -398,6 +408,7 @@ for opt do CPPFLAGS="-DMY_RX_MESSAGE_BUFFER_FEATURE -DMY_RF24_IRQ_PIN=${optarg} $CPPFLAGS" ;; --my-rf24-encryption-enabled*) + encryption=true CPPFLAGS="-DMY_RF24_ENABLE_ENCRYPTION $CPPFLAGS" ;; --my-rx-message-buffer-size=*) @@ -425,6 +436,10 @@ for opt do --my-rfm69-cs-pin=*) CPPFLAGS="-DMY_RFM69_CS_PIN=${optarg} $CPPFLAGS" ;; + --my-rfm69-encryption-enabled*) + encryption=true + CPPFLAGS="-DMY_RFM69_ENABLE_ENCRYPTION $CPPFLAGS" + ;; --my-rs485-serial-port=*) CPPFLAGS="-DMY_RS485_HWSERIAL=\\\"${optarg}\\\" $CPPFLAGS" ;; @@ -461,8 +476,14 @@ for opt do --my-signing-weak_security*) CPPFLAGS="-DMY_SIGNING_WEAK_SECURITY $CPPFLAGS" ;; - --my-signing-password=*) - signing_password=${optarg} + --my-signing-whitelist*) + CPPFLAGS="-DMY_SIGNING_NODE_WHITELISTING=${optarg} $CPPFLAGS" + ;; + --my-signing-verification-timeout-ms*) + CPPFLAGS="-DMY_VERIFICATION_TIMEOUT_MS=${optarg} $CPPFLAGS" + ;; + --my-security-password=*) + security_password=${optarg} ;; *) echo "[WARNING] Unknown option detected:$opt, ignored" @@ -573,15 +594,25 @@ elif [[ ${signing} == "software" ]]; then CPPFLAGS="-DMY_SIGNING_REQUEST_SIGNATURES $CPPFLAGS" fi elif [[ ${signing} == "password" ]]; then - if [ -z "${signing_password}" ]; then - die "You need to set the password for signing with --my-signing-password= option" 6 + if [ -z "${security_password}" ]; then + die "You need to set the password for signing with --my-security-password= option" 6 fi echo "Simplified signing using password" - CPPFLAGS="-DMY_SIGNING_SIMPLE_PASSWD=\\\"${signing_password}\\\" $CPPFLAGS" + CPPFLAGS="-DMY_SIGNING_SIMPLE_PASSWD=\\\"${security_password}\\\" $CPPFLAGS" else die "Invalid signing type." 7 fi +if [[ ${encryption} == true ]]; then + # Encryption enabled on some transport + if [ -z "${security_password}" ]; then + echo "Encryption key from configuration" + else + echo "Simplified encryption using password" + CPPFLAGS="-DMY_ENCRYPTION_SIMPLE_PASSWD=\\\"${security_password}\\\" $CPPFLAGS" + fi +fi + LDFLAGS="-pthread $LDFLAGS" CPPFLAGS="$CPUFLAGS $CPPFLAGS" diff --git a/core/MySigning.h b/core/MySigning.h index cce6309..4c6df24 100644 --- a/core/MySigning.h +++ b/core/MySigning.h @@ -177,6 +177,16 @@ * personalization has finished, you just program the sketch you plan to use (with the appropriate * signing flags set). * + * If you are using a Raspberry PI-based gateway, personalizaion is done slightly differently: + * 1. Generate keys, execute @c mysgw with arguments + * * To generate HMAC key @verbatim --gen-soft-hmac-key @endverbatim + * * To generate %AES key @verbatim --gen-aes-key @endverbatim + * * To generate a soft serial number @verbatim --gen-soft-serial @endverbatim + * 2. Store keys/values to the gateway, execute @c mysgw with arguments + * * To store HMAC key @verbatim --set-soft-hmac-key= @endverbatim + * * To store %AES key @verbatim --set-aes-key= @endverbatim + * * To store soft serial number @verbatim --set-soft-serial-key= @endverbatim + * * You are now set and ready to use message signing in your network. * As of now, the following restrictions will be applied to your nodes: * * If a node does require signing, any unsigned message sent to the node will be rejected. @@ -393,8 +403,7 @@ * is to set your preferences in your sketch and personalize accordingly. * That is enough to enable protection from both Eve and Mallory in your network * although if you do not also enable encryption, Eve can eavesdrop, but not do anything about, - * your messages (except possibly preventing them from arriving). @ref MY_SIGNING_SIMPLE_PASSWD also - * enable encryption automatically. + * your messages (except possibly preventing them from arriving). * * How are the messages actually affected by the signing?
* The following illustration shows what part of the message is signed, and where the signature is diff --git a/hal/architecture/Linux/MyMainLinux.cpp b/hal/architecture/Linux/MyMainLinux.cpp index f67ea2f..6faf52e 100644 --- a/hal/architecture/Linux/MyMainLinux.cpp +++ b/hal/architecture/Linux/MyMainLinux.cpp @@ -134,7 +134,7 @@ void print_soft_sign_hmac_key(uint8_t *key_ptr = NULL) printf("\n\n"); printf("The next line is intended to be used in SecurityPersonalizer.ino:\n"); - printf("#define MY_SOFT_HMAC_KEY "); + printf("#define MY_HMAC_KEY "); for (int i=0; i<32; i++) { printf("%#02X", key_ptr[i]); if (i < 31) { @@ -265,9 +265,9 @@ void print_aes_key(uint8_t *key_ptr = NULL) uint8_t key[16]; if (key_ptr == NULL) { -#ifdef MY_SIGNING_SIMPLE_PASSWD +#ifdef MY_ENCRYPTION_SIMPLE_PASSWD memset(key, 0, 16); - memcpy(key, MY_SIGNING_SIMPLE_PASSWD, strnlen(MY_SIGNING_SIMPLE_PASSWD, 16)); + memcpy(key, MY_ENCRYPTION_SIMPLE_PASSWD, strnlen(MY_ENCRYPTION_SIMPLE_PASSWD, 16)); #else hwReadConfigBlock(&key, reinterpret_castEEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); #endif diff --git a/hal/transport/MyTransportNRF5_ESB.cpp b/hal/transport/MyTransportNRF5_ESB.cpp index 93f1366..49d2f25 100644 --- a/hal/transport/MyTransportNRF5_ESB.cpp +++ b/hal/transport/MyTransportNRF5_ESB.cpp @@ -39,9 +39,9 @@ uint8_t _psk[16]; bool transportInit(void) { #if defined(MY_NRF5_ESB_ENABLE_ENCRYPTION) -#ifdef MY_SIGNING_SIMPLE_PASSWD +#ifdef MY_ENCRYPTION_SIMPLE_PASSWD memset(_psk, 0, 16); - memcpy(_psk, MY_SIGNING_SIMPLE_PASSWD, strnlen(MY_SIGNING_SIMPLE_PASSWD, 16)); + memcpy(_psk, MY_ENCRYPTION_SIMPLE_PASSWD, strnlen(MY_ENCRYPTION_SIMPLE_PASSWD, 16)); #else hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); #endif diff --git a/hal/transport/MyTransportRF24.cpp b/hal/transport/MyTransportRF24.cpp index 10d6949..a858d5b 100644 --- a/hal/transport/MyTransportRF24.cpp +++ b/hal/transport/MyTransportRF24.cpp @@ -68,9 +68,9 @@ uint8_t _psk[16]; bool transportInit(void) { #if defined(MY_RF24_ENABLE_ENCRYPTION) -#ifdef MY_SIGNING_SIMPLE_PASSWD +#ifdef MY_ENCRYPTION_SIMPLE_PASSWD memset(_psk, 0, 16); - memcpy(_psk, MY_SIGNING_SIMPLE_PASSWD, strnlen(MY_SIGNING_SIMPLE_PASSWD, 16)); + memcpy(_psk, MY_ENCRYPTION_SIMPLE_PASSWD, strnlen(MY_ENCRYPTION_SIMPLE_PASSWD, 16)); #else hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); #endif diff --git a/hal/transport/MyTransportRFM69.cpp b/hal/transport/MyTransportRFM69.cpp index 31501bf..d21cbb1 100644 --- a/hal/transport/MyTransportRFM69.cpp +++ b/hal/transport/MyTransportRFM69.cpp @@ -35,9 +35,9 @@ bool transportInit(void) #ifdef MY_RFM69_ENABLE_ENCRYPTION uint8_t _psk[16]; -#ifdef MY_SIGNING_SIMPLE_PASSWD +#ifdef MY_ENCRYPTION_SIMPLE_PASSWD memset(_psk, 0, 16); - memcpy(_psk, MY_SIGNING_SIMPLE_PASSWD, strnlen(MY_SIGNING_SIMPLE_PASSWD, 16)); + memcpy(_psk, MY_ENCRYPTION_SIMPLE_PASSWD, strnlen(MY_ENCRYPTION_SIMPLE_PASSWD, 16)); #else hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); #endif @@ -170,9 +170,9 @@ bool transportInit(void) if (_radio.initialize(MY_RFM69_FREQUENCY, _address, MY_RFM69_NETWORKID)) { #ifdef MY_RFM69_ENABLE_ENCRYPTION uint8_t _psk[16]; -#ifdef MY_SIGNING_SIMPLE_PASSWD +#ifdef MY_ENCRYPTION_SIMPLE_PASSWD memset(_psk, 0, 16); - memcpy(_psk, MY_SIGNING_SIMPLE_PASSWD, strnlen(MY_SIGNING_SIMPLE_PASSWD, 16)); + memcpy(_psk, MY_ENCRYPTION_SIMPLE_PASSWD, strnlen(MY_ENCRYPTION_SIMPLE_PASSWD, 16)); #else hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); #endif diff --git a/keywords.txt b/keywords.txt index 15fa12a..86e9943 100644 --- a/keywords.txt +++ b/keywords.txt @@ -84,7 +84,9 @@ MY_DEBUG_OTA_DISABLE_ACK LITERAL1 # Signing MY_DEBUG_VERBOSE_SIGNING LITERAL1 +MY_SECURITY_SIMPLE_PASSWD LITERAL1 MY_SIGNING_SIMPLE_PASSWD LITERAL1 +MY_ENCRYPTION_SIMPLE_PASSWD LITERAL1 MY_SIGNING_ATSHA204 LITERAL1 MY_SIGNING_SOFT LITERAL1 MY_VERIFICATION_TIMEOUT_MS LITERAL1 From 6794c72ecd8c35c1a7587f73996d50c347b17f93 Mon Sep 17 00:00:00 2001 From: tekka Date: Sun, 11 Feb 2018 16:48:11 +0100 Subject: [PATCH 11/60] Restructure transport HAL (#1062) --- MySensors.h | 28 ++++------- hal/architecture/AVR/MyHwAVR.cpp | 1 + ...MyMainLinux.cpp => MyMainLinuxGeneric.cpp} | 0 hal/transport/MyTransportHAL.h | 50 +++++++++++-------- .../{ => NRF5_ESB}/MyTransportNRF5_ESB.cpp | 43 +++++++--------- hal/transport/{ => RF24}/MyTransportRF24.cpp | 39 +++++++-------- .../{ => RFM69}/MyTransportRFM69.cpp | 39 +++++++++------ .../{ => RFM95}/MyTransportRFM95.cpp | 8 +-- .../{ => RS485}/MyTransportRS485.cpp | 13 +++-- 9 files changed, 109 insertions(+), 112 deletions(-) rename hal/architecture/Linux/{MyMainLinux.cpp => MyMainLinuxGeneric.cpp} (100%) rename hal/transport/{ => NRF5_ESB}/MyTransportNRF5_ESB.cpp (76%) rename hal/transport/{ => RF24}/MyTransportRF24.cpp (86%) rename hal/transport/{ => RFM69}/MyTransportRFM69.cpp (85%) rename hal/transport/{ => RFM95}/MyTransportRFM95.cpp (95%) rename hal/transport/{ => RS485}/MyTransportRS485.cpp (99%) diff --git a/MySensors.h b/MySensors.h index 28676c5..8ef1198 100644 --- a/MySensors.h +++ b/MySensors.h @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2017 Sensnology AB + * Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -147,8 +147,8 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs #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) @@ -188,6 +188,7 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs // 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 @@ -268,7 +269,7 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs #endif #if defined(MY_TRANSPORT_DONT_CARE_MODE) -#error This directive is deprecated, set MY_TRANSPORT_WAIT_READY_MS instead! +#error MY_TRANSPORT_DONT_CARE_MODE is deprecated, set MY_TRANSPORT_WAIT_READY_MS instead! #endif // RAM ROUTING TABLE @@ -315,21 +316,15 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs // Transport drivers #if defined(MY_RADIO_RF24) -#if defined(MY_RF24_ENABLE_ENCRYPTION) -#include "drivers/AES/AES.cpp" -#endif #include "drivers/RF24/RF24.cpp" -#include "hal/transport/MyTransportRF24.cpp" +#include "hal/transport/RF24/MyTransportRF24.cpp" #elif defined(MY_RADIO_NRF5_ESB) #if !defined(ARDUINO_ARCH_NRF5) #error No support for nRF5 radio on this platform #endif -#if defined(MY_NRF5_ESB_ENABLE_ENCRYPTION) -#include "drivers/AES/AES.cpp" -#endif #include "drivers/NRF5/Radio.cpp" #include "drivers/NRF5/Radio_ESB.cpp" -#include "hal/transport/MyTransportNRF5_ESB.cpp" +#include "hal/transport/NRF5_ESB/MyTransportNRF5_ESB.cpp" #elif defined(MY_RS485) #if !defined(MY_RS485_HWSERIAL) #if defined(__linux__) @@ -337,20 +332,17 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs #endif #include "drivers/AltSoftSerial/AltSoftSerial.cpp" #endif -#include "hal/transport/MyTransportRS485.cpp" +#include "hal/transport/RS485/MyTransportRS485.cpp" #elif defined(MY_RADIO_RFM69) #if defined(MY_RFM69_NEW_DRIVER) #include "drivers/RFM69/new/RFM69_new.cpp" #else #include "drivers/RFM69/old/RFM69_old.cpp" #endif -#include "hal/transport/MyTransportRFM69.cpp" +#include "hal/transport/RFM69/MyTransportRFM69.cpp" #elif defined(MY_RADIO_RFM95) -#if defined(MY_RFM95_ENABLE_ENCRYPTION) -#include "drivers/AES/AES.cpp" -#endif #include "drivers/RFM95/RFM95.cpp" -#include "hal/transport/MyTransportRFM95.cpp" +#include "hal/transport/RFM95/MyTransportRFM95.cpp" #endif // PASSIVE MODE @@ -406,7 +398,7 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs #elif defined(ARDUINO_ARCH_NRF5) #include "hal/architecture/NRF5/MyMainNRF5.cpp" #elif defined(__linux__) -#include "hal/architecture/Linux/MyMainLinux.cpp" +#include "hal/architecture/Linux/MyMainLinuxGeneric.cpp" #elif defined(ARDUINO_ARCH_STM32F1) #include "hal/architecture/STM32F1/MyMainSTM32F1.cpp" #elif defined(TEENSYDUINO) diff --git a/hal/architecture/AVR/MyHwAVR.cpp b/hal/architecture/AVR/MyHwAVR.cpp index 07f50ea..2083fc3 100644 --- a/hal/architecture/AVR/MyHwAVR.cpp +++ b/hal/architecture/AVR/MyHwAVR.cpp @@ -20,6 +20,7 @@ #include "MyHwAVR.h" #include "avr/boot.h" + bool hwInit(void) { #if !defined(MY_DISABLED_SERIAL) diff --git a/hal/architecture/Linux/MyMainLinux.cpp b/hal/architecture/Linux/MyMainLinuxGeneric.cpp similarity index 100% rename from hal/architecture/Linux/MyMainLinux.cpp rename to hal/architecture/Linux/MyMainLinuxGeneric.cpp diff --git a/hal/transport/MyTransportHAL.h b/hal/transport/MyTransportHAL.h index a651b16..a3da513 100644 --- a/hal/transport/MyTransportHAL.h +++ b/hal/transport/MyTransportHAL.h @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2017 Sensnology AB + * Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -20,10 +20,10 @@ #ifndef MyTransportHAL_h #define MyTransportHAL_h -#define INVALID_SNR ((int16_t)-256) //!< INVALID_SNR -#define INVALID_RSSI ((int16_t)-256) //!< INVALID_RSSI -#define INVALID_PERCENT ((int16_t)-100) //!< INVALID_PERCENT -#define INVALID_LEVEL ((int16_t)-256) //!< INVALID_LEVEL +#define INVALID_SNR ((int16_t)-256) //!< INVALID_SNR +#define INVALID_RSSI ((int16_t)-256) //!< INVALID_RSSI +#define INVALID_PERCENT ((int16_t)-100) //!< INVALID_PERCENT +#define INVALID_LEVEL ((int16_t)-256) //!< INVALID_LEVEL #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) #if defined(MY_RADIO_NRF5_ESB) @@ -46,14 +46,14 @@ * @brief Signal report selector */ typedef enum { - SR_RX_RSSI, //!< SR_RX_RSSI - SR_TX_RSSI, //!< SR_TX_RSSI - SR_RX_SNR, //!< SR_RX_SNR - SR_TX_SNR, //!< SR_TX_SNR - SR_TX_POWER_LEVEL, //!< SR_TX_POWER_LEVEL - SR_TX_POWER_PERCENT, //!< SR_TX_POWER_PERCENT - SR_UPLINK_QUALITY, //!< SR_UPLINK_QUALITY - SR_NOT_DEFINED //!< SR_NOT_DEFINED + SR_RX_RSSI, //!< SR_RX_RSSI + SR_TX_RSSI, //!< SR_TX_RSSI + SR_RX_SNR, //!< SR_RX_SNR + SR_TX_SNR, //!< SR_TX_SNR + SR_TX_POWER_LEVEL, //!< SR_TX_POWER_LEVEL + SR_TX_POWER_PERCENT, //!< SR_TX_POWER_PERCENT + SR_UPLINK_QUALITY, //!< SR_UPLINK_QUALITY + SR_NOT_DEFINED //!< SR_NOT_DEFINED } signalReport_t; @@ -69,7 +69,7 @@ void transportSetAddress(const uint8_t address); /** * @brief Retrieve node address */ -uint8_t transportGetAddress(void); +uint8_t transportGetAddress(void) __attribute__((unused)); /** * @brief Send message * @param to recipient @@ -78,7 +78,7 @@ uint8_t transportGetAddress(void); * @param noACK do not wait for ACK * @return true if message sent successfully */ -bool transportSend(const uint8_t to, const void* data, const uint8_t len, +bool transportSend(const uint8_t to, const void *data, const uint8_t len, const bool noACK = false); /** * @brief Verify if RX FIFO has pending messages @@ -86,7 +86,7 @@ bool transportSend(const uint8_t to, const void* data, const uint8_t len, */ bool transportAvailable(void); /** -* @brief Sanity check for transport: is transport still responsive? +* @brief Sanity check for transport: is transport HW still responsive? * @return true if transport HW is ok */ bool transportSanityCheck(void); @@ -94,7 +94,7 @@ bool transportSanityCheck(void); * @brief Receive message from FIFO * @return length of received message (header + payload) */ -uint8_t transportReceive(void* data); +uint8_t transportReceive(void *data); /** * @brief Power down transport HW (if corresponding MY_XYZ_POWER_PIN defined) */ @@ -113,30 +113,36 @@ void transportSleep(void); void transportStandBy(void); /** * @brief transportGetSendingRSSI -* @return RSSI +* @return RSSI of outgoing message (via ACK packet) */ int16_t transportGetSendingRSSI(void); /** * @brief transportGetReceivingRSSI -* @return RSSI +* @return RSSI of incoming message */ int16_t transportGetReceivingRSSI(void); /** * @brief transportGetSendingSNR -* @return SNR +* @return SNR of outgoing message (via ACK packet) */ int16_t transportGetSendingSNR(void); /** * @brief transportGetReceivingSNR -* @return SNR +* @return SNR of incoming message */ int16_t transportGetReceivingSNR(void); /** * @brief transportGetTxPowerPercent -* @return TX power in percent +* @return TX power level in percent */ int16_t transportGetTxPowerPercent(void); /** +* @brief transportSetTxPowerPercent +* @param powerPercent power level in percent +* @return True if power level set +*/ +bool transportSetTxPowerPercent(const uint8_t powerPercent) __attribute__((unused)); +/** * @brief transportGetTxPowerLevel * @return TX power in dBm */ diff --git a/hal/transport/MyTransportNRF5_ESB.cpp b/hal/transport/NRF5_ESB/MyTransportNRF5_ESB.cpp similarity index 76% rename from hal/transport/MyTransportNRF5_ESB.cpp rename to hal/transport/NRF5_ESB/MyTransportNRF5_ESB.cpp index 49d2f25..ddc29a6 100644 --- a/hal/transport/MyTransportNRF5_ESB.cpp +++ b/hal/transport/NRF5_ESB/MyTransportNRF5_ESB.cpp @@ -2,12 +2,11 @@ * 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 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 + * Copyright (C) 2013-2018 Sensnology AB * Copyright (C) 2017 Frank Holtz * Full contributor list: * https://github.com/mysensors/Arduino/graphs/contributors @@ -20,37 +19,33 @@ * version 2 as published by the Free Software Foundation. */ -#include "MyTransportHAL.h" #include "drivers/NRF5/Radio.h" #include "drivers/NRF5/Radio_ESB.h" #include "drivers/CircularBuffer/CircularBuffer.h" #if defined(MY_NRF5_ESB_ENABLE_ENCRYPTION) -#include "drivers/AES/AES.h" -#endif - -#if defined(MY_NRF5_ESB_ENABLE_ENCRYPTION) -AES _aes; -uint8_t _dataenc[32] = {0}; -uint8_t _psk[16]; +#include "drivers/AES/AES.cpp" +AES NRF5_ESB_aes; +uint8_t NRF5_ESB_dataenc[32] = {0}; #endif bool transportInit(void) { #if defined(MY_NRF5_ESB_ENABLE_ENCRYPTION) + uint8_t NRF5_ESB_psk[16]; #ifdef MY_ENCRYPTION_SIMPLE_PASSWD - memset(_psk, 0, 16); - memcpy(_psk, MY_ENCRYPTION_SIMPLE_PASSWD, strnlen(MY_ENCRYPTION_SIMPLE_PASSWD, 16)); + (void)memset(NRF5_ESB_psk, 0, 16); + (void)memcpy(NRF5_ESB_psk, MY_ENCRYPTION_SIMPLE_PASSWD, strnlen(MY_ENCRYPTION_SIMPLE_PASSWD, 16)); #else - hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); + hwReadConfigBlock((void*)NRF5_ESB_psk, (void*)EEPROM_RF_ENCRYPTION_KEY_ADDRESS, + 16); #endif // set up AES-key - _aes.set_key(_psk, 16); + NRF5_ESB_aes.set_key(NRF5_ESB_psk, 16); // Make sure it is purged from memory when set - memset(_psk, 0, 16); + (void)memset(NRF5_ESB_psk, 0, 16); #endif - return NRF5_ESB_initialize(); } @@ -69,13 +64,13 @@ bool transportSend(const uint8_t to, const void *data, const uint8_t len, const { #if defined(MY_NRF5_ESB_ENABLE_ENCRYPTION) // copy input data because it is read-only - (void)memcpy(_dataenc, data, len); + (void)memcpy(NRF5_ESB_dataenc, data, len); // has to be adjusted, WIP! - _aes.set_IV(0); + NRF5_ESB_aes.set_IV(0); const uint8_t finalLength = len > 16 ? 32 : 16; // encrypt data - _aes.cbc_encrypt(_dataenc, _dataenc, finalLength / 16); - return NRF5_ESB_sendMessage(to, _dataenc, finalLength, noACK); + NRF5_ESB_aes.cbc_encrypt(NRF5_ESB_dataenc, NRF5_ESB_dataenc, finalLength / 16); + return NRF5_ESB_sendMessage(to, NRF5_ESB_dataenc, finalLength, noACK); #else return NRF5_ESB_sendMessage(to, data, len, noACK); #endif @@ -97,10 +92,10 @@ uint8_t transportReceive(void *data) len = NRF5_ESB_readMessage(data); #if defined(MY_NRF5_ESB_ENABLE_ENCRYPTION) // has to be adjusted, WIP! - _aes.set_IV(0); + NRF5_ESB_aes.set_IV(0); // decrypt data - if (_aes.cbc_decrypt((uint8_t *)(data), (uint8_t *)(data), - len > 16 ? 2 : 1) != AES_SUCCESS) { + if (NRF5_ESB_aes.cbc_decrypt((uint8_t *)(data), (uint8_t *)(data), + len > 16 ? 2 : 1) != AES_SUCCESS) { len = 0; } #endif diff --git a/hal/transport/MyTransportRF24.cpp b/hal/transport/RF24/MyTransportRF24.cpp similarity index 86% rename from hal/transport/MyTransportRF24.cpp rename to hal/transport/RF24/MyTransportRF24.cpp index a858d5b..e76025b 100644 --- a/hal/transport/MyTransportRF24.cpp +++ b/hal/transport/RF24/MyTransportRF24.cpp @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2017 Sensnology AB + * Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -17,11 +17,12 @@ * version 2 as published by the Free Software Foundation. */ -#include "MyTransportHAL.h" #include "drivers/RF24/RF24.h" #if defined(MY_RF24_ENABLE_ENCRYPTION) -#include "drivers/AES/AES.h" +#include "drivers/AES/AES.cpp" +AES RF24_aes; +uint8_t RF24_dataenc[32] = {0}; #endif #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) @@ -59,25 +60,20 @@ static void transportRxCallback(void) } #endif -#if defined(MY_RF24_ENABLE_ENCRYPTION) -AES _aes; -uint8_t _dataenc[32] = {0}; -uint8_t _psk[16]; -#endif - bool transportInit(void) { #if defined(MY_RF24_ENABLE_ENCRYPTION) + uint8_t RF24_psk[16]; #ifdef MY_ENCRYPTION_SIMPLE_PASSWD - memset(_psk, 0, 16); - memcpy(_psk, MY_ENCRYPTION_SIMPLE_PASSWD, strnlen(MY_ENCRYPTION_SIMPLE_PASSWD, 16)); + (void)memset(RF24_psk, 0, 16); + (void)memcpy(RF24_psk, MY_ENCRYPTION_SIMPLE_PASSWD, strnlen(MY_ENCRYPTION_SIMPLE_PASSWD, 16)); #else - hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); + hwReadConfigBlock((void*)RF24_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); #endif //set up AES-key - _aes.set_key(_psk, 16); + RF24_aes.set_key(RF24_psk, 16); // Make sure it is purged from memory when set - memset(_psk, 0, 16); + (void)memset(RF24_psk, 0, 16); #endif #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) @@ -101,13 +97,13 @@ bool transportSend(const uint8_t to, const void* data, const uint8_t len, const { #if defined(MY_RF24_ENABLE_ENCRYPTION) // copy input data because it is read-only - (void)memcpy(_dataenc,data,len); + (void)memcpy(RF24_dataenc,data,len); // has to be adjusted, WIP! - _aes.set_IV(0); + RF24_aes.set_IV(0); const uint8_t finalLength = len > 16 ? 32 : 16; //encrypt data - _aes.cbc_encrypt(_dataenc, _dataenc, finalLength /16); - return RF24_sendMessage(to, _dataenc, finalLength, noACK); + RF24_aes.cbc_encrypt(RF24_dataenc, RF24_dataenc, finalLength / 16); + return RF24_sendMessage(to, RF24_dataenc, finalLength, noACK); #else return RF24_sendMessage(to, data, len, noACK); #endif @@ -143,9 +139,9 @@ uint8_t transportReceive(void* data) #endif #if defined(MY_RF24_ENABLE_ENCRYPTION) // has to be adjusted, WIP! - _aes.set_IV(0); + RF24_aes.set_IV(0); // decrypt data - if (_aes.cbc_decrypt((uint8_t*)(data), (uint8_t*)(data), len > 16 ? 2 : 1) != AES_SUCCESS) { + if (RF24_aes.cbc_decrypt((uint8_t*)(data), (uint8_t*)(data), len > 16 ? 2 : 1) != AES_SUCCESS) { len = 0; } #endif @@ -176,6 +172,7 @@ int16_t transportGetSendingRSSI(void) { return RF24_getSendingRSSI(); } + int16_t transportGetReceivingRSSI(void) { // not available, only bool RPD @@ -206,5 +203,3 @@ bool transportSetTxPowerPercent(const uint8_t powerPercent) { return RF24_setTxPowerPercent(powerPercent); } - - diff --git a/hal/transport/MyTransportRFM69.cpp b/hal/transport/RFM69/MyTransportRFM69.cpp similarity index 85% rename from hal/transport/MyTransportRFM69.cpp rename to hal/transport/RFM69/MyTransportRFM69.cpp index d21cbb1..7cc6973 100644 --- a/hal/transport/MyTransportRFM69.cpp +++ b/hal/transport/RFM69/MyTransportRFM69.cpp @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2017 Sensnology AB + * Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -17,8 +17,6 @@ * version 2 as published by the Free Software Foundation. */ -#include "MyTransportHAL.h" - #if defined(MY_RFM69_NEW_DRIVER) #include "drivers/RFM69/new/RFM69_new.h" @@ -34,17 +32,16 @@ bool transportInit(void) #endif #ifdef MY_RFM69_ENABLE_ENCRYPTION - uint8_t _psk[16]; + uint8_t RFM69_psk[16]; #ifdef MY_ENCRYPTION_SIMPLE_PASSWD - memset(_psk, 0, 16); - memcpy(_psk, MY_ENCRYPTION_SIMPLE_PASSWD, strnlen(MY_ENCRYPTION_SIMPLE_PASSWD, 16)); + (void)memset(RFM69_psk, 0, 16); + (void)memcpy(RFM69_psk, MY_ENCRYPTION_SIMPLE_PASSWD, strnlen(MY_ENCRYPTION_SIMPLE_PASSWD, 16)); #else - hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); + hwReadConfigBlock((void*)RFM69_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); #endif - RFM69_encrypt((const char*)_psk); - (void)memset(_psk, 0, 16); // Make sure it is purged from memory when set + RFM69_encrypt((const char*)RFM69_psk); + (void)memset(RFM69_psk, 0, 16); // Make sure it is purged from memory when set #endif - return result; } @@ -146,6 +143,7 @@ int16_t transportGetTxPowerLevel(void) { return RFM69_getTxPowerLevel(); } + bool transportSetTxPowerPercent(const uint8_t powerPercent) { return RFM69_setTxPowerPercent(powerPercent); @@ -169,15 +167,15 @@ bool transportInit(void) // 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]; + uint8_t RFM69_psk[16]; #ifdef MY_ENCRYPTION_SIMPLE_PASSWD - memset(_psk, 0, 16); - memcpy(_psk, MY_ENCRYPTION_SIMPLE_PASSWD, strnlen(MY_ENCRYPTION_SIMPLE_PASSWD, 16)); + (void)memset(RFM69_psk, 0, 16); + (void)memcpy(RFM69_psk, MY_ENCRYPTION_SIMPLE_PASSWD, strnlen(MY_ENCRYPTION_SIMPLE_PASSWD, 16)); #else - hwReadConfigBlock((void*)_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); + hwReadConfigBlock((void*)RFM69_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); #endif - _radio.encrypt((const char*)_psk); - (void)memset(_psk, 0, 16); // Make sure it is purged from memory when set + _radio.encrypt((const char*)RFM69_psk); + (void)memset(RFM69_psk, 0, 16); // Make sure it is purged from memory when set #endif return true; } @@ -235,10 +233,12 @@ void transportStandBy(void) { _radio.standBy(); } + void transportPowerDown(void) { _radio.powerDown(); } + void transportPowerUp(void) { _radio.powerUp(); @@ -274,4 +274,11 @@ int16_t transportGetTxPowerLevel(void) return INVALID_LEVEL; } +bool transportSetTxPowerLevel(const uint8_t powerLevel) +{ + // not implemented + (void)powerLevel; + return false; +} + #endif diff --git a/hal/transport/MyTransportRFM95.cpp b/hal/transport/RFM95/MyTransportRFM95.cpp similarity index 95% rename from hal/transport/MyTransportRFM95.cpp rename to hal/transport/RFM95/MyTransportRFM95.cpp index 5d6278f..5d3aa85 100644 --- a/hal/transport/MyTransportRFM95.cpp +++ b/hal/transport/RFM95/MyTransportRFM95.cpp @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2017 Sensnology AB + * Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -15,12 +15,14 @@ * 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 "MyTransportHAL.h" #include "drivers/RFM95/RFM95.h" +#if defined(MY_RFM95_ENABLE_ENCRYPTION) +#include "drivers/AES/AES.cpp" +#endif + bool transportInit(void) { const bool result = RFM95_initialise(MY_RFM95_FREQUENCY); diff --git a/hal/transport/MyTransportRS485.cpp b/hal/transport/RS485/MyTransportRS485.cpp similarity index 99% rename from hal/transport/MyTransportRS485.cpp rename to hal/transport/RS485/MyTransportRS485.cpp index 1f4a125..2cbe8d9 100644 --- a/hal/transport/MyTransportRS485.cpp +++ b/hal/transport/RS485/MyTransportRS485.cpp @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2017 Sensnology AB + * Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -52,9 +52,6 @@ // Serial Transport - -#include "MyTransportHAL.h" - #ifdef __linux__ #include "SerialPort.h" #endif @@ -367,15 +364,17 @@ void transportPowerDown(void) void transportPowerUp(void) { - + // not implemented } + void transportSleep(void) { - + // not implemented } + void transportStandBy(void) { - + // not implemented } int16_t transportGetSendingRSSI(void) From 54fb250ab278324d60f404b23d87867bbd3e54d7 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Tue, 13 Feb 2018 10:22:27 -0200 Subject: [PATCH 12/60] Linux: Serial minor update (#1053) - The symlink name for the PTY device is set using --my-serial-port making --my-serial-pty deprecated - Replace MY_LINUX_IS_SERIAL_PTY with MY_LINUX_SERIAL_IS_PTY - MY_DEBUGDEVICE can be used to print debug messages from MySensors (as it is currently in the other architectures) - Rename SerialSimulator class to StdInOutStream - Remove old deprecated option --my-radio --- MyConfig.h | 35 +++++++++++++------ configure | 14 ++++---- ...SerialSimulator.cpp => StdInOutStream.cpp} | 16 ++++----- .../{SerialSimulator.h => StdInOutStream.h} | 8 ++--- examples_linux/mysgw.cpp | 7 ++-- hal/architecture/Linux/MyHwLinuxGeneric.cpp | 29 +++++++++++++++ hal/architecture/Linux/MyHwLinuxGeneric.h | 12 +++---- 7 files changed, 80 insertions(+), 41 deletions(-) rename drivers/Linux/{SerialSimulator.cpp => StdInOutStream.cpp} (80%) rename drivers/Linux/{SerialSimulator.h => StdInOutStream.h} (91%) diff --git a/MyConfig.h b/MyConfig.h index 865f44d..f3d2a59 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -1805,29 +1805,39 @@ * @brief These options control Linux specific configurations. * @{ */ + /** * @def MY_LINUX_SERIAL_PORT * @brief Serial device port */ -#ifndef MY_LINUX_SERIAL_PORT -#define MY_LINUX_SERIAL_PORT "/dev/ttyACM0" +//#define MY_LINUX_SERIAL_PORT "/dev/ttyUSB0" + +/** + * @def MY_LINUX_SERIAL_PTY + * @brief deprecated option + */ +#ifdef MY_LINUX_SERIAL_PTY +#warning MY_LINUX_SERIAL_PTY is deprecated, please use MY_LINUX_SERIAL_PORT +#define MY_LINUX_SERIAL_PORT MY_LINUX_SERIAL_PTY #endif /** * @def MY_LINUX_IS_SERIAL_PTY + * @brief deprecated option + */ +#ifdef MY_LINUX_IS_SERIAL_PTY +#warning MY_LINUX_IS_SERIAL_PTY is deprecated, please use MY_LINUX_SERIAL_IS_PTY +#define MY_LINUX_SERIAL_IS_PTY +#endif + +/** + * @def MY_LINUX_SERIAL_IS_PTY * @brief Set serial as a pseudo terminal. * * Enable this if you need to connect to a controller running on the same device. + * You also need to define MY_LINUX_SERIAL_PORT with the symlink name for the PTY device. */ -//#define MY_LINUX_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 +//#define MY_LINUX_SERIAL_IS_PTY /** * @def MY_LINUX_SERIAL_GROUPNAME @@ -1983,7 +1993,10 @@ #define MY_DISABLED_SERIAL #define MY_SPLASH_SCREEN_DISABLED // linux +#define MY_LINUX_SERIAL_PORT +#define MY_LINUX_SERIAL_IS_PTY #define MY_LINUX_SERIAL_GROUPNAME +#define MY_LINUX_SERIAL_PTY #define MY_LINUX_IS_SERIAL_PTY // inclusion mode #define MY_INCLUSION_MODE_FEATURE diff --git a/configure b/configure index 81c6efd..77df143 100755 --- a/configure +++ b/configure @@ -47,11 +47,12 @@ MySensors options: Controller or MQTT broker ip. --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] + --my-serial-port= Serial port. --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] + You also need to set the symlink name for the PTY device with + the --my-serial-port option. --my-serial-groupname= Grant access to the specified system group for the serial device. --my-mqtt-client-id= MQTT client id. @@ -348,10 +349,6 @@ 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=*) CPPFLAGS="-DMY_LINUX_SERIAL_PORT=\\\"${optarg}\\\" $CPPFLAGS" ;; @@ -359,10 +356,11 @@ for opt do CPPFLAGS="-DMY_BAUD_RATE=${optarg} $CPPFLAGS" ;; --my-serial-is-pty*) - CPPFLAGS="-DMY_LINUX_IS_SERIAL_PTY $CPPFLAGS" + CPPFLAGS="-DMY_LINUX_SERIAL_IS_PTY $CPPFLAGS" ;; --my-serial-pty=*) - CPPFLAGS="-DMY_LINUX_SERIAL_PTY=\\\"${optarg}\\\" $CPPFLAGS" + echo "Warning: --my-serial-pty is deprecated, please use --my-serial-port" + CPPFLAGS="-DMY_LINUX_SERIAL_PORT=\\\"${optarg}\\\" $CPPFLAGS" ;; --my-serial-groupname=*) CPPFLAGS="-DMY_LINUX_SERIAL_GROUPNAME=\\\"${optarg}\\\" $CPPFLAGS" diff --git a/drivers/Linux/SerialSimulator.cpp b/drivers/Linux/StdInOutStream.cpp similarity index 80% rename from drivers/Linux/SerialSimulator.cpp rename to drivers/Linux/StdInOutStream.cpp index b14cb65..d9867d1 100644 --- a/drivers/Linux/SerialSimulator.cpp +++ b/drivers/Linux/StdInOutStream.cpp @@ -18,39 +18,39 @@ */ #include -#include "SerialSimulator.h" +#include "StdInOutStream.h" -void SerialSimulator::begin(int baud) +void StdInOutStream::begin(int baud) { (void)baud; } -int SerialSimulator::available() +int StdInOutStream::available() { return 1; } -int SerialSimulator::read() +int StdInOutStream::read() { return getchar(); } -size_t SerialSimulator::write(uint8_t b) +size_t StdInOutStream::write(uint8_t b) { return (size_t)::printf("%c", b); } -int SerialSimulator::peek() +int StdInOutStream::peek() { return -1; } -void SerialSimulator::flush() +void StdInOutStream::flush() { fflush(stdout); } -void SerialSimulator::end() +void StdInOutStream::end() { flush(); } diff --git a/drivers/Linux/SerialSimulator.h b/drivers/Linux/StdInOutStream.h similarity index 91% rename from drivers/Linux/SerialSimulator.h rename to drivers/Linux/StdInOutStream.h index 2007d21..2f0356e 100644 --- a/drivers/Linux/SerialSimulator.h +++ b/drivers/Linux/StdInOutStream.h @@ -17,8 +17,8 @@ * version 2 as published by the Free Software Foundation. */ -#ifndef SerialSimulator_h -#define SerialSimulator_h +#ifndef StdInOutStream_h +#define StdInOutStream_h #include #include @@ -26,9 +26,9 @@ #include "Stream.h" /** - * @brief A class equivalent to Serial in Arduino but outputs to stdout + * @brief A class that prints to stdout and reads from stdin */ -class SerialSimulator : public Stream +class StdInOutStream : public Stream { public: diff --git a/examples_linux/mysgw.cpp b/examples_linux/mysgw.cpp index da5ba05..28024f1 100644 --- a/examples_linux/mysgw.cpp +++ b/examples_linux/mysgw.cpp @@ -31,11 +31,10 @@ // Serial config // Enable this if you are using an Arduino connected to the USB -//#define MY_LINUX_SERIAL_PORT "/dev/ttyACM0" +//#define MY_LINUX_SERIAL_PORT "/dev/ttyUSB0" // Enable this if you need to connect to a controller running on the same device -//#define MY_LINUX_IS_SERIAL_PTY -// Choose a symlink name for the PTY device -//#define MY_LINUX_SERIAL_PTY "/dev/ttyMySensorsGateway" +// You also need to define MY_LINUX_SERIAL_PORT above with the symlink name for the PTY device +//#define MY_LINUX_SERIAL_IS_PTY // Grant access to the specified system group for the serial device //#define MY_LINUX_SERIAL_GROUPNAME "tty" diff --git a/hal/architecture/Linux/MyHwLinuxGeneric.cpp b/hal/architecture/Linux/MyHwLinuxGeneric.cpp index 6256e66..18d0906 100644 --- a/hal/architecture/Linux/MyHwLinuxGeneric.cpp +++ b/hal/architecture/Linux/MyHwLinuxGeneric.cpp @@ -165,8 +165,37 @@ void hwPinMode(uint8_t pin, uint8_t mode) void hwDebugPrint(const char *fmt, ...) { +#ifndef MY_DISABLED_SERIAL +#ifdef MY_DEBUGDEVICE + char fmtBuffer[MY_SERIAL_OUTPUT_SIZE]; +#ifdef MY_GATEWAY_SERIAL + // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) + snprintf_P(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%" PRIu8 ";0;%" PRIu8 ";%" PRIu32 " "), + C_INTERNAL, I_LOG_MESSAGE, hwMillis()); + MY_DEBUGDEVICE.print(fmtBuffer); +#else + // prepend timestamp + MY_DEBUGDEVICE.print(hwMillis()); + MY_DEBUGDEVICE.print(" "); +#endif + va_list args; + va_start (args, fmt ); + vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args); +#ifdef MY_GATEWAY_SERIAL + // Truncate message if this is gateway node + fmtBuffer[sizeof(fmtBuffer) - 2] = '\n'; + fmtBuffer[sizeof(fmtBuffer) - 1] = '\0'; +#endif + va_end (args); + MY_DEBUGDEVICE.print(fmtBuffer); + MY_DEBUGDEVICE.flush(); +#else va_list args; va_start(args, fmt); vlogDebug(fmt, args); va_end(args); +#endif +#else + (void)fmt; +#endif } diff --git a/hal/architecture/Linux/MyHwLinuxGeneric.h b/hal/architecture/Linux/MyHwLinuxGeneric.h index a933632..40d7950 100644 --- a/hal/architecture/Linux/MyHwLinuxGeneric.h +++ b/hal/architecture/Linux/MyHwLinuxGeneric.h @@ -23,16 +23,16 @@ #include #include #include "SerialPort.h" -#include "SerialSimulator.h" +#include "StdInOutStream.h" -#ifdef MY_GATEWAY_SERIAL -#ifdef MY_LINUX_IS_SERIAL_PTY -SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PTY, true); +#ifdef MY_LINUX_SERIAL_PORT +#ifdef MY_LINUX_SERIAL_IS_PTY +SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PORT, true); #else -SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PORT); +SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PORT, false); #endif #else -SerialSimulator Serial = SerialSimulator(); +StdInOutStream Serial = StdInOutStream(); #endif #ifndef MY_SERIALDEVICE From 0bc3ac9cb32e6f984f826a653cd872ba2e8bf88a Mon Sep 17 00:00:00 2001 From: tekka Date: Sun, 18 Feb 2018 21:05:25 +0100 Subject: [PATCH 13/60] RFM95: Updates and optimizations (#1063) --- MyConfig.h | 6 +- drivers/RFM95/RFM95.cpp | 343 ++++++++++++----------- drivers/RFM95/RFM95.h | 188 +++++++------ drivers/RFM95/RFM95registers.h | 57 ++-- hal/transport/RFM95/MyTransportRFM95.cpp | 3 +- keywords.txt | 1 + 6 files changed, 314 insertions(+), 284 deletions(-) diff --git a/MyConfig.h b/MyConfig.h index f3d2a59..5b78c01 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -863,7 +863,7 @@ /** * @def MY_RFM95_IRQ_PIN - * @brief Define this to use the RFM95 IRQ pin (optional). + * @brief Define this to use the RFM95 IRQ pin. */ #ifndef MY_RFM95_IRQ_PIN #define MY_RFM95_IRQ_PIN DEFAULT_RFM95_IRQ_PIN @@ -874,7 +874,7 @@ * @brief RFM95 IRQ number. */ #ifndef MY_RFM95_IRQ_NUM -#define MY_RFM95_IRQ_NUM DEFAULT_RFM95_IRQ_NUM +#define MY_RFM95_IRQ_NUM digitalPinToInterrupt(MY_RFM95_IRQ_PIN) #endif /** @@ -914,7 +914,7 @@ * @brief Target RSSI level (in dBm) for RFM95 ATC mode */ #ifndef MY_RFM95_ATC_TARGET_RSSI -#define MY_RFM95_ATC_TARGET_RSSI (-60) +#define MY_RFM95_ATC_TARGET_RSSI (-70) #endif /** diff --git a/drivers/RFM95/RFM95.cpp b/drivers/RFM95/RFM95.cpp index cc55a41..2ca352e 100644 --- a/drivers/RFM95/RFM95.cpp +++ b/drivers/RFM95/RFM95.cpp @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2017 Sensnology AB + * Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -18,7 +18,11 @@ * * 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) 2017 Olivier Mauti + * + * RFM95 driver refactored and optimized for MySensors, Copyright (C) 2017-2018 Olivier Mauti + * + * Definitions for HopeRF LoRa radios: + * http://www.hoperf.com/upload/rf/RFM95_96_97_98W.pdf * */ @@ -31,41 +35,33 @@ #define RFM95_DEBUG(x,...) //!< DEBUG null #endif -#if defined (SREG) // To identify AVR vs EP8266 -uint8_t _SREG; // Used to save and restore the SREG values in SPI transactions -#endif - -#if defined (SPCR) && defined (SPSR) -uint8_t _SPCR; //!< _SPCR -uint8_t _SPSR; //!< _SPSR -#endif - #if defined(LINUX_SPI_BCM) // SPI RX and TX buffers (max packet len + 1 byte for the command) uint8_t spi_rxbuff[RFM95_MAX_PACKET_LEN + 1]; uint8_t spi_txbuff[RFM95_MAX_PACKET_LEN + 1]; #endif -volatile rfm95_internal_t RFM95; //!< internal variables +rfm95_internal_t RFM95; //!< internal variables +volatile uint8_t rfm95_irq; //(externalRSSI + RFM95_RSSI_OFFSET); +} + +LOCAL inline int16_t RFM95_internalToRSSI(const rfm95_RSSI_t internalRSSI) +{ + return static_cast(internalRSSI - RFM95_RSSI_OFFSET); +} LOCAL bool RFM95_initialise(const uint32_t frequencyHz) { RFM95_DEBUG(PSTR("RFM95:INIT\n")); - // reset radio module if rst pin defined + // power pin, if defined #if defined(MY_RFM95_POWER_PIN) hwPinMode(MY_RFM95_POWER_PIN, OUTPUT); #endif RFM95_powerUp(); + // reset radio module if rst pin defined #if defined(MY_RFM95_RST_PIN) hwPinMode(MY_RFM95_RST_PIN, OUTPUT); hwDigitalWrite(MY_RFM95_RST_PIN, LOW); // 100uS - delayMicroseconds(100); + delayMicroseconds(RFM95_POWERUP_DELAY_MS); hwDigitalWrite(MY_RFM95_RST_PIN, HIGH); // wait until chip ready delay(5); @@ -168,16 +190,20 @@ LOCAL bool RFM95_initialise(const uint32_t frequencyHz) RFM95_SPI.begin(); // Set LoRa mode (during sleep mode) - RFM95_writeReg(RFM95_REG_01_OP_MODE, RFM95_MODE_SLEEP | RFM95_LONG_RANGE_MODE); + (void)RFM95_writeReg(RFM95_REG_01_OP_MODE, RFM95_MODE_SLEEP | RFM95_LONG_RANGE_MODE); delay(10); // Wait for sleep mode to take over - if (RFM95_readReg(RFM95_REG_01_OP_MODE) != (RFM95_MODE_SLEEP | RFM95_LONG_RANGE_MODE)) { - return false; // No device present? - } + + // TCXO init, if present +#if defined(MY_RFM95_TCXO) + RFM95_enableTCXO(); +#else + (void)RFM95_enableTCXO; +#endif // 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_writeReg(RFM95_REG_0F_FIFO_RX_BASE_ADDR, RFM95_RX_FIFO_ADDR); + (void)RFM95_writeReg(RFM95_REG_0E_FIFO_TX_BASE_ADDR, RFM95_TX_FIFO_ADDR); + (void)RFM95_writeReg(RFM95_REG_23_MAX_PAYLOAD_LENGTH, RFM95_MAX_PACKET_LEN); (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); const rfm95_modemConfig_t configuration = { MY_RFM95_MODEM_CONFIGRUATION }; @@ -185,64 +211,77 @@ LOCAL bool RFM95_initialise(const uint32_t frequencyHz) RFM95_setPreambleLength(RFM95_PREAMBLE_LENGTH); RFM95_setFrequency(frequencyHz); (void)RFM95_setTxPowerLevel(MY_RFM95_TX_POWER_DBM); - // IRQ - hwPinMode(MY_RFM95_IRQ_PIN, INPUT); -#if defined(SPI_HAS_TRANSACTION) && !defined(ESP8266) && !defined(MY_SOFTSPI) - RFM95_SPI.usingInterrupt(MY_RFM95_IRQ_NUM); -#endif + if (!RFM95_sanityCheck()) { - RFM95_DEBUG( - PSTR("!RFM95:INIT:SANCHK FAIL\n")); // sanity check failed, check wiring or replace module + // sanity check failed, check wiring or replace module + RFM95_DEBUG(PSTR("!RFM95:INIT:SANCHK FAIL\n")); return false; } - attachInterrupt(digitalPinToInterrupt(MY_RFM95_IRQ_PIN), RFM95_interruptHandler, RISING); + // IRQ + rfm95_irq = false; + hwPinMode(MY_RFM95_IRQ_PIN, INPUT); + attachInterrupt(MY_RFM95_IRQ_NUM, RFM95_interruptHandler, RISING); return true; } -// RxDone, TxDone, CADDone is mapped to DI0 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)) ) { - // 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)) { - // 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), (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)); - RFM95_burstReadReg(RFM95_REG_00_FIFO, RFM95.currentPacket.data, bufLen); - RFM95.currentPacket.RSSI = static_cast(RFM95_readReg( - RFM95_REG_1A_PKT_RSSI_VALUE)); // RSSI of latest packet received - 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.ackReceived = RFM95_getACKReceived(RFM95.currentPacket.header.controlFlags) && - !RFM95_getACKRequested(RFM95.currentPacket.header.controlFlags); - RFM95.dataReceived = !RFM95.ackReceived; - } - } + // set flag + rfm95_irq = true; +} +// RxDone, TxDone, CADDone is mapped to DI0 +LOCAL void RFM95_interruptHandling(void) +{ + // read interrupt register + const uint8_t irqFlags = RFM95_readReg(RFM95_REG_12_IRQ_FLAGS); + if (RFM95.radioMode == RFM95_RADIO_MODE_RX && (irqFlags & RFM95_RX_DONE)) { + // RXSingle mode: Radio goes automatically to STDBY after packet received + (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); + // Check CRC flag + if (!(irqFlags & RFM95_PAYLOAD_CRC_ERROR)) { + 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 + (void)RFM95_writeReg(RFM95_REG_0D_FIFO_ADDR_PTR, RFM95_readReg(RFM95_REG_10_FIFO_RX_CURRENT_ADDR)); + (void)RFM95_burstReadReg(RFM95_REG_00_FIFO, RFM95.currentPacket.data, bufLen); + RFM95.currentPacket.RSSI = static_cast(RFM95_readReg( + RFM95_REG_1A_PKT_RSSI_VALUE)); // RSSI of latest packet received + RFM95.currentPacket.SNR = static_cast(RFM95_readReg(RFM95_REG_19_PKT_SNR_VALUE)); + RFM95.currentPacket.payloadLen = bufLen - RFM95_HEADER_LEN; + 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)) { + // Message for us + RFM95.ackReceived = RFM95_getACKReceived(RFM95.currentPacket.header.controlFlags) && + !RFM95_getACKRequested(RFM95.currentPacket.header.controlFlags); + RFM95.dataReceived = !RFM95.ackReceived; + } + } + } else { + // CRC error + RFM95_DEBUG(PSTR("!RFM95:IRH:CRC ERROR\n")); + // FIFO is cleared when switch from STDBY to RX or TX + (void)RFM95_setRadioMode(RFM95_RADIO_MODE_RX); + } } else if (RFM95.radioMode == RFM95_RADIO_MODE_TX && (irqFlags & RFM95_TX_DONE) ) { - (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); // change eventually to RX + (void)RFM95_setRadioMode(RFM95_RADIO_MODE_RX); } else if (RFM95.radioMode == RFM95_RADIO_MODE_CAD && (irqFlags & RFM95_CAD_DONE) ) { - RFM95.cad = irqFlags & RFM95_CAD_DETECTED; + RFM95.channelActive = irqFlags & RFM95_CAD_DETECTED; (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); } + // Clear IRQ flags + RFM95_writeReg(RFM95_REG_12_IRQ_FLAGS, RFM95_CLEAR_IRQ); +} - // Clear all IRQ flags - RFM95_writeReg(RFM95_REG_12_IRQ_FLAGS, 0xFF); +LOCAL void RFM95_handler(void) +{ + if (rfm95_irq) { + rfm95_irq = false; + RFM95_interruptHandling(); + } } LOCAL bool RFM95_available(void) @@ -253,73 +292,68 @@ LOCAL bool RFM95_available(void) } else if (RFM95.radioMode == RFM95_RADIO_MODE_TX) { return false; } else if (RFM95.radioMode != RFM95_RADIO_MODE_RX) { - // we are not in RX, and no data received + // we are not in RX, not CAD, and no data received (void)RFM95_setRadioMode(RFM95_RADIO_MODE_RX); } return false; } -LOCAL uint8_t RFM95_recv(uint8_t* buf, const uint8_t maxBufSize) +LOCAL uint8_t RFM95_receive(uint8_t *buf, const uint8_t maxBufSize) { - - // atomic -#ifdef SREG - _SREG = SREG; -#endif - - noInterrupts(); - - const uint8_t payloadLen = RFM95.currentPacket.payloadLen < maxBufSize? - RFM95.currentPacket.payloadLen : maxBufSize; + const uint8_t payloadLen = min(RFM95.currentPacket.payloadLen, maxBufSize); const uint8_t sender = RFM95.currentPacket.header.sender; const rfm95_sequenceNumber_t sequenceNumber = RFM95.currentPacket.header.sequenceNumber; const rfm95_controlFlags_t controlFlags = RFM95.currentPacket.header.controlFlags; const rfm95_RSSI_t RSSI = RFM95.currentPacket.RSSI; const rfm95_SNR_t SNR = RFM95.currentPacket.SNR; if (buf != NULL) { - (void)memcpy((void*)buf, (void*)RFM95.currentPacket.payload, payloadLen); - RFM95.dataReceived = false; + (void)memcpy((void *)buf, (void *)&RFM95.currentPacket.payload, payloadLen); } -#ifdef SREG - SREG = _SREG; // restore interrupts -#endif - - interrupts(); // explicitly re-enable interrupts - + // clear data flag + RFM95.dataReceived = false; // ACK handling if (RFM95_getACKRequested(controlFlags) && !RFM95_getACKReceived(controlFlags)) { +#if defined(MY_GATEWAY_FEATURE) && (F_CPU>16*1000000ul) + // delay for fast GW and slow nodes + delay(50); +#endif RFM95_sendACK(sender, sequenceNumber, RSSI, SNR); } - return payloadLen; } -LOCAL bool RFM95_sendFrame(rfm95_packet_t &packet, const bool increaseSequenceCounter) +LOCAL bool RFM95_sendFrame(rfm95_packet_t *packet, const bool increaseSequenceCounter) { - const uint8_t finalLen = packet.payloadLen + RFM95_HEADER_LEN; - // Make sure we dont interrupt an outgoing message - (void)RFM95_waitPacketSent(); - (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); //==> not needed // Check channel activity if (!RFM95_waitCAD()) { return false; } + // radio is in STDBY if (increaseSequenceCounter) { // increase sequence counter, overflow is ok RFM95.txSequenceNumber++; } - packet.header.sequenceNumber = RFM95.txSequenceNumber; + 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); + (void)RFM95_writeReg(RFM95_REG_0D_FIFO_ADDR_PTR, RFM95_TX_FIFO_ADDR); // write packet - RFM95_burstWriteReg(RFM95_REG_00_FIFO, packet.data, finalLen); + const uint8_t finalLen = packet->payloadLen + RFM95_HEADER_LEN; + (void)RFM95_burstWriteReg(RFM95_REG_00_FIFO, packet->data, finalLen); // total payload length - RFM95_writeReg(RFM95_REG_22_PAYLOAD_LENGTH, finalLen); + (void)RFM95_writeReg(RFM95_REG_22_PAYLOAD_LENGTH, finalLen); // send message, if sent, irq fires and radio returns to standby - return RFM95_setRadioMode(RFM95_RADIO_MODE_TX); + (void)RFM95_setRadioMode(RFM95_RADIO_MODE_TX); + // wait until IRQ fires or timeout + const uint32_t startTX_MS = hwMillis(); + while (!rfm95_irq && + (hwMillis() - startTX_MS < + MY_RFM95_TX_TIMEOUT_MS) ) { // make this payload length + bit rate dependend + doYield(); + } + return rfm95_irq; } -LOCAL bool RFM95_send(const uint8_t recipient, uint8_t* data, const uint8_t len, +LOCAL bool RFM95_send(const uint8_t recipient, uint8_t *data, const uint8_t len, const rfm95_controlFlags_t flags, const bool increaseSequenceCounter) { rfm95_packet_t packet; @@ -328,16 +362,16 @@ LOCAL bool RFM95_send(const uint8_t recipient, uint8_t* data, const uint8_t len, packet.header.recipient = recipient; packet.payloadLen = min(len, (uint8_t)RFM95_MAX_PAYLOAD_LEN); packet.header.controlFlags = flags; - (void)memcpy(&packet.payload, data, packet.payloadLen); - return RFM95_sendFrame(packet, increaseSequenceCounter); + (void)memcpy((void *)&packet.payload, (void *)data, packet.payloadLen); + return RFM95_sendFrame(&packet, increaseSequenceCounter); } LOCAL void RFM95_setFrequency(const uint32_t frequencyHz) { const uint32_t freqReg = (uint32_t)(frequencyHz / RFM95_FSTEP); - RFM95_writeReg(RFM95_REG_06_FRF_MSB, (freqReg >> 16) & 0xff); - RFM95_writeReg(RFM95_REG_07_FRF_MID, (freqReg >> 8) & 0xff); - RFM95_writeReg(RFM95_REG_08_FRF_LSB, freqReg & 0xff); + (void)RFM95_writeReg(RFM95_REG_06_FRF_MSB, (freqReg >> 16) & 0xff); + (void)RFM95_writeReg(RFM95_REG_07_FRF_MID, (freqReg >> 8) & 0xff); + (void)RFM95_writeReg(RFM95_REG_08_FRF_LSB, freqReg & 0xff); } LOCAL bool RFM95_setTxPowerLevel(rfm95_powerLevel_t newPowerLevel) @@ -352,13 +386,13 @@ LOCAL bool RFM95_setTxPowerLevel(rfm95_powerLevel_t newPowerLevel) // 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. Measurements show 20dBm is correct - RFM95_writeReg(RFM95_REG_4D_PA_DAC, RFM95_PA_DAC_ENABLE); + (void)RFM95_writeReg(RFM95_REG_4D_PA_DAC, RFM95_PA_DAC_ENABLE); val = newPowerLevel - 8; } else { - RFM95_writeReg(RFM95_REG_4D_PA_DAC, RFM95_PA_DAC_DISABLE); + (void)RFM95_writeReg(RFM95_REG_4D_PA_DAC, RFM95_PA_DAC_DISABLE); val = newPowerLevel - 5; } - RFM95_writeReg(RFM95_REG_09_PA_CONFIG, RFM95_PA_SELECT | val); + (void)RFM95_writeReg(RFM95_REG_09_PA_CONFIG, RFM95_PA_SELECT | val); RFM95_DEBUG(PSTR("RFM95:PTX:LEVEL=%" PRIi8 "\n"), newPowerLevel); return true; } @@ -366,28 +400,26 @@ LOCAL bool RFM95_setTxPowerLevel(rfm95_powerLevel_t newPowerLevel) } -#if defined(MY_RFM95_TCXO) LOCAL void RFM95_enableTCXO(void) { while ((RFM95_readReg(RFM95_REG_4B_TCXO) & RFM95_TCXO_TCXO_INPUT_ON) != RFM95_TCXO_TCXO_INPUT_ON) { - RFM95_sleep(); - RFM95_writeReg(RFM95_REG_4B_TCXO, (RFM95_readReg(RFM95_REG_4B_TCXO) | RFM95_TCXO_TCXO_INPUT_ON)); + (void)RFM95_writeReg(RFM95_REG_4B_TCXO, + (RFM95_readReg(RFM95_REG_4B_TCXO) | RFM95_TCXO_TCXO_INPUT_ON)); } } -#endif // 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); + (void)RFM95_writeReg(RFM95_REG_1D_MODEM_CONFIG1, config->reg_1d); + (void)RFM95_writeReg(RFM95_REG_1E_MODEM_CONFIG2, config->reg_1e); + (void)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); + (void)RFM95_writeReg(RFM95_REG_20_PREAMBLE_MSB, (preambleLength >> 8) & 0xff); + (void)RFM95_writeReg(RFM95_REG_21_PREAMBLE_LSB, preambleLength & 0xff); } LOCAL void RFM95_setAddress(const uint8_t addr) @@ -413,19 +445,21 @@ LOCAL bool RFM95_setRadioMode(const rfm95_radioMode_t newRadioMode) 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 + (void)RFM95_writeReg(RFM95_REG_40_DIO_MAPPING1, 0x80); // Interrupt on CadDone, DIO0 } else if (newRadioMode == RFM95_RADIO_MODE_RX) { RFM95.dataReceived = false; RFM95.ackReceived = false; regMode = RFM95_MODE_RXCONTINUOUS; - RFM95_writeReg(RFM95_REG_40_DIO_MAPPING1, 0x00); // Interrupt on RxDone, DIO0 + (void)RFM95_writeReg(RFM95_REG_40_DIO_MAPPING1, 0x00); // Interrupt on RxDone, DIO0 + (void)RFM95_writeReg(RFM95_REG_0D_FIFO_ADDR_PTR, + RFM95_RX_FIFO_ADDR); // set FIFO ptr to beginning of RX FIFO address } else if (newRadioMode == RFM95_RADIO_MODE_TX) { regMode = RFM95_MODE_TX; - RFM95_writeReg(RFM95_REG_40_DIO_MAPPING1, 0x40); // Interrupt on TxDone, DIO0 + (void)RFM95_writeReg(RFM95_REG_40_DIO_MAPPING1, 0x40); // Interrupt on TxDone, DIO0 } else { return false; } - RFM95_writeReg(RFM95_REG_01_OP_MODE, regMode); + (void)RFM95_writeReg(RFM95_REG_01_OP_MODE, regMode); RFM95.radioMode = newRadioMode; return true; @@ -434,6 +468,7 @@ LOCAL bool RFM95_setRadioMode(const rfm95_radioMode_t newRadioMode) LOCAL void RFM95_powerUp(void) { #if defined(MY_RFM95_POWER_PIN) + RFM69_DEBUG(PSTR("RFM95:PWU\n")); // power up radio hwDigitalWrite(MY_RFM95_POWER_PIN, HIGH); delay(RFM95_POWERUP_DELAY_MS); #endif @@ -441,6 +476,7 @@ LOCAL void RFM95_powerUp(void) LOCAL void RFM95_powerDown(void) { #if defined(MY_RFM95_POWER_PIN) + RFM69_DEBUG(PSTR("RFM95:PWD\n")); // power down radio hwDigitalWrite(MY_RFM95_POWER_PIN, LOW); #endif } @@ -469,52 +505,53 @@ LOCAL void RFM95_sendACK(const uint8_t recipient, const rfm95_sequenceNumber_t s ACK.sequenceNumber = sequenceNumber; ACK.RSSI = RSSI; ACK.SNR = SNR; - rfm95_controlFlags_t flags = 0x00; + rfm95_controlFlags_t flags = 0u; RFM95_setACKReceived(flags, true); RFM95_setACKRSSIReport(flags, true); - (void)RFM95_send(recipient, (uint8_t*)&ACK, sizeof(rfm95_ack_t), flags); + (void)RFM95_send(recipient, (uint8_t *)&ACK, sizeof(rfm95_ack_t), flags); } LOCAL bool RFM95_executeATC(const rfm95_RSSI_t currentRSSI, const rfm95_RSSI_t targetRSSI) { rfm95_powerLevel_t newPowerLevel = RFM95.powerLevel; - if (RFM95_internalToRSSI(currentRSSI) < RFM95_internalToRSSI(targetRSSI * - (1 + RFM95_ATC_TARGET_RANGE_PERCENT / 100)) && - RFM95.powerLevel < RFM95_MAX_POWER_LEVEL_DBM) { + const int16_t ownRSSI = RFM95_internalToRSSI(currentRSSI); + const int16_t uRange = RFM95_internalToRSSI(targetRSSI) + RFM95_ATC_TARGET_RANGE_DBM; + const int16_t lRange = RFM95_internalToRSSI(targetRSSI) - RFM95_ATC_TARGET_RANGE_DBM; + if (ownRSSI < lRange && RFM95.powerLevel < RFM95_MAX_POWER_LEVEL_DBM) { // increase transmitter power newPowerLevel++; - } else if (RFM95_internalToRSSI(currentRSSI) > RFM95_internalToRSSI(targetRSSI * - (1 - RFM95_ATC_TARGET_RANGE_PERCENT / 100)) && - RFM95.powerLevel > RFM95_MIN_POWER_LEVEL_DBM) { + } else if (ownRSSI > uRange && RFM95.powerLevel > RFM95_MIN_POWER_LEVEL_DBM) { // decrease transmitter power newPowerLevel--; } else { // nothing to adjust return false; } - RFM95_DEBUG(PSTR("RFM95:ATC:ADJ TXL,cR=%" PRIi16 ",tR=%" PRIi16 ",TXL=%" PRIi8 "\n"), - RFM95_internalToRSSI(currentRSSI), - RFM95_internalToRSSI(targetRSSI), RFM95.powerLevel); + RFM95_DEBUG(PSTR("RFM95:ATC:ADJ TXL,cR=%" PRIi16 ",tR=%" PRIi16 "..%" PRIi16 ",TXL=%" PRIi8 "\n"), + ownRSSI, lRange, uRange, RFM95.powerLevel); return RFM95_setTxPowerLevel(newPowerLevel); } -LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, +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=%" PRIu8 ",SEQ=%" PRIu16 ",RETRY=%" PRIu8 "\n"), recipient, RFM95.txSequenceNumber, retry); - rfm95_controlFlags_t flags = 0x00; + rfm95_controlFlags_t flags = 0u; RFM95_setACKRequested(flags, (recipient != RFM95_BROADCAST_ADDRESS)); - (void)RFM95_send(recipient, (uint8_t*)buffer, bufferSize, flags, !retry); - (void)RFM95_waitPacketSent(); + // send packet + if (!RFM95_send(recipient, (uint8_t *)buffer, bufferSize, flags, !retry)) { + return false; + } (void)RFM95_setRadioMode(RFM95_RADIO_MODE_RX); if (recipient == RFM95_BROADCAST_ADDRESS) { return true; } const uint32_t enterMS = hwMillis(); while (hwMillis() - enterMS < retryWaitTime) { + RFM95_handler(); if (RFM95.ackReceived) { const uint8_t sender = RFM95.currentPacket.header.sender; const rfm95_sequenceNumber_t ACKsequenceNumber = RFM95.currentPacket.ACK.sequenceNumber; @@ -533,7 +570,7 @@ LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, // ATC if (RFM95.ATCenabled && RFM95_getACKRSSIReport(flag)) { (void)RFM95_executeATC(RSSI, RFM95.ATCtargetRSSI); - } // ATC + } return true; } // seq check } @@ -541,7 +578,7 @@ LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, } RFM95_DEBUG(PSTR("!RFM95:SWR:NACK\n")); const uint32_t enterCSMAMS = hwMillis(); - const uint16_t randDelayCSMA = enterMS & 100; + const uint16_t randDelayCSMA = enterMS % 100; while (hwMillis() - enterCSMAMS < randDelayCSMA) { doYield(); } @@ -556,24 +593,15 @@ LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, // Wait until no channel activity detected or timeout LOCAL bool RFM95_waitCAD(void) { + // receiver needs to be in STDBY before entering CAD mode + (void)RFM95_setRadioMode(RFM95_RADIO_MODE_STDBY); (void)RFM95_setRadioMode(RFM95_RADIO_MODE_CAD); const uint32_t enterMS = hwMillis(); - while (RFM95.radioMode == RFM95_RADIO_MODE_CAD) { - if (hwMillis() - enterMS > RFM95_CAD_TIMEOUT_MS) { - return false; - } + while (RFM95.radioMode == RFM95_RADIO_MODE_CAD && (hwMillis() - enterMS < RFM95_CAD_TIMEOUT_MS) ) { doYield(); + RFM95_handler(); } - return !RFM95.cad; -} - -// Wait for any previous transmission to finish -LOCAL bool RFM95_waitPacketSent(void) -{ - while (RFM95.radioMode == RFM95_RADIO_MODE_TX) { - doYield(); - } - return true; + return !RFM95.channelActive; } LOCAL void RFM95_ATCmode(const bool OnOff, const int16_t targetRSSI) @@ -588,7 +616,6 @@ LOCAL bool RFM95_sanityCheck(void) result &= RFM95_readReg(RFM95_REG_0F_FIFO_RX_BASE_ADDR) == RFM95_RX_FIFO_ADDR; result &= RFM95_readReg(RFM95_REG_0E_FIFO_TX_BASE_ADDR) == RFM95_TX_FIFO_ADDR; result &= RFM95_readReg(RFM95_REG_23_MAX_PAYLOAD_LENGTH) == RFM95_MAX_PACKET_LEN; - return result; } diff --git a/drivers/RFM95/RFM95.h b/drivers/RFM95/RFM95.h index f7d5d34..2e5dd59 100644 --- a/drivers/RFM95/RFM95.h +++ b/drivers/RFM95/RFM95.h @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2017 Sensnology AB + * Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -18,7 +18,8 @@ * * 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) 2017 Olivier Mauti + * + * RFM95 driver refactored and optimized for MySensors, Copyright (C) 2017-2018 Olivier Mauti * * Changelog: * - ACK with sequenceNumber @@ -26,7 +27,6 @@ * * 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 * */ @@ -40,19 +40,22 @@ * RFM95 driver-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE * - [!] Exclamation mark is prepended in case of error * -* |E| SYS | SUB | Message | Comment -* |-|-------|------|------------------------------------|----------------------------------------------------------------------------------- -* | | RFM95 | INIT | | Initialise RFM95 radio -* | | RFM95 | INIT | PIN,CS=%d,IQP=%d,IQN=%d[,RST=%d] | Pin configuration: chip select (CS), IRQ pin (IQP), IRQ number (IQN), Reset (RST) -* |!| RFM95 | INIT | SANCHK FAIL | Sanity check failed, check wiring or replace module -* | | 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,SNR=%d | Send ACK to node (TO), RSSI of received message (RSSI), SNR of message (SNR) -* | | 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 | SPP | PCT=%d,TX LEVEL=%d | Set TX level percent (PCT), TX level (LEVEL) +* |E| SYS | SUB | Message | Comment +* |-|-------|------|----------------------------------------|----------------------------------------------------------------------------------- +* | | RFM95 | INIT | | Initialise RFM95 radio +* | | RFM95 | INIT | PIN,CS=%%d,IQP=%%d,IQN=%%d[,RST=%%d] | Pin configuration: chip select (CS), IRQ pin (IQP), IRQ number (IQN), Reset (RST) +* |!| RFM95 | INIT | SANCHK FAIL | Sanity check failed, check wiring or replace module +* |!| RFM95 | IRH | CRC FAIL | Incoming packet has CRC error, skip +* | | 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,SNR=%%d | Send ACK to node (TO), RSSI of received message (RSSI), SNR of message (SNR) +* | | RFM95 | ATC | ADJ TXL,cR=%%d,tR=%%d..%%d,TXL=%%d | Adjust TX level, current RSSI (cR), target RSSI range (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 | SPP | PCT=%%d,TX LEVEL=%%d | Set TX level percent (PCT), TX level (LEVEL) +* | | RFM95 | PWD | | Power down radio +* | | RFM95 | PWU | | Power up radio * * RFM95 modem configuration * @@ -60,12 +63,12 @@ * CR = Error correction code * SF = Spreading factor, chips / symbol * -* | CONFIG | REG_1D | REG_1E | REG_26 | BW | CR | SF | Comment | air-time (15 bytes) -* |------------------|--------|--------|--------|-------|-----|------|-----------------------|------------------------ -* | BW125CR45SF128 | 0x72 | 0x74 | 0x04 | 125 | 4/5 | 128 | Default, medium range | 50ms -* | BW500CR45SF128 | 0x92 | 0x74 | 0x04 | 500 | 4/5 | 128 | Fast, short range | 15ms -* | BW31_25CR48SF512 | 0x48 | 0x94 | 0x04 | 31.25 | 4/8 | 512 | Slow, long range | 900ms -* | BW125CR48SF4096 | 0x78 | 0xC4 | 0x0C | 125 | 4/8 | 4096 | Slow, long range | 1500ms +* | CONFIG | BW | CR | SF | Comment | air-time (15 bytes) +* |------------------|-------|-----|------|-----------------------|------------------------ +* | BW125CR45SF128 | 125 | 4/5 | 128 | Default, medium range | 50ms +* | BW500CR45SF128 | 500 | 4/5 | 128 | Fast, short range | 15ms +* | BW31_25CR48SF512 | 31.25 | 4/8 | 512 | Slow, long range | 900ms +* | BW125CR48SF4096 | 125 | 4/8 | 4096 | Slow, long range | 1500ms * * See here for air-time calculation: https://docs.google.com/spreadsheets/d/1voGAtQAjC1qBmaVuP1ApNKs1ekgUjavHuVQIXyYSvNc * @@ -81,34 +84,27 @@ // default PIN assignments, can be overridden #if defined(ARDUINO_ARCH_AVR) #if defined(__AVR_ATmega32U4__) -#define DEFAULT_RFM95_IRQ_PIN (3) //!< DEFAULT_RFM95_IRQ_PIN +#define DEFAULT_RFM95_IRQ_PIN (3) //!< DEFAULT_RFM95_IRQ_PIN #else -#define DEFAULT_RFM95_IRQ_PIN (2) //!< DEFAULT_RFM95_IRQ_PIN +#define DEFAULT_RFM95_IRQ_PIN (2) //!< DEFAULT_RFM95_IRQ_PIN #endif -#define DEFAULT_RFM95_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM95_IRQ_PIN) //!< DEFAULT_RFM95_IRQ_NUM #elif defined(ARDUINO_ARCH_ESP8266) -#define DEFAULT_RFM95_IRQ_PIN (2) //!< DEFAULT_RFM95_IRQ_PIN -#define DEFAULT_RFM95_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM95_IRQ_PIN) //!< DEFAULT_RFM95_IRQ_NUM +#define DEFAULT_RFM95_IRQ_PIN (2) //!< DEFAULT_RFM95_IRQ_PIN #elif defined(ARDUINO_ARCH_ESP32) #warning not implemented yet #elif defined(ARDUINO_ARCH_SAMD) -#define DEFAULT_RFM95_IRQ_PIN (2) //!< DEFAULT_RFM95_IRQ_PIN -#define DEFAULT_RFM95_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM95_IRQ_PIN) //!< DEFAULT_RFM95_IRQ_NUM +#define DEFAULT_RFM95_IRQ_PIN (2) //!< DEFAULT_RFM95_IRQ_PIN #elif defined(LINUX_ARCH_RASPBERRYPI) -#define DEFAULT_RFM95_IRQ_PIN (22) //!< DEFAULT_RFM95_IRQ_PIN -#define DEFAULT_RFM95_IRQ_NUM DEFAULT_RFM95_IRQ_PIN //!< DEFAULT_RFM95_IRQ_NUM +#define DEFAULT_RFM95_IRQ_PIN (22) //!< DEFAULT_RFM95_IRQ_PIN #elif defined(ARDUINO_ARCH_STM32F1) -#define DEFAULT_RFM95_IRQ_PIN (PA3) //!< DEFAULT_RFM95_IRQ_PIN -#define DEFAULT_RFM95_IRQ_NUM DEFAULT_RFM95_IRQ_PIN //!< DEFAULT_RFM95_IRQ_NUM +#define DEFAULT_RFM95_IRQ_PIN (PA3) //!< DEFAULT_RFM95_IRQ_PIN #elif defined(TEENSYDUINO) -#define DEFAULT_RFM95_IRQ_PIN (8) //!< DEFAULT_RFM95_IRQ_PIN -#define DEFAULT_RFM95_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM95_IRQ_PIN) //!< DEFAULT_RFM95_IRQ_NUM +#define DEFAULT_RFM95_IRQ_PIN (8) //!< DEFAULT_RFM95_IRQ_PIN #else -#define DEFAULT_RFM95_IRQ_PIN (2) //!< DEFAULT_RFM95_IRQ_PIN -#define DEFAULT_RFM95_IRQ_NUM DEFAULT_RFM95_IRQ_PIN //!< DEFAULT_RFM95_IRQ_NUM +#define DEFAULT_RFM95_IRQ_PIN (2) //!< DEFAULT_RFM95_IRQ_PIN #endif -#define DEFAULT_RFM95_CS_PIN (SS) //!< DEFAULT_RFM95_CS_PIN +#define DEFAULT_RFM95_CS_PIN (SS) //!< DEFAULT_RFM95_CS_PIN // SPI settings #define MY_RFM95_SPI_DATA_ORDER MSBFIRST //!< SPI data order @@ -149,36 +145,40 @@ extern HardwareSPI SPI; //!< SPI #define RFM95_RETRY_TIMEOUT_MS (500ul) //!< Timeout for ACK, adjustments needed if modem configuration changed (air time different) #endif +#if !defined(MY_RFM95_TX_TIMEOUT_MS) +#define MY_RFM95_TX_TIMEOUT_MS (5*1000ul) //!< TX timeout +#endif + // Frequency definitions -#define RFM95_169MHZ (169000000ul) //!< 169 Mhz -#define RFM95_315MHZ (315000000ul) //!< 315 Mhz -#define RFM95_434MHZ (433920000ul) //!< 433.92 Mhz -#define RFM95_868MHZ (868100000ul) //!< 868.1 Mhz -#define RFM95_915MHZ (915000000ul) //!< 915 Mhz +#define RFM95_169MHZ (169000000ul) //!< 169 Mhz +#define RFM95_315MHZ (315000000ul) //!< 315 Mhz +#define RFM95_434MHZ (433920000ul) //!< 433.92 Mhz +#define RFM95_868MHZ (868100000ul) //!< 868.1 Mhz +#define RFM95_915MHZ (915000000ul) //!< 915 Mhz -#define RFM95_RETRIES (5u) //!< Retries in case of failed transmission -#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_PREAMBLE_LENGTH (8u) //!< Preamble length, default=8 -#define RFM95_CAD_TIMEOUT_MS (2*1000ul) //!< channel activity detection timeout -#define RFM95_POWERUP_DELAY_MS (100u) //!< Power up delay, allow VCC to settle, transport to become fully operational +#define RFM95_RETRIES (5u) //!< Retries in case of failed transmission +#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_PREAMBLE_LENGTH (8u) //!< Preamble length, default=8 +#define RFM95_CAD_TIMEOUT_MS (2*1000ul) //!< channel activity detection timeout +#define RFM95_POWERUP_DELAY_MS (100u) //!< Power up delay, allow VCC to settle, transport to become fully operational -#define RFM95_PACKET_HEADER_VERSION (1u) //!< RFM95 packet header version -#define RFM95_MIN_PACKET_HEADER_VERSION (1u) //!< Minimal RFM95 packet header version -#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_PACKET_HEADER_VERSION (1u) //!< RFM95 packet header version +#define RFM95_MIN_PACKET_HEADER_VERSION (1u) //!< Minimal RFM95 packet header version +#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_ATC_TARGET_RANGE_PERCENT (5u) //!< ATC target range +/-% -#define RFM95_RSSI_OFFSET (137u) //!< RSSI offset -#define RFM95_TARGET_RSSI (-60) //!< RSSI target -#define RFM95_PROMISCUOUS (false) //!< RFM95 promiscuous mode +#define RFM95_BROADCAST_ADDRESS (255u) //!< Broadcasting address +#define RFM95_ATC_TARGET_RANGE_DBM (2u) //!< ATC target range +/- dBm +#define RFM95_RSSI_OFFSET (137u) //!< RSSI offset +#define RFM95_TARGET_RSSI (-70) //!< RSSI target +#define RFM95_PROMISCUOUS (false) //!< RFM95 promiscuous mode -#define RFM95_FXOSC (32*1000000ul) //!< The crystal oscillator frequency of the module -#define RFM95_FSTEP (RFM95_FXOSC / 524288.0f) //!< The Frequency Synthesizer step = RFM95_FXOSC / +#define RFM95_FXOSC (32*1000000ul) //!< The crystal oscillator frequency of the module +#define RFM95_FSTEP (RFM95_FXOSC / 524288.0f) //!< The Frequency Synthesizer step // helper macros #define RFM95_getACKRequested(__value) ((bool)bitRead(__value, RFM95_BIT_ACK_REQUESTED)) //!< getACKRequested @@ -187,8 +187,8 @@ extern HardwareSPI SPI; //!< SPI #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 -#define RFM95_internalToRSSI(__value) ((int16_t)(__value - RFM95_RSSI_OFFSET)) //!< Convert internal RSSI to RSSI -#define RFM95_RSSItoInternal(__value) ((uint8_t)(__value + RFM95_RSSI_OFFSET)) //!< Convert RSSI to internal RSSI +//#define RFM95_internalToRSSI(__value) ((int16_t)(__value - RFM95_RSSI_OFFSET)) //!< Convert internal RSSI to RSSI +//#define RFM95_RSSItoInternal(__value) ((uint8_t)(__value + RFM95_RSSI_OFFSET)) //!< Convert RSSI to internal RSSI #define RFM95_internalToSNR(__value) ((int8_t)(__value / 4)) //!< Convert internal SNR to SNR #define RFM95_MIN_POWER_LEVEL_DBM ((rfm95_powerLevel_t)5u) //!< min. power level @@ -220,7 +220,7 @@ typedef struct { /** * @brief Sequence number data type */ -typedef uint16_t rfm95_sequenceNumber_t; +typedef uint16_t rfm95_sequenceNumber_t; // will eventually change to uint8_t in 3.0 /** * @brief RSSI data type */ @@ -285,18 +285,18 @@ typedef struct { * @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 - rfm95_powerLevel_t powerLevel; //!< TX power level dBm - rfm95_RSSI_t ATCtargetRSSI; //!< ATC: target RSSI + uint8_t address; //!< Node address + rfm95_packet_t currentPacket; //!< Buffer for current packet + rfm95_sequenceNumber_t txSequenceNumber; //!< RFM95_txSequenceNumber + rfm95_powerLevel_t powerLevel; //!< TX power level dBm + rfm95_RSSI_t ATCtargetRSSI; //!< ATC: target RSSI // 8 bit - rfm95_radioMode_t radioMode : 3; //!< current transceiver state - bool cad : 1; //!< RFM95_cad - bool ATCenabled : 1; //!< ATC enabled - bool ackReceived : 1; //!< ACK received - bool dataReceived : 1; //!< AData received - uint8_t reserved : 1; //!< reserved + rfm95_radioMode_t radioMode : 3; //!< current transceiver state + bool channelActive : 1; //!< RFM95_cad + bool ATCenabled : 1; //!< ATC enabled + bool ackReceived : 1; //!< ACK received + bool dataReceived : 1; //!< Data received + bool reserved : 1; //!< unused } rfm95_internal_t; #define LOCAL static //!< static @@ -318,14 +318,14 @@ LOCAL void RFM95_setAddress(const uint8_t addr); */ 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 +* @brief Sets all the registers 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 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() +* @return True if a new, complete, error-free uncollected message is available to be retreived by @ref RFM95_receive() */ LOCAL bool RFM95_available(void); /** @@ -334,7 +334,7 @@ LOCAL bool RFM95_available(void); * @param maxBufSize Max buffer size * @return Number of bytes */ -LOCAL uint8_t RFM95_recv(uint8_t* buf, const uint8_t maxBufSize); +LOCAL uint8_t RFM95_receive(uint8_t *buf, const uint8_t maxBufSize); /** * @brief RFM95_send * @param recipient @@ -344,7 +344,7 @@ LOCAL uint8_t RFM95_recv(uint8_t* buf, const uint8_t maxBufSize); * @param increaseSequenceCounter * @return True if packet sent */ -LOCAL bool RFM95_send(const uint8_t recipient, uint8_t* data, const uint8_t len, +LOCAL bool RFM95_send(const uint8_t recipient, uint8_t *data, const uint8_t len, const rfm95_controlFlags_t flags, const bool increaseSequenceCounter = true); /** * @brief RFM95_sendFrame @@ -352,7 +352,7 @@ LOCAL bool RFM95_send(const uint8_t recipient, uint8_t* data, const uint8_t len, * @param increaseSequenceCounter * @return True if frame sent */ -LOCAL bool RFM95_sendFrame(rfm95_packet_t &packet, const bool increaseSequenceCounter = true); +LOCAL bool RFM95_sendFrame(rfm95_packet_t *packet, const bool increaseSequenceCounter = true); /** * @brief RFM95_setPreambleLength * @param preambleLength @@ -377,17 +377,15 @@ LOCAL bool RFM95_setTxPowerLevel(rfm95_powerLevel_t newPowerLevel); */ LOCAL bool RFM95_setTxPowerPercent(const uint8_t newPowerPercent); -#if defined(MY_RFM95_TCXO) /** * @brief Enable TCXO mode * Call this immediately after init(), to force your radio to use an external * frequency source, such as a Temperature Compensated Crystal Oscillator (TCXO). * See the comments in the main documentation about the sensitivity of this radio to * clock frequency especially when using narrow bandwidths. -* Leaves the module in sleep mode. +* @note Has to be called while radio is in sleep mode. */ LOCAL void RFM95_enableTCXO(void); -#endif /** * @brief Sets the radio into low-power sleep mode @@ -425,7 +423,7 @@ 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, +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); /** @@ -433,11 +431,7 @@ LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void* buffer, * @return True if no channel activity detected, False if timeout occured */ LOCAL bool RFM95_waitCAD(void); -/** -* @brief RFM95_waitPacketSent -* @return True if packet sent -*/ -LOCAL bool RFM95_waitPacketSent(void); + /** * @brief RFM95_setRadioMode * @param newRadioMode @@ -448,6 +442,16 @@ LOCAL bool RFM95_setRadioMode(const rfm95_radioMode_t newRadioMode); * @brief Low level interrupt handler */ LOCAL void RFM95_interruptHandler(void); + +/** +* @brief Packet engine +*/ +LOCAL void RFM95_interruptHandling(void); + +/** +* @brief RFM95_handler +*/ +LOCAL void RFM95_handler(void); /** * @brief RFM95_getSendingRSSI * @return RSSI Signal strength of last packet received diff --git a/drivers/RFM95/RFM95registers.h b/drivers/RFM95/RFM95registers.h index c7dd630..33d2562 100644 --- a/drivers/RFM95/RFM95registers.h +++ b/drivers/RFM95/RFM95registers.h @@ -1,34 +1,30 @@ /* -* 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 -* -*/ + * 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-2018 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) 2017-2018 Olivier Mauti + * + * Definitions for HopeRF LoRa radios: + * http://www.hoperf.com/upload/rf/RFM95_96_97_98W.pdf + * + */ // Register access #define RFM95_READ_REGISTER (0x7Fu) //!< reading register @@ -152,6 +148,7 @@ #define RFM95_PAYLOAD_CRC_ERROR 0x20 //!< PAYLOAD_CRC_ERROR #define RFM95_RX_DONE 0x40 //!< RX_DONE #define RFM95_RX_TIMEOUT 0x80 //!< RX_TIMEOUT +#define RFM95_CLEAR_IRQ 0xFF // Date: Sun, 18 Feb 2018 21:06:28 +0100 Subject: [PATCH 14/60] RFM69: Updates and optimizations (#1049) * RFM69: Updates and optimizations * RFM69: Updates and optimizations --- MyConfig.h | 57 +- drivers/RFM69/new/RFM69_new.cpp | 768 ++++++----------------- drivers/RFM69/new/RFM69_new.h | 372 ++++++----- drivers/RFM69/new/RFM69registers_new.h | 72 ++- hal/transport/RFM69/MyTransportRFM69.cpp | 9 +- 5 files changed, 459 insertions(+), 819 deletions(-) diff --git a/MyConfig.h b/MyConfig.h index 5b78c01..6c72ba9 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -572,7 +572,7 @@ /** * @def MY_RADIO_RFM69 - * @brief Define this to use RFM69 based radios for sensor network communication. + * @brief Define this to use %RFM69 based radios for sensor network communication. */ //#define MY_RADIO_RFM69 @@ -641,7 +641,7 @@ /** * @def MY_RFM69_ATC_TARGET_RSSI_DBM - * @brief Target RSSI level (in dBm) for RFM69 ATC mode. + * @brief Target RSSI level (in dBm) for %RFM69 ATC mode. */ #ifndef MY_RFM69_ATC_TARGET_RSSI_DBM #define MY_RFM69_ATC_TARGET_RSSI_DBM (-80) @@ -649,7 +649,7 @@ /** * @def MY_RFM69_ATC_MODE_DISABLED - * @brief Define to disable ATC mode of RFM69 driver. + * @brief Define to disable ATC mode of %RFM69 driver. */ //#define MY_RFM69_ATC_MODE_DISABLED @@ -668,7 +668,7 @@ /** * @def MY_RFM69_NETWORKID - * @brief RFM69 Network ID. Use the same for all nodes that will talk to each other. + * @brief %RFM69 Network ID. Use the same for all nodes that will talk to each other. */ #ifndef MY_RFM69_NETWORKID #define MY_RFM69_NETWORKID (100) @@ -682,6 +682,7 @@ #ifdef MY_RF69_RESET // legacy, older board files +// not enabled now: #warning MY_RF69_RESET is depreciated, please use MY_RFM69_RST_PIN instead. #define MY_RFM69_RST_PIN MY_RF69_RESET #endif @@ -693,11 +694,12 @@ /** * @def MY_RFM69_IRQ_PIN - * @brief Define this to use the %RFM69 IRQ pin (optional). + * @brief Define this to override the default %RFM69 IRQ pin assignment. */ #ifndef MY_RFM69_IRQ_PIN #ifdef MY_RF69_IRQ_PIN // legacy, older board files +// not enabled now: #warning MY_RF69_IRQ_PIN is depreciated, please use MY_RFM69_IRQ_PIN instead. #define MY_RFM69_IRQ_PIN MY_RF69_IRQ_PIN #else #define MY_RFM69_IRQ_PIN DEFAULT_RFM69_IRQ_PIN @@ -711,19 +713,21 @@ #ifndef MY_RFM69_IRQ_NUM #ifdef MY_RF69_IRQ_NUM // legacy, older board files +// not enabled now: #warning MY_RF69_IRQ_NUM is depreciated, please use MY_RFM69_IRQ_NUM instead. #define MY_RFM69_IRQ_NUM MY_RF69_IRQ_NUM #else -#define MY_RFM69_IRQ_NUM DEFAULT_RFM69_IRQ_NUM +#define MY_RFM69_IRQ_NUM digitalPinToInterrupt(MY_RFM69_IRQ_PIN) #endif #endif /** * @def MY_RFM69_CS_PIN - * @brief RFM69 SPI chip select pin. + * @brief %RFM69 SPI chip select pin. */ #ifndef MY_RFM69_CS_PIN #ifdef MY_RF69_SPI_CS // legacy, older board files +// not enabled now: #warning MY_RF69_SPI_CS is depreciated, please use MY_RFM69_CS_PIN instead. #define MY_RFM69_CS_PIN MY_RF69_SPI_CS #else #define MY_RFM69_CS_PIN DEFAULT_RFM69_CS_PIN @@ -764,29 +768,29 @@ #define MY_RFM69_DEFAULT_LISTEN_IDLE_US (1*1000000ul) #endif -#if !defined(MY_RFM69_BITRATE_MSB) && !defined(MY_RFM69_BITRATE_LSB) /** - * @def MY_RFM69_BITRATE_MSB - * @brief %RFM69 bit rate (most significant bits) + * @def MY_RFM69_MODEM_CONFIGURATION + * @brief %RFM69 modem configuration, default is %RFM69_FSK_BR55_5_FD50 * - * Bitrate between the transmitter and the receiver must be better than 6.5. - * Refer to RFM69registers_old.h (L.153) or RFM69registers_new.h (L.154) for settings or - * http://www.semtech.com/apps/filedown/down.php?file=sx1231.pdf - * @note RFM69_FOSC(Hz)/MSB_LSBVALUE = Bitrate in kbits + * | Configuration | Modulation (xxx) | Bit rate | FD | RXBW | Additional settings + * |-------------------------|------------------|----------|--------|----------|--------------------------- + * | RFM69_xxx_BR2_FD5 | FSK/GFSK/OOK | 2000 | 5000 | 111_24_4 | Whitening + * | RFM69_xxx_BR2_4_FD4_8 | FSK/GFSK/OOK | 2400 | 4800 | 111_24_4 | Whitening + * | RFM69_xxx_BR4_8_FD9_6 | FSK/GFSK/OOK | 4800 | 9600 | 111_24_4 | Whitening + * | RFM69_xxx_BR9_6_FD19_2 | FSK/GFSK/OOK | 9600 | 19200 | 111_24_4 | Whitening + * | RFM69_xxx_BR19_2_FD38_4 | FSK/GFSK/OOK | 19200 | 38400 | 111_24_3 | Whitening + * | RFM69_xxx_BR38_4_FD76_8 | FSK/GFSK/OOK | 38400 | 76800 | 111_24_2 | Whitening + * | RFM69_xxx_BR55_5_FD50 | FSK/GFSK/OOK | 55555 | 50000 | 111_16_2 | Whitening + * | RFM69_xxx_BR57_6_FD120 | FSK/GFSK/OOK | 57600 | 120000 | 111_16_1 | Whitening + * | RFM69_xxx_BR125_FD125 | FSK/GFSK/OOK | 125000 | 125000 | 010_16_2 | Whitening + * | RFM69_xxx_BR250_FD250 | FSK/GFSK/OOK | 250000 | 250000 | 111_16_0 | Whitening + * + * https://www.semtech.com/uploads/documents/sx1231.pdf * */ -#define MY_RFM69_BITRATE_MSB (RFM69_BITRATEMSB_55555) -/** - * @def MY_RFM69_BITRATE_LSB - * @brief %RFM69 bit rate (least significant bits) - * - * Bitrate between the transmitter and the receiver must be better than 6.5. - * Refer to RFM69registers_old.h (L.153) or RFM69registers_new.h (L.154) for settings or - * http://www.semtech.com/apps/filedown/down.php?file=sx1231.pdf - * @note RFM69_FOSC(Hz)/MSB_LSBVALUE = Bitrate in kbits - */ -#define MY_RFM69_BITRATE_LSB (RFM69_BITRATELSB_55555) -#endif +//#define MY_RFM69_MODEM_CONFIGURATION (RFM69_FSK_BR55_5_FD50) + + /** @}*/ // End of RFM69SettingGrpPub group /** @@ -2073,6 +2077,7 @@ #define MY_IS_RFM69HW #define MY_RFM69_NEW_DRIVER #define MY_RFM69_POWER_PIN +#define MY_RFM69_MODEM_CONFIGURATION #define MY_RFM69_ENABLE_ENCRYPTION #define MY_RFM69_ATC_MODE_DISABLED #define MY_RFM69_MAX_POWER_LEVEL_DBM diff --git a/drivers/RFM69/new/RFM69_new.cpp b/drivers/RFM69/new/RFM69_new.cpp index 7cfb8b8..111d83d 100644 --- a/drivers/RFM69/new/RFM69_new.cpp +++ b/drivers/RFM69/new/RFM69_new.cpp @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2017 Sensnology AB + * Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -16,20 +16,20 @@ * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * - * RFM69 driver refactored for Mysensors + * RFM69 driver refactored for MySensors * * Based on : * - LowPowerLab RFM69 Lib Copyright Felix Rusu (2014), felix@lowpowerlab.com * - Automatic Transmit Power Control class derived from RFM69 library. * Discussion and details in this forum post: https://lowpowerlab.com/forum/index.php/topic,688.0.html * Copyright Thomas Studwell (2014,2015) - * - Mysensors generic radio driver implementation Copyright (C) 2017 Olivier Mauti + * - MySensors generic radio driver implementation Copyright (C) 2017, 2018 Olivier Mauti * * Changes by : @tekka, @scalz, @marceloagno * * Definitions for Semtech SX1231/H radios: - * http://www.semtech.com/images/datasheet/sx1231.pdf - * http://www.semtech.com/images/datasheet/sx1231h.pdf + * https://www.semtech.com/uploads/documents/sx1231.pdf + * https://www.semtech.com/uploads/documents/sx1231h.pdf */ #include "RFM69_new.h" @@ -41,18 +41,10 @@ #define RFM69_DEBUG(x,...) //!< DEBUG null #endif -volatile rfm69_internal_t RFM69; //!< internal variables +rfm69_internal_t RFM69; //!< internal variables +volatile uint8_t rfm69_irq; //!< rfm69 irq flag -#if defined (SREG) && !defined(SPI_HAS_TRANSACTION) -uint8_t _SREG; // Used to save and restore the SREG values in SPI transactions -#endif - -#if defined (SPCR) && defined (SPSR) && !defined(SPI_HAS_TRANSACTION) -uint8_t _SPCR; //!< _SPCR -uint8_t _SPSR; //!< _SPSR -#endif - -#ifdef LINUX_SPI_BCM +#if defined(LINUX_SPI_BCM) // SPI RX and TX buffers (max packet len + 1 byte for the command) uint8_t spi_rxbuff[RFM69_MAX_PACKET_LEN + 1]; uint8_t spi_txbuff[RFM69_MAX_PACKET_LEN + 1]; @@ -111,14 +103,14 @@ LOCAL uint8_t RFM69_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_ const bool aReadMode) { uint8_t status; - uint8_t* current = buf; + uint8_t *current = buf; RFM69_prepareSPITransaction(); RFM69_csn(LOW); -#ifdef LINUX_SPI_BCM - uint8_t * prx = spi_rxbuff; - uint8_t * ptx = spi_txbuff; +#if defined(LINUX_SPI_BCM) + uint8_t *prx = spi_rxbuff; + uint8_t *ptx = spi_txbuff; uint8_t size = len + 1; // Add register value to transmit buffer *ptx++ = cmd; @@ -156,33 +148,52 @@ LOCAL uint8_t RFM69_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_ } } #endif - RFM69_csn(HIGH); RFM69_concludeSPITransaction(); - return status; } // low level register access -LOCAL uint8_t RFM69_RAW_readByteRegister(const uint8_t address) +LOCAL inline uint8_t RFM69_RAW_readByteRegister(const uint8_t address) { - const uint8_t value = RFM69_spiMultiByteTransfer(address, NULL, 1, true); - //RFM69_DEBUG(PSTR("RFM69:read register, reg=0x%02" PRIx8 ", value=%" PRIu8 "\n"), address, value); - return value; + return RFM69_spiMultiByteTransfer(address, NULL, 1, true); } -// low level register access -LOCAL uint8_t RFM69_RAW_writeByteRegister(const uint8_t address, uint8_t value) +LOCAL inline uint8_t RFM69_RAW_writeByteRegister(const uint8_t address, uint8_t value) { - //RFM69_DEBUG(PSTR("RFM69:write register, reg=0x%02" PRIx8 ", value=%" PRIu8 "\n"), address & 0x7F, value); return RFM69_spiMultiByteTransfer(address, &value, 1, false); } -// macros, saves space -#define RFM69_readReg(__reg) RFM69_RAW_readByteRegister(__reg & RFM69_READ_REGISTER) -#define RFM69_writeReg(__reg, __value) RFM69_RAW_writeByteRegister((__reg | RFM69_WRITE_REGISTER), __value ) -#define RFM69_burstReadReg(__reg, __buf, __len) RFM69_spiMultiByteTransfer( __reg & RFM69_READ_REGISTER, (uint8_t*)__buf, __len, true ) -#define RFM69_burstWriteReg(__reg, __buf, __len) RFM69_spiMultiByteTransfer( __reg | RFM69_WRITE_REGISTER, (uint8_t*)__buf, __len, false ) +// helper functions +LOCAL inline uint8_t RFM69_readReg(const uint8_t reg) +{ + return RFM69_RAW_readByteRegister(reg & RFM69_READ_REGISTER); +} + +LOCAL inline uint8_t RFM69_writeReg(const uint8_t reg, const uint8_t value) +{ + return RFM69_RAW_writeByteRegister(reg | RFM69_WRITE_REGISTER, value); +} + +LOCAL inline uint8_t RFM69_burstReadReg(const uint8_t reg, void *buf, uint8_t len) +{ + return RFM69_spiMultiByteTransfer(reg & RFM69_READ_REGISTER, (uint8_t *)buf, len, true); +} + +LOCAL inline uint8_t RFM69_burstWriteReg(const uint8_t reg, const void *buf, uint8_t len) +{ + return RFM69_spiMultiByteTransfer(reg | RFM69_WRITE_REGISTER, (uint8_t *)buf, len, false); +} + +LOCAL inline rfm69_RSSI_t RFM69_RSSItoInternal(const int16_t externalRSSI) +{ + return (rfm69_RSSI_t)-(externalRSSI * 2); +} + +LOCAL inline int16_t RFM69_internalToRSSI(const rfm69_RSSI_t internalRSSI) +{ + return (int16_t)-(internalRSSI / 2); +} LOCAL bool RFM69_initialise(const uint32_t frequencyHz) { @@ -219,64 +230,60 @@ LOCAL bool RFM69_initialise(const uint32_t frequencyHz) RFM69.radioMode = RFM69_RADIO_MODE_SLEEP; RFM69.ATCenabled = false; RFM69.listenModeEnabled = false; - RFM69.ATCtargetRSSI = RFM69_RSSItoInternal(RFM69_TARGET_RSSI_DBM); + RFM69.ATCtargetRSSI = RFM69_RSSItoInternal(MY_RFM69_ATC_TARGET_RSSI_DBM); // SPI init hwDigitalWrite(MY_RFM69_CS_PIN, HIGH); hwPinMode(MY_RFM69_CS_PIN, OUTPUT); RFM69_SPI.begin(); - + (void)RFM69_setRadioMode(RFM69_RADIO_MODE_STDBY); + // set configuration, encryption is disabled RFM69_setConfiguration(); RFM69_setFrequency(frequencyHz); - (void)RFM69_setRadioMode(RFM69_RADIO_MODE_STDBY); - - // Encryption is persistent between resets and can trip you up during debugging. - // Disable it during initialization so we always start from a known state. - RFM69_encrypt(0); (void)RFM69_setTxPowerLevel(MY_RFM69_TX_POWER_DBM); - // IRQ - hwPinMode(MY_RFM69_IRQ_PIN, INPUT); -#if defined (SPI_HAS_TRANSACTION) && !defined (ESP8266) && !defined (MY_SOFTSPI) - RFM69_SPI.usingInterrupt(digitalPinToInterrupt(MY_RFM69_IRQ_PIN)); -#endif -#ifdef MY_DEBUG_VERBOSE_RFM69_REGISTERS +#if defined(MY_DEBUG_VERBOSE_RFM69_REGISTERS) RFM69_readAllRegs(); +#else + (void)RFM69_readAllRegs; #endif + //RFM69_DEBUG(PSTR("RFM69:INIT:HWV=%" PRIu8 "\n"),RFM69_readReg(RFM69_REG_VERSION)); if (!RFM69_sanityCheck()) { - RFM69_DEBUG( - PSTR("!RFM69:INIT:SANCHK FAIL\n")); // sanity check failed, check wiring or replace module + // sanity check failed, check wiring or replace module + RFM69_DEBUG(PSTR("!RFM69:INIT:SANCHK FAIL\n")); return false; } - attachInterrupt(digitalPinToInterrupt(MY_RFM69_IRQ_PIN), RFM69_interruptHandler, RISING); + // clear FIFO and flags + RFM69_clearFIFO(); + // IRQ + rfm69_irq = false; + hwPinMode(MY_RFM69_IRQ_PIN, INPUT); + attachInterrupt(MY_RFM69_IRQ_NUM, RFM69_interruptHandler, RISING); return true; } +LOCAL void RFM69_clearFIFO(void) +{ + (void)RFM69_writeReg(RFM69_REG_IRQFLAGS2, 0x10u); +} // IRQ handler: PayloadReady (RX) & PacketSent (TX) mapped to DI0 LOCAL void RFM69_interruptHandler(void) { -#if defined(MY_RFM69_ENABLE_LISTENMODE) - if (RFM69.listenModeEnabled) { - RFM69_listenModeReset(); - //noInterrupts(); - union { // union to simplify addressing of long and short parts of time offset - uint32_t l; - uint8_t b[4]; - } burstRemaining; + // set flag + rfm69_irq = true; +} - burstRemaining.l = 0; - } -#endif +LOCAL void RFM69_interruptHandling(void) +{ const uint8_t regIrqFlags2 = RFM69_readReg(RFM69_REG_IRQFLAGS2); - if ( RFM69.radioMode == RFM69_RADIO_MODE_RX && (regIrqFlags2 & RFM69_IRQFLAGS2_PAYLOADREADY) ) { - RFM69.currentPacket.RSSI = RFM69_readRSSI(); + if (RFM69.radioMode == RFM69_RADIO_MODE_RX && (regIrqFlags2 & RFM69_IRQFLAGS2_PAYLOADREADY)) { (void)RFM69_setRadioMode(RFM69_RADIO_MODE_STDBY); // use the fifo level irq as indicator if header bytes received if (regIrqFlags2 & RFM69_IRQFLAGS2_FIFOLEVEL) { RFM69_prepareSPITransaction(); RFM69_csn(LOW); -#ifdef LINUX_SPI_BCM +#if defined(LINUX_SPI_BCM) char data[RFM69_MAX_PACKET_LEN + 1]; // max packet len + 1 byte for the command data[0] = RFM69_REG_FIFO & RFM69_READ_REGISTER; RFM69_SPI.transfern(data, 3); @@ -292,8 +299,8 @@ LOCAL void RFM69_interruptHandler(void) //SPI.transfern(data, RFM69.currentPacket.header.packetLen - 1); //TODO: Wrong packetLen? RFM69_SPI.transfern(data, RFM69.currentPacket.header.packetLen); - //(void)memcpy((void*)&RFM69.currentPacket.data[2], (void*)&data[1], RFM69.currentPacket.header.packetLen - 2); //TODO: Wrong packetLen? - (void)memcpy((void*)&RFM69.currentPacket.data[2], (void*)&data[1], + //(void)memcpy((void *)&RFM69.currentPacket.data[2], (void *)&data[1], RFM69.currentPacket.header.packetLen - 2); //TODO: Wrong packetLen? + (void)memcpy((void *)&RFM69.currentPacket.data[2], (void *)&data[1], RFM69.currentPacket.header.packetLen - 1); if (RFM69.currentPacket.header.version >= RFM69_MIN_PACKET_HEADER_VERSION) { @@ -303,23 +310,22 @@ LOCAL void RFM69_interruptHandler(void) RFM69.dataReceived = !RFM69.ackReceived; } #else - RFM69_SPI.transfer(RFM69_REG_FIFO & RFM69_READ_REGISTER); + (void)RFM69_SPI.transfer(RFM69_REG_FIFO & RFM69_READ_REGISTER); // set reading pointer - uint8_t* current = (uint8_t*)&RFM69.currentPacket; + uint8_t *current = (uint8_t *)&RFM69.currentPacket; bool headerRead = false; // first read header uint8_t readingLength = RFM69_HEADER_LEN; while (readingLength--) { - *current++ = RFM69_SPI.transfer((uint8_t)0x00); + *current++ = RFM69_SPI.transfer((uint8_t)RFM69_NOP); if (!readingLength && !headerRead) { // header read headerRead = true; if (RFM69.currentPacket.header.version >= RFM69_MIN_PACKET_HEADER_VERSION) { // read payload - readingLength = RFM69.currentPacket.header.packetLen - (RFM69_HEADER_LEN - 1); - if (readingLength > RFM69_MAX_PACKET_LEN) { - readingLength = RFM69_MAX_PACKET_LEN; - } + readingLength = min(RFM69.currentPacket.header.packetLen - (RFM69_HEADER_LEN - 1), + RFM69_MAX_PACKET_LEN); + // save payload length RFM69.currentPacket.payloadLen = readingLength; RFM69.ackReceived = RFM69_getACKReceived(RFM69.currentPacket.header.controlFlags); RFM69.dataReceived = !RFM69.ackReceived; @@ -330,94 +336,106 @@ LOCAL void RFM69_interruptHandler(void) RFM69_csn(HIGH); RFM69_concludeSPITransaction(); } - // radio remains in stdby until paket read - } else if (RFM69.radioMode == RFM69_RADIO_MODE_TX && (regIrqFlags2 & RFM69_IRQFLAGS2_PACKETSENT) ) { - RFM69.dataSent = true; + RFM69.currentPacket.RSSI = RFM69_readRSSI(); + // radio remains in stdby until packet read + } else { // back to RX (void)RFM69_setRadioMode(RFM69_RADIO_MODE_RX); } } +LOCAL void RFM69_handler(void) +{ + if (rfm69_irq) { + // radio is in STDBY + // clear flag, 8bit - no need for critical section + rfm69_irq = false; + RFM69_interruptHandling(); + } +} + LOCAL bool RFM69_available(void) { if (RFM69.dataReceived) { - // data received - we are still in STDBY from IRQ handler - //(void)RFM69_setRadioMode(RFM69_RADIO_MODE_STDBY); + // data received - we are still in STDBY return true; } else if (RFM69.radioMode == RFM69_RADIO_MODE_TX) { + // still in TX return false; - } else if (RFM69.radioMode != RFM69_RADIO_MODE_RX) { - // we are not in RX, and no data received - RFM69_setRadioMode(RFM69_RADIO_MODE_RX); + } else if (RFM69.radioMode != RFM69_RADIO_MODE_RX) { // adding this check speeds up loop() :) + // no data received and not in RX + (void)RFM69_setRadioMode(RFM69_RADIO_MODE_RX); } return false; } - - -LOCAL uint8_t RFM69_recv(uint8_t* buf, const uint8_t maxBufSize) +LOCAL uint8_t RFM69_receive(uint8_t *buf, const uint8_t maxBufSize) { - // atomic - noInterrupts(); - - const uint8_t payloadLen = RFM69.currentPacket.payloadLen < maxBufSize? - RFM69.currentPacket.payloadLen : maxBufSize; + const uint8_t payloadLen = min(RFM69.currentPacket.payloadLen, maxBufSize); const uint8_t sender = RFM69.currentPacket.header.sender; const rfm69_sequenceNumber_t sequenceNumber = RFM69.currentPacket.header.sequenceNumber; const uint8_t controlFlags = RFM69.currentPacket.header.controlFlags; - const rfm69_RSSI_t RSSI = RFM69.currentPacket.RSSI; // of incoming packet + const rfm69_RSSI_t RSSI = RFM69.currentPacket.RSSI; if (buf != NULL) { - (void)memcpy((void*)buf, (void*)RFM69.currentPacket.payload, payloadLen); - // packet read - RFM69.dataReceived = false; + (void)memcpy((void *)buf, (void *)&RFM69.currentPacket.payload, payloadLen); } - - interrupts(); // explicitly re-enable interrupts - + // clear data flag + RFM69.dataReceived = false; if (RFM69_getACKRequested(controlFlags) && !RFM69_getACKReceived(controlFlags)) { - RFM69_sendACK(sender, sequenceNumber,RSSI); +#if defined(MY_GATEWAY_FEATURE) && (F_CPU>16000000) + // delay for fast GW and slow nodes + delay(50); +#endif + RFM69_sendACK(sender, sequenceNumber, RSSI); } - return payloadLen; } -LOCAL bool RFM69_sendFrame(rfm69_packet_t &packet, const bool increaseSequenceCounter) +LOCAL bool RFM69_channelFree(void) { - /* - if(!RFM69_waitCAD()) { - // channel not free - return false; + // returns true if channel activity under RFM69_CSMA_LIMIT_DBM + const rfm69_RSSI_t RSSI = RFM69_readRSSI(false); + RFM69_DEBUG(PSTR("RFM69:CSMA:RSSI=%" PRIi16 "\n"), RFM69_internalToRSSI(RSSI)); + return (RSSI > RFM69_RSSItoInternal(MY_RFM69_CSMA_LIMIT_DBM)); +} + +LOCAL bool RFM69_sendFrame(rfm69_packet_t *packet, const bool increaseSequenceCounter) +{ + // ensure we are in RX for correct RSSI sampling, dirty hack to enforce rx restart :) + RFM69.radioMode = RFM69_RADIO_MODE_STDBY; + (void)RFM69_setRadioMode(RFM69_RADIO_MODE_RX); + delay(1); // timing for correct RSSI sampling + const uint32_t CSMA_START_MS = hwMillis(); + while (!RFM69_channelFree() && + ((hwMillis() - CSMA_START_MS) < MY_RFM69_CSMA_TIMEOUT_MS)) { + doYield(); } - */ - - // set radio to standby to load fifo (void)RFM69_setRadioMode(RFM69_RADIO_MODE_STDBY); if (increaseSequenceCounter) { // increase sequence counter, overflow is ok RFM69.txSequenceNumber++; } - packet.header.sequenceNumber = RFM69.txSequenceNumber; - - RFM69_writeReg(RFM69_REG_PACKETCONFIG2, - (RFM69_readReg(RFM69_REG_PACKETCONFIG2) & 0xFB) | RFM69_PACKET2_RXRESTART); // avoid RX deadlocks + // clear FIFO and flags + RFM69_clearFIFO(); + // assign sequence number + packet->header.sequenceNumber = RFM69.txSequenceNumber; // write packet - const uint8_t finalLen = packet.payloadLen + RFM69_HEADER_LEN; // including length byte - RFM69_burstWriteReg(RFM69_REG_FIFO, packet.data, finalLen); + const uint8_t finalLen = packet->payloadLen + RFM69_HEADER_LEN; // including length byte + (void)RFM69_burstWriteReg(RFM69_REG_FIFO, packet->data, finalLen); // send message - (void)RFM69_setRadioMode(RFM69_RADIO_MODE_TX); - const uint32_t txStart = hwMillis(); - // irq handler set radiomode to rx once packet sent - while (!RFM69.dataSent && hwMillis() - txStart < RFM69_TX_LIMIT_MS) { // wait until packet sent + (void)RFM69_setRadioMode(RFM69_RADIO_MODE_TX); // irq upon txsent + const uint32_t txStartMS = hwMillis(); + while (!rfm69_irq && (hwMillis() - txStartMS < MY_RFM69_TX_TIMEOUT_MS)) { doYield(); - } - return RFM69.dataSent; + }; + return rfm69_irq; } -LOCAL bool RFM69_send(const uint8_t recipient, uint8_t* data, const uint8_t len, +LOCAL bool RFM69_send(const uint8_t recipient, uint8_t *data, const uint8_t len, const rfm69_controlFlags_t flags, const bool increaseSequenceCounter) { // assemble packet @@ -425,20 +443,20 @@ LOCAL bool RFM69_send(const uint8_t recipient, uint8_t* data, const uint8_t len, packet.header.version = RFM69_PACKET_HEADER_VERSION; packet.header.sender = RFM69.address; packet.header.recipient = recipient; - packet.header.controlFlags = 0x00; // reset + packet.header.controlFlags = 0u; // reset packet.payloadLen = min(len, (uint8_t)RFM69_MAX_PAYLOAD_LEN); packet.header.controlFlags = flags; - (void)memcpy(&packet.payload, data, packet.payloadLen); // copy payload + (void)memcpy((void *)&packet.payload, (void *)data, packet.payloadLen); // copy payload packet.header.packetLen = packet.payloadLen + (RFM69_HEADER_LEN - 1); // -1 length byte - return RFM69_sendFrame(packet, increaseSequenceCounter); + return RFM69_sendFrame(&packet, increaseSequenceCounter); } LOCAL void RFM69_setFrequency(const uint32_t frequencyHz) { const uint32_t freqHz = (uint32_t)(frequencyHz / RFM69_FSTEP); - RFM69_writeReg(RFM69_REG_FRFMSB, freqHz >> 16); - RFM69_writeReg(RFM69_REG_FRFMID, freqHz >> 8); - RFM69_writeReg(RFM69_REG_FRFLSB, freqHz); + RFM69_writeReg(RFM69_REG_FRFMSB, (freqHz >> 16) & 0xFF); + RFM69_writeReg(RFM69_REG_FRFMID, (freqHz >> 8) & 0xFF); + RFM69_writeReg(RFM69_REG_FRFLSB, freqHz & 0xFF); } LOCAL void RFM69_setHighPowerRegs(const bool onOff) @@ -521,62 +539,12 @@ LOCAL bool RFM69_setRadioMode(const rfm69_radio_mode_t newRadioMode) RFM69_writeReg(RFM69_REG_PACKETCONFIG2, (RFM69_readReg(RFM69_REG_PACKETCONFIG2) & 0xFB) | RFM69_PACKET2_RXRESTART); // avoid RX deadlocks } else if (newRadioMode == RFM69_RADIO_MODE_TX) { - RFM69.dataSent = false; regMode = RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_LISTEN_OFF | RFM69_OPMODE_TRANSMITTER; RFM69_writeReg(RFM69_REG_DIOMAPPING1, RFM69_DIOMAPPING1_DIO0_00); // Interrupt on PacketSent, DIO0 RFM69_setHighPowerRegs(RFM69.powerLevel >= (rfm69_powerlevel_t)RFM69_HIGH_POWER_DBM); } else if (newRadioMode == RFM69_RADIO_MODE_SYNTH) { regMode = RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_LISTEN_OFF | RFM69_OPMODE_SYNTHESIZER; - } -#if defined(MY_RFM69_ENABLE_LISTENMODE) - else if (newRadioMode == RFM69_RADIO_MODE_LISTEN) { - // Start LISTENMODE - regMode = RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_LISTEN_ON; - - RFM69.listenModeEnabled = true; - - RFM69_DEBUG(PSTR("RFM69:LSM:Start..\n")); - while (RFM69_readReg(RFM69_REG_IRQFLAGS2) & RFM69_IRQFLAGS2_PACKETSENT == - 0x00); // wait for ModeReady - - RFM69_listenModeReset(); - detachInterrupt(digitalPinToInterrupt(MY_RFM69_IRQ_PIN)); - attachInterrupt(digitalPinToInterrupt(MY_RFM69_IRQ_PIN), RFM69_interruptHandler, RISING); - - RFM69_writeReg(RFM69_REG_OPMODE, - RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_LISTEN_OFF | RFM69_OPMODE_STANDBY); //standby mode - - //TODO _isHighSpeed = true; - //TODO _haveEncryptKey = false; - uint32_t rxDuration = RFM69_LISTEN_RX_US; - uint32_t idleDuration = RFM69_LISTEN_IDLE_US; - RFM69_listenModeSetDurations(rxDuration, idleDuration); - - RFM69_writeReg(RFM69_REG_DIOMAPPING1, RFM69_DIOMAPPING1_DIO0_01); - RFM69_writeReg(RFM69_REG_FRFMSB, RFM69_readReg(RFM69_REG_FRFMSB) + 1); - RFM69_writeReg(RFM69_REG_FRFLSB, - RFM69_readReg(RFM69_REG_FRFLSB)); // MUST write to LSB to affect change! - RFM69_listenModeApplyHighSpeedSettings(); - RFM69_writeReg(RFM69_REG_PACKETCONFIG1, - RFM69_PACKET1_FORMAT_VARIABLE | RFM69_PACKET1_DCFREE_WHITENING | RFM69_PACKET1_CRC_ON | - RFM69_PACKET1_CRCAUTOCLEAR_ON); - RFM69_writeReg(RFM69_REG_PACKETCONFIG2, - RFM69_PACKET2_RXRESTARTDELAY_NONE | RFM69_PACKET2_AUTORXRESTART_ON | RFM69_PACKET2_AES_OFF); - RFM69_writeReg(RFM69_REG_SYNCVALUE1, 0x5A); - RFM69_writeReg(RFM69_REG_SYNCVALUE2, 0x5A); - RFM69_setListenConfig(idleListenResolution, rxListenResolution, RFM69_LISTEN1_CRITERIA_RSSI, - RFM69_LISTEN1_END_10); - RFM69_setListenCoefIdle(idleListenCoef); - RFM69_setListenCoefRx(rxListenCoef); - RFM69_writeReg(RFM69_REG_RSSITHRESH, 180); - RFM69_writeReg(RFM69_REG_RXTIMEOUT2, 75); - RFM69_writeReg(RFM69_REG_OPMODE, RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_STANDBY); - RFM69_writeReg(RFM69_REG_OPMODE, - RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_LISTEN_ON | RFM69_OPMODE_STANDBY); - //WIP - } -#endif - else { + } else { regMode = RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_LISTEN_OFF | RFM69_OPMODE_STANDBY; } @@ -597,6 +565,7 @@ LOCAL bool RFM69_setRadioMode(const rfm69_radio_mode_t newRadioMode) LOCAL void RFM69_powerUp(void) { #if defined(MY_RFM69_POWER_PIN) + RFM69_DEBUG(PSTR("RFM69:PWU\n")); // power up radio hwDigitalWrite(MY_RFM69_POWER_PIN, HIGH); delay(RFM69_POWERUP_DELAY_MS); #endif @@ -604,6 +573,7 @@ LOCAL void RFM69_powerUp(void) LOCAL void RFM69_powerDown(void) { #if defined(MY_RFM69_POWER_PIN) + RFM69_DEBUG(PSTR("RFM69:PWD\n")); // power down radio hwDigitalWrite(MY_RFM69_POWER_PIN, LOW); #endif } @@ -630,33 +600,31 @@ LOCAL void RFM69_sendACK(const uint8_t recipient, const rfm69_sequenceNumber_t s rfm69_ack_t ACK; ACK.sequenceNumber = sequenceNumber; ACK.RSSI = RSSI; - rfm69_controlFlags_t flags = 0x00; // reset flags + rfm69_controlFlags_t flags = 0u; // reset flags RFM69_setACKReceived(flags, true); RFM69_setACKRSSIReport(flags, true); - (void)RFM69_send(recipient, (uint8_t*)&ACK, sizeof(rfm69_ack_t), flags); + (void)RFM69_send(recipient, (uint8_t *)&ACK, sizeof(rfm69_ack_t), flags); } LOCAL bool RFM69_executeATC(const rfm69_RSSI_t currentRSSI, const rfm69_RSSI_t targetRSSI) { + // RSSI range -80..-70 = internal representation 160(l)..140(u) rfm69_powerlevel_t newPowerLevel = RFM69.powerLevel; - if (RFM69_internalToRSSI(currentRSSI) < RFM69_internalToRSSI(targetRSSI * - (1 + RFM69_ATC_TARGET_RANGE_PERCENT/100)) && - newPowerLevel < RFM69_MAX_POWER_LEVEL_DBM) { + const rfm69_RSSI_t uRange = targetRSSI - RFM69_RSSItoInternal(RFM69_ATC_TARGET_RANGE_DBM); + const rfm69_RSSI_t lRange = targetRSSI + RFM69_RSSItoInternal(RFM69_ATC_TARGET_RANGE_DBM); + if (currentRSSI > lRange && newPowerLevel < RFM69_MAX_POWER_LEVEL_DBM) { // increase transmitter power newPowerLevel++; - } else if (RFM69_internalToRSSI(currentRSSI) > RFM69_internalToRSSI(targetRSSI * - (1 - RFM69_ATC_TARGET_RANGE_PERCENT/100)) && - newPowerLevel > RFM69_MIN_POWER_LEVEL_DBM) { + } else if (currentRSSI < uRange && newPowerLevel > RFM69_MIN_POWER_LEVEL_DBM) { // decrease transmitter power newPowerLevel--; } else { // nothing to adjust return false; } - RFM69_DEBUG(PSTR("RFM69:ATC:ADJ TXL,cR=%" PRIi16 ",tR=%" PRIi16 ",TXL=%" PRIi16 "\n"), - RFM69_internalToRSSI(currentRSSI), - RFM69_internalToRSSI(targetRSSI), newPowerLevel); - + RFM69_DEBUG(PSTR("RFM69:ATC:ADJ TXL,cR=%" PRIi16 ",tR=%" PRIi16 "..%" PRIi16 ",TXL=%" PRIi8 "\n"), + RFM69_internalToRSSI(currentRSSI), RFM69_internalToRSSI(lRange), RFM69_internalToRSSI(uRange), + RFM69.powerLevel); return RFM69_setTxPowerLevel(newPowerLevel); } @@ -667,15 +635,16 @@ LOCAL void RFM69_ATCmode(const bool onOff, const int16_t targetRSSI) } -LOCAL bool RFM69_sendWithRetry(const uint8_t recipient, const void* buffer, +LOCAL bool RFM69_sendWithRetry(const uint8_t recipient, const void *buffer, const uint8_t bufferSize, const uint8_t retries, const uint32_t retryWaitTimeMS) { for (uint8_t retry = 0; retry <= retries; retry++) { - RFM69_DEBUG(PSTR("RFM69:SWR:SEND,TO=%" PRIu8 ",RETRY=%" PRIu8 "\n"), recipient, retry); - rfm69_controlFlags_t flags = 0x00; // reset all flags + RFM69_DEBUG(PSTR("RFM69:SWR:SEND,TO=%" PRIu8 ",SEQ=%" PRIu16 ",RETRY=%" PRIu8 "\n"), recipient, + RFM69.txSequenceNumber,retry); + rfm69_controlFlags_t flags = 0u; // reset all flags RFM69_setACKRequested(flags, (recipient != RFM69_BROADCAST_ADDRESS)); RFM69_setACKRSSIReport(flags, RFM69.ATCenabled); - (void)RFM69_send(recipient, (uint8_t*)buffer, bufferSize, flags, !retry); + (void)RFM69_send(recipient, (uint8_t *)buffer, bufferSize, flags, !retry); if (recipient == RFM69_BROADCAST_ADDRESS) { // no ACK requested return true; @@ -683,6 +652,7 @@ LOCAL bool RFM69_sendWithRetry(const uint8_t recipient, const void* buffer, // radio is in RX const uint32_t enterMS = hwMillis(); while (hwMillis() - enterMS < retryWaitTimeMS) { + RFM69_handler(); if (RFM69.ackReceived) { // radio is in stdby const uint8_t sender = RFM69.currentPacket.header.sender; @@ -700,24 +670,12 @@ LOCAL bool RFM69_sendWithRetry(const uint8_t recipient, const void* buffer, // ATC if (RFM69.ATCenabled && RFM69_getACKRSSIReport(flags)) { (void)RFM69_executeATC(RSSI,RFM69.ATCtargetRSSI); - } // ATC - // return to RX + } return true; } // seq check } - doYield(); } RFM69_DEBUG(PSTR("!RFM69:SWR:NACK\n")); - if (RFM69.ATCenabled) { - // No ACK received, maybe out of reach: increase power level - RFM69_setTxPowerLevel(RFM69.powerLevel + 1); - } - // random 100ms - const uint32_t enterCSMAMS = hwMillis(); - const uint16_t randDelayCSMA = enterMS & 40; // 61 bytes + ACK take ~40ms - while (hwMillis() - enterCSMAMS < randDelayCSMA) { - doYield(); - } } return false; } @@ -770,90 +728,79 @@ LOCAL uint8_t RFM69_getTxPowerPercent(void) LOCAL bool RFM69_sanityCheck(void) { bool result = true; // default - result &= RFM69_readReg(RFM69_REG_DATAMODUL) == (RFM69_DATAMODUL_DATAMODE_PACKET | - RFM69_DATAMODUL_MODULATIONTYPE_FSK | RFM69_DATAMODUL_MODULATIONSHAPING_00); - // check Bitrate - result &= RFM69_readReg(RFM69_REG_BITRATEMSB) == MY_RFM69_BITRATE_MSB; - result &= RFM69_readReg(RFM69_REG_BITRATELSB) == MY_RFM69_BITRATE_LSB; - // default: 5KHz, (FDEV + BitRate / 2 <= 500KHz) - result &= RFM69_readReg(RFM69_REG_FDEVMSB) == RFM69_FDEVMSB_50000; - result &= RFM69_readReg(RFM69_REG_FDEVLSB) == RFM69_FDEVLSB_50000; - // check network + result &= RFM69_readReg(RFM69_REG_RSSITHRESH) == RFM69_RSSITHRESH_VALUE; + result &= RFM69_readReg(RFM69_REG_SYNCVALUE1) == RFM69_SYNCVALUE1; result &= RFM69_readReg(RFM69_REG_SYNCVALUE2) == MY_RFM69_NETWORKID; return result; } LOCAL void RFM69_setConfiguration(void) { + const uint8_t rfm69_modem_config[] = { MY_RFM69_MODEM_CONFIGURATION }; const uint8_t CONFIG[][2] = { { RFM69_REG_OPMODE, RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_LISTEN_OFF | RFM69_OPMODE_STANDBY }, - { RFM69_REG_DATAMODUL, RFM69_DATAMODUL_DATAMODE_PACKET | RFM69_DATAMODUL_MODULATIONTYPE_FSK | RFM69_DATAMODUL_MODULATIONSHAPING_00 }, - { RFM69_REG_BITRATEMSB, MY_RFM69_BITRATE_MSB }, - { RFM69_REG_BITRATELSB, MY_RFM69_BITRATE_LSB }, - { RFM69_REG_FDEVMSB, RFM69_FDEVMSB_50000 }, - { RFM69_REG_FDEVLSB, RFM69_FDEVLSB_50000 }, - //{ RFM69_REG_FRFMSB, RFM69_FREQ_MSB }, - //{ RFM69_REG_FRFMID, RFM69_FREQ_MID }, - //{ RFM69_REG_FRFLSB, RFM69_FREQ_LSB }, + { RFM69_REG_DATAMODUL, rfm69_modem_config[0] }, + { RFM69_REG_BITRATEMSB, rfm69_modem_config[1] }, + { RFM69_REG_BITRATELSB, rfm69_modem_config[2] }, + { RFM69_REG_FDEVMSB, rfm69_modem_config[3] }, + { RFM69_REG_FDEVLSB, rfm69_modem_config[4] }, { RFM69_REG_LNA, RFM69_LNA_ZIN_200 | RFM69_LNA_CURRENTGAIN }, - { RFM69_REG_RXBW, RFM69_RXBW_DCCFREQ_010 | RFM69_RXBW_MANT_16 | RFM69_RXBW_EXP_2 }, + { RFM69_REG_RXBW, rfm69_modem_config[5] }, + { RFM69_REG_AFCBW, rfm69_modem_config[5] }, // same as rxbw, experimental, based on datasheet //{ RFM69_REG_DIOMAPPING1, RFM69_DIOMAPPING1_DIO0_01 }, { RFM69_REG_DIOMAPPING2, RFM69_DIOMAPPING2_CLKOUT_OFF }, { RFM69_REG_IRQFLAGS2, RFM69_IRQFLAGS2_FIFOOVERRUN }, - { RFM69_REG_RSSITHRESH, 220 /*RFM69_RSSITHRESH_VALUE*/ }, - { RFM69_REG_PREAMBLEMSB, 0 }, // default - { RFM69_REG_PREAMBLELSB, 3 }, // default + { RFM69_REG_RSSITHRESH, RFM69_RSSITHRESH_VALUE }, + { RFM69_REG_PREAMBLEMSB, RFM69_PREAMBLESIZE_MSB_VALUE }, + { RFM69_REG_PREAMBLELSB, RFM69_PREAMBLESIZE_LSB_VALUE }, { RFM69_REG_SYNCCONFIG, RFM69_SYNC_ON | RFM69_SYNC_FIFOFILL_AUTO | RFM69_SYNC_SIZE_2 | RFM69_SYNC_TOL_0 }, { RFM69_REG_SYNCVALUE1, RFM69_SYNCVALUE1 }, { RFM69_REG_SYNCVALUE2, MY_RFM69_NETWORKID }, - // changed from dcfree_none to dcfree_whitening - { RFM69_REG_PACKETCONFIG1, RFM69_PACKET1_FORMAT_VARIABLE | RFM69_PACKET1_DCFREE_WHITENING | RFM69_PACKET1_CRC_ON | RFM69_PACKET1_CRCAUTOCLEAR_ON | RFM69_PACKET1_ADRSFILTERING_NODEBROADCAST }, - { RFM69_REG_PAYLOADLENGTH, 66 }, // in variable length mode: the max frame size, not used in TX + { RFM69_REG_PACKETCONFIG1, rfm69_modem_config[6] }, + { RFM69_REG_PAYLOADLENGTH, RFM69_MAX_PACKET_LEN }, // in variable length mode: the max frame size, not used in TX { RFM69_REG_NODEADRS, RFM69_BROADCAST_ADDRESS }, // init { RFM69_REG_BROADCASTADRS, RFM69_BROADCAST_ADDRESS }, { RFM69_REG_FIFOTHRESH, RFM69_FIFOTHRESH_TXSTART_FIFOTHRESH | (RFM69_HEADER_LEN - 1) }, // start transmitting when rfm69 header loaded, fifo level irq when header bytes received (irq asserted when n bytes exceeded) { RFM69_REG_PACKETCONFIG2, RFM69_PACKET2_RXRESTARTDELAY_2BITS | RFM69_PACKET2_AUTORXRESTART_OFF | RFM69_PACKET2_AES_OFF }, - { RFM69_REG_TESTDAGC, RFM69_DAGC_IMPROVED_LOWBETA0 }, + { RFM69_REG_TESTDAGC, RFM69_DAGC_IMPROVED_LOWBETA0 }, // continuous DAGC mode, use 0x30 if afc offset == 0 { 255, 0} }; - for (uint8_t i = 0; CONFIG[i][0] != 255; i++) { RFM69_writeReg(CONFIG[i][0], CONFIG[i][1]); } - } LOCAL bool RFM69_isModeReady(void) { - const uint32_t enterMS = hwMillis(); - while (hwMillis() - enterMS < RFM69_MODE_READY_TIMEOUT_MS) { - if (RFM69_readReg(RFM69_REG_IRQFLAGS1) & RFM69_IRQFLAGS1_MODEREADY) { - return true; - } - } - return false; + uint16_t timeout = 0xFFFF; + while (!(RFM69_readReg(RFM69_REG_IRQFLAGS1) & RFM69_IRQFLAGS1_MODEREADY) && timeout--) { + }; + return timeout; } -LOCAL void RFM69_encrypt(const char* key) +LOCAL void RFM69_encrypt(const char *key) { (void)RFM69_setRadioMode(RFM69_RADIO_MODE_STDBY); if (key != NULL) { RFM69_burstWriteReg(RFM69_REG_AESKEY1, key, 16); } RFM69_writeReg(RFM69_REG_PACKETCONFIG2, - (RFM69_readReg(RFM69_REG_PACKETCONFIG2) & 0xFE) | (key ? 1 : 0)); + (RFM69_readReg(RFM69_REG_PACKETCONFIG2) & 0xFE) | (key ? RFM69_PACKET2_AES_ON : + RFM69_PACKET2_AES_OFF)); } -LOCAL rfm69_RSSI_t RFM69_readRSSI(bool forceTrigger) +LOCAL rfm69_RSSI_t RFM69_readRSSI(const bool forceTrigger) { - // RSSI trigger not needed if DAGC is in continuous mode (we are) - if (forceTrigger) { + // RssiStart command and RssiDone flags are not usable when DAGC is turned on + /*if (forceTrigger) { RFM69_writeReg(RFM69_REG_RSSICONFIG, RFM69_RSSI_START); uint16_t timeout = 0xFFFF; while (!(RFM69_readReg(RFM69_REG_RSSICONFIG) & RFM69_RSSI_DONE) && timeout--) { }; } - return RFM69_readReg(RFM69_REG_RSSIVALUE); + */ + (void)forceTrigger; + return (rfm69_RSSI_t)RFM69_readReg(RFM69_REG_RSSIVALUE); } /* UNUSED @@ -873,14 +820,6 @@ LOCAL uint8_t RFM69_readTemperature(const uint8_t calFactor) calFactor; // 'complement' corrects the slope, rising temp = rising val } -LOCAL void RFM69_rcCalibration(void) -{ - RFM69_writeReg(RFM69_REG_OSC1, RFM69_OSC1_RCCAL_START); - const uint32_t enterMS = hwMillis(); - while (!(RFM69_readReg(RFM69_REG_OSC1) & RFM69_OSC1_RCCAL_DONE) && hwMillis() - enterMS < 500) { - }; -} - LOCAL uint8_t RFM69_setLNA(const uint8_t newReg) { const uint8_t oldReg = RFM69_readReg(RFM69_REG_LNA); @@ -889,12 +828,6 @@ LOCAL uint8_t RFM69_setLNA(const uint8_t newReg) return oldReg; // return the original value in case we need to restore it } -LOCAL void RFM69_ATCmode(const bool onOff, const int16_t targetRSSI) -{ - RFM69.ATCenabled = onOff; - RFM69.ATCtargetRSSI = RFM69_RSSItoInternal(targetRSSI); -} - LOCAL bool RFM69_waitCAD(void) { const uint32_t enterMS = hwMillis(); @@ -908,309 +841,22 @@ LOCAL bool RFM69_waitCAD(void) return true; } +LOCAL void RFM69_rcCalibration(void) +{ + // RC oscillator calibration + // On the SX1231 V2a, RC calibration at power-up needs to be performed + // This is not required in the version V2b any more, where the calibration is fully automatic + // see SX1231 datasheet, chapter 9 (Chip Revision) + RFM69_writeReg(0x57, 0x80); + RFM69_writeReg(RFM69_REG_OSC1, RFM69_OSC1_RCCAL_START); + while (!(RFM69_readReg(RFM69_REG_OSC1) & RFM69_OSC1_RCCAL_DONE)) {}; + RFM69_writeReg(RFM69_REG_OSC1, RFM69_OSC1_RCCAL_START); + while (!(RFM69_readReg(RFM69_REG_OSC1) & RFM69_OSC1_RCCAL_DONE)) {}; + RFM69_writeReg(0x57, 0x00); +} + */ - -// ************************ LISTENMODE SECTION ************************ - -#if defined(MY_RFM69_ENABLE_LISTENMODE) -LOCAL void RFM69_setListenConfig(const uint8_t listenResolIdle, const uint8_t listenResolRx, - const uint8_t listenCriteria, const uint8_t listenEnd) -{ - /* - ListenResolIdle one of: - RFM69_LISTEN_RESOL_IDLE_64US - RFM69_LISTEN_RESOL_IDLE_4_1MS - RFM69_LISTEN_RESOL_IDLE_262MS - Sets the listen mode idle time to 64 usec, 4.1ms or 262 ms - ListenResolRx one of: - RFM69_LISTEN_RESOL_RX_64US - RFM69_LISTEN_RESOL_RX_4_1MS - RFM69_LISTEN_RESOL_RX_262MS - Sets the listen mode Rx time to 64 usec, 4.1ms or 262 ms - ListenCriteria - Criteria for packet acceptance in listen mode, either: - RFM69_LISTEN_CRITERIA_RSSI - signal strength above RssiThreshold - RFM69_LISTEN_CRITERIA_RSSI_SYNC - Signal strength above RssiThresshold and SyncAddress matched. - ListenEnd: - Action taken after acceptance of a packet in Listen mode: - RFM69_LISTEN_END_STAY_RX_LISTEN_STOP - Chip stays in Rx mode, listen mode stops and must be disabled. - RFM69_LISTEN_END_RX_UNTIL_LISTEN_STOP - Chip stays in Rx mode until PayloadReady or Timeout interrupt - occurs. Listen mode stops and must be disabled. - RFM69_LISTEN_END_RX_UNTIL_LISTEN_RESUME - Chip stays in Rx mode until PayloadReady or Timeout interrupt - occurs. Listen mode then resumes in Idle State. - FIFO lost at next RX wakeup. - Default: (RFM69_LISTEN_RESOL_IDLE_4_1MS, RFM69_LISTEN_RESOL_RX_64US, - RFM69_LISTEN_CRITERIA_RSSI, RFM69_LISTEN_END_RX_UNTIL_LISTEN_STOP) - */ - - RFM69_writeReg(RFM69_REG_LISTEN1, listenResolIdle | listenResolRx | listenCriteria | listenEnd); -} - -LOCAL void RFM69_setListenCoefIdle(const uint8_t coeffIdle) -{ - /* - Duration of the Idle phase in Listen mode. - t ListenIdle = ListenCoefIdle * ListenResolIdle - Default 0xf5; 245 - */ - - RFM69_writeReg(RFM69_REG_LISTEN2, coeffIdle); -} - -LOCAL void RFM69_setListenCoefRx(const uint8_t coeffRX) -{ - /* - Duration of the Rx phase in Listen mode. - t ListenRx = ListenCoefRx * ListenResolRx - Default 0x20; 32 - */ - - RFM69_writeReg(RFM69_REG_LISTEN3, coeffRX); -} - -LOCAL void RFM69_listenModeApplyHighSpeedSettings(void) -{ - if (!_isHighSpeed) { - return; - } - RFM69_writeReg(RFM69_REG_BITRATEMSB, RFM69_BITRATEMSB_200000); - RFM69_writeReg(RFM69_REG_BITRATELSB, RFM69_BITRATELSB_200000); - RFM69_writeReg(RFM69_REG_FDEVMSB, RFM69_FDEVMSB_100000); - RFM69_writeReg(RFM69_REG_FDEVLSB, RFM69_FDEVLSB_100000); - RFM69_writeReg(RFM69_REG_RXBW, RFM69_RXBW_DCCFREQ_000 | RFM69_RXBW_MANT_20 | RFM69_RXBW_EXP_0); - - // Force LNA to the highest gain - //RFM69_writeReg(RFM69_REG_LNA, (RFM69_readReg(REG_LNA) << 2) | RF_LNA_GAINSELECT_MAX); -} - -LOCAL void RFM69_listenModeReset(void) -{ - // reset vars - - //DATALEN = 0; - //SENDERID = 0; - //TARGETID = 0; - //PAYLOADLEN = 0; - //ACK_REQUESTED = 0; - //ACK_RECEIVED = 0; - //LISTEN_BURST_REMAINING_MS = 0; -} - -LOCAL void RFM69_ListenModeStart(void) -{ - (void)RFM69_setRadioMode(RFM69_RADIO_MODE_LISTEN); - /* - RFM69_DEBUG(PSTR("RFM69:LSM:Start..\n")); - while (RFM69_readReg(RFM69_REG_IRQFLAGS2) & RFM69_IRQFLAGS2_PACKETSENT == 0x00); // wait for ModeReady - RFM69_listenModeReset(); - - detachInterrupt(digitalPinToInterrupt(MY_RFM69_IRQ_PIN)); - attachInterrupt(digitalPinToInterrupt(MY_RFM69_IRQ_PIN), RFM69_interruptHandler, RISING); - - (void)RFM69_setRadioMode(RFM69_RADIO_MODE_STDBY); - - RFM69_writeReg(RFM69_REG_DIOMAPPING1, RFM69_DIOMAPPING1_DIO0_01); - RFM69_writeReg(RFM69_REG_FRFMSB, RFM69_readReg(RFM69_REG_FRFMSB) + 1); - RFM69_writeReg(RFM69_REG_FRFLSB, RFM69_readReg(RFM69_REG_FRFLSB)); // MUST write to LSB to affect change! - - RFM69_listenModeApplyHighSpeedSettings(); - - RFM69_writeReg(RFM69_REG_PACKETCONFIG1, RFM69_PACKET1_FORMAT_VARIABLE | RFM69_PACKET1_DCFREE_WHITENING | RFM69_PACKET1_CRC_ON | RFM69_PACKET1_CRCAUTOCLEAR_ON); - RFM69_writeReg(RFM69_REG_PACKETCONFIG2, RFM69_PACKET2_RXRESTARTDELAY_NONE | RFM69_PACKET2_AUTORXRESTART_ON | RFM69_PACKET2_AES_OFF); - RFM69_writeReg(RFM69_REG_SYNCVALUE1, 0x5A); - RFM69_writeReg(RFM69_REG_SYNCVALUE2, 0x5A); - - RFM69_setListenConfig(idleListenResolution, rxListenResolution, RFM69_LISTEN1_CRITERIA_RSSI, RFM69_LISTEN1_END_10); - RFM69_setListenCoefIdle(idleListenCoef); - RFM69_setListenCoefRx(rxListenCoef); - - RFM69_writeReg(RFM69_REG_RSSITHRESH, 180); - RFM69_writeReg(RFM69_REG_RXTIMEOUT2, 75); - RFM69_writeReg(RFM69_REG_OPMODE, RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_STANDBY); - RFM69_writeReg(RFM69_REG_OPMODE, RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_LISTEN_ON | RFM69_OPMODE_STANDBY); - */ -} - -LOCAL bool RFM69_listenModeEnd(void) -{ - RFM69_DEBUG(PSTR("RFM69:LSM:End..\n")); - detachInterrupt(digitalPinToInterrupt(MY_RFM69_IRQ_PIN)); - - RFM69_writeReg(RFM69_REG_OPMODE, - RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_LISTENABORT | RFM69_OPMODE_STANDBY); - RFM69_writeReg(RFM69_REG_OPMODE, RFM69_OPMODE_SEQUENCER_ON | RFM69_OPMODE_STANDBY); - RFM69_writeReg(RFM69_REG_RXTIMEOUT2, 0); - - (void)RFM69_setRadioMode(RFM69_RADIO_MODE_STDBY); - - // wait for ModeReady - //if (!rfm69_ismodeready()) { - // return false; - //} - RFM69_isModeReady(); - RFM69_listenModeReset(); - RFM69_reinitRadio(); -} - -LOCAL bool RFM69_reinitRadio(void) -{ - if (!RFM69_initialise(MY_RFM69_FREQUENCY)) { - return false; - } - //TODO - //if (_haveEncryptKey) RFM69_encrypt(_encryptKey); // Restore the encryption key if necessary - //if (_isHighSpeed) RFM69_writeReg(RFM69_REG_LNA, (RFM69_readReg(RFM69_REG_LNA) & ~0x3) | RFM69_LNA_GAINSELECT_AUTO); - return true; -} - -LOCAL void RFM69_listenModeSendBurst(const uint8_t recipient, uint8_t* data, const uint8_t len) -{ - - detachInterrupt(digitalPinToInterrupt(MY_RFM69_IRQ_PIN)); - (void)RFM69_setRadioMode(RFM69_RADIO_MODE_STDBY); - RFM69_writeReg(RFM69_REG_PACKETCONFIG1, - RFM69_PACKET1_FORMAT_VARIABLE | RFM69_PACKET1_DCFREE_WHITENING | RFM69_PACKET1_CRC_ON | - RFM69_PACKET1_CRCAUTOCLEAR_ON); - RFM69_writeReg(RFM69_REG_PACKETCONFIG2, - RFM69_PACKET2_RXRESTARTDELAY_NONE | RFM69_PACKET2_AUTORXRESTART_ON | RFM69_PACKET2_AES_OFF); - RFM69_writeReg(RFM69_REG_SYNCVALUE1, 0x5A); - RFM69_writeReg(RFM69_REG_SYNCVALUE2, 0x5A); - RFM69_listenModeApplyHighSpeedSettings(); - RFM69_writeReg(RFM69_REG_FRFMSB, RFM69_readReg(RFM69_REG_FRFMSB) + 1); - RFM69_writeReg(RFM69_REG_FRFLSB, - RFM69_readReg(RFM69_REG_FRFLSB)); // MUST write to LSB to affect change! - - // TODO set high power level - - union { // union to simplify addressing of long and short parts of time offset - int32_t l; - uint8_t b[4]; - } timeRemaining; - - uint16_t cycleDurationMs = listenCycleDurationUs / 1000; - - timeRemaining.l = cycleDurationMs; - - RFM69_DEBUG(PSTR("RFM69:LSM:Send burst for %d ms\n"), cycleDurationMs); - - (void)RFM69_setRadioMode(RFM69_RADIO_MODE_TX); - uint32_t startTime = hwMillis(); - - while (timeRemaining.l > 0) { - // send burst - // write to FIFO TODO refactorize with func, check if send/sendframe could be used, and prepare packet struct - RFM69_prepareSPITransaction(); - RFM69_csn(LOW); - RFM69_SPI.transfer(RFM69_REG_FIFO | 0x80); - RFM69_SPI(len + - 4); // two bytes for target and sender node, two bytes for the burst time remaining - RFM69_SPI.transfer(recipient); - RFM69_SPI.transfer(_address); - - // We send the burst time remaining with the packet so the receiver knows how long to wait before trying to reply - RFM69_SPI.transfer(timeRemaining.b[0]); - RFM69_SPI.transfer(timeRemaining.b[1]); - - for (uint8_t i = 0; i < len; i++) { - RFM69_SPI.transfer(((uint8_t*)data)[i]); - } - - RFM69_csn(HIGH); - RFM69_concludeSPITransaction(); - - while ((RFM69_readReg(RFM69_REG_IRQFLAGS2) & RFM69_IRQFLAGS2_FIFONOTEMPTY) != - 0x00); // make sure packet is sent before putting more into the FIFO - timeRemaining.l = cycleDurationMs - (hwMillis() - startTime); - } - - (void)RFM69_setRadioMode(RFM69_RADIO_MODE_TX); - RFM69_reinitRadio(); -} - -LOCAL uint32_t RFM69_getUsForResolution(uint8_t resolution) -{ - switch (resolution) { - case RFM69_LISTEN1_RESOL_RX_64: - case RFM69_LISTEN1_RESOL_IDLE_64: - return 64; - case RFM69_LISTEN1_RESOL_RX_4100: - case RFM69_LISTEN1_RESOL_IDLE_4100: - return 4100; - case RFM69_LISTEN1_RESOL_RX_262000: - case RFM69_LISTEN1_RESOL_IDLE_262000: - return 262000; - default: - // Whoops - return 0; - } -} - -LOCAL uint32_t RFM69_getCoefForResolution(uint8_t resolution, uint32_t duration) -{ - uint32_t resolDuration = RFM69_getUsForResolution(resolution); - uint32_t result = duration / resolDuration; - - // If the next-higher coefficient is closer, use that - if (abs(duration - ((result + 1) * resolDuration)) < abs(duration - (result * resolDuration))) { - return result + 1; - } - - return result; -} - -LOCAL bool RFM69_chooseResolutionAndCoef(uint8_t *resolutions, uint32_t duration, uint8_t& resolOut, - uint8_t& coefOut) -{ - for (int i = 0; resolutions[i]; i++) { - uint32_t coef = RFM69_getCoefForResolution(resolutions[i], duration); - if (coef <= 255) { - coefOut = coef; - resolOut = resolutions[i]; - return true; - } - } - - // out of range - return false; -} - -LOCAL bool RFM69_listenModeSetDurations(uint32_t& rxDuration, uint32_t& idleDuration) -{ - uint8_t rxResolutions[] = { RFM69_LISTEN1_RESOL_RX_64, RFM69_LISTEN1_RESOL_RX_4100, RFM69_LISTEN1_RESOL_RX_262000, 0 }; - uint8_t idleResolutions[] = { RFM69_LISTEN1_RESOL_IDLE_64, RFM69_LISTEN1_RESOL_IDLE_4100, RFM69_LISTEN1_RESOL_IDLE_262000, 0 }; - - if (!RFM69_chooseResolutionAndCoef(rxResolutions, rxDuration, rxListenResolution, rxListenCoef)) { - return false; - } - - if (!RFM69_chooseResolutionAndCoef(idleResolutions, idleDuration, idleListenResolution, - idleListenCoef)) { - return false; - } - - rxDuration = RFM69_getUsForResolution(rxListenResolution) * rxListenCoef; - idleDuration = RFM69_getUsForResolution(idleListenResolution) * idleListenCoef; - listenCycleDurationUs = rxDuration + idleDuration; - - return true; -} - -LOCAL void RFM69_listenModeGetDurations(uint32_t &rxDuration, uint32_t &idleDuration) -{ - rxDuration = RFM69_getUsForResolution(rxListenResolution) * rxListenCoef; - idleDuration = RFM69_getUsForResolution(idleListenResolution) * idleListenCoef; -} - -#endif - -#ifdef MY_DEBUG_VERBOSE_RFM69_REGISTERS - LOCAL void RFM69_readAllRegs(void) { #ifdef RFM69_REGISTER_DETAIL @@ -1470,5 +1116,3 @@ LOCAL void RFM69_readAllRegs(void) (void)regVal; } } - -#endif diff --git a/drivers/RFM69/new/RFM69_new.h b/drivers/RFM69/new/RFM69_new.h index bc5df4a..204ad24 100644 --- a/drivers/RFM69/new/RFM69_new.h +++ b/drivers/RFM69/new/RFM69_new.h @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2017 Sensnology AB + * Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -16,22 +16,23 @@ * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * - * RFM69 driver refactored for Mysensors + * RFM69 driver refactored for MySensors * * Based on : * - LowPowerLab RFM69 Lib Copyright Felix Rusu (2014), felix@lowpowerlab.com * - Automatic Transmit Power Control class derived from RFM69 library. * Discussion and details in this forum post: https://lowpowerlab.com/forum/index.php/topic,688.0.html * Copyright Thomas Studwell (2014,2015) - * - Mysensors generic radio driver implementation, Copyright (C) 2017 Olivier Mauti + * - MySensors generic radio driver implementation Copyright (C) 2017, 2018 Olivier Mauti * * Changes by : @tekka, @scalz, @marceloagno * * Definitions for Semtech SX1231/H radios: - * http://www.semtech.com/images/datasheet/sx1231.pdf - * http://www.semtech.com/images/datasheet/sx1231h.pdf + * https://www.semtech.com/uploads/documents/sx1231.pdf + * https://www.semtech.com/uploads/documents/sx1231h.pdf */ + /** * @file RFM69_new.h * @@ -42,20 +43,24 @@ * RFM69 driver-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE * - [!] Exclamation mark is prepended in case of error * -* |E| SYS | SUB | Message | Comment -* |-|-------|-------|----------------------------------|----------------------------------------------------------------------------------- -* | | RFM69 | INIT | | Initialise RFM69 radio -* | | RFM69 | INIT | PIN,CS=%d,IQP=%d,IQN=%d[,RST=%d] | Pin configuration: chip select (CS), IRQ pin (IQP), IRQ number (IQN), Reset (RST) -* |!| RFM69 | INIT | SANCHK FAIL | Sanity check failed, check wiring or replace module -* | | RFM69 | PTX | NO ADJ | TX power level, no adjustment -* | | RFM69 | PTX | LEVEL=%d dbM | TX power level, set to (LEVEL) dBm -* | | RFM69 | SLEEP | | Radio in sleep mode -* | | RFM69 | SAC | SEND ACK,TO=%d,RSSI=%d | ACK sent to (TO), RSSI of incoming message (RSSI) -* | | RFM69 | ATC | ADJ TXL,cR=%d,tR=%d,TXL=%d | Adjust TX power level (TXL) to match set RSSI (sR), current RSSI (cR) -* | | RFM69 | SWR | SEND,TO=%d,RETRY=%d | Send to (TO), retry if no ACK received (RETRY) -* | | RFM69 | SWR | ACK,FROM=%d,SEQ=%d,RSSI=%d | ACK received from (FROM), sequence nr (SEQ), ACK RSSI (RSSI) -* |!| RFM69 | SWR | NACK | Message sent, no ACK received -* | | RFM69 | SPP | PCT=%d,TX LEVEL=%d | Set TX level, input TX percent (PCT) +* |E| SYS | SUB | Message | Comment +* |-|-------|------|--------------------------------------|----------------------------------------------------------------------------------- +* | | RFM69 | INIT | | Initialise RFM69 radio +* | | RFM69 | INIT | PIN,CS=%%d,IQP=%%d,IQN=%%d[,RST=%%d] | Pin configuration: chip select (CS), IRQ pin (IQP), IRQ number (IQN), Reset (RST) +* | | RFM69 | INIT | HWV=%%d | HW version, see datasheet chapter 9 +* |!| RFM69 | INIT | SANCHK FAIL | Sanity check failed, check wiring or replace module +* | | RFM69 | PTX | NO ADJ | TX power level, no adjustment +* | | RFM69 | PTX | LEVEL=%%d dbM | TX power level, set to (LEVEL) dBm +* | | RFM69 | SAC | SEND ACK,TO=%%d,RSSI=%%d | ACK sent to (TO), RSSI of incoming message (RSSI) +* | | RFM69 | ATC | ADJ TXL,cR=%%d,tR=%%d..%%d,TXL=%%d | Adjust TX level, current RSSI (cR), target RSSI range (tR), TX level (TXL) +* | | RFM69 | SWR | SEND,TO=%%d,SEQ=%%d,RETRY=%%d | Send to (TO), sequence number (SWQ), retry if no ACK received (RETRY) +* | | RFM69 | SWR | ACK,FROM=%%d,SEQ=%%d,RSSI=%%d | ACK received from (FROM), sequence nr (SEQ), ACK RSSI (RSSI) +* |!| RFM69 | SWR | NACK | Message sent, no ACK received +* | | RFM69 | SPP | PCT=%%d,TX LEVEL=%%d | Set TX level, input TX percent (PCT) +* | | RFM69 | RSL | | Radio in sleep mode +* | | RFM69 | RSB | | Radio in standby mode +* | | RFM69 | PWD | | Power down radio +* | | RFM69 | PWU | | Power up radio * * @brief API declaration for RFM69 * @@ -72,27 +77,20 @@ #else #define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN #endif -#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM #elif defined(ARDUINO_ARCH_ESP8266) #define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN -#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM #elif defined(ARDUINO_ARCH_ESP32) #warning not implemented yet #elif defined(ARDUINO_ARCH_SAMD) #define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN -#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM #elif defined(LINUX_ARCH_RASPBERRYPI) #define DEFAULT_RFM69_IRQ_PIN (22) //!< DEFAULT_RFM69_IRQ_PIN -#define DEFAULT_RFM69_IRQ_NUM DEFAULT_RFM69_IRQ_PIN //!< DEFAULT_RFM69_IRQ_NUM #elif defined(ARDUINO_ARCH_STM32F1) #define DEFAULT_RFM69_IRQ_PIN (PA3) //!< DEFAULT_RFM69_IRQ_PIN -#define DEFAULT_RFM69_IRQ_NUM DEFAULT_RFM69_IRQ_PIN //!< DEFAULT_RFM69_IRQ_NUM #elif defined(TEENSYDUINO) #define DEFAULT_RFM69_IRQ_PIN (8) //!< DEFAULT_RFM69_IRQ_PIN -#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM #else #define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN -#define DEFAULT_RFM69_IRQ_NUM (2) //!< DEFAULT_RFM69_IRQ_NUM #endif #define DEFAULT_RFM69_CS_PIN (SS) //!< DEFAULT_RFM69_CS_PIN @@ -120,7 +118,7 @@ #define RFM69_CLOCK_DIV SPI_CLOCK_DIV256 //!< SPI clock divider 256 #endif -#if defined (ARDUINO) && !defined (__arm__) && !defined (RFM69_SPI) +#if defined(ARDUINO) && !defined(__arm__) && !defined(RFM69_SPI) #include #if defined(MY_SOFTSPI) SoftSPI @@ -147,7 +145,7 @@ extern HardwareSPI SPI; //!< SPI #if (MY_RFM69HW==true) // RFM69H(C)W #define RFM69_VERSION_HW //!< HW version -#define RFM69_MIN_POWER_LEVEL_DBM ((rfm69_powerlevel_t)-2) //!< min. power level, -18dBm +#define RFM69_MIN_POWER_LEVEL_DBM ((rfm69_powerlevel_t)-2) //!< min. power level, -2dBm #if defined(MY_RFM69_MAX_POWER_LEVEL_DBM) #define RFM69_MAX_POWER_LEVEL_DBM MY_RFM69_MAX_POWER_LEVEL_DBM //!< MY_RFM69_MAX_POWER_LEVEL_DBM #else @@ -163,71 +161,121 @@ extern HardwareSPI SPI; //!< SPI #endif #endif -#define RFM69_FIFO_SIZE (0xFFu) //!< Max number of bytes the Rx/Tx FIFO can hold -#define RFM69_MAX_PACKET_LEN (0x40u) //!< This is the maximum number of bytes that can be carried -#define RFM69_ATC_TARGET_RANGE_PERCENT (5u) //!< ATC target range +/-% -#define RFM69_PACKET_HEADER_VERSION (1u) //!< RFM69 packet header version -#define RFM69_MIN_PACKET_HEADER_VERSION (1u) //!< Minimal RFM69 packet header version -#define RFM69_RETRIES (5u) //!< Retries in case of failed transmission -#define RFM69_RETRY_TIMEOUT_MS (200ul) //!< Timeout for ACK, adjustments needed if modem configuration changed (air time different) -#define RFM69_MODE_READY_TIMEOUT_MS (50ul) //!< Timeout for mode ready -#define RFM69_TX_LIMIT_MS (1*1000ul) //!< Timeout for packet sent +#define RFM69_FIFO_SIZE (0xFFu) //!< Max number of bytes the Rx/Tx FIFO can hold +#define RFM69_MAX_PACKET_LEN (0x40u) //!< This is the maximum number of bytes that can be carried +#define RFM69_ATC_TARGET_RANGE_DBM (2u) //!< ATC target range +/- dBm +#define RFM69_PACKET_HEADER_VERSION (1u) //!< RFM69 packet header version +#define RFM69_MIN_PACKET_HEADER_VERSION (1u) //!< Minimal RFM69 packet header version -#define RFM69_ACK_REQUESTED (7u) //!< RFM69 header, controlFlag, bit 7 -#define RFM69_ACK_RECEIVED (6u) //!< RFM69 header, controlFlag, bit 6 -#define RFM69_ACK_RSSI_REPORT (5u) //!< RFM69 header, controlFlag, bit 5 +#define RFM69_RETRIES (5u) //!< Retries in case of failed transmission +#define RFM69_RETRY_TIMEOUT_MS (200ul) //!< Timeout for ACK, adjustments needed if modem configuration changed (air time different) +#define RFM69_MODE_READY_TIMEOUT_MS (50ul) //!< Timeout for mode ready -#define RFM69_BROADCAST_ADDRESS (255u) //!< Broadcasting address -#define RFM69_TARGET_RSSI_DBM (-60) //!< RSSI target -#define RFM69_HIGH_POWER_DBM (18u) //!< High power threshold, dBm -#define RFM69_PROMISCUOUS (false) //!< RFM69 promiscuous mode +#define RFM69_ACK_REQUESTED (7u) //!< RFM69 header, controlFlag, bit 7 +#define RFM69_ACK_RECEIVED (6u) //!< RFM69 header, controlFlag, bit 6 +#define RFM69_ACK_RSSI_REPORT (5u) //!< RFM69 header, controlFlag, bit 5 -#define RFM69_RSSItoInternal(__value) ((uint8_t)-(__value*2)) //!< RSSI converting macro -#define RFM69_internalToRSSI(__value) ((int16_t)-(__value/2)) //!< RSSI converting macro +#define RFM69_BROADCAST_ADDRESS (255u) //!< Broadcasting address +#define RFM69_TARGET_RSSI_DBM (-75) //!< RSSI target +#define RFM69_HIGH_POWER_DBM (18u) //!< High power threshold, dBm + +#if !defined(MY_RFM69_TX_TIMEOUT_MS) +#define MY_RFM69_TX_TIMEOUT_MS (2*1000ul) //!< Timeout for packet sent +#endif + +// CSMA settings +#if !defined(MY_RFM69_CSMA_LIMIT_DBM) +#define MY_RFM69_CSMA_LIMIT_DBM (-95) //!< upper RX signal sensitivity threshold in dBm for carrier sense access +#endif +#if !defined(MY_RFM69_CSMA_TIMEOUT_MS) +#define MY_RFM69_CSMA_TIMEOUT_MS (500ul) //!< CSMA timeout +#endif +// powerup delay +#define RFM69_POWERUP_DELAY_MS (100ul) //!< Power up delay, allow VCC to settle, transport to become fully operational + +// available frequency bands, non trivial values to avoid misconfiguration +#define RFM69_315MHZ (315000000ul) //!< RFM69_315MHZ +#define RFM69_433MHZ (433920000ul) //!< RFM69_433MHZ, center frequencz 433.92 MHz +#define RFM69_868MHZ (868000000ul) //!< RFM69_868MHZ +#define RFM69_915MHZ (915000000ul) //!< RFM69_915MHZ + +#define RFM69_COURSE_TEMP_COEF (-90) //!< puts the temperature reading in the ballpark, user can fine tune the returned value +#define RFM69_FXOSC (32*1000000ul) //!< OSC freq, 32MHz +#define RFM69_FSTEP (RFM69_FXOSC / 524288.0f) //!< FXOSC / 2^19 = 32MHz / 2^19 (p13 in datasheet) // helper macros #define RFM69_getACKRequested(__value) ((bool)bitRead(__value,RFM69_ACK_REQUESTED)) //!< getACKRequested -#define RFM69_setACKRequested(__value, __flag) bitWrite(__value,RFM69_ACK_REQUESTED,__flag) //!< setACKRequested -#define RFM69_getACKReceived(__value) ((bool)bitRead(__value,RFM69_ACK_RECEIVED)) //!< getACKReceived -#define RFM69_setACKReceived(__value, __flag) bitWrite(__value,RFM69_ACK_RECEIVED,__flag) //!< setACKReceived -#define RFM69_setACKRSSIReport(__value, __flag) bitWrite(__value,RFM69_ACK_RSSI_REPORT,__flag) //!< setACKRSSIReport -#define RFM69_getACKRSSIReport(__value) ((bool)bitRead(__value,RFM69_ACK_RSSI_REPORT)) //!< getACKRSSIReport - +#define RFM69_setACKRequested(__value, __flag) bitWrite(__value,RFM69_ACK_REQUESTED,__flag) //!< setACKRequested +#define RFM69_getACKReceived(__value) ((bool)bitRead(__value,RFM69_ACK_RECEIVED)) //!< getACKReceived +#define RFM69_setACKReceived(__value, __flag) bitWrite(__value,RFM69_ACK_RECEIVED,__flag) //!< setACKReceived +#define RFM69_setACKRSSIReport(__value, __flag) bitWrite(__value,RFM69_ACK_RSSI_REPORT,__flag)//!< setACKRSSIReport +#define RFM69_getACKRSSIReport(__value) ((bool)bitRead(__value,RFM69_ACK_RSSI_REPORT)) //!< getACKRSSIReport // Register access #define RFM69_READ_REGISTER (0x7Fu) //!< reading register #define RFM69_WRITE_REGISTER (0x80u) //!< writing register -// CAD & CSMA -#define RFM69_CAD_TIMEOUT_MS (2*1000ul) //!< Channel activity detection timeout -#define RFM69_CSMA_LIMIT_DBM (-90) //!< upper RX signal sensitivity threshold in dBm for carrier sense access -#define RFM69_CSMA_TIMEOUT_MS (1000ul) //!< CSMA timeout +// Modem configuration section +#define RFM69_CONFIG_FSK (RFM69_DATAMODUL_DATAMODE_PACKET | RFM69_DATAMODUL_MODULATIONTYPE_FSK | RFM69_DATAMODUL_MODULATIONSHAPING_00) //!< RFM69_CONFIG_FSK +#define RFM69_CONFIG_GFSK (RFM69_DATAMODUL_DATAMODE_PACKET | RFM69_DATAMODUL_MODULATIONTYPE_FSK | RFM69_DATAMODUL_MODULATIONSHAPING_10) //!< RFM69_CONFIG_GFSK +#define RFM69_CONFIG_OOK (RFM69_DATAMODUL_DATAMODE_PACKET | RFM69_DATAMODUL_MODULATIONTYPE_OOK | RFM69_DATAMODUL_MODULATIONSHAPING_00) //!< RFM69_CONFIG_OOK -// powerup delay -#define RFM69_POWERUP_DELAY_MS (100u) //!< Power up delay, allow VCC to settle, transport to become fully operational +#define RFM69_CONFIG_NOWHITE (RFM69_PACKET1_FORMAT_VARIABLE | RFM69_PACKET1_DCFREE_OFF | RFM69_PACKET1_CRC_ON | RFM69_PACKET1_CRCAUTOCLEAR_ON | RFM69_PACKET1_ADRSFILTERING_NODEBROADCAST) //!< RFM69_CONFIG_NOWHITE +#define RFM69_CONFIG_WHITE (RFM69_PACKET1_FORMAT_VARIABLE | RFM69_PACKET1_DCFREE_WHITENING | RFM69_PACKET1_CRC_ON | RFM69_PACKET1_CRCAUTOCLEAR_ON | RFM69_PACKET1_ADRSFILTERING_NODEBROADCAST) //!< RFM69_CONFIG_WHITE +#define RFM69_CONFIG_MANCHESTER (RFM69_PACKET1_FORMAT_VARIABLE | RFM69_PACKET1_DCFREE_MANCHESTER | RFM69_PACKET1_CRC_ON | RFM69_PACKET1_CRCAUTOCLEAR_ON | RFM69_PACKET1_ADRSFILTERING_NODEBROADCAST) //!< RFM69_CONFIG_MANCHESTER -// available frequency bands, non trivial values to avoid misconfiguration -#define RFM69_315MHZ (315000000ul) //!< RFM69_315MHZ -#define RFM69_433MHZ (433920000ul) //!< RFM69_433MHZ, center frequencz 433.92 MHz -#define RFM69_868MHZ (868000000ul) //!< RFM69_868MHZ -#define RFM69_915MHZ (915000000ul) //!< RFM69_915MHZ +#define RFM69_RXBW_111_24_4 (RFM69_RXBW_DCCFREQ_111 | RFM69_RXBW_MANT_24 | RFM69_RXBW_EXP_4) //!< RFM69_RXBW_111_24_4 +#define RFM69_RXBW_111_24_3 (RFM69_RXBW_DCCFREQ_111 | RFM69_RXBW_MANT_24 | RFM69_RXBW_EXP_3) //!< RFM69_RXBW_111_24_3 +#define RFM69_RXBW_111_24_2 (RFM69_RXBW_DCCFREQ_111 | RFM69_RXBW_MANT_24 | RFM69_RXBW_EXP_2) //!< RFM69_RXBW_111_24_2 +#define RFM69_RXBW_111_16_2 (RFM69_RXBW_DCCFREQ_111 | RFM69_RXBW_MANT_16 | RFM69_RXBW_EXP_2) //!< RFM69_RXBW_111_16_2 +#define RFM69_RXBW_111_16_1 (RFM69_RXBW_DCCFREQ_111 | RFM69_RXBW_MANT_16 | RFM69_RXBW_EXP_1) //!< RFM69_RXBW_111_16_1 +#define RFM69_RXBW_111_16_0 (RFM69_RXBW_DCCFREQ_111 | RFM69_RXBW_MANT_16 | RFM69_RXBW_EXP_0) //!< RFM69_RXBW_111_16_0 +#define RFM69_RXBW_010_16_2 (RFM69_RXBW_DCCFREQ_010 | RFM69_RXBW_MANT_16 | RFM69_RXBW_EXP_2) //!< RFM69_RXBW_010_16_2 -#define RFM69_COURSE_TEMP_COEF (-90) //!< puts the temperature reading in the ballpark, user can fine tune the returned value -#define RFM69_FXOSC (32*1000000ul) //!< OSC freq, 32MHz -#define RFM69_FSTEP (RFM69_FXOSC / 524288.0f) //!< FXOSC / 2^19 = 32MHz / 2^19 (p13 in datasheet) +#define RFM69_FSK_BR2_FD5 RFM69_CONFIG_FSK, RFM69_BITRATEMSB_2000, RFM69_BITRATELSB_2000, RFM69_FDEVMSB_5000, RFM69_FDEVLSB_5000, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_FSK_BR2_FD5 +#define RFM69_FSK_BR2_4_FD4_8 RFM69_CONFIG_FSK, RFM69_BITRATEMSB_2400, RFM69_BITRATELSB_2400, RFM69_FDEVMSB_4800, RFM69_FDEVLSB_4800, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_FSK_BR2_4_FD4_8 +#define RFM69_FSK_BR4_8_FD9_6 RFM69_CONFIG_FSK, RFM69_BITRATEMSB_4800, RFM69_BITRATELSB_4800, RFM69_FDEVMSB_9600, RFM69_FDEVLSB_9600, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_FSK_BR4_8_FD9_6 +#define RFM69_FSK_BR9_6_FD19_2 RFM69_CONFIG_FSK, RFM69_BITRATEMSB_9600, RFM69_BITRATELSB_9600, RFM69_FDEVMSB_19200, RFM69_FDEVLSB_19200, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_FSK_BR9_6_FD19_2 +#define RFM69_FSK_BR19_2_FD38_4 RFM69_CONFIG_FSK, RFM69_BITRATEMSB_19200, RFM69_BITRATELSB_19200, RFM69_FDEVMSB_38400, RFM69_FDEVLSB_38400, RFM69_RXBW_111_24_3, RFM69_CONFIG_WHITE //!< RFM69_FSK_BR19_2_FD38_4 +#define RFM69_FSK_BR38_4_FD76_8 RFM69_CONFIG_FSK, RFM69_BITRATEMSB_38400, RFM69_BITRATELSB_38400, RFM69_FDEVMSB_76800, RFM69_FDEVLSB_76800, RFM69_RXBW_111_24_2, RFM69_CONFIG_WHITE //!< RFM69_FSK_BR38_4_FD76_8 +#define RFM69_FSK_BR55_5_FD50 RFM69_CONFIG_FSK, RFM69_BITRATEMSB_55555, RFM69_BITRATELSB_55555, RFM69_FDEVMSB_50000, RFM69_FDEVLSB_50000, RFM69_RXBW_111_16_2, RFM69_CONFIG_WHITE //!< RFM69_FSK_BR55_5_FD50 +#define RFM69_FSK_BR57_6_FD120 RFM69_CONFIG_FSK, RFM69_BITRATEMSB_57600, RFM69_BITRATELSB_57600, RFM69_FDEVMSB_120000, RFM69_FDEVLSB_120000, RFM69_RXBW_111_16_1, RFM69_CONFIG_WHITE //!< RFM69_FSK_BR57_6_FD120 +#define RFM69_FSK_BR125_FD125 RFM69_CONFIG_FSK, RFM69_BITRATEMSB_125000, RFM69_BITRATELSB_125000, RFM69_FDEVMSB_125000, RFM69_FDEVLSB_125000, RFM69_RXBW_010_16_2, RFM69_CONFIG_WHITE //!< RFM69_FSK_BR125_FD125 +#define RFM69_FSK_BR250_FD250 RFM69_CONFIG_FSK, RFM69_BITRATEMSB_250000, RFM69_BITRATELSB_250000, RFM69_FDEVMSB_250000, RFM69_FDEVLSB_250000, RFM69_RXBW_111_16_0, RFM69_CONFIG_WHITE //!< RFM69_FSK_BR250_FD250 -#if defined(MY_RFM69_ENABLE_LISTENMODE) -#define RFM69_LISTEN_RX_US MY_RFM69_DEFAULT_LISTEN_RX_US //!< RFM69_LISTEN_RX_US -#define RFM69_LISTEN_IDLE_US MY_RFM69_DEFAULT_LISTEN_IDLE_US //!< RFM69_LISTEN_IDLE_US +#define RFM69_GFSK_BR2_FD5 RFM69_CONFIG_GFSK, RFM69_BITRATEMSB_2000, RFM69_BITRATELSB_2000, RFM69_FDEVMSB_5000, RFM69_FDEVLSB_5000, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_GFSK_BR2_FD5 +#define RFM69_GFSK_BR2_4_FD4_8 RFM69_CONFIG_GFSK, RFM69_BITRATEMSB_2400, RFM69_BITRATELSB_2400, RFM69_FDEVMSB_4800, RFM69_FDEVLSB_4800, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_GFSK_BR2_4_FD4_8 +#define RFM69_GFSK_BR4_8_FD9_6 RFM69_CONFIG_GFSK, RFM69_BITRATEMSB_4800, RFM69_BITRATELSB_4800, RFM69_FDEVMSB_9600, RFM69_FDEVLSB_9600, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_GFSK_BR4_8_FD9_6 +#define RFM69_GFSK_BR9_6_FD19_2 RFM69_CONFIG_GFSK, RFM69_BITRATEMSB_9600, RFM69_BITRATELSB_9600, RFM69_FDEVMSB_19200, RFM69_FDEVLSB_19200, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_GFSK_BR9_6_FD19_2 +#define RFM69_GFSK_BR19_2_FD38_4 RFM69_CONFIG_GFSK, RFM69_BITRATEMSB_19200, RFM69_BITRATELSB_19200, RFM69_FDEVMSB_38400, RFM69_FDEVLSB_38400, RFM69_RXBW_111_24_3, RFM69_CONFIG_WHITE //!< RFM69_GFSK_BR19_2_FD38_4 +#define RFM69_GFSK_BR38_4_FD76_8 RFM69_CONFIG_GFSK, RFM69_BITRATEMSB_38400, RFM69_BITRATELSB_38400, RFM69_FDEVMSB_76800, RFM69_FDEVLSB_76800, RFM69_RXBW_111_24_2, RFM69_CONFIG_WHITE //!< RFM69_GFSK_BR38_4_FD76_8 +#define RFM69_GFSK_BR55_5_FD50 RFM69_CONFIG_GFSK, RFM69_BITRATEMSB_55555, RFM69_BITRATELSB_55555, RFM69_FDEVMSB_50000, RFM69_FDEVLSB_50000, RFM69_RXBW_111_16_2, RFM69_CONFIG_WHITE //!< RFM69_GFSK_BR55_5_FD50 +#define RFM69_GFSK_BR57_6_FD120 RFM69_CONFIG_GFSK, RFM69_BITRATEMSB_57600, RFM69_BITRATELSB_57600, RFM69_FDEVMSB_120000, RFM69_FDEVLSB_120000, RFM69_RXBW_111_16_1, RFM69_CONFIG_WHITE //!< RFM69_GFSK_BR57_6_FD120 +#define RFM69_GFSK_BR125_FD125 RFM69_CONFIG_GFSK, RFM69_BITRATEMSB_125000, RFM69_BITRATELSB_125000, RFM69_FDEVMSB_125000, RFM69_FDEVLSB_125000, RFM69_RXBW_010_16_2, RFM69_CONFIG_WHITE //!< RFM69_GFSK_BR125_FD125 +#define RFM69_GFSK_BR250_FD250 RFM69_CONFIG_GFSK, RFM69_BITRATEMSB_250000, RFM69_BITRATELSB_250000, RFM69_FDEVMSB_250000, RFM69_FDEVLSB_250000, RFM69_RXBW_111_16_0, RFM69_CONFIG_WHITE //!< RFM69_GFSK_BR250_FD250 + +#define RFM69_OOK_BR2_FD5 RFM69_CONFIG_OOK, RFM69_BITRATEMSB_2000, RFM69_BITRATELSB_2000, RFM69_FDEVMSB_5000, RFM69_FDEVLSB_5000, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_OOK_BR2_FD5 +#define RFM69_OOK_BR2_4_FD4_8 RFM69_CONFIG_OOK, RFM69_BITRATEMSB_2400, RFM69_BITRATELSB_2400, RFM69_FDEVMSB_4800, RFM69_FDEVLSB_4800, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_OOK_BR2_4_FD4_8 +#define RFM69_OOK_BR4_8_FD9_6 RFM69_CONFIG_OOK, RFM69_BITRATEMSB_4800, RFM69_BITRATELSB_4800, RFM69_FDEVMSB_9600, RFM69_FDEVLSB_9600, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_OOK_BR4_8_FD9_6 +#define RFM69_OOK_BR9_6_FD19_2 RFM69_CONFIG_OOK, RFM69_BITRATEMSB_9600, RFM69_BITRATELSB_9600, RFM69_FDEVMSB_19200, RFM69_FDEVLSB_19200, RFM69_RXBW_111_24_4, RFM69_CONFIG_WHITE //!< RFM69_OOK_BR9_6_FD19_2 +#define RFM69_OOK_BR19_2_FD38_4 RFM69_CONFIG_OOK, RFM69_BITRATEMSB_19200, RFM69_BITRATELSB_19200, RFM69_FDEVMSB_38400, RFM69_FDEVLSB_38400, RFM69_RXBW_111_24_3, RFM69_CONFIG_WHITE //!< RFM69_OOK_BR19_2_FD38_4 +#define RFM69_OOK_BR38_4_FD76_8 RFM69_CONFIG_OOK, RFM69_BITRATEMSB_38400, RFM69_BITRATELSB_38400, RFM69_FDEVMSB_76800, RFM69_FDEVLSB_76800, RFM69_RXBW_111_24_2, RFM69_CONFIG_WHITE //!< RFM69_OOK_BR38_4_FD76_8 +#define RFM69_OOK_BR55_5_FD50 RFM69_CONFIG_OOK, RFM69_BITRATEMSB_55555, RFM69_BITRATELSB_55555, RFM69_FDEVMSB_50000, RFM69_FDEVLSB_50000, RFM69_RXBW_111_16_2, RFM69_CONFIG_WHITE //!< RFM69_OOK_BR55_5_FD50 +#define RFM69_OOK_BR57_6_FD120 RFM69_CONFIG_OOK, RFM69_BITRATEMSB_57600, RFM69_BITRATELSB_57600, RFM69_FDEVMSB_120000, RFM69_FDEVLSB_120000, RFM69_RXBW_111_16_1, RFM69_CONFIG_WHITE //!< RFM69_OOK_BR57_6_FD120 +#define RFM69_OOK_BR125_FD125 RFM69_CONFIG_OOK, RFM69_BITRATEMSB_125000, RFM69_BITRATELSB_125000, RFM69_FDEVMSB_125000, RFM69_FDEVLSB_125000, RFM69_RXBW_010_16_2, RFM69_CONFIG_WHITE //!< RFM69_OOK_BR125_FD125 +#define RFM69_OOK_BR250_FD250 RFM69_CONFIG_OOK, RFM69_BITRATEMSB_250000, RFM69_BITRATELSB_250000, RFM69_FDEVMSB_250000, RFM69_FDEVLSB_250000, RFM69_RXBW_111_16_0, RFM69_CONFIG_WHITE //!< RFM69_OOK_BR250_FD250 + +#if !defined(MY_RFM69_MODEM_CONFIGURATION) +#define MY_RFM69_MODEM_CONFIGURATION RFM69_FSK_BR55_5_FD50 //!< default setting, RFM69_FSK_BR55_5_FD50 #endif /** * @brief Radio modes */ typedef enum { - RFM69_RADIO_MODE_RX = 0, //!< RX mode - RFM69_RADIO_MODE_TX = 1, //!< TX mode - RFM69_RADIO_MODE_CAD = 2, //!< CAD mode + RFM69_RADIO_MODE_RX = 0, //!< RX mode + RFM69_RADIO_MODE_TX = 1, //!< TX mode + RFM69_RADIO_MODE_CAD = 2, //!< CAD mode RFM69_RADIO_MODE_SLEEP = 3, //!< SLEEP mode RFM69_RADIO_MODE_STDBY = 4, //!< STDBY mode RFM69_RADIO_MODE_SYNTH = 5, //!< SYNTH mode @@ -260,19 +308,20 @@ typedef int8_t rfm69_powerlevel_t; * IMPORTANT: Do not change order (see datasheet for packet structure) */ typedef struct { - uint8_t packetLen; //!< Packet length - uint8_t recipient; //!< Payload recipient - uint8_t version; //!< Header version - uint8_t sender; //!< Payload sender - rfm69_controlFlags_t controlFlags; //!< Control flags, used for ACK - rfm69_sequenceNumber_t sequenceNumber; //!< Packet sequence number, used for ACK + uint8_t packetLen; //!< packet length + uint8_t recipient; //!< payload recipient + uint8_t version; //!< header version (20180128tk: >=3.0.0 fused with controlFlags) + uint8_t sender; //!< payload sender + rfm69_controlFlags_t controlFlags; //!< control flags, used for ACK + rfm69_sequenceNumber_t sequenceNumber; //!< packet sequence number, used for ACK } __attribute__((packed)) rfm69_header_t; + /** * @brief RFM69 ACK packet structure */ typedef struct { - rfm69_sequenceNumber_t sequenceNumber; //!< sequence number - rfm69_RSSI_t RSSI; //!< RSSI + rfm69_sequenceNumber_t sequenceNumber; //!< sequence number + rfm69_RSSI_t RSSI; //!< RSSI } __attribute__((packed)) rfm69_ack_t; #define RFM69_HEADER_LEN sizeof(rfm69_header_t) //!< Size header inside payload @@ -280,6 +329,7 @@ typedef struct { /** * @brief Packet structure +* IMPORTANT: Do not change order */ typedef struct { union { @@ -301,30 +351,43 @@ typedef struct { * @brief RFM69 internal variables */ typedef struct { - uint8_t address; //!< Node address - rfm69_packet_t currentPacket; //!< Buffer for current packet - rfm69_sequenceNumber_t txSequenceNumber; //!< RFM69_txSequenceNumber - rfm69_powerlevel_t powerLevel; //!< TX power level dBm - uint8_t ATCtargetRSSI; //!< ATC: target RSSI + uint8_t address; //!< Node address + rfm69_packet_t currentPacket; //!< Buffer for current packet + rfm69_sequenceNumber_t txSequenceNumber; //!< RFM69_txSequenceNumber + rfm69_powerlevel_t powerLevel; //!< TX power level dBm + uint8_t ATCtargetRSSI; //!< ATC: target RSSI // 8 bit - rfm69_radio_mode_t radioMode : 3; //!< current transceiver state - bool dataSent : 1; //!< Data sent - bool dataReceived : 1; //!< data received - bool ackReceived : 1; //!< ack received - bool ATCenabled : 1; //!< ATC enabled - bool listenModeEnabled : 1; //!< Listen Mode enabled + rfm69_radio_mode_t radioMode : 3; //!< current transceiver state + bool dataReceived : 1; //!< data received + bool ackReceived : 1; //!< ACK received + bool ATCenabled : 1; //!< ATC enabled + bool listenModeEnabled : 1; //!< Listen mode enabled + bool reserved : 1; //!< Reserved } rfm69_internal_t; -#if defined(MY_RFM69_ENABLE_LISTENMODE) -uint8_t rxListenCoef; -uint8_t rxListenResolution; -uint8_t idleListenCoef; -uint8_t idleListenResolution; -uint32_t listenCycleDurationUs; -#endif - #define LOCAL static //!< static +/** +* @brief RFM69_handler +*/ +LOCAL void RFM69_handler(void); + +/** +* @brief Clear flags and FIFO +*/ +LOCAL void RFM69_clearFIFO(void); + +/** +* @brief Check for channel activity +* @return True if channel activity under RFM69_CSMA_LIMIT_DBM +*/ +LOCAL bool RFM69_channelFree(void); + +/** +* @brief RFM69_interruptHandling +*/ +LOCAL void RFM69_interruptHandling(void); + /** * @brief Initialise the driver transport hardware and software * @param frequencyHz Frequency in Hz @@ -346,7 +409,7 @@ LOCAL uint8_t RFM69_getAddress(void); /** * @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 RFM69_recv() +* @return True if a new, complete, error-free uncollected message is available to be retreived by @ref RFM69_receive() */ LOCAL bool RFM69_available(void); @@ -356,7 +419,7 @@ LOCAL bool RFM69_available(void); * @param maxBufSize Max buffer size * @return Number of bytes */ -LOCAL uint8_t RFM69_recv(uint8_t* buf, const uint8_t maxBufSize); +LOCAL uint8_t RFM69_receive(uint8_t *buf, const uint8_t maxBufSize); /** * @brief RFM69_sendFrame @@ -364,7 +427,7 @@ LOCAL uint8_t RFM69_recv(uint8_t* buf, const uint8_t maxBufSize); * @param increaseSequenceCounter * @return True if packet sent */ -LOCAL bool RFM69_sendFrame(rfm69_packet_t &packet, const bool increaseSequenceCounter = true); +LOCAL bool RFM69_sendFrame(rfm69_packet_t *packet, const bool increaseSequenceCounter = true); /** * @brief RFM69_send @@ -375,7 +438,7 @@ LOCAL bool RFM69_sendFrame(rfm69_packet_t &packet, const bool increaseSequenceCo * @param increaseSequenceCounter * @return True if frame sent */ -LOCAL bool RFM69_send(const uint8_t recipient, uint8_t* data, const uint8_t len, +LOCAL bool RFM69_send(const uint8_t recipient, uint8_t *data, const uint8_t len, const rfm69_controlFlags_t flags, const bool increaseSequenceCounter = true); /** @@ -396,25 +459,30 @@ LOCAL bool RFM69_setTxPowerLevel(rfm69_powerlevel_t newPowerLevel); * @return power level */ LOCAL rfm69_powerlevel_t RFM69_getTxPowerLevel(void); + /** * @brief Reports the transmitter power output level in percents * @return power level */ LOCAL uint8_t RFM69_getTxPowerPercent(void); + /** * @brief Sets the radio into low-power sleep mode * @return true if sleep mode was successfully entered */ LOCAL bool RFM69_sleep(void); + /** * @brief Sets the radio to standby mode * @return true if standby mode was successfully entered */ LOCAL bool RFM69_standBy(void); + /** * @brief Power down radio (HW) */ LOCAL void RFM69_powerDown(void); + /** * @brief Power up radio (HW) */ @@ -438,7 +506,7 @@ LOCAL void RFM69_sendACK(const uint8_t recipient, const rfm69_sequenceNumber_t s * @param retryWaitTimeMS * @return True if packet successfully sent */ -LOCAL bool RFM69_sendWithRetry(const uint8_t recipient, const void* buffer, +LOCAL bool RFM69_sendWithRetry(const uint8_t recipient, const void *buffer, const uint8_t bufferSize, const uint8_t retries = RFM69_RETRIES, const uint32_t retryWaitTimeMS = RFM69_RETRY_TIMEOUT_MS); @@ -465,6 +533,7 @@ LOCAL int16_t RFM69_getSendingRSSI(void); * @return RSSI Signal strength of last received packet */ LOCAL int16_t RFM69_getReceivingRSSI(void); + /** * @brief RFM69_executeATC * @param currentRSSI @@ -491,12 +560,11 @@ LOCAL bool RFM69_isModeReady(void); */ LOCAL bool RFM69_sanityCheck(void); - /** * @brief RFM69_encrypt Set encryption mode * @param key if key is null, encryption is disabled. Key has to be 16 bytes! */ -LOCAL void RFM69_encrypt(const char* key); +LOCAL void RFM69_encrypt(const char *key); /** * @brief RFM69_setHighPowerRegs @@ -509,7 +577,7 @@ LOCAL void RFM69_setHighPowerRegs(const bool onOff); * @param forceTrigger * @return RSSI (internal format) */ -LOCAL rfm69_RSSI_t RFM69_readRSSI(bool forceTrigger = false); +LOCAL rfm69_RSSI_t RFM69_readRSSI(const bool forceTrigger = false); /** * @brief RFM69_ATCmode @@ -518,96 +586,12 @@ LOCAL rfm69_RSSI_t RFM69_readRSSI(bool forceTrigger = false); */ LOCAL void RFM69_ATCmode(const bool onOff, const int16_t targetRSSI = RFM69_TARGET_RSSI_DBM); -#ifdef MY_DEBUG_VERBOSE_RFM69_REGISTERS /** -* @brief RFM69_readAllRegs Read and display RFM69 register contents +* @brief RFM69_readAllRegs +* Read and display all RFM69 register contents. +* @note define RFM69_REGISTER_DETAIL for register content decoding. */ LOCAL void RFM69_readAllRegs(void); -#endif -// ************************ LISTENMODE SECTION ************************ - -#if defined(MY_RFM69_ENABLE_LISTENMODE) - -/** -* @brief RFM69_listenModeApplyHighSpeedSettings Set high speed settings -*/ -LOCAL void RFM69_listenModeApplyHighSpeedSettings(void); - -/** -* @brief RFM69_ListenModeStart Switch radio to listen Mode in prep for sleep until burst -*/ -LOCAL void RFM69_ListenModeStart(void); - -/** -* @brief RFM69_listenModeEnd Exit listen mode and reinit the radio -* @return -*/ -LOCAL bool RFM69_listenModeEnd(void); - -/** -* @brief RFM69_listenModeReset Reset listen mode -*/ -LOCAL void RFM69_listenModeReset(void); - -/** -* @brief RFM69_reinitRadio Restore previous radio settigns for normal mode -* @return -*/ -LOCAL bool RFM69_reinitRadio(void); - -/** -* @brief RFM69_listenModeSendBurst This repeatedly sends the message to the target node for - * the duration of an entire listen cycle. The amount of time remaining in the burst is - * transmitted to the receiver, and it is expected that the receiver - * wait for the burst to end before attempting a reply. -* @param recipient -* @param data -* @param len -*/ -LOCAL void RFM69_listenModeSendBurst(const uint8_t recipient, uint8_t* data, const uint8_t len); - -/** -* @brief getUsForResolution -* @param resolution -* @return -*/ -LOCAL uint32_t RFM69_getUsForResolution(uint8_t resolution); - -/** -* @brief getCoefForResolution -* @param resolution -* @param duration -* @return -*/ -LOCAL uint32_t RFM69_getCoefForResolution(uint8_t resolution, uint32_t duration); - -/** -* @brief RFM69_chooseResolutionAndCoef -* @param resolutions -* @param duration -* @param resolOut -* @param coefOut -* @return -*/ -LOCAL bool RFM69_chooseResolutionAndCoef(uint8_t *resolutions, uint32_t duration, uint8_t& resolOut, - uint8_t& coefOut); - -/** -* @brief RFM69_listenModeSetDurations -* @param rxDuration -* @param idleDuration -* @return -*/ -LOCAL bool RFM69_listenModeSetDurations(uint32_t& rxDuration, uint32_t& idleDuration); - -/** -* @brief RFM69_listenModeGetDurations -* @param rxDuration -* @param idleDuration -*/ -LOCAL void RFM69_listenModeGetDurations(uint32_t &rxDuration, uint32_t &idleDuration); - -#endif #endif diff --git a/drivers/RFM69/new/RFM69registers_new.h b/drivers/RFM69/new/RFM69registers_new.h index 19af8ea..2c2dade 100644 --- a/drivers/RFM69/new/RFM69registers_new.h +++ b/drivers/RFM69/new/RFM69registers_new.h @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2016 Sensnology AB + * Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -16,20 +16,20 @@ * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * - * RFM69 driver refactored for Mysensors + * RFM69 driver refactored for MySensors * * Based on : * - LowPowerLab RFM69 Lib Copyright Felix Rusu (2014), felix@lowpowerlab.com * - Automatic Transmit Power Control class derived from RFM69 library. * Discussion and details in this forum post: https://lowpowerlab.com/forum/index.php/topic,688.0.html * Copyright Thomas Studwell (2014,2015) - * - Mysensors generic radio driver implementation, Copyright (C) 2017 Olivier Mauti + * - MySensors generic radio driver implementation Copyright (C) 2017, 2018 Olivier Mauti * * Changes by : @tekka, @scalz, @marceloagno * * Definitions for Semtech SX1231/H radios: - * http://www.semtech.com/images/datasheet/sx1231.pdf - * http://www.semtech.com/images/datasheet/sx1231h.pdf + * https://www.semtech.com/uploads/documents/sx1231.pdf + * https://www.semtech.com/uploads/documents/sx1231h.pdf */ #define RFM69_REG_FIFO 0x00 @@ -150,71 +150,69 @@ #define RFM69_DATAMODUL_MODULATIONSHAPING_10 0x02 #define RFM69_DATAMODUL_MODULATIONSHAPING_11 0x03 - // RegBitRate (bits/sec) example bit rates #define RFM69_BITRATEMSB_1200 0x68 #define RFM69_BITRATELSB_1200 0x2B +#define RFM69_BITRATEMSB_2000 0x3e +#define RFM69_BITRATELSB_2000 0x80 #define RFM69_BITRATEMSB_2400 0x34 #define RFM69_BITRATELSB_2400 0x15 #define RFM69_BITRATEMSB_4800 0x1A // Default #define RFM69_BITRATELSB_4800 0x0B // Default #define RFM69_BITRATEMSB_9600 0x0D #define RFM69_BITRATELSB_9600 0x05 -#define RFM69_BITRATEMSB_19200 0x06 -#define RFM69_BITRATELSB_19200 0x83 -#define RFM69_BITRATEMSB_38400 0x03 -#define RFM69_BITRATELSB_38400 0x41 - -#define RFM69_BITRATEMSB_38323 0x03 -#define RFM69_BITRATELSB_38323 0x43 - -#define RFM69_BITRATEMSB_34482 0x03 -#define RFM69_BITRATELSB_34482 0xA0 - -#define RFM69_BITRATEMSB_76800 0x01 -#define RFM69_BITRATELSB_76800 0xA1 -#define RFM69_BITRATEMSB_153600 0x00 -#define RFM69_BITRATELSB_153600 0xD0 -#define RFM69_BITRATEMSB_57600 0x02 -#define RFM69_BITRATELSB_57600 0x2C -#define RFM69_BITRATEMSB_115200 0x01 -#define RFM69_BITRATELSB_115200 0x16 #define RFM69_BITRATEMSB_12500 0x0A #define RFM69_BITRATELSB_12500 0x00 +#define RFM69_BITRATEMSB_19200 0x06 +#define RFM69_BITRATELSB_19200 0x83 #define RFM69_BITRATEMSB_25000 0x05 #define RFM69_BITRATELSB_25000 0x00 +#define RFM69_BITRATEMSB_32768 0x03 +#define RFM69_BITRATELSB_32768 0xD1 +#define RFM69_BITRATEMSB_38400 0x03 +#define RFM69_BITRATELSB_38400 0x41 #define RFM69_BITRATEMSB_50000 0x02 #define RFM69_BITRATELSB_50000 0x80 +#define RFM69_BITRATEMSB_55555 0x02 +#define RFM69_BITRATELSB_55555 0x40 +#define RFM69_BITRATEMSB_57600 0x02 +#define RFM69_BITRATELSB_57600 0x2C +#define RFM69_BITRATEMSB_76800 0x01 +#define RFM69_BITRATELSB_76800 0xA1 #define RFM69_BITRATEMSB_100000 0x01 #define RFM69_BITRATELSB_100000 0x40 +#define RFM69_BITRATEMSB_115200 0x01 +#define RFM69_BITRATELSB_115200 0x16 +#define RFM69_BITRATEMSB_125000 0x01 +#define RFM69_BITRATELSB_125000 0x00 #define RFM69_BITRATEMSB_150000 0x00 #define RFM69_BITRATELSB_150000 0xD5 +#define RFM69_BITRATEMSB_153600 0x00 +#define RFM69_BITRATELSB_153600 0xD0 #define RFM69_BITRATEMSB_200000 0x00 #define RFM69_BITRATELSB_200000 0xA0 #define RFM69_BITRATEMSB_250000 0x00 #define RFM69_BITRATELSB_250000 0x80 #define RFM69_BITRATEMSB_300000 0x00 #define RFM69_BITRATELSB_300000 0x6B -#define RFM69_BITRATEMSB_32768 0x03 -#define RFM69_BITRATELSB_32768 0xD1 -// custom bit rates -#define RFM69_BITRATEMSB_55555 0x02 -#define RFM69_BITRATELSB_55555 0x40 -#define RFM69_BITRATEMSB_200KBPS 0x00 -#define RFM69_BITRATELSB_200KBPS 0xa0 - // RegFdev - frequency deviation (Hz) #define RFM69_FDEVMSB_2000 0x00 #define RFM69_FDEVLSB_2000 0x21 +#define RFM69_FDEVMSB_4800 0x00 +#define RFM69_FDEVLSB_4800 0x4f #define RFM69_FDEVMSB_5000 0x00 // Default #define RFM69_FDEVLSB_5000 0x52 // Default #define RFM69_FDEVMSB_7500 0x00 #define RFM69_FDEVLSB_7500 0x7B +#define RFM69_FDEVMSB_9600 0x00 +#define RFM69_FDEVLSB_9600 0x9d #define RFM69_FDEVMSB_10000 0x00 #define RFM69_FDEVLSB_10000 0xA4 #define RFM69_FDEVMSB_15000 0x00 #define RFM69_FDEVLSB_15000 0xF6 +#define RFM69_FDEVMSB_19200 0x01 +#define RFM69_FDEVLSB_19200 0x3b #define RFM69_FDEVMSB_20000 0x01 #define RFM69_FDEVLSB_20000 0x48 #define RFM69_FDEVMSB_25000 0x01 @@ -223,6 +221,8 @@ #define RFM69_FDEVLSB_30000 0xEC #define RFM69_FDEVMSB_35000 0x02 #define RFM69_FDEVLSB_35000 0x3D +#define RFM69_FDEVMSB_38400 0x02 +#define RFM69_FDEVLSB_38400 0x75 #define RFM69_FDEVMSB_40000 0x02 #define RFM69_FDEVLSB_40000 0x8F #define RFM69_FDEVMSB_45000 0x02 @@ -239,6 +239,8 @@ #define RFM69_FDEVLSB_70000 0x7B #define RFM69_FDEVMSB_75000 0x04 #define RFM69_FDEVLSB_75000 0xCD +#define RFM69_FDEVMSB_76800 0x04 +#define RFM69_FDEVLSB_76800 0xea #define RFM69_FDEVMSB_80000 0x05 #define RFM69_FDEVLSB_80000 0x1F #define RFM69_FDEVMSB_85000 0x05 @@ -253,6 +255,8 @@ #define RFM69_FDEVLSB_110000 0x0A #define RFM69_FDEVMSB_120000 0x07 #define RFM69_FDEVLSB_120000 0xAE +#define RFM69_FDEVMSB_125000 0x08 +#define RFM69_FDEVLSB_125000 0x00 #define RFM69_FDEVMSB_130000 0x08 #define RFM69_FDEVLSB_130000 0x52 #define RFM69_FDEVMSB_140000 0x08 @@ -290,7 +294,7 @@ #define RFM69_FDEVMSB_300000 0x13 #define RFM69_FDEVLSB_300000 0x33 -#define RFM69_NOP 0x00 +#define RFM69_NOP 0x00 // RegOsc1 #define RFM69_OSC1_RCCAL_START 0x80 diff --git a/hal/transport/RFM69/MyTransportRFM69.cpp b/hal/transport/RFM69/MyTransportRFM69.cpp index 7cc6973..b35f3ba 100644 --- a/hal/transport/RFM69/MyTransportRFM69.cpp +++ b/hal/transport/RFM69/MyTransportRFM69.cpp @@ -25,8 +25,8 @@ bool transportInit(void) { const bool result = RFM69_initialise(MY_RFM69_FREQUENCY); #if defined(MY_GATEWAY_FEATURE) || defined(MY_RFM69_ATC_MODE_DISABLED) - // ATC mode disabled on GW - RFM69_ATCmode(false); + // ATC mode function not used + (void)RFM69_ATCmode; #else RFM69_ATCmode(true, MY_RFM69_ATC_TARGET_RSSI_DBM); #endif @@ -41,6 +41,8 @@ bool transportInit(void) #endif RFM69_encrypt((const char*)RFM69_psk); (void)memset(RFM69_psk, 0, 16); // Make sure it is purged from memory when set +#else + (void)RFM69_encrypt; #endif return result; } @@ -66,6 +68,7 @@ bool transportSend(const uint8_t to, const void* data, uint8_t len, const bool n bool transportAvailable(void) { + RFM69_handler(); return RFM69_available(); } @@ -76,7 +79,7 @@ bool transportSanityCheck(void) uint8_t transportReceive(void* data) { - return RFM69_recv((uint8_t*)data, MAX_MESSAGE_LENGTH); + return RFM69_receive((uint8_t*)data, MAX_MESSAGE_LENGTH); } void transportSleep(void) From 345d6d7d119f5d2446c7d6a41e6f749e6ca8741c Mon Sep 17 00:00:00 2001 From: tekka Date: Mon, 19 Feb 2018 13:26:14 +0100 Subject: [PATCH 15/60] Fix variable names, minor updates (#1071) --- drivers/RF24/RF24.cpp | 37 ++++++++++++----------- drivers/RF24/RF24.h | 52 ++++++++++++++++---------------- drivers/RF24/RF24registers.h | 2 +- drivers/RFM69/new/RFM69_new.cpp | 53 ++++++++------------------------- drivers/RFM69/new/RFM69_new.h | 22 +------------- drivers/RFM95/RFM95.cpp | 38 ++++++++++++----------- drivers/RFM95/RFM95.h | 7 ++--- 7 files changed, 83 insertions(+), 128 deletions(-) diff --git a/drivers/RF24/RF24.cpp b/drivers/RF24/RF24.cpp index 025ad60..fa048e3 100644 --- a/drivers/RF24/RF24.cpp +++ b/drivers/RF24/RF24.cpp @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad -* Copyright (C) 2013-2017 Sensnology AB +* Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -36,9 +36,10 @@ LOCAL uint8_t RF24_NODE_ADDRESS = RF24_BROADCAST_ADDRESS; LOCAL RF24_receiveCallbackType RF24_receiveCallback = NULL; #endif -#ifdef LINUX_SPI_BCM -uint8_t spi_rxbuff[32+1] ; //SPI receive buffer (payload max 32 bytes) -uint8_t spi_txbuff[32+1] ; //SPI transmit buffer (payload max 32 bytes + 1 byte for the command) +#if defined(LINUX_SPI_BCM) +uint8_t RF24_spi_rxbuff[32+1] ; //SPI receive buffer (payload max 32 bytes) +uint8_t RF24_spi_txbuff[32+1] +; //SPI transmit buffer (payload max 32 bytes + 1 byte for the command) #endif LOCAL void RF24_csn(const bool level) @@ -51,21 +52,22 @@ LOCAL void RF24_ce(const bool level) hwDigitalWrite(MY_RF24_CE_PIN, level); } -LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_t len, +LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t *buf, uint8_t len, const bool readMode) { uint8_t status; - uint8_t* current = buf; + uint8_t *current = buf; #if !defined(MY_SOFTSPI) && defined(SPI_HAS_TRANSACTION) RF24_SPI.beginTransaction(SPISettings(MY_RF24_SPI_SPEED, RF24_SPI_DATA_ORDER, RF24_SPI_DATA_MODE)); #endif + RF24_csn(LOW); // timing delayMicroseconds(10); #ifdef LINUX_SPI_BCM - uint8_t * prx = spi_rxbuff; - uint8_t * ptx = spi_txbuff; + uint8_t *prx = RF24_spi_rxbuff; + uint8_t *ptx = RF24_spi_txbuff; uint8_t size = len + 1; // Add register value to transmit buffer *ptx++ = cmd; @@ -76,7 +78,7 @@ LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_t *ptx++ = *current++; } } - RF24_SPI.transfernb( (char *) spi_txbuff, (char *) spi_rxbuff, size); + RF24_SPI.transfernb( (char *) RF24_spi_txbuff, (char *) RF24_spi_rxbuff, size); if (readMode) { if (size == 2) { status = *++prx; // result is 2nd byte of receive buffer @@ -103,6 +105,7 @@ LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_t } } #endif + RF24_csn(HIGH); #if !defined(MY_SOFTSPI) && defined(SPI_HAS_TRANSACTION) RF24_SPI.endTransaction(); @@ -198,7 +201,7 @@ LOCAL void RF24_setRFConfiguration(const uint8_t configuration) RF24_writeByteRegister(RF24_REG_NRF_CONFIG, configuration); } -LOCAL void RF24_setPipeAddress(const uint8_t pipe, uint8_t* address, const uint8_t addressWidth) +LOCAL void RF24_setPipeAddress(const uint8_t pipe, uint8_t *address, const uint8_t addressWidth) { RF24_writeMultiByteRegister(pipe, address, addressWidth); } @@ -283,7 +286,7 @@ LOCAL void RF24_standBy(void) } -LOCAL bool RF24_sendMessage(const uint8_t recipient, const void* buf, const uint8_t len, +LOCAL bool RF24_sendMessage(const uint8_t recipient, const void *buf, const uint8_t len, const bool noACK) { uint8_t RF24_status; @@ -296,7 +299,7 @@ LOCAL bool RF24_sendMessage(const uint8_t recipient, const void* buf, const uint // AutoACK is disabled on the broadcasting pipe - NO_ACK prevents resending RF24_spiMultiByteTransfer((recipient == RF24_BROADCAST_ADDRESS || noACK) ? RF24_CMD_WRITE_TX_PAYLOAD_NO_ACK : - RF24_CMD_WRITE_TX_PAYLOAD, (uint8_t*)buf, len, false ); + RF24_CMD_WRITE_TX_PAYLOAD, (uint8_t *)buf, len, false ); // go, TX starts after ~10us, CE high also enables PA+LNA on supported HW RF24_ce(HIGH); // timeout counter to detect HW issues @@ -337,11 +340,11 @@ LOCAL bool RF24_isDataAvailable(void) } -LOCAL uint8_t RF24_readMessage(void* buf) +LOCAL uint8_t RF24_readMessage(void *buf) { const uint8_t len = RF24_getDynamicPayloadSize(); RF24_DEBUG(PSTR("RF24:RXM:LEN=%" PRIu8 "\n"), len); // read message - RF24_spiMultiByteTransfer(RF24_CMD_READ_RX_PAYLOAD,(uint8_t*)buf,len,true); + RF24_spiMultiByteTransfer(RF24_CMD_READ_RX_PAYLOAD,(uint8_t *)buf,len,true); // clear RX interrupt RF24_setStatus(_BV(RF24_RX_DR)); return len; @@ -500,11 +503,11 @@ LOCAL bool RF24_initialize(void) RF24_setDynamicPayload(_BV(RF24_DPL_P0 + RF24_BROADCAST_PIPE) | _BV(RF24_DPL_P0)); // listen to broadcast pipe RF24_BASE_ID[0] = RF24_BROADCAST_ADDRESS; - RF24_setPipeAddress(RF24_REG_RX_ADDR_P0 + RF24_BROADCAST_PIPE, (uint8_t*)&RF24_BASE_ID, + RF24_setPipeAddress(RF24_REG_RX_ADDR_P0 + RF24_BROADCAST_PIPE, (uint8_t *)&RF24_BASE_ID, RF24_BROADCAST_PIPE > 1 ? 1 : MY_RF24_ADDR_WIDTH); // pipe 0, set full address, later only LSB is updated - RF24_setPipeAddress(RF24_REG_RX_ADDR_P0, (uint8_t*)&RF24_BASE_ID, MY_RF24_ADDR_WIDTH); - RF24_setPipeAddress(RF24_REG_TX_ADDR, (uint8_t*)&RF24_BASE_ID, MY_RF24_ADDR_WIDTH); + RF24_setPipeAddress(RF24_REG_RX_ADDR_P0, (uint8_t *)&RF24_BASE_ID, MY_RF24_ADDR_WIDTH); + RF24_setPipeAddress(RF24_REG_TX_ADDR, (uint8_t *)&RF24_BASE_ID, MY_RF24_ADDR_WIDTH); // reset FIFO RF24_flushRX(); RF24_flushTX(); diff --git a/drivers/RF24/RF24.h b/drivers/RF24/RF24.h index d44e9f3..cecaf7c 100644 --- a/drivers/RF24/RF24.h +++ b/drivers/RF24/RF24.h @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad -* Copyright (C) 2013-2017 Sensnology AB +* Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -34,26 +34,26 @@ * RF24 driver-related log messages, format: [!]SYSTEM:[SUB SYSTEM:]MESSAGE * - [!] Exclamation mark is prepended in case of error * -* |E| SYS | SUB | Message | Comment -* |-|------|------|--------------------|--------------------------------------------------------------------- -* | | RF24 | INIT | | Initialise RF24 radio -* | | RF24 | INIT | PIN,CE=%d,CS=%d | Pin configuration: chip enable (CE), chip select (CS) -* |!| RF24 | INIT | SANCHK FAIL | Sanity check failed, check wiring or replace module -* | | RF24 | SPP | PCT=%d,TX LEVEL=%d | Set TX level, input TX percent (PCT) -* | | RF24 | RBR | REG=%d,VAL=%d | Read register (REG), value=(VAL) -* | | RF24 | WBR | REG=%d,VAL=%d | Write register (REG), value=(VAL) -* | | RF24 | FRX | | Flush RX buffer -* | | RF24 | FTX | | Flush TX buffer -* | | RF24 | OWP | RCPT=%d | Open writing pipe, recipient=(RCPT) -* | | RF24 | STL | | Start listening -* | | RF24 | SPL | | Stop listening -* | | RF24 | SLP | | Set radio to sleep -* | | RF24 | SBY | | Set radio to standby -* | | RF24 | TXM | TO=%d,LEN=%d | Transmit message to=(TO), length=(LEN) -* |!| RF24 | TXM | MAX_RT | Max TX retries, no ACK received -* |!| RF24 | GDP | PYL INV | Invalid payload size -* | | RF24 | RXM | LEN=%d | Read message, length=(LEN) -* | | RF24 | STX | LEVEL=%d | Set TX level, level=(LEVEL) +* |E| SYS | SUB | Message | Comment +* |-|------|------|----------------------|--------------------------------------------------------------------- +* | | RF24 | INIT | | Initialise RF24 radio +* | | RF24 | INIT | PIN,CE=%%d,CS=%%d | Pin configuration: chip enable (CE), chip select (CS) +* |!| RF24 | INIT | SANCHK FAIL | Sanity check failed, check wiring or replace module +* | | RF24 | SPP | PCT=%%d,TX LEVEL=%%d | Set TX level, input TX percent (PCT) +* | | RF24 | RBR | REG=%%d,VAL=%%d | Read register (REG), value=(VAL) +* | | RF24 | WBR | REG=%%d,VAL=%%d | Write register (REG), value=(VAL) +* | | RF24 | FRX | | Flush RX buffer +* | | RF24 | FTX | | Flush TX buffer +* | | RF24 | OWP | RCPT=%%d | Open writing pipe, recipient=(RCPT) +* | | RF24 | STL | | Start listening +* | | RF24 | SPL | | Stop listening +* | | RF24 | SLP | | Set radio to sleep +* | | RF24 | SBY | | Set radio to standby +* | | RF24 | TXM | TO=%%d,LEN=%%d | Transmit message to=(TO), length=(LEN) +* |!| RF24 | TXM | MAX_RT | Max TX retries, no ACK received +* |!| RF24 | GDP | PYL INV | Invalid payload size +* | | RF24 | RXM | LEN=%%d | Read message, length=(LEN) +* | | RF24 | STX | LEVEL=%%d | Set TX level, level=(LEVEL) * */ @@ -174,7 +174,7 @@ LOCAL void RF24_ce(const bool level); * @param readMode * @return */ -LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, const uint8_t len, +LOCAL uint8_t RF24_spiMultiByteTransfer(const uint8_t cmd, uint8_t *buf, const uint8_t len, const bool readMode); /** * @brief RF24_spiByteTransfer @@ -199,7 +199,7 @@ LOCAL uint8_t RF24_RAW_writeByteRegister(const uint8_t cmd, const uint8_t value) // helper macros #define RF24_readByteRegister(__reg) RF24_RAW_readByteRegister(RF24_CMD_READ_REGISTER | (RF24_REGISTER_MASK & (__reg))) //!< RF24_readByteRegister #define RF24_writeByteRegister(__reg,__value) RF24_RAW_writeByteRegister(RF24_CMD_WRITE_REGISTER | (RF24_REGISTER_MASK & (__reg)), __value) //!< RF24_writeByteRegister -#define RF24_writeMultiByteRegister(__reg,__buf,__len) RF24_spiMultiByteTransfer(RF24_CMD_WRITE_REGISTER | (RF24_REGISTER_MASK & (__reg)),(uint8_t*)__buf, __len,false) //!< RF24_writeMultiByteRegister +#define RF24_writeMultiByteRegister(__reg,__buf,__len) RF24_spiMultiByteTransfer(RF24_CMD_WRITE_REGISTER | (RF24_REGISTER_MASK & (__reg)),(uint8_t *)__buf, __len,false) //!< RF24_writeMultiByteRegister /** * @brief RF24_flushRX @@ -256,7 +256,7 @@ LOCAL void RF24_powerUp(void); * @param noACK set True if no ACK is required * @return */ -LOCAL bool RF24_sendMessage(const uint8_t recipient, const void* buf, const uint8_t len, +LOCAL bool RF24_sendMessage(const uint8_t recipient, const void *buf, const uint8_t len, const bool noACK = false); /** * @brief RF24_getDynamicPayloadSize @@ -272,7 +272,7 @@ LOCAL bool RF24_isDataAvailable(void); * @brief RF24_readMessage * @return */ -LOCAL uint8_t RF24_readMessage(void* buf); +LOCAL uint8_t RF24_readMessage(void *buf); /** * @brief RF24_setNodeAddress * @param address @@ -345,7 +345,7 @@ LOCAL void RF24_setRFConfiguration(const uint8_t configuration); * @param address * @param addressWidth */ -LOCAL void RF24_setPipeAddress(const uint8_t pipe, uint8_t* address, const uint8_t addressWidth); +LOCAL void RF24_setPipeAddress(const uint8_t pipe, uint8_t *address, const uint8_t addressWidth); /** * @brief RF24_setPipeLSB * @param pipe diff --git a/drivers/RF24/RF24registers.h b/drivers/RF24/RF24registers.h index 195056e..83b2298 100644 --- a/drivers/RF24/RF24registers.h +++ b/drivers/RF24/RF24registers.h @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad -* Copyright (C) 2013-2017 Sensnology AB +* Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org diff --git a/drivers/RFM69/new/RFM69_new.cpp b/drivers/RFM69/new/RFM69_new.cpp index 111d83d..a0a8877 100644 --- a/drivers/RFM69/new/RFM69_new.cpp +++ b/drivers/RFM69/new/RFM69_new.cpp @@ -42,12 +42,12 @@ #endif rfm69_internal_t RFM69; //!< internal variables -volatile uint8_t rfm69_irq; //!< rfm69 irq flag +volatile uint8_t RFM69_irq; //!< rfm69 irq flag #if defined(LINUX_SPI_BCM) // SPI RX and TX buffers (max packet len + 1 byte for the command) -uint8_t spi_rxbuff[RFM69_MAX_PACKET_LEN + 1]; -uint8_t spi_txbuff[RFM69_MAX_PACKET_LEN + 1]; +uint8_t RFM69_spi_rxbuff[RFM69_MAX_PACKET_LEN + 1]; +uint8_t RFM69_spi_txbuff[RFM69_MAX_PACKET_LEN + 1]; #endif LOCAL void RFM69_csn(const bool level) @@ -60,24 +60,6 @@ LOCAL void RFM69_prepareSPITransaction(void) #if !defined(MY_SOFTSPI) && defined(SPI_HAS_TRANSACTION) RFM69_SPI.beginTransaction(SPISettings(MY_RFM69_SPI_SPEED, RFM69_SPI_DATA_ORDER, RFM69_SPI_DATA_MODE)); -#else -#if defined(SREG) - _SREG = SREG; -#endif - noInterrupts(); -#if defined(SPCR) && defined(SPSR) - // save current SPI settings - _SPCR = SPCR; - _SPSR = SPSR; -#endif - - // set RFM69 SPI settings -#if !defined(MY_SOFTSPI) - RFM69_SPI.setDataMode(RFM69_SPI_DATA_MODE); - RFM69_SPI.setBitOrder(RFM69_SPI_DATA_ORDER); - RFM69_SPI.setClockDivider(RFM69_CLOCK_DIV); -#endif - #endif } @@ -85,17 +67,6 @@ LOCAL void RFM69_concludeSPITransaction(void) { #if !defined(MY_SOFTSPI) && defined(SPI_HAS_TRANSACTION) RFM69_SPI.endTransaction(); -#else - // restore SPI settings to what they were before talking to RFM69 -#if defined(SPCR) && defined(SPSR) - SPCR = _SPCR; - SPSR = _SPSR; -#endif - // restore the prior interrupt state -#if defined(SREG) - SREG = _SREG; -#endif - interrupts(); #endif } @@ -109,8 +80,8 @@ LOCAL uint8_t RFM69_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_ RFM69_csn(LOW); #if defined(LINUX_SPI_BCM) - uint8_t *prx = spi_rxbuff; - uint8_t *ptx = spi_txbuff; + uint8_t *prx = RFM69_spi_rxbuff; + uint8_t *ptx = RFM69_spi_txbuff; uint8_t size = len + 1; // Add register value to transmit buffer *ptx++ = cmd; @@ -121,7 +92,7 @@ LOCAL uint8_t RFM69_spiMultiByteTransfer(const uint8_t cmd, uint8_t* buf, uint8_ *ptx++ = *current++; } } - RFM69_SPI.transfernb((char *)spi_txbuff, (char *)spi_rxbuff, size); + RFM69_SPI.transfernb((char *)RFM69_spi_txbuff, (char *)RFM69_spi_rxbuff, size); if (aReadMode) { if (size == 2) { status = *++prx; // result is 2nd byte of receive buffer @@ -257,7 +228,7 @@ LOCAL bool RFM69_initialise(const uint32_t frequencyHz) // clear FIFO and flags RFM69_clearFIFO(); // IRQ - rfm69_irq = false; + RFM69_irq = false; hwPinMode(MY_RFM69_IRQ_PIN, INPUT); attachInterrupt(MY_RFM69_IRQ_NUM, RFM69_interruptHandler, RISING); return true; @@ -271,7 +242,7 @@ LOCAL void RFM69_clearFIFO(void) LOCAL void RFM69_interruptHandler(void) { // set flag - rfm69_irq = true; + RFM69_irq = true; } LOCAL void RFM69_interruptHandling(void) @@ -346,10 +317,10 @@ LOCAL void RFM69_interruptHandling(void) LOCAL void RFM69_handler(void) { - if (rfm69_irq) { + if (RFM69_irq) { // radio is in STDBY // clear flag, 8bit - no need for critical section - rfm69_irq = false; + RFM69_irq = false; RFM69_interruptHandling(); } } @@ -429,10 +400,10 @@ LOCAL bool RFM69_sendFrame(rfm69_packet_t *packet, const bool increaseSequenceCo // send message (void)RFM69_setRadioMode(RFM69_RADIO_MODE_TX); // irq upon txsent const uint32_t txStartMS = hwMillis(); - while (!rfm69_irq && (hwMillis() - txStartMS < MY_RFM69_TX_TIMEOUT_MS)) { + while (!RFM69_irq && (hwMillis() - txStartMS < MY_RFM69_TX_TIMEOUT_MS)) { doYield(); }; - return rfm69_irq; + return RFM69_irq; } LOCAL bool RFM69_send(const uint8_t recipient, uint8_t *data, const uint8_t len, diff --git a/drivers/RFM69/new/RFM69_new.h b/drivers/RFM69/new/RFM69_new.h index 204ad24..3c1d820 100644 --- a/drivers/RFM69/new/RFM69_new.h +++ b/drivers/RFM69/new/RFM69_new.h @@ -99,30 +99,10 @@ #define RFM69_SPI_DATA_ORDER MSBFIRST //!< SPI data order #define RFM69_SPI_DATA_MODE SPI_MODE0 //!< SPI mode -// SPI clock divier for non-transaction implementations -#if (MY_RFM69_SPI_SPEED >= F_CPU / 2) -#define RFM69_CLOCK_DIV SPI_CLOCK_DIV2 //!< SPI clock divider 2 -#elif (MY_RFM69_SPI_SPEED >= F_CPU / 4) -#define RFM69_CLOCK_DIV SPI_CLOCK_DIV4 //!< SPI clock divider 4 -#elif (MY_RFM69_SPI_SPEED >= F_CPU / 8) -#define RFM69_CLOCK_DIV SPI_CLOCK_DIV8 //!< SPI clock divider 8 -#elif (MY_RFM69_SPI_SPEED >= F_CPU / 16) -#define RFM69_CLOCK_DIV SPI_CLOCK_DIV16 //!< SPI clock divider 16 -#elif (MY_RFM69_SPI_SPEED >= F_CPU / 32) -#define RFM69_CLOCK_DIV SPI_CLOCK_DIV32 //!< SPI clock divider 32 -#elif (MY_RFM69_SPI_SPEED >= F_CPU / 64) -#define RFM69_CLOCK_DIV SPI_CLOCK_DIV64 //!< SPI clock divider 64 -#elif (MY_RFM69_SPI_SPEED >= F_CPU / 128) -#define RFM69_CLOCK_DIV SPI_CLOCK_DIV128 //!< SPI clock divider 128 -#else -#define RFM69_CLOCK_DIV SPI_CLOCK_DIV256 //!< SPI clock divider 256 -#endif - #if defined(ARDUINO) && !defined(__arm__) && !defined(RFM69_SPI) #include #if defined(MY_SOFTSPI) -SoftSPI -RFM69_SPI; +SoftSPIRFM69_SPI; #else #define RFM69_SPI SPI #endif diff --git a/drivers/RFM95/RFM95.cpp b/drivers/RFM95/RFM95.cpp index 2ca352e..03313ed 100644 --- a/drivers/RFM95/RFM95.cpp +++ b/drivers/RFM95/RFM95.cpp @@ -35,15 +35,15 @@ #define RFM95_DEBUG(x,...) //!< DEBUG null #endif +rfm95_internal_t RFM95; //!< internal variables +volatile uint8_t RFM95_irq; // #if defined(MY_SOFTSPI) -SoftSPI -RFM95_SPI; +SoftSPIRFM95_SPI; #else #define RFM95_SPI SPI //!< SPI #endif From b51981ab3d11454eca450adbbcfe6e3749d2dff2 Mon Sep 17 00:00:00 2001 From: tekka Date: Tue, 20 Feb 2018 12:32:03 +0100 Subject: [PATCH 16/60] Fix MY_CORE_ONLY: Initialize HW (#1070) --- MySensors.h | 2 -- core/MySensorsCore.cpp | 8 ++++++++ examples/SecurityPersonalizer/SecurityPersonalizer.ino | 2 -- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/MySensors.h b/MySensors.h index 8ef1198..295888a 100644 --- a/MySensors.h +++ b/MySensors.h @@ -388,7 +388,6 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs #include "core/MySensorsCore.cpp" // HW mains -#if !defined(MY_CORE_ONLY) #if defined(ARDUINO_ARCH_AVR) #include "hal/architecture/AVR/MyMainAVR.cpp" #elif defined(ARDUINO_ARCH_SAMD) @@ -404,7 +403,6 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs #elif defined(TEENSYDUINO) #include "hal/architecture/Teensy3/MyMainTeensy3.cpp" #endif -#endif #endif diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 5412e87..fcb6939 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -88,6 +88,14 @@ void _infiniteLoop(void) void _begin(void) { +#if defined(MY_CORE_ONLY) + // initialize HW and run setup if present + (void)hwInit(); + if (setup) { + setup(); + } + return; +#endif // reset wdt hwWatchdogReset(); diff --git a/examples/SecurityPersonalizer/SecurityPersonalizer.ino b/examples/SecurityPersonalizer/SecurityPersonalizer.ino index 882d523..58ae759 100644 --- a/examples/SecurityPersonalizer/SecurityPersonalizer.ino +++ b/examples/SecurityPersonalizer/SecurityPersonalizer.ino @@ -439,9 +439,7 @@ void setup() hwRandomNumberInit(); #endif - Serial.begin(MY_BAUD_RATE); while(!Serial); // For USB enabled devices, wait for USB enumeration before continuing - hwInit(); print_greeting(); From 57eca4f4afb3a26f4ef0ec10d522ac062de4d101 Mon Sep 17 00:00:00 2001 From: tekka Date: Tue, 20 Feb 2018 12:32:17 +0100 Subject: [PATCH 17/60] Transport code harmonization (#1072) --- drivers/RFM69/new/RFM69_new.cpp | 63 ++---------------------- drivers/RFM69/new/RFM69_new.h | 4 +- drivers/RFM95/RFM95.cpp | 15 +++--- drivers/RFM95/RFM95.h | 2 - hal/transport/RF24/MyTransportRF24.cpp | 8 +-- hal/transport/RFM69/MyTransportRFM69.cpp | 22 ++++----- hal/transport/RFM95/MyTransportRFM95.cpp | 6 +-- 7 files changed, 30 insertions(+), 90 deletions(-) diff --git a/drivers/RFM69/new/RFM69_new.cpp b/drivers/RFM69/new/RFM69_new.cpp index a0a8877..5a952cb 100644 --- a/drivers/RFM69/new/RFM69_new.cpp +++ b/drivers/RFM69/new/RFM69_new.cpp @@ -200,7 +200,6 @@ LOCAL bool RFM69_initialise(const uint32_t frequencyHz) RFM69.powerLevel = MY_RFM69_TX_POWER_DBM + 1; // will be overwritten when set RFM69.radioMode = RFM69_RADIO_MODE_SLEEP; RFM69.ATCenabled = false; - RFM69.listenModeEnabled = false; RFM69.ATCtargetRSSI = RFM69_RSSItoInternal(MY_RFM69_ATC_TARGET_RSSI_DBM); // SPI init @@ -354,7 +353,7 @@ LOCAL uint8_t RFM69_receive(uint8_t *buf, const uint8_t maxBufSize) // clear data flag RFM69.dataReceived = false; if (RFM69_getACKRequested(controlFlags) && !RFM69_getACKReceived(controlFlags)) { -#if defined(MY_GATEWAY_FEATURE) && (F_CPU>16000000) +#if defined(MY_GATEWAY_FEATURE) && (F_CPU>16*1000000ul) // delay for fast GW and slow nodes delay(50); #endif @@ -425,9 +424,9 @@ LOCAL bool RFM69_send(const uint8_t recipient, uint8_t *data, const uint8_t len, LOCAL void RFM69_setFrequency(const uint32_t frequencyHz) { const uint32_t freqHz = (uint32_t)(frequencyHz / RFM69_FSTEP); - RFM69_writeReg(RFM69_REG_FRFMSB, (freqHz >> 16) & 0xFF); - RFM69_writeReg(RFM69_REG_FRFMID, (freqHz >> 8) & 0xFF); - RFM69_writeReg(RFM69_REG_FRFLSB, freqHz & 0xFF); + RFM69_writeReg(RFM69_REG_FRFMSB, (uint8_t)((freqHz >> 16) & 0xFF)); + RFM69_writeReg(RFM69_REG_FRFMID, (uint8_t)((freqHz >> 8) & 0xFF)); + RFM69_writeReg(RFM69_REG_FRFLSB, (uint8_t)(freqHz & 0xFF)); } LOCAL void RFM69_setHighPowerRegs(const bool onOff) @@ -774,60 +773,6 @@ LOCAL rfm69_RSSI_t RFM69_readRSSI(const bool forceTrigger) return (rfm69_RSSI_t)RFM69_readReg(RFM69_REG_RSSIVALUE); } -/* UNUSED - -LOCAL uint8_t RFM69_getVersion(void) -{ - return RFM69_readReg(RFM69_REG_VERSION); -} - -LOCAL uint8_t RFM69_readTemperature(const uint8_t calFactor) -{ - (void)RFM69_setRadioMode(RFM69_RADIO_MODE_STDBY); - RFM69_writeReg(RFM69_REG_TEMP1, RFM69_TEMP1_MEAS_START); - const uint32_t enterMS = hwMillis(); - while ((RFM69_readReg(RFM69_REG_TEMP1) & RFM69_TEMP1_MEAS_RUNNING) && hwMillis() - enterMS < 500); - return ~RFM69_readReg(RFM69_REG_TEMP2) + RFM69_COURSE_TEMP_COEF + - calFactor; // 'complement' corrects the slope, rising temp = rising val -} - -LOCAL uint8_t RFM69_setLNA(const uint8_t newReg) -{ - const uint8_t oldReg = RFM69_readReg(RFM69_REG_LNA); - RFM69_writeReg(RFM69_REG_LNA, ((newReg & 7) | (oldReg & - ~7))); // just control the LNA Gain bits for now - return oldReg; // return the original value in case we need to restore it -} - -LOCAL bool RFM69_waitCAD(void) -{ - const uint32_t enterMS = hwMillis(); - (void)RFM69_setRadioMode(RFM69_RADIO_MODE_RX); - while (RFM69.radioMode == RFM69_RADIO_MODE_RX && !RFM69.dataReceived && - RFM69_RSSItoInternal(RFM69_readRSSI()) > RFM69_RSSItoInternal(RFM69_CSMA_LIMIT_DBM)) { - if (hwMillis() - enterMS > RFM69_CSMA_TIMEOUT_MS) { - return false; - } - } - return true; -} - -LOCAL void RFM69_rcCalibration(void) -{ - // RC oscillator calibration - // On the SX1231 V2a, RC calibration at power-up needs to be performed - // This is not required in the version V2b any more, where the calibration is fully automatic - // see SX1231 datasheet, chapter 9 (Chip Revision) - RFM69_writeReg(0x57, 0x80); - RFM69_writeReg(RFM69_REG_OSC1, RFM69_OSC1_RCCAL_START); - while (!(RFM69_readReg(RFM69_REG_OSC1) & RFM69_OSC1_RCCAL_DONE)) {}; - RFM69_writeReg(RFM69_REG_OSC1, RFM69_OSC1_RCCAL_START); - while (!(RFM69_readReg(RFM69_REG_OSC1) & RFM69_OSC1_RCCAL_DONE)) {}; - RFM69_writeReg(0x57, 0x00); -} - -*/ - LOCAL void RFM69_readAllRegs(void) { #ifdef RFM69_REGISTER_DETAIL diff --git a/drivers/RFM69/new/RFM69_new.h b/drivers/RFM69/new/RFM69_new.h index 3c1d820..8503d71 100644 --- a/drivers/RFM69/new/RFM69_new.h +++ b/drivers/RFM69/new/RFM69_new.h @@ -326,7 +326,6 @@ typedef struct { rfm69_RSSI_t RSSI; //!< RSSI of current packet, RSSI = value - 137 } __attribute__((packed)) rfm69_packet_t; - /** * @brief RFM69 internal variables */ @@ -341,8 +340,7 @@ typedef struct { bool dataReceived : 1; //!< data received bool ackReceived : 1; //!< ACK received bool ATCenabled : 1; //!< ATC enabled - bool listenModeEnabled : 1; //!< Listen mode enabled - bool reserved : 1; //!< Reserved + uint8_t reserved : 2; //!< Reserved } rfm69_internal_t; #define LOCAL static //!< static diff --git a/drivers/RFM95/RFM95.cpp b/drivers/RFM95/RFM95.cpp index 03313ed..903d5e4 100644 --- a/drivers/RFM95/RFM95.cpp +++ b/drivers/RFM95/RFM95.cpp @@ -347,9 +347,8 @@ LOCAL bool RFM95_sendFrame(rfm95_packet_t *packet, const bool increaseSequenceCo (void)RFM95_setRadioMode(RFM95_RADIO_MODE_TX); // wait until IRQ fires or timeout const uint32_t startTX_MS = hwMillis(); - while (!RFM95_irq && - (hwMillis() - startTX_MS < - MY_RFM95_TX_TIMEOUT_MS) ) { // make this payload length + bit rate dependend + // todo: make this payload length + bit rate dependend + while (!RFM95_irq && (hwMillis() - startTX_MS < MY_RFM95_TX_TIMEOUT_MS) ) { doYield(); } return RFM95_irq; @@ -371,9 +370,9 @@ LOCAL bool RFM95_send(const uint8_t recipient, uint8_t *data, const uint8_t len, LOCAL void RFM95_setFrequency(const uint32_t frequencyHz) { const uint32_t freqReg = (uint32_t)(frequencyHz / RFM95_FSTEP); - (void)RFM95_writeReg(RFM95_REG_06_FRF_MSB, (freqReg >> 16) & 0xff); - (void)RFM95_writeReg(RFM95_REG_07_FRF_MID, (freqReg >> 8) & 0xff); - (void)RFM95_writeReg(RFM95_REG_08_FRF_LSB, freqReg & 0xff); + (void)RFM95_writeReg(RFM95_REG_06_FRF_MSB, (uint8_t)((freqReg >> 16) & 0xff)); + (void)RFM95_writeReg(RFM95_REG_07_FRF_MID, (uint8_t)((freqReg >> 8) & 0xff)); + (void)RFM95_writeReg(RFM95_REG_08_FRF_LSB, (uint8_t)(freqReg & 0xff)); } LOCAL bool RFM95_setTxPowerLevel(rfm95_powerLevel_t newPowerLevel) @@ -420,8 +419,8 @@ LOCAL void RFM95_setModemRegisters(const rfm95_modemConfig_t *config) LOCAL void RFM95_setPreambleLength(const uint16_t preambleLength) { - (void)RFM95_writeReg(RFM95_REG_20_PREAMBLE_MSB, (preambleLength >> 8) & 0xff); - (void)RFM95_writeReg(RFM95_REG_21_PREAMBLE_LSB, preambleLength & 0xff); + (void)RFM95_writeReg(RFM95_REG_20_PREAMBLE_MSB, (uint8_t)((preambleLength >> 8) & 0xff)); + (void)RFM95_writeReg(RFM95_REG_21_PREAMBLE_LSB, (uint8_t)(preambleLength & 0xff)); } LOCAL void RFM95_setAddress(const uint8_t addr) diff --git a/drivers/RFM95/RFM95.h b/drivers/RFM95/RFM95.h index 52f69a8..ab34832 100644 --- a/drivers/RFM95/RFM95.h +++ b/drivers/RFM95/RFM95.h @@ -186,8 +186,6 @@ extern HardwareSPI SPI; //!< SPI #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 -//#define RFM95_internalToRSSI(__value) ((int16_t)(__value - RFM95_RSSI_OFFSET)) //!< Convert internal RSSI to RSSI -//#define RFM95_RSSItoInternal(__value) ((uint8_t)(__value + RFM95_RSSI_OFFSET)) //!< Convert RSSI to internal RSSI #define RFM95_internalToSNR(__value) ((int8_t)(__value / 4)) //!< Convert internal SNR to SNR #define RFM95_MIN_POWER_LEVEL_DBM ((rfm95_powerLevel_t)5u) //!< min. power level diff --git a/hal/transport/RF24/MyTransportRF24.cpp b/hal/transport/RF24/MyTransportRF24.cpp index e76025b..85b1b0b 100644 --- a/hal/transport/RF24/MyTransportRF24.cpp +++ b/hal/transport/RF24/MyTransportRF24.cpp @@ -68,7 +68,7 @@ bool transportInit(void) (void)memset(RF24_psk, 0, 16); (void)memcpy(RF24_psk, MY_ENCRYPTION_SIMPLE_PASSWD, strnlen(MY_ENCRYPTION_SIMPLE_PASSWD, 16)); #else - hwReadConfigBlock((void*)RF24_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); + hwReadConfigBlock((void *)RF24_psk, (void *)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); #endif //set up AES-key RF24_aes.set_key(RF24_psk, 16); @@ -93,7 +93,7 @@ uint8_t transportGetAddress(void) return RF24_getNodeID(); } -bool transportSend(const uint8_t to, const void* data, const uint8_t len, const bool noACK) +bool transportSend(const uint8_t to, const void *data, const uint8_t len, const bool noACK) { #if defined(MY_RF24_ENABLE_ENCRYPTION) // copy input data because it is read-only @@ -124,7 +124,7 @@ bool transportSanityCheck(void) return RF24_sanityCheck(); } -uint8_t transportReceive(void* data) +uint8_t transportReceive(void *data) { uint8_t len = 0; #if defined(MY_RX_MESSAGE_BUFFER_FEATURE) @@ -141,7 +141,7 @@ uint8_t transportReceive(void* data) // has to be adjusted, WIP! RF24_aes.set_IV(0); // decrypt data - if (RF24_aes.cbc_decrypt((uint8_t*)(data), (uint8_t*)(data), len > 16 ? 2 : 1) != AES_SUCCESS) { + if (RF24_aes.cbc_decrypt((uint8_t *)data, (uint8_t *)data, len > 16 ? 2 : 1) != AES_SUCCESS) { len = 0; } #endif diff --git a/hal/transport/RFM69/MyTransportRFM69.cpp b/hal/transport/RFM69/MyTransportRFM69.cpp index b35f3ba..b1ff3db 100644 --- a/hal/transport/RFM69/MyTransportRFM69.cpp +++ b/hal/transport/RFM69/MyTransportRFM69.cpp @@ -37,9 +37,9 @@ bool transportInit(void) (void)memset(RFM69_psk, 0, 16); (void)memcpy(RFM69_psk, MY_ENCRYPTION_SIMPLE_PASSWD, strnlen(MY_ENCRYPTION_SIMPLE_PASSWD, 16)); #else - hwReadConfigBlock((void*)RFM69_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); + hwReadConfigBlock((void *)RFM69_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); #endif - RFM69_encrypt((const char*)RFM69_psk); + RFM69_encrypt((const char *)RFM69_psk); (void)memset(RFM69_psk, 0, 16); // Make sure it is purged from memory when set #else (void)RFM69_encrypt; @@ -57,7 +57,7 @@ uint8_t transportGetAddress(void) return RFM69_getAddress(); } -bool transportSend(const uint8_t to, const void* data, uint8_t len, const bool noACK) +bool transportSend(const uint8_t to, const void *data, uint8_t len, const bool noACK) { if (noACK) { (void)RFM69_sendWithRetry(to, data, len, 0, 0); @@ -77,9 +77,9 @@ bool transportSanityCheck(void) return RFM69_sanityCheck(); } -uint8_t transportReceive(void* data) +uint8_t transportReceive(void *data) { - return RFM69_receive((uint8_t*)data, MAX_MESSAGE_LENGTH); + return RFM69_receive((uint8_t *)data, MAX_MESSAGE_LENGTH); } void transportSleep(void) @@ -108,7 +108,7 @@ bool transportSetTxPowerLevel(const uint8_t powerLevel) return RFM69_setTxPowerLevel(powerLevel); } -void transportSetTargetRSSI(int16_t targetSignalStrength) +void transportSetTargetRSSI(const int16_t targetSignalStrength) { #if !defined(MY_GATEWAY_FEATURE) && !defined(MY_RFM69_ATC_MODE_DISABLED) RFM69_ATCmode(true, targetSignalStrength); @@ -175,9 +175,9 @@ bool transportInit(void) (void)memset(RFM69_psk, 0, 16); (void)memcpy(RFM69_psk, MY_ENCRYPTION_SIMPLE_PASSWD, strnlen(MY_ENCRYPTION_SIMPLE_PASSWD, 16)); #else - hwReadConfigBlock((void*)RFM69_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); + hwReadConfigBlock((void *)RFM69_psk, (void *)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); #endif - _radio.encrypt((const char*)RFM69_psk); + _radio.encrypt((const char *)RFM69_psk); (void)memset(RFM69_psk, 0, 16); // Make sure it is purged from memory when set #endif return true; @@ -196,7 +196,7 @@ uint8_t transportGetAddress(void) return _address; } -bool transportSend(const uint8_t to, const void* data, const uint8_t len, const bool noACK) +bool transportSend(const uint8_t to, const void *data, const uint8_t len, const bool noACK) { if (noACK) { (void)_radio.sendWithRetry(to, data, len, 0, 0); @@ -215,11 +215,11 @@ bool transportSanityCheck(void) return _radio.sanityCheck(); } -uint8_t transportReceive(void* data) +uint8_t transportReceive(void *data) { // save payload length const uint8_t dataLen = _radio.DATALEN < MAX_MESSAGE_LENGTH? _radio.DATALEN : MAX_MESSAGE_LENGTH; - (void)memcpy((void*)data, (void*)_radio.DATA, dataLen); + (void)memcpy((void *)data, (void *)_radio.DATA, dataLen); // Send ack back if this message wasn't a broadcast if (_radio.ACKRequested()) { _radio.sendACK(); diff --git a/hal/transport/RFM95/MyTransportRFM95.cpp b/hal/transport/RFM95/MyTransportRFM95.cpp index 3001c59..7003012 100644 --- a/hal/transport/RFM95/MyTransportRFM95.cpp +++ b/hal/transport/RFM95/MyTransportRFM95.cpp @@ -46,7 +46,7 @@ uint8_t transportGetAddress(void) return RFM95_getAddress(); } -bool transportSend(const uint8_t to, const void* data, const uint8_t len, const bool noACK) +bool transportSend(const uint8_t to, const void *data, const uint8_t len, const bool noACK) { if (noACK) { (void)RFM95_sendWithRetry(to, data, len, 0, 0); @@ -66,9 +66,9 @@ bool transportSanityCheck(void) return RFM95_sanityCheck(); } -uint8_t transportReceive(void* data) +uint8_t transportReceive(void *data) { - const uint8_t len = RFM95_receive((uint8_t*)data, MAX_MESSAGE_LENGTH); + const uint8_t len = RFM95_receive((uint8_t *)data, MAX_MESSAGE_LENGTH); return len; } From 599c0bada60089c74ecf187001cb57845c37a472 Mon Sep 17 00:00:00 2001 From: Mikael Falkvidd Date: Thu, 22 Feb 2018 12:04:03 +0100 Subject: [PATCH 18/60] ESP8266 Gateway examples: clarify inclusion pin (#1065) The comment for inclusion mode pin and the definition of MY_INCLUSION_MODE_BUTTON_PIN did not match. GPIO5 should be safe to use, while GPIO3 is used for the UART which might result in conflict. This fixes https://github.com/mysensors/MySensors/issues/993 --- examples/GatewayESP8266/GatewayESP8266.ino | 4 ++-- .../GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/GatewayESP8266/GatewayESP8266.ino b/examples/GatewayESP8266/GatewayESP8266.ino index b8c277b..54af4dc 100644 --- a/examples/GatewayESP8266/GatewayESP8266.ino +++ b/examples/GatewayESP8266/GatewayESP8266.ino @@ -58,7 +58,7 @@ * - 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') + * - Connect GPIO5 (=D1) via switch to GND ('inclusion switch') * * Hardware SHA204 signing is currently not supported! * @@ -113,7 +113,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 D1 // Set blinking period //#define MY_DEFAULT_LED_BLINK_PERIOD 300 diff --git a/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino b/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino index 4fe945f..57fff44 100644 --- a/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino +++ b/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino @@ -50,7 +50,7 @@ * - 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') + * - Connect GPIO5 (=D1) via switch to GND ('inclusion switch') * * Hardware SHA204 signing is currently not supported! * @@ -113,7 +113,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 D1 // Set blinking period //#define MY_DEFAULT_LED_BLINK_PERIOD 300 From fe42dbdcca4ced335e880f3627fe684a8893d922 Mon Sep 17 00:00:00 2001 From: d00616 Date: Wed, 28 Feb 2018 20:03:34 +0100 Subject: [PATCH 19/60] Nvm fota (#1018) * New Firmware OTA for NVM/mcuboot (nRF5) - Support for mcuboot (nRF5) - Support for run length encoded data - Support for smaller FIRMWARE_BLOCK_SIZE, if required * Update NVM * New MY_LOCK_MCU for NRF5 * Test with Sensebender GW + Sensebender Micro was successful --- MyConfig.h | 18 ++ MySensors.h | 2 + core/MyMessage.h | 4 +- core/MyOTAFirmwareUpdate.cpp | 210 ++++++++++++------ core/MyOTAFirmwareUpdate.h | 47 ++++ drivers/NRF5/Flash.cpp | 2 + drivers/NVM/VirtualPage.cpp | 86 +++---- .../SecurityPersonalizer.ino | 4 + hal/architecture/NRF5/MyHwNRF5.cpp | 25 +++ 9 files changed, 292 insertions(+), 106 deletions(-) diff --git a/MyConfig.h b/MyConfig.h index 6c72ba9..387d0c6 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -1654,6 +1654,23 @@ #define MY_SIGNING_SOFT_RANDOMSEED_PIN (7) #endif +/** + * @def MY_LOCK_DEVICE + * @brief Enable read back protection + * + * Enable read back protection feature. Currently only supported by NRF51+NRF52. + * Use this flag to protect signing and encryption keys stored in the MCU. + * + * Set this flag, when you use softsigning in MySensors. Don't set this + * in SecurityPersonalizer. + * + * @warning YOU CAN BRICK YOUR DEVICE!!! + * Don't set this flag without having an boot loader, OTA firmware update and + * an Gateway connection. To reset an device, you can try >> + * openocd -f interface/cmsis-dap.cfg -f target/nrf52.cfg -c "program dap apreg 1 0x04 0x01" + */ +//#define MY_LOCK_DEVICE + /** * @def MY_SIGNING_FEATURE * @ingroup internals @@ -2023,6 +2040,7 @@ #define MY_INDICATION_HANDLER #define MY_DISABLE_REMOTE_RESET #define MY_DISABLE_RAM_ROUTING_TABLE_FEATURE +#define MY_LOCK_DEVICE // core #define MY_CORE_ONLY // GW diff --git a/MySensors.h b/MySensors.h index 295888a..dd233e1 100644 --- a/MySensors.h +++ b/MySensors.h @@ -126,11 +126,13 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs // FLASH #if defined(MY_OTA_FIRMWARE_FEATURE) +#ifndef MCUBOOT_PRESENT #if defined(MY_OTA_USE_I2C_EEPROM) #include "drivers/I2CEeprom/I2CEeprom.cpp" #else #include "drivers/SPIFlash/SPIFlash.cpp" #endif +#endif #include "core/MyOTAFirmwareUpdate.cpp" #endif diff --git a/core/MyMessage.h b/core/MyMessage.h index ad10e34..bdd4654 100644 --- a/core/MyMessage.h +++ b/core/MyMessage.h @@ -208,7 +208,9 @@ typedef enum { ST_FIRMWARE_REQUEST = 2, //!< Request FW block ST_FIRMWARE_RESPONSE = 3, //!< Response FW block ST_SOUND = 4, //!< Sound - ST_IMAGE = 5 //!< Image + ST_IMAGE = 5, //!< Image + ST_FIRMWARE_CONFIRM = 6, //!< Mark running firmware as valid (MyOTAFirmwareUpdateNVM + mcuboot) + ST_FIRMWARE_RESPONSE_RLE = 7, //!< Response FW block with run length encoded data } mysensor_stream; /// @brief Type of payload diff --git a/core/MyOTAFirmwareUpdate.cpp b/core/MyOTAFirmwareUpdate.cpp index 1b2aca8..35e3ce7 100644 --- a/core/MyOTAFirmwareUpdate.cpp +++ b/core/MyOTAFirmwareUpdate.cpp @@ -26,15 +26,30 @@ extern MyMessage _msgTmp; // local variables #ifdef MY_OTA_USE_I2C_EEPROM I2CEeprom _flash(MY_OTA_I2C_ADDR); -#else +#elif !defined(MCUBOOT_PRESENT) SPIFlash _flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID); #endif +// Map flash functions +#ifndef MCUBOOT_PRESENT +#define _flash_initialize() _flash.initialize() +#define _flash_readByte(addr) _flash.readByte(addr) +#define _flash_writeBytes( dstaddr, data, size) _flash.writeBytes( dstaddr, data, size) +#define _flash_blockErase32K(num) _flash.blockErase32K(num) +#define _flash_busy() _flash.busy() +#else +#define _flash_initialize() true +#define _flash_readByte(addr) (*((uint8_t *)(addr))) +#define _flash_blockErase32K(num) Flash.erase((uint32_t *)FLASH_AREA_IMAGE_1_OFFSET_0, FLASH_AREA_IMAGE_1_SIZE_0) +#define _flash_busy() false +#endif + LOCAL nodeFirmwareConfig_t _nodeFirmwareConfig; LOCAL bool _firmwareUpdateOngoing = false; LOCAL uint32_t _firmwareLastRequest; LOCAL uint16_t _firmwareBlock; LOCAL uint8_t _firmwareRetry; +LOCAL bool _firmwareResponse(uint16_t block, uint8_t *data); LOCAL void readFirmwareSettings(void) { @@ -83,15 +98,15 @@ LOCAL bool firmwareOTAUpdateProcess(void) // copy new FW config (void)memcpy(&_nodeFirmwareConfig, firmwareConfigResponse, sizeof(nodeFirmwareConfig_t)); // Init flash - if (!_flash.initialize()) { + if (!_flash_initialize()) { setIndication(INDICATION_ERR_FW_FLASH_INIT); OTA_DEBUG(PSTR("!OTA:FWP:FLASH INIT FAIL\n")); // failed to initialise flash _firmwareUpdateOngoing = false; } else { // erase lower 32K -> max flash size for ATMEGA328 - _flash.blockErase32K(0); + _flash_blockErase32K(0); // wait until flash erased - while ( _flash.busy() ) {} + while ( _flash_busy() ) {} _firmwareBlock = _nodeFirmwareConfig.blocks; _firmwareUpdateOngoing = true; // reset flags @@ -102,68 +117,46 @@ LOCAL bool firmwareOTAUpdateProcess(void) } OTA_DEBUG(PSTR("OTA:FWP:UPDATE SKIPPED\n")); // FW update skipped, no newer version available } else if (_msg.type == ST_FIRMWARE_RESPONSE) { - if (_firmwareUpdateOngoing) { - // extract FW block - replyFirmwareBlock_t *firmwareResponse = (replyFirmwareBlock_t *)_msg.data; - - OTA_DEBUG(PSTR("OTA:FWP:RECV B=%04" PRIX16 "\n"), firmwareResponse->block); // received FW block - if (firmwareResponse->block != _firmwareBlock - 1) { - OTA_DEBUG(PSTR("!OTA:FWP:WRONG FWB\n")); // received FW block - // wrong firmware block received - setIndication(INDICATION_FW_UPDATE_RX_ERR); - // no further processing required - return true; - } - setIndication(INDICATION_FW_UPDATE_RX); - // Save block to flash - _flash.writeBytes( ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, - firmwareResponse->data, FIRMWARE_BLOCK_SIZE); - // wait until flash written - while (_flash.busy()) {} -#ifdef OTA_EXTRA_FLASH_DEBUG - { - char prbuf[8]; - uint32_t addr = ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET; - OTA_DEBUG(PSTR("OTA:FWP:FL DUMP ")); - sprintf_P(prbuf,PSTR("%04" PRIX16 ":"), (uint16_t)addr); - MY_SERIALDEVICE.print(prbuf); - for(uint8_t i=0; i> 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); - OTA_DEBUG(PSTR("!OTA:FWP:CRC FAIL\n")); - } - } - // reset flags - _firmwareRetry = MY_OTA_RETRY + 1; - _firmwareLastRequest = 0; - } else { - OTA_DEBUG(PSTR("!OTA:FWP:NO UPDATE\n")); + // extract FW block + replyFirmwareBlock_t *firmwareResponse = (replyFirmwareBlock_t *)_msg.data; + // Proceed firmware data + return _firmwareResponse(firmwareResponse->block, firmwareResponse->data); +#ifdef FIRMWARE_PROTOCOL_31 + } else if (_msg.type == ST_FIRMWARE_RESPONSE_RLE) { + // RLE encoded block + // extract FW block + replyFirmwareBlockRLE_t *firmwareResponse = (replyFirmwareBlockRLE_t *)_msg.data; + uint8_t data[FIRMWARE_BLOCK_SIZE]; + for (uint8_t i=0; idata; + } + while ((_firmwareBlock) && (firmwareResponse->number_of_blocks)) { + _firmwareResponse(firmwareResponse->block, data); + firmwareResponse->number_of_blocks--; + firmwareResponse->block--; } return true; +#endif + } else { +#ifdef MCUBOOT_PRESENT + if (_msg.type == ST_FIRMWARE_CONFIRM) { + if (*(uint16_t *)MCUBOOT_IMAGE_0_MAGIC_ADDR == ((uint16_t)MCUBOOT_IMAGE_MAGIC)) { + if (*(uint8_t*)(MCUBOOT_IMAGE_0_IMG_OK_ADDR)!=MCUBOOT_IMAGE_0_IMG_OK_BYTE) { + // Calculate data word to write + uint32_t *img_ok_base_addr = (uint32_t*)(MCUBOOT_IMAGE_0_IMG_OK_ADDR & ~3); // align word wise + uint32_t img_ok_data = *img_ok_base_addr; + // Set copy of MCUBOOT_IMAGE_0_IMG_OK_ADDR to MCUBOOT_IMAGE_0_IMG_OK_BYTE (0x01) + uint8_t * img_ok_array = (uint8_t*)(&img_ok_data); + img_ok_array[MCUBOOT_IMAGE_0_IMG_OK_ADDR % 4] = MCUBOOT_IMAGE_0_IMG_OK_BYTE; + // Write word back + Flash.write(img_ok_base_addr, img_ok_data); + } + OTA_DEBUG(PSTR("!OTA:FWP:IMAGE CONFIRMED\n")); + } else { + OTA_DEBUG(PSTR("!OTA:FWP:INVALID MCUBOOT MAGIC\n")); + } + } +#endif } return false; } @@ -178,6 +171,18 @@ LOCAL void presentBootloaderInformation(void) (void)memcpy(requestFirmwareConfig, &_nodeFirmwareConfig, sizeof(nodeFirmwareConfig_t)); // add bootloader information requestFirmwareConfig->BLVersion = MY_OTA_BOOTLOADER_VERSION; +#ifdef FIRMWARE_PROTOCOL_31 + requestFirmwareConfig->blockSize = FIRMWARE_BLOCK_SIZE; +#ifndef MCUBOOT_PRESENT + requestFirmwareConfig->img_commited = 0x2; + requestFirmwareConfig->img_revision = 0x00; + requestFirmwareConfig->img_build_num = 0x00; +#else + requestFirmwareConfig->img_commited = *((uint8_t*)(MCUBOOT_IMAGE_0_IMG_OK_ADDR)); + requestFirmwareConfig->img_revision = *((uint16_t*)(MCUBOOT_IMAGE_0_IMG_REVISION_ADDR)); + requestFirmwareConfig->img_build_num = *((uint16_t*)(MCUBOOT_IMAGE_0_IMG_BUILD_NUM_ADDR)); +#endif +#endif _firmwareUpdateOngoing = false; (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_CONFIG_REQUEST, false)); @@ -192,8 +197,8 @@ LOCAL bool transportIsValidFirmware(void) { // init crc uint16_t crc = ~0; - for (uint16_t i = 0; i < _nodeFirmwareConfig.blocks * FIRMWARE_BLOCK_SIZE; ++i) { - crc ^= _flash.readByte(i + FIRMWARE_START_OFFSET); + for (uint32_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; @@ -207,3 +212,76 @@ LOCAL bool transportIsValidFirmware(void) _nodeFirmwareConfig.crc); return crc == _nodeFirmwareConfig.crc; } + +LOCAL bool _firmwareResponse(uint16_t block, uint8_t *data) +{ + if (_firmwareUpdateOngoing) { + OTA_DEBUG(PSTR("OTA:FWP:RECV B=%04" PRIX16 "\n"), block); // received FW block + if (block != _firmwareBlock - 1) { + OTA_DEBUG(PSTR("!OTA:FWP:WRONG FWB\n")); // received FW block + // wrong firmware block received + setIndication(INDICATION_FW_UPDATE_RX_ERR); + // no further processing required + return true; + } + setIndication(INDICATION_FW_UPDATE_RX); + // Save block to flash +#ifdef MCUBOOT_PRESENT + uint32_t addr = ((size_t)(((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE)) + (size_t)( + FIRMWARE_START_OFFSET)); + if (addr>2); + } +#else + _flash_writeBytes( ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET, + data, FIRMWARE_BLOCK_SIZE); +#endif + // wait until flash written + while (_flash_busy()) {} +#ifdef OTA_EXTRA_FLASH_DEBUG + { + char prbuf[8]; + uint32_t addr = ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET; + OTA_DEBUG(PSTR("OTA:FWP:FL DUMP ")); + sprintf_P(prbuf,PSTR("%04" PRIX16 ":"), (uint16_t)addr); + MY_SERIALDEVICE.print(prbuf); + for(uint8_t i=0; i> 8), (uint8_t)(firmwareSize & 0xff),':'}; + _flash_writeBytes(0, OTAbuffer, FIRMWARE_START_OFFSET); + // wait until flash ready + while (_flash_busy()) {} +#endif + hwReboot(); + } else { + setIndication(INDICATION_ERR_FW_CHECKSUM); + OTA_DEBUG(PSTR("!OTA:FWP:CRC FAIL\n")); + } + } + // reset flags + _firmwareRetry = MY_OTA_RETRY + 1; + _firmwareLastRequest = 0; + } else { + OTA_DEBUG(PSTR("!OTA:FWP:NO UPDATE\n")); + } + return true; +} diff --git a/core/MyOTAFirmwareUpdate.h b/core/MyOTAFirmwareUpdate.h index 3e011df..321ffd3 100644 --- a/core/MyOTAFirmwareUpdate.h +++ b/core/MyOTAFirmwareUpdate.h @@ -58,17 +58,36 @@ #define MyOTAFirmwareUpdate_h #include "MySensorsCore.h" +#ifdef MCUBOOT_PRESENT +#include "generated_dts_board.h" +#define FIRMWARE_PROTOCOL_31 +#endif #define LOCAL static //!< static +#if MAX_PAYLOAD >= 22 #define FIRMWARE_BLOCK_SIZE (16u) //!< Size of each firmware block +#else +#define FIRMWARE_BLOCK_SIZE (8u) //!< Size of each firmware block +#ifndef FIRMWARE_PROTOCOL_31 +#define FIRMWARE_PROTOCOL_31 +#endif +#endif #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 +#ifndef MCUBOOT_PRESENT #define FIRMWARE_START_OFFSET (10u) //!< Start offset for firmware in flash (DualOptiboot wants to keeps a signature first) +#else +#define FIRMWARE_START_OFFSET (FLASH_AREA_IMAGE_1_OFFSET_0) //!< Use offset from generated_dts_board.h (mcuboot) +#endif #define MY_OTA_BOOTLOADER_MAJOR_VERSION (3u) //!< Bootloader version major +#ifdef FIRMWARE_PROTOCOL_31 +#define MY_OTA_BOOTLOADER_MINOR_VERSION (1u) //!< Bootloader version minor +#else #define MY_OTA_BOOTLOADER_MINOR_VERSION (0u) //!< Bootloader version minor +#endif #define MY_OTA_BOOTLOADER_VERSION (MY_OTA_BOOTLOADER_MINOR_VERSION * 256 + MY_OTA_BOOTLOADER_MAJOR_VERSION) //!< Bootloader version #if defined(MY_DEBUG_VERBOSE_OTA_UPDATE) @@ -77,6 +96,18 @@ #else #define OTA_DEBUG(x,...) //!< debug NULL #endif + +#if defined(DOXYGEN) && !defined(FIRMWARE_PROTOCOL_31) +/** + * @brief Enabled FOTA 3.1 protocol extensions + * + * Supports smaller FIRMWARE_BLOCK_SIZE, RLE and NVM for nRF5 with mcuboot. The + * extension is enabled per default when mcuboot is present or full FIRMWARE_BLOCK_SIZE + * exeeds MAX_PAYLOAD. + */ +#define FIRMWARE_PROTOCOL_31 +#endif + /** * @brief FW config structure, stored in eeprom */ @@ -96,6 +127,12 @@ typedef struct { uint16_t blocks; //!< Number of blocks uint16_t crc; //!< CRC of block data uint16_t BLVersion; //!< Bootloader version +#ifdef FIRMWARE_PROTOCOL_31 + uint8_t blockSize; //!< Blocksize, when protocol version >= 3.1 is reported. Otherwhise the blocksize is 16 + uint8_t img_commited; //!< mcuboot image_ok attribute commited firmware=0x01(mcuboot)|0x02(DualOptiboot), when protocol version >= 3.1 is reported + uint16_t img_revision; //!< mcuboot revision attribute, when protocol version >= 3.1 is reported + uint32_t img_build_num; //!< mcuboot build_num attribute, when protocol version >= 3.1 is reported +#endif } __attribute__((packed)) requestFirmwareConfig_t; /** @@ -117,6 +154,16 @@ typedef struct { uint8_t data[FIRMWARE_BLOCK_SIZE]; //!< Block data } __attribute__((packed)) replyFirmwareBlock_t; +/** +* @brief FW block reply structure (RLE) +*/ +typedef struct { + uint16_t type; //!< Type of config + uint16_t version; //!< Version of config + uint16_t block; //!< Block index + uint16_t number_of_blocks; //!< Number of blocks to fill with data + uint8_t data; //!< Block data +} __attribute__((packed)) replyFirmwareBlockRLE_t; /** * @brief Read firmware settings from EEPROM diff --git a/drivers/NRF5/Flash.cpp b/drivers/NRF5/Flash.cpp index 298f0f1..bc7720e 100644 --- a/drivers/NRF5/Flash.cpp +++ b/drivers/NRF5/Flash.cpp @@ -52,12 +52,14 @@ uint32_t *FlashClass::page_address(size_t page) uint32_t *FlashClass::top_app_page_address() { +#if !defined(MCUBOOT_PRESENT) // Bootcode at the top of the flash memory? // https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v12.0.0%2Flib_bootloader.html if (NRF_UICR->NRFFW[0]<0xFFFFFFFF) { // Return pointer calculated by SoftDevice/bootloader return (uint32_t *)NRF_UICR->NRFFW[0]; } +#endif // Return flash length return (uint32_t *)(Flash.page_count() << Flash.page_size_bits()); diff --git a/drivers/NVM/VirtualPage.cpp b/drivers/NVM/VirtualPage.cpp index 760120c..6eaeb7e 100644 --- a/drivers/NVM/VirtualPage.cpp +++ b/drivers/NVM/VirtualPage.cpp @@ -21,37 +21,45 @@ VirtualPageClass VirtualPage; -#ifndef VNM_VIRTUAL_PAGE_SIZE_BITS -#define VNM_VIRTUAL_PAGE_SIZE_BITS 12 -#elif VNM_VIRTUAL_PAGE_SIZE_BITS < 12 -#error "VNM_VIRTUAL_PAGE_SIZE_BITS must be >= 12" +#ifndef NVM_VIRTUAL_PAGE_SIZE_BITS +#define NVM_VIRTUAL_PAGE_SIZE_BITS 12 +#elif NVM_VIRTUAL_PAGE_SIZE_BITS < 12 +#error "NVM_VIRTUAL_PAGE_SIZE_BITS must be >= 12" +#endif + +// Calculate virtual page count, when mcuboot is present +#if defined(MCUBOOT_PRESENT) && !defined(NVM_VIRTUAL_PAGE_COUNT) +// mcuboot zephyr build via generated_dts_board.h +#include "generated_dts_board.h" +// Calculate number of free pages after scratch area +#define NVM_VIRTUAL_PAGE_COUNT (((CONFIG_FLASH_SIZE_0<<10)-(FLASH_AREA_IMAGE_SCRATCH_OFFSET_0+FLASH_AREA_IMAGE_SCRATCH_SIZE_0)) >> NVM_VIRTUAL_PAGE_SIZE_BITS) #endif // check page size -#ifndef VNM_VIRTUAL_PAGE_COUNT +#ifndef NVM_VIRTUAL_PAGE_COUNT #if FLASH_ERASE_CYCLES >= 20000 // use 16k of flash memory -#define VNM_VIRTUAL_PAGE_COUNT 4 +#define NVM_VIRTUAL_PAGE_COUNT 4 #else // use 32k of flash memory -#define VNM_VIRTUAL_PAGE_COUNT 8 +#define NVM_VIRTUAL_PAGE_COUNT 8 #endif #endif /* * How many virtual pages are skipped from top of flash */ -#ifndef VNM_VIRTUAL_PAGE_SKIP_FROM_TOP -#define VNM_VIRTUAL_PAGE_SKIP_FROM_TOP 0 +#ifndef NVM_VIRTUAL_PAGE_SKIP_FROM_TOP +#define NVM_VIRTUAL_PAGE_SKIP_FROM_TOP 0 #endif /* - * Calculate things around VNM_VIRTUAL_PAGE_SIZE + * Calculate things around NVM_VIRTUAL_PAGE_SIZE */ -#define VNM_VIRTUAL_PAGE_SIZE (1 << (VNM_VIRTUAL_PAGE_SIZE_BITS)) -#define VNM_VIRTUAL_PAGE_ADDRESS_MASK (~(VNM_VIRTUAL_PAGE_SIZE - 1)) -#define VNM_VIRTUAL_PAGE_ALIGN(address) \ - { address = (uint32_t *)((uint32_t)address & VNM_VIRTUAL_PAGE_ADDRESS_MASK); } +#define NVM_VIRTUAL_PAGE_SIZE (1 << (NVM_VIRTUAL_PAGE_SIZE_BITS)) +#define NVM_VIRTUAL_PAGE_ADDRESS_MASK (~(NVM_VIRTUAL_PAGE_SIZE - 1)) +#define NVM_VIRTUAL_PAGE_ALIGN(address) \ + { address = (uint32_t *)((uint32_t)address & NVM_VIRTUAL_PAGE_ADDRESS_MASK); } /* * Defines the position of status words in a page. @@ -79,8 +87,8 @@ VirtualPageClass VirtualPage; #define OFFSET_MAGIC 1 #define OFFSET_COUNTER 0 #define MASK_ERASE_COUNTER 0x00FFFFFF -#define OFFSET_STATUS_RELEASE_PREPARE VNM_VIRTUAL_PAGE_SIZE - 8 -#define OFFSET_STATUS_RELEASE_END VNM_VIRTUAL_PAGE_SIZE - 4 +#define OFFSET_STATUS_RELEASE_PREPARE NVM_VIRTUAL_PAGE_SIZE - 8 +#define OFFSET_STATUS_RELEASE_END NVM_VIRTUAL_PAGE_SIZE - 4 #define METADATA_SIZE 16 #define OFFSET_DATA 4 #endif @@ -88,45 +96,45 @@ VirtualPageClass VirtualPage; #define BIT_STATUS_RELEASE_PREPARE (1 << 30) #define BIT_STATUS_RELEASE_END (1 << 31) -#define VNM_VIRTUAL_PAGE_DATA_SIZE (VNM_VIRTUAL_PAGE_SIZE - METADATA_SIZE) +#define NVM_VIRTUAL_PAGE_DATA_SIZE (NVM_VIRTUAL_PAGE_SIZE - METADATA_SIZE) #else // use first 8 byte for magic and erase counter and last 8 byte for page release #define OFFSET_MAGIC 1 #define OFFSET_ERASE_COUNTER 0 #define OFFSET_DATA 2 #define OFFSET_STATUS_RELEASE_PREPARE \ - ((VNM_VIRTUAL_PAGE_SIZE - 8) / sizeof(uint32_t)) + ((NVM_VIRTUAL_PAGE_SIZE - 8) / sizeof(uint32_t)) #define OFFSET_STATUS_RELEASE_END \ - ((VNM_VIRTUAL_PAGE_SIZE - 4) / sizeof(uint32_t)) + ((NVM_VIRTUAL_PAGE_SIZE - 4) / sizeof(uint32_t)) #define MASK_ERASE_COUNTER 0xFFFFFFFF #define BIT_STATUS_RELEASE_PREPARE 1 #define BIT_STATUS_RELEASE_END 1 -#define VNM_VIRTUAL_PAGE_DATA_SIZE (VNM_VIRTUAL_PAGE_SIZE - 16) +#define NVM_VIRTUAL_PAGE_DATA_SIZE (NVM_VIRTUAL_PAGE_SIZE - 16) #endif uint16_t VirtualPageClass::size() const { - return (VNM_VIRTUAL_PAGE_DATA_SIZE); + return (NVM_VIRTUAL_PAGE_DATA_SIZE); } uint16_t VirtualPageClass::length() const { - return (VNM_VIRTUAL_PAGE_DATA_SIZE / 4); + return (NVM_VIRTUAL_PAGE_DATA_SIZE / 4); } uint16_t VirtualPageClass::page_count() const { - return (VNM_VIRTUAL_PAGE_COUNT - 1); + return (NVM_VIRTUAL_PAGE_COUNT - 1); } uint32_t VirtualPageClass::wear_level() { uint32_t max_erase_cycles = 0; - for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) { + for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) { uint32_t erase_cycles = get_page_erase_cycles(get_page_address(i)); if (erase_cycles > max_erase_cycles) { max_erase_cycles = erase_cycles; @@ -140,7 +148,7 @@ uint32_t *VirtualPageClass::get(uint32_t magic) { // Give back a page prepared for release and not closed - for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) { + for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) { uint32_t *page = get_page_address(i); if ( // correct magic is set @@ -156,7 +164,7 @@ uint32_t *VirtualPageClass::get(uint32_t magic) } // check if a unreleased page is available - for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) { + for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) { uint32_t *page = get_page_address(i); if ( // correct magic is set @@ -177,7 +185,7 @@ uint32_t *VirtualPageClass::allocate(uint32_t magic) uint32_t max_erase_cycles = (uint32_t)~0; // Avoid duplicate allocation of pages, look for the less used page - for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) { + for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) { uint32_t *page = get_page_address(i); // Delete duplicated pages @@ -225,7 +233,7 @@ uint32_t *VirtualPageClass::allocate(uint32_t magic, uint32_t max_writes) void VirtualPageClass::release_prepare(uint32_t *address) { // move pointer to beginning of the page - VNM_VIRTUAL_PAGE_ALIGN(address); + NVM_VIRTUAL_PAGE_ALIGN(address); // Nothing to do at a empty page if (address[OFFSET_MAGIC] == (uint32_t)~0) { @@ -244,7 +252,7 @@ void VirtualPageClass::release_prepare(uint32_t *address) void VirtualPageClass::release(uint32_t *address) { // move pointer to beginning of the page - VNM_VIRTUAL_PAGE_ALIGN(address); + NVM_VIRTUAL_PAGE_ALIGN(address); // Nothing to do at a empty page if (address[OFFSET_MAGIC] == (uint32_t)~0) { @@ -263,7 +271,7 @@ void VirtualPageClass::release(uint32_t *address) bool VirtualPageClass::release_started(uint32_t *address) { // move pointer to beginning of the page - VNM_VIRTUAL_PAGE_ALIGN(address); + NVM_VIRTUAL_PAGE_ALIGN(address); return (address[OFFSET_STATUS_RELEASE_PREPARE] & BIT_STATUS_RELEASE_PREPARE) == 0; @@ -272,7 +280,7 @@ bool VirtualPageClass::release_started(uint32_t *address) void VirtualPageClass::fail(uint32_t *address) { // move pointer to beginning of the page - VNM_VIRTUAL_PAGE_ALIGN(address); + NVM_VIRTUAL_PAGE_ALIGN(address); build_page(address, 0x00000000); return; @@ -281,7 +289,7 @@ void VirtualPageClass::fail(uint32_t *address) void VirtualPageClass::clean_up() { // No page found -> try to give back a page prepared for release - for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) { + for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) { uint32_t *page = get_page_address(i); if ((page[OFFSET_STATUS_RELEASE_END] & BIT_STATUS_RELEASE_END) == 0) { build_page(get_page_address(i), ~0); @@ -292,7 +300,7 @@ void VirtualPageClass::clean_up() void VirtualPageClass::format() { - for (int i = 1; i <= VNM_VIRTUAL_PAGE_COUNT; i++) { + for (int i = 1; i <= NVM_VIRTUAL_PAGE_COUNT; i++) { uint32_t *address = get_page_address(i); build_page(address, (uint32_t)~0); } @@ -301,25 +309,25 @@ void VirtualPageClass::format() uint32_t *VirtualPageClass::get_page_address(uint16_t page) { return (uint32_t *)(Flash.top_app_page_address() - - ((page + VNM_VIRTUAL_PAGE_SKIP_FROM_TOP) - << VNM_VIRTUAL_PAGE_SIZE_BITS)); + ((page + NVM_VIRTUAL_PAGE_SKIP_FROM_TOP) + << NVM_VIRTUAL_PAGE_SIZE_BITS)); } void VirtualPageClass::build_page(uint32_t *address, uint32_t magic) { // move pointer to beginning of the page - VNM_VIRTUAL_PAGE_ALIGN(address); + NVM_VIRTUAL_PAGE_ALIGN(address); // get erase counter uint32_t erase_counter = get_page_erase_cycles(address); // Check if a magic is set if (address[OFFSET_MAGIC] != (uint32_t)~0) { - Flash.erase(address, VNM_VIRTUAL_PAGE_SIZE); + Flash.erase(address, NVM_VIRTUAL_PAGE_SIZE); } else { // check if page is empty - for (int i = OFFSET_DATA; i < (VNM_VIRTUAL_PAGE_SIZE / 4); i++) { + for (int i = OFFSET_DATA; i < (NVM_VIRTUAL_PAGE_SIZE / 4); i++) { if (address[i] != (uint32_t)~0) { - Flash.erase(address, VNM_VIRTUAL_PAGE_SIZE); + Flash.erase(address, NVM_VIRTUAL_PAGE_SIZE); break; } } diff --git a/examples/SecurityPersonalizer/SecurityPersonalizer.ino b/examples/SecurityPersonalizer/SecurityPersonalizer.ino index 58ae759..17eeac5 100644 --- a/examples/SecurityPersonalizer/SecurityPersonalizer.ino +++ b/examples/SecurityPersonalizer/SecurityPersonalizer.ino @@ -234,6 +234,10 @@ #define GENERATE_SOMETHING #endif +#if defined(MY_LOCK_MCU) +#undefine MY_LOCK_MCU // The Sketch after SecurityPersonaliter should lock the MCU +#endif + /********************************** Preprocessor sanitychecks *************************************/ #if defined(GENERATE_SOFT_SERIAL) && !defined(USE_SOFT_SIGNING) #error Cannot generate soft serial using ATSHA204A, use USE_SOFT_SINGING for this diff --git a/hal/architecture/NRF5/MyHwNRF5.cpp b/hal/architecture/NRF5/MyHwNRF5.cpp index b1b7dc7..921bbf8 100644 --- a/hal/architecture/NRF5/MyHwNRF5.cpp +++ b/hal/architecture/NRF5/MyHwNRF5.cpp @@ -66,6 +66,31 @@ void hwWriteConfig(int adr, uint8_t value) bool hwInit() { +#ifdef MY_LOCK_MCU +#ifdef NRF51 + // Lock MCU + if((uint32_t)((NRF_UICR->RBPCONF & UICR_RBPCONF_PALL_Msk) >> UICR_RBPCONF_PALL_Pos) != + UICR_RBPCONF_PALL_Enabled) { + Flash.write((uint32_t *)&NRF_UICR->RBPCONF, (NRF_UICR->RBPCONF & ~UICR_RBPCONF_PALL_Msk)); + hwReboot(); + } +#else + // Lock MCU + if((uint32_t)((NRF_UICR->APPROTECT & UICR_APPROTECT_PALL_Msk) >> UICR_APPROTECT_PALL_Pos) != + UICR_APPROTECT_PALL_Enabled) { + Flash.write((uint32_t *)&NRF_UICR->APPROTECT, (NRF_UICR->APPROTECT & ~UICR_APPROTECT_PALL_Msk)); + hwReboot(); + } +#endif +#endif + +#if defined(NRF51) && defined(CONFIG_ENABLE_PINRESET) + // Enabling reset for NRF51 isn't handled by arduino-nrf5. Enable it, if requested. + NRF_POWER->RESET = POWER_RESET_RESET_Enabled; + NRF_POWER->RAMON |= (POWER_RAMON_ONRAM0_RAM0On << POWER_RAMON_ONRAM0_Pos) | + (POWER_RAMON_ONRAM1_RAM1On << POWER_RAMON_ONRAM1_Pos); +#endif + // Clock is manged by sleep modes. Radio depends on HFCLK. // Force to start HFCLK NRF_CLOCK->EVENTS_HFCLKSTARTED = 0; From c805f77f202cfc290a2f00bf8df16943f67fbdaf Mon Sep 17 00:00:00 2001 From: tekka Date: Thu, 1 Mar 2018 20:27:07 +0100 Subject: [PATCH 20/60] AVR: Fix OTA logging (#1074) --- core/MyOTALogging.cpp | 9 --------- examples/LogOTANode/LogOTANode.ino | 8 ++++---- hal/architecture/SAMD/MyHwSAMD.h | 1 + 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/core/MyOTALogging.cpp b/core/MyOTALogging.cpp index 179934d..693290f 100644 --- a/core/MyOTALogging.cpp +++ b/core/MyOTALogging.cpp @@ -36,11 +36,7 @@ void OTALog(uint8_t logNode, bool enableAck, const char *fmt, ... ) // create message va_start (args, fmt ); -#ifdef vsnprintf_P int n = vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args); -#else - int n = vsnprintf(fmtBuffer, sizeof(fmtBuffer), fmt, args); -#endif va_end (args); // Check number of chars @@ -92,14 +88,9 @@ void OTALogPrintPrefix() { char prefix[37]; // prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE) -#ifdef snprintf_P snprintf_P(prefix, sizeof(prefix), PSTR("%" PRId8 ";%" PRId8 ";%" PRId8 ";0;%" PRId8 ";%" PRIu32 " "), OTALogBufferNode, OTALogBufferSensor, C_INTERNAL, I_LOG_MESSAGE, hwMillis()); -#else - snprintf(prefix, sizeof(prefix), PSTR("%" PRId8 ";%" PRId8 ";%" PRId8 ";0;%" PRId8 ";%" PRIu32 " "), - OTALogBufferNode, OTALogBufferSensor, C_INTERNAL, I_LOG_MESSAGE, hwMillis()); -#endif MY_SERIALDEVICE.print(prefix); } diff --git a/examples/LogOTANode/LogOTANode.ino b/examples/LogOTANode/LogOTANode.ino index 891cd54..aaf1384 100644 --- a/examples/LogOTANode/LogOTANode.ino +++ b/examples/LogOTANode/LogOTANode.ino @@ -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-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -67,8 +67,8 @@ void loop() c++; // A debug message - DEBUG_OUTPUT(PSTR("DEBUG\nc=%" PRId16 "\nmillis=" PRId32 "\n"), c, hwMillis()); + DEBUG_OUTPUT(PSTR("DEBUG\nc=%" PRId16 "\nmillis=%" PRId32 "\n"), c, hwMillis()); // Send a log message with ACK to a node - OTALog(0, true, PSTR("LOG\nc=%" PRId16 "\nmillis=" PRId32 "\n"), c, hwMillis()); -} + OTALog(0, true, PSTR("LOG\nc=%" PRId16 "\nmillis=%" PRId32 "\n"), c, hwMillis()); +} \ No newline at end of file diff --git a/hal/architecture/SAMD/MyHwSAMD.h b/hal/architecture/SAMD/MyHwSAMD.h index a567092..178ec10 100644 --- a/hal/architecture/SAMD/MyHwSAMD.h +++ b/hal/architecture/SAMD/MyHwSAMD.h @@ -40,6 +40,7 @@ extEEPROM eep(MY_EXT_EEPROM_SIZE, 1, MY_EXT_EEPROM_PAGE_SIZE, #define MIN(a,b) min(a,b) #define MAX(a,b) max(a,b) #define snprintf_P(s, f, ...) snprintf((s), (f), __VA_ARGS__) +#define vsnprintf_P(s, n, f, ...) vsnprintf((s), (n), (f), __VA_ARGS__) // Define these as macros to save valuable space #define hwDigitalWrite(__pin, __value) digitalWrite(__pin, __value) From eb839464b8e17f91de7ccbdba72f12e57af9a456 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sun, 4 Mar 2018 17:49:51 +0100 Subject: [PATCH 21/60] Development version 2.3.0-alpha (#1073) --- README.md | 2 +- core/Version.h | 4 ++-- library.json | 2 +- library.properties | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b86fa20..3f4c23a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -MySensors Library v2.2.1-alpha +MySensors Library v2.3.0-alpha Please visit www.mysensors.org for more information diff --git a/core/Version.h b/core/Version.h index 12b135b..ed4712a 100644 --- a/core/Version.h +++ b/core/Version.h @@ -47,8 +47,8 @@ #define STR(x) STR_HELPER(x) //!< Helper macro, STR() #define MYSENSORS_LIBRARY_VERSION_MAJOR 2 //!< Major release version -#define MYSENSORS_LIBRARY_VERSION_MINOR 2 //!< Minor release version -#define MYSENSORS_LIBRARY_VERSION_PATCH 1 //!< Patch version +#define MYSENSORS_LIBRARY_VERSION_MINOR 3 //!< Minor release version +#define MYSENSORS_LIBRARY_VERSION_PATCH 0 //!< Patch version #define MYSENSORS_LIBRARY_VERSION_PRERELEASE "alpha" //!< Pre-release suffix, i.e. alpha, beta, rc.1, etc #define MYSENSORS_LIBRARY_VERSION_PRERELEASE_NUMBER 0x00 //!< incremental counter, starting at 0x00. 0xFF for final release diff --git a/library.json b/library.json index 0f1bdb9..5405a46 100644 --- a/library.json +++ b/library.json @@ -7,7 +7,7 @@ "type": "git", "url": "https://github.com/mysensors/MySensors.git" }, - "version": "2.2.1-alpha", + "version": "2.3.0-alpha", "frameworks": "arduino", "platforms": [ "atmelavr", diff --git a/library.properties b/library.properties index 6f210d4..89857a5 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=MySensors -version=2.2.1-alpha +version=2.3.0-alpha author=The MySensors Team maintainer=The MySensors Team sentence=Home Automation Framework From 3f2d2921428ef2a4cdfe94217d7fad7e04928fce Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Tue, 6 Mar 2018 17:32:54 +0100 Subject: [PATCH 22/60] Add git commit message hook to the mystools bundle (#1067) The message hook validates that the c ommit message follows the MySensors requirements. More specifically, it checks that - Commit message does not exceed a line length of 72 characters - Commit title start with an uppercase character - Commit title does not end with a period ('.') Fixes #672 --- .mystools/hooks/commit-msg.sh | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .mystools/hooks/commit-msg.sh diff --git a/.mystools/hooks/commit-msg.sh b/.mystools/hooks/commit-msg.sh new file mode 100644 index 0000000..4b5f780 --- /dev/null +++ b/.mystools/hooks/commit-msg.sh @@ -0,0 +1,23 @@ +#!/bin/bash +too_long_lines=$(awk 'length>72' $1) +if [[ ! -z $too_long_lines ]]; then + echo "Too long commit message lines:" $too_long_lines + has_failed=1 +fi + +leading_lowercases=$(awk 'NR==1' $1 | awk '/^[[:lower:][:punct:]]/') +if [[ ! -z $leading_lowercases ]]; then + echo "Leading lowercase in subject:" $leading_lowercases + has_failed=1 +fi + +trailing_periods=$(awk 'NR==1' $1 | awk '/(\.)$/') +if [[ ! -z $trailing_periods ]]; then + echo "Trailing periods in subject:" $trailing_periods + has_failed=1 +fi + +if [[ ! -z $has_failed ]]; then + echo "Please recommit with a new commit message." + exit 1 +fi From 3d093e6beda34feb2f931e22212100e6ad0a2d90 Mon Sep 17 00:00:00 2001 From: kvoit Date: Thu, 8 Mar 2018 17:56:22 +0100 Subject: [PATCH 23/60] Fix default IRQ pins on ESP8266 that prevent MCU from boot (#1076) * Derive default interrupt from configured instead of default pin Derive DEFAULT_RFM69_IRQ_NUM from MY_RFM69_IRQ_PIN instead of DEFAULT_RFM69_IRQ_PIN so that _NUM does not have to be defined if _PIN is redefined * Change default IRQ pin for RFM69/95 on ESP8266 to GPIO5=D1 The originally defined pin GPIO2 prevent ESP8266 from booting, since it has to be pulled high for booting and DIO0 from the RFM69 is defaul low. For this reason, it is improbably that anyone is using the default and would be affected by this change. --- drivers/RFM69/new/RFM69_new.h | 2 +- drivers/RFM69/old/RFM69_old.h | 10 +++++----- drivers/RFM95/RFM95.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/RFM69/new/RFM69_new.h b/drivers/RFM69/new/RFM69_new.h index 8503d71..5b74c38 100644 --- a/drivers/RFM69/new/RFM69_new.h +++ b/drivers/RFM69/new/RFM69_new.h @@ -78,7 +78,7 @@ #define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN #endif #elif defined(ARDUINO_ARCH_ESP8266) -#define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN +#define DEFAULT_RFM69_IRQ_PIN (5) //!< DEFAULT_RFM69_IRQ_PIN #elif defined(ARDUINO_ARCH_ESP32) #warning not implemented yet #elif defined(ARDUINO_ARCH_SAMD) diff --git a/drivers/RFM69/old/RFM69_old.h b/drivers/RFM69/old/RFM69_old.h index 3129b65..42a1aaa 100644 --- a/drivers/RFM69/old/RFM69_old.h +++ b/drivers/RFM69/old/RFM69_old.h @@ -41,15 +41,15 @@ #else #define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN #endif -#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM +#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(MY_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM #elif defined(ARDUINO_ARCH_ESP8266) -#define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN -#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM +#define DEFAULT_RFM69_IRQ_PIN (5) //!< DEFAULT_RFM69_IRQ_PIN +#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(MY_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM #elif defined(ARDUINO_ARCH_ESP32) #warning not implemented yet #elif defined(ARDUINO_ARCH_SAMD) #define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN -#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM +#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(MY_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM #elif defined(LINUX_ARCH_RASPBERRYPI) #define DEFAULT_RFM69_IRQ_PIN (22) //!< DEFAULT_RFM69_IRQ_PIN #define DEFAULT_RFM69_IRQ_NUM DEFAULT_RFM69_IRQ_PIN //!< DEFAULT_RFM69_IRQ_NUM @@ -58,7 +58,7 @@ #define DEFAULT_RFM69_IRQ_NUM DEFAULT_RFM69_IRQ_PIN //!< DEFAULT_RFM69_IRQ_NUM #elif defined(TEENSYDUINO) #define DEFAULT_RFM69_IRQ_PIN (8) //!< DEFAULT_RFM69_IRQ_PIN -#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM +#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(MY_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM #else #define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN #define DEFAULT_RFM69_IRQ_NUM (2) //!< DEFAULT_RFM69_IRQ_NUM diff --git a/drivers/RFM95/RFM95.h b/drivers/RFM95/RFM95.h index ab34832..a302ac6 100644 --- a/drivers/RFM95/RFM95.h +++ b/drivers/RFM95/RFM95.h @@ -89,7 +89,7 @@ #define DEFAULT_RFM95_IRQ_PIN (2) //!< DEFAULT_RFM95_IRQ_PIN #endif #elif defined(ARDUINO_ARCH_ESP8266) -#define DEFAULT_RFM95_IRQ_PIN (2) //!< DEFAULT_RFM95_IRQ_PIN +#define DEFAULT_RFM95_IRQ_PIN (5) //!< DEFAULT_RFM95_IRQ_PIN #elif defined(ARDUINO_ARCH_ESP32) #warning not implemented yet #elif defined(ARDUINO_ARCH_SAMD) From 7a33082eaf506c12cec03be85e6d4a9cf02849a7 Mon Sep 17 00:00:00 2001 From: Mikael Falkvidd Date: Mon, 12 Mar 2018 11:47:39 +0100 Subject: [PATCH 24/60] Simplify doxygen for ./configure (#1080) No need to grep when we have a command that outputs exactly what we want. --- Documentation/doxygen.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/doxygen.sh b/Documentation/doxygen.sh index 36bf079..8fcf4de 100755 --- a/Documentation/doxygen.sh +++ b/Documentation/doxygen.sh @@ -3,8 +3,8 @@ # Generate doxygen file for Raspberry Pi configure command echo -e "/**\n * @defgroup RaspberryPiGateway Raspberry Pi Gateway\n * @ingroup MyConfigGrp\n * @brief Configuration options for the Raspberry Pi Gateway\n@{\n@verbatim" > configure.h - grep -A999 '<> configure.h - echo -e "@endverbatim\n@}*/\n" >> configure.h +./configure --help >> configure.h +echo -e "@endverbatim\n@}*/\n" >> configure.h # Generate version information export PROJECTNUMBER=$(git fetch --tags; git describe --tags;) From c9c461846a8ce771eacca8976ce26cfce5a3c8e6 Mon Sep 17 00:00:00 2001 From: Mikael Falkvidd Date: Wed, 21 Mar 2018 15:08:02 +0100 Subject: [PATCH 25/60] Add missing keywords (#1084) A blacklist is available at the end of keywords.txt I decided to blacklist all the LINUX keywords. I guess people could use the Arduino IDE to edit the sketch for the raspberry pi gateway, but I'm not sure we should encourage that. I'll add gitler support for auto-detecting missing keywords in a separate PR. --- keywords.txt | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/keywords.txt b/keywords.txt index a7fdf1a..473c5da 100644 --- a/keywords.txt +++ b/keywords.txt @@ -37,6 +37,10 @@ MY_BAUD_RATE LITERAL1 MY_CRITICAL_SECTION LITERAL1 MY_RX_MESSAGE_BUFFER_SIZE LITERAL1 MY_RX_MESSAGE_BUFFER_FEATURE LITERAL1 +MY_DISABLED_SERIAL LITERAL1 +MY_SPLASH_SCREEN_DISABLED LITERAL1 +MY_INDICATION_HANDLER LITERAL1 +MY_DISABLE_RAM_ROUTING_TABLE_FEATURE LITERAL1 # transport AUTO LITERAL1 @@ -51,8 +55,10 @@ MY_CORE_COMPATIBILITY_CHECK LITERAL1 MY_TRANSPORT_SANITY_CHECK LITERAL1 MY_TRANSPORT_SANITY_CHECK_INTERVAL LITERAL1 MY_TRANSPORT_WAIT_READY_MS LITERAL1 +MY_TRANSPORT_UPLINK_CHECK_DISABLED LITERAL1 MY_REPEATER_FEATURE LITERAL1 MY_PASSIVE_NODE LITERAL1 +MY_SIGNAL_REPORT_ENABLED LITERAL1 # debug MY_DEBUG LITERAL1 @@ -60,6 +66,7 @@ MY_DEBUGDEVICE LITERAL1 MY_DEBUG_OTA LITERAL1 MY_DEBUG_OTA_DISABLE_ACK LITERAL1 MY_SPECIAL_DEBUG LITERAL1 +MY_DEBUG_VERBOSE_GATEWAY LITERAL1 # OTA MY_OTA_FIRMWARE_FEATURE LITERAL1 @@ -77,10 +84,12 @@ MY_INCLUSION_MODE_FEATURE LITERAL1 MY_INCLUSION_BUTTON_FEATURE LITERAL1 MY_INCLUSION_MODE_BUTTON_PIN LITERAL1 MY_INCLUSION_MODE_DURATION LITERAL1 +MY_INCLUSION_LED_PIN LITERAL1 MY_OTA_LOG_RECEIVER_FEATURE LITERAL1 MY_OTA_LOG_SENDER_FEATURE LITERAL1 MY_DEBUG_OTA LITERAL1 MY_DEBUG_OTA_DISABLE_ACK LITERAL1 +MY_OTA_USE_I2C_EEPROM LITERAL1 # Signing MY_DEBUG_VERBOSE_SIGNING LITERAL1 @@ -121,6 +130,7 @@ MY_RF24_PA_LEVEL LITERAL1 MY_RF24_CHANNEL LITERAL1 MY_RF24_DATARATE LITERAL1 MY_RF24_BASE_RADIO_ID LITERAL1 +MY_RF24_POWER_PIN LITERAL1 # NRF5 MY_RADIO_NRF5_ESB LITERAL1 @@ -132,6 +142,8 @@ MY_NRF5_ESB_ENABLE_ENCRYPTION LITERAL1 MY_NRF5_ESB_MODE LITERAL1 MY_NRF5_ESB_PA_LEVEL LITERAL1 MY_NRF5_ESB_RX_BUFFER_SIZE LITERAL1 +MY_NRF5_ESB_REVERSE_ACK_RX LITERAL1 +MY_NRF5_ESB_REVERSE_ACK_TX LITERAL1 # RFM95 MY_RADIO_RFM95 LITERAL1 @@ -148,6 +160,8 @@ MY_RFM95_ATC_TARGET_RSSI LITERAL1 MY_RFM95_ATC_MODE_DISABLED LITERAL1 MY_RFM95_ATC_TARGET_RSSI_DBM LITERAL1 MY_RFM95_MAX_POWER_LEVEL_DBM LITERAL1 +MY_RFM95_POWER_PIN LITERAL1 +MY_RFM95_TCXO LITERAL1 # RFM69 MY_RADIO_RFM69 LITERAL1 @@ -174,6 +188,8 @@ MY_RFM69_BITRATE_MSB LITERAL1 MY_RFM69_BITRATE_LSB LITERAL1 MY_RFM69_CSMA_ADD_DELAY_BASE LITERAL1 MY_RFM69_CSMA_ADD_DELAY_COUNT LITERAL1 +MY_RFM69_POWER_PIN LITERAL1 +MY_RFM69_MODEM_CONFIGURATION LITERAL1 # RS485 MY_RS485 LITERAL1 @@ -194,6 +210,7 @@ MY_MQTT_SUBSCRIBE_TOPIC_PREFIX LITERAL1 MY_MQTT_PUBLISH_TOPIC_PREFIX LITERAL1 MY_MQTT_CLIENT_ID LITERAL1 MY_GATEWAY_MQTT_CLIENT LITERAL1 +MY_MQTT_CLIENT_PUBLISH_RETAIN LITERAL1 # Ethernet MY_PORT LITERAL1 @@ -215,3 +232,15 @@ MY_ESP8266_PASSWORD LITERAL1 MY_ESP8266_BSSID LITERAL1 MY_ESP8266_HOSTNAME LITERAL1 MY_ESP8266_SERIAL_MODE LITERAL1 + +# Blacklist - autodefines that are used internally and should not be highlighted, hence commented. +# MY_SIGNING_FEATURE +# MY_ENCRYPTION_FEATURE +# MY_LOCK_DEVICE +# MY_LINUX_SERIAL_PORT +# MY_LINUX_SERIAL_IS_PTY +# MY_LINUX_SERIAL_GROUPNAME +# MY_LINUX_SERIAL_PTY +# MY_LINUX_IS_SERIAL_PTY +# MY_GATEWAY_LINUX + From 06f8d2b7e5dc3cc6d9f41c23a6ebf456fd6cd6bb Mon Sep 17 00:00:00 2001 From: Mikael Falkvidd Date: Thu, 22 Mar 2018 08:26:27 +0100 Subject: [PATCH 26/60] Add detection of missing keywords to gitler (#1085) --- .ci/gitler.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.ci/gitler.sh b/.ci/gitler.sh index 5d815e6..9c5a78d 100755 --- a/.ci/gitler.sh +++ b/.ci/gitler.sh @@ -8,6 +8,7 @@ echo "No subjects are of invalid size
" > too_long_subjects.txt echo "No subjects with leading lower case characters
" > leading_lowercases.txt echo "No subjects with trailing periods
" > trailing_periods.txt echo "No body lines are too wide
" > too_long_body_lines.txt +echo "No keywords are missing in keywords.txt
" > missing_keywords.txt too_long_subjects=`awk 'length > 72' subjects.txt` if [ -n "$too_long_subjects" ]; then @@ -39,8 +40,17 @@ if [ -n "$too_long_body_lines" ]; then result=1 fi +missing_keywords=$(for keyword in $(grep -A999 '#if DOXYGEN' MyConfig.h | grep -B999 '#endif' | grep '#define' | awk '{ print $2 '} | grep -e '^MY_'); do grep -q $keyword keywords.txt || echo $keyword; done) +if [ -n "$missing_keywords" ]; then + echo "Keywords that are missing from keywords.txt:" > missing_keywords.txt + echo "$missing_keywords" >> missing_keywords.txt + sed -i -e 's/$/
/' missing_keywords.txt + result=1 +fi + + printf "%s" "" > gitler.html -awk 'FNR==1{print "
"}1' too_long_subjects.txt leading_lowercases.txt trailing_periods.txt too_long_body_lines.txt >> gitler.html +awk 'FNR==1{print "
"}1' too_long_subjects.txt leading_lowercases.txt trailing_periods.txt too_long_body_lines.txt missing_keywords.txt >> gitler.html echo "
" >> gitler.html if [ $result -ne 0 ]; then echo "You should follow this guide when writing your commit messages.
" >> gitler.html From 2175c993ef81b78527c85649f5bdc3585d2f41b2 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Fri, 23 Mar 2018 07:00:34 -0300 Subject: [PATCH 27/60] Linux: Use config file for gateway settings (#1061) - The following settings can be use on the config file: - verbose=[debug,info,notice,warn,err] - Logging verbosity. - log_file[0|1] - Enable logging to a file. - log_filepath=(FILE) - Log file path. - log_pipe=[0|1] - Enable logging to a named pipe(aka fifo). Use this option to view your gateway's log messages from the log_pipe_file (defined below). To do so, run the following command on another terminal: - $ cat "log_pipe_file" - log_pipe_file=(FILE) - syslog=[0|1] - Enable logging to syslog. - eeprom_file=[/etc/mysensors.eeprom] - eeprom_size=[1024] - Change some mysgw parameters: - Added: - -q, --quiet: for quiet mode, disable log messages written to the terminal. - Removed: - -d, --debug: removed, log messages are now enabled by default. - Replaced: - -b, --background: replaced by --daemon - isatty() is no longer used, log messages by default are printed to stderr unless the gateway is started with --quiet (#1022) - MY_LINUX_CONFIG_FILE: no longer holds the path to the eeprom file, but to the configuration file --- MyConfig.h | 2 +- configure | 2 +- drivers/Linux/SoftEeprom.cpp | 106 ++++--- drivers/Linux/SoftEeprom.h | 17 +- drivers/Linux/config.c | 249 +++++++++++++++ drivers/Linux/config.h | 45 +++ drivers/Linux/log.c | 287 +++++++++++++----- drivers/Linux/log.h | 39 ++- examples_linux/mysgw.cpp | 4 +- hal/architecture/Linux/MyHwLinuxGeneric.cpp | 9 +- hal/architecture/Linux/MyHwLinuxGeneric.h | 2 +- hal/architecture/Linux/MyMainLinuxGeneric.cpp | 91 +++--- initscripts/mysgw.systemd | 2 +- initscripts/mysgw.sysvinit | 2 +- 14 files changed, 681 insertions(+), 176 deletions(-) create mode 100644 drivers/Linux/config.c create mode 100644 drivers/Linux/config.h diff --git a/MyConfig.h b/MyConfig.h index 387d0c6..ce73dea 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -1873,7 +1873,7 @@ * @note 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" +#define MY_LINUX_CONFIG_FILE "/etc/mysensors.conf" #endif /** @}*/ // End of LinuxSettingGrpPub group /** @}*/ // End of PlatformSettingGrpPub group diff --git a/configure b/configure index 77df143..c03f3b2 100755 --- a/configure +++ b/configure @@ -37,7 +37,7 @@ 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-config-file= Config file path. [/etc/mysensors.conf] --my-gateway=[none|ethernet|serial|mqtt] Set the protocol used to communicate with the controller. [ethernet] --my-node-id= Disable gateway feature and run as a node with the specified id. diff --git a/drivers/Linux/SoftEeprom.cpp b/drivers/Linux/SoftEeprom.cpp index 4c04f5d..ac00553 100644 --- a/drivers/Linux/SoftEeprom.cpp +++ b/drivers/Linux/SoftEeprom.cpp @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2017 Sensnology AB + * Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -26,46 +26,8 @@ #include "log.h" #include "SoftEeprom.h" -SoftEeprom::SoftEeprom(const char *fileName, size_t length) +SoftEeprom::SoftEeprom() : _length(0), _fileName(NULL), _values(NULL) { - struct stat fileInfo; - - _fileName = strdup(fileName); - if (_fileName == NULL) { - logError("Error: %s\n", strerror(errno)); - 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. - 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) { - 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) { - 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) { - logError("Unable to open config to file %s for reading.\n", _fileName); - exit(1); - } - myFile.read((char*)_values, _length); - myFile.close(); - } } SoftEeprom::SoftEeprom(const SoftEeprom& other) @@ -81,8 +43,63 @@ SoftEeprom::SoftEeprom(const SoftEeprom& other) SoftEeprom::~SoftEeprom() { - delete[] _values; - free(_fileName); + destroy(); +} + +int SoftEeprom::init(const char *fileName, size_t length) +{ + struct stat fileInfo; + + destroy(); + + _fileName = strdup(fileName); + if (_fileName == NULL) { + logError("Error: %s\n", strerror(errno)); + return -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. + logInfo("EEPROM file %s does not exist, creating new file.\n", _fileName); + std::ofstream myFile(_fileName, std::ios::out | std::ios::binary); + if (!myFile) { + logError("Unable to create config file %s.\n", _fileName); + return -1; + } + myFile.write((const char*)_values, _length); + myFile.close(); + } else if (fileInfo.st_size < 0 || (size_t)fileInfo.st_size != _length) { + logError("EEPROM file %s is not the correct size of %zu. Please remove the file and a new one will be created.\n", + _fileName, _length); + return -1; + } else { + //Read config into local memory. + std::ifstream myFile(_fileName, std::ios::in | std::ios::binary); + if (!myFile) { + logError("Unable to open EEPROM file %s for reading.\n", _fileName); + return -1; + } + myFile.read((char*)_values, _length); + myFile.close(); + } + + return 0; +} + +void SoftEeprom::destroy() +{ + if (_values) { + delete[] _values; + } + if (_fileName) { + free(_fileName); + } } void SoftEeprom::readBlock(void* buf, void* addr, size_t length) @@ -90,7 +107,7 @@ 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) { + if (!config_to_mem && length) { //Read config into local memory. std::ifstream myFile(_fileName, std::ios::in | std::ios::binary); if (!myFile) { @@ -144,6 +161,9 @@ void SoftEeprom::writeByte(int addr, uint8_t value) SoftEeprom& SoftEeprom::operator=(const SoftEeprom& other) { if (this != &other) { + delete[] _values; + free(_fileName); + _fileName = strdup(other._fileName); _length = other._length; diff --git a/drivers/Linux/SoftEeprom.h b/drivers/Linux/SoftEeprom.h index 6b24318..806bb0a 100644 --- a/drivers/Linux/SoftEeprom.h +++ b/drivers/Linux/SoftEeprom.h @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2017 Sensnology AB + * Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -37,7 +37,7 @@ public: /** * @brief SoftEeprom constructor. */ - SoftEeprom(const char *fileName, size_t length); + SoftEeprom(); /** * @brief SoftEeprom copy constructor. */ @@ -46,6 +46,19 @@ public: * @brief SoftEeprom destructor. */ ~SoftEeprom(); + /** + * @brief Initializes the eeprom class. + * + * @param fileName filepath where the data is saved. + * @param length eeprom size in bytes. + * @return 0 if SUCCESS or -1 if FAILURE. + */ + int init(const char *fileName, size_t length); + /** + * @brief Clear all allocated memory variables. + * + */ + void destroy(); /** * @brief Read a block of bytes from eeprom. * diff --git a/drivers/Linux/config.c b/drivers/Linux/config.c new file mode 100644 index 0000000..db0b7dd --- /dev/null +++ b/drivers/Linux/config.c @@ -0,0 +1,249 @@ +/* + * 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-2018 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 mosquitto project, Copyright (c) 2012 Roger Light + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include "log.h" + +static int _config_create(const char *config_file); +static int _config_parse_int(char *token, const char *name, int *value); +static int _config_parse_string(char *token, const char *name, char **value); + +int config_parse(const char *config_file) +{ + FILE *fptr; + char buf[1024]; + struct stat fileInfo; + + if (stat(config_file, &fileInfo) != 0) { + //File does not exist. Create it. + logInfo("Config file %s does not exist, creating new file.\n", config_file); + _config_create(config_file); + } + + fptr = fopen(config_file, "rt"); + if (!fptr) { + logError("Error opening config file \"%s\".\n", config_file); + return -1; + } + + conf.verbose = 4; + conf.log_pipe = 0; + conf.log_pipe_file = NULL; + conf.syslog = 0; + conf.eeprom_file = NULL; + conf.eeprom_size = 1024; + + while (fgets(buf, 1024, fptr)) { + if (buf[0] != '#' && buf[0] != 10 && buf[0] != 13) { + while (buf[strlen(buf)-1] == 10 || buf[strlen(buf)-1] == 13) { + buf[strlen(buf)-1] = 0; + } + + if (!strncmp(buf, "verbose=", 8)) { + char *verbose = NULL; + if (_config_parse_string(&(buf[8]), "verbose", &verbose)) { + fclose(fptr); + return -1; + } else { + if (!strncmp(verbose, "err", 3)) { + conf.verbose = 3; + } else if (!strncmp(verbose, "warn", 4)) { + conf.verbose = 4; + } else if (!strncmp(verbose, "notice", 6)) { + conf.verbose = 5; + } else if (!strncmp(verbose, "info", 4)) { + conf.verbose = 6; + } else if (!strncmp(verbose, "debug", 5)) { + conf.verbose = 7; + } else { + logError("Invalid value for verbose in configuration.\n"); + fclose(fptr); + free(verbose); + return -1; + } + free(verbose); + } + } else if (!strncmp(buf, "log_file=", 9)) { + if (_config_parse_int(&(buf[9]), "log_file", &conf.log_file)) { + fclose(fptr); + return -1; + } else { + if (conf.log_file != 0 && conf.log_file != 1) { + logError("log_file must be 1 or 0 in configuration.\n"); + fclose(fptr); + return -1; + } + } + } else if (!strncmp(buf, "log_filepath=", 13)) { + if (_config_parse_string(&(buf[13]), "log_filepath", &conf.log_filepath)) { + fclose(fptr); + return -1; + } + } else if (!strncmp(buf, "log_pipe=", 9)) { + if (_config_parse_int(&(buf[9]), "log_pipe", &conf.log_pipe)) { + fclose(fptr); + return -1; + } else { + if (conf.log_pipe != 0 && conf.log_pipe != 1) { + logError("log_pipe must be 1 or 0 in configuration.\n"); + fclose(fptr); + return -1; + } + } + } else if (!strncmp(buf, "log_pipe_file=", 14)) { + if (_config_parse_string(&(buf[14]), "log_pipe_file", &conf.log_pipe_file)) { + fclose(fptr); + return -1; + } + } else if (!strncmp(buf, "syslog=", 7)) { + if (_config_parse_int(&(buf[7]), "syslog", &conf.syslog)) { + fclose(fptr); + return -1; + } else { + if (conf.syslog != 0 && conf.syslog != 1) { + logError("syslog must be 1 or 0 in configuration.\n"); + fclose(fptr); + return -1; + } + } + } else if (!strncmp(buf, "eeprom_file=", 12)) { + if (_config_parse_string(&(buf[12]), "eeprom_file", &conf.eeprom_file)) { + fclose(fptr); + return -1; + } + } else if (!strncmp(buf, "eeprom_size=", 12)) { + if (_config_parse_int(&(buf[12]), "eeprom_size", &conf.eeprom_size)) { + fclose(fptr); + return -1; + } else { + if (conf.eeprom_size <= 0) { + logError("eeprom_size value must be greater than 0 in configuration.\n"); + fclose(fptr); + return -1; + } + } + } else { + logWarning("Unknown config option \"%s\".\n", buf); + } + } + } + fclose(fptr); + + if (!conf.eeprom_file) { + logError("No eeprom_file found in configuration.\n"); + return -1; + } + + if (conf.log_file && !conf.log_filepath) { + logError("log_filepath must be set if you enable log_file in configuration.\n"); + return -1; + } + + if (conf.log_pipe && !conf.log_pipe_file) { + logError("log_pipe_file must be set if you enable log_pipe in configuration.\n"); + return -1; + } + + return 0; +} + +void config_cleanup(void) +{ + if (conf.eeprom_file) { + free(conf.eeprom_file); + } + if (conf.log_pipe_file) { + free(conf.log_pipe_file); + } +} + +int _config_create(const char *config_file) +{ + FILE *myFile; + int ret; + + const char default_conf[] = "# Logging verbosity: debug,info,notice,warn,err\n" \ + "verbose=debug\n" \ + "# Enable logging to a file.\n" \ + "log_file=0\n" \ + "# Log file path.\n" \ + "log_filepath=/tmp/mysgw.log\n" \ + "# Enable logging to a named pipe.\n" \ + "# Use this option to view your gateway's log messages\n" \ + "# from the log_pipe_file defined bellow.\n" \ + "# To do so, run the following command on another terminal:\n" \ + "# cat \"log_pipe_file\"\n" \ + "log_pipe=0\n" \ + "log_pipe_file=/tmp/mysgw.pipe\n" \ + "# Enable logging to syslog.\n" \ + "syslog=0\n" \ + "eeprom_file=/etc/mysensors.eeprom\n" \ + "eeprom_size=1024\n"; + + myFile = fopen(config_file, "w"); + if (!myFile) { + logError("Unable to create config file %s.\n", config_file); + return -1; + } + ret = fputs(default_conf, myFile); + fclose(myFile); + + return (ret > 0); +} + +int _config_parse_int(char *token, const char *name, int *value) +{ + if (token) { + *value = atoi(token); + } else { + logError("Empty %s value in configuration.\n", name); + return 1; + } + + return 0; +} + +int _config_parse_string(char *token, const char *name, char **value) +{ + if (token) { + if (*value) { + logError("Duplicate %s value in configuration.\n", name); + return 1; + } + while (token[0] == ' ' || token[0] == '\t') { + token++; + } + *value = strdup(token); + if (!*value) { + logError("Out of memory.\n"); + return 1; + } + } else { + logError("Empty %s value in configuration.\n", name); + return 1; + } + return 0; +} diff --git a/drivers/Linux/config.h b/drivers/Linux/config.h new file mode 100644 index 0000000..5c5dbc5 --- /dev/null +++ b/drivers/Linux/config.h @@ -0,0 +1,45 @@ +/* + * 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-2018 Sensnology AB + * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifndef CONFIG_H +#define CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct config { + int verbose; + int log_file; + char *log_filepath; + int log_pipe; + char *log_pipe_file; + int syslog; + char *eeprom_file; + int eeprom_size; +} conf; + +int config_parse(const char *config_file); +void config_cleanup(void); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/drivers/Linux/log.c b/drivers/Linux/log.c index 8d33c6f..e7bd817 100644 --- a/drivers/Linux/log.c +++ b/drivers/Linux/log.c @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2017 Sensnology AB + * Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -19,49 +19,201 @@ #include "log.h" #include -#include -#include #include +#include +#include +#include +#include +#include +#include +#include -// Default values -static const int log_opts = LOG_CONS | LOG_PERROR; // print syslog to stderror -static const int log_facility = LOG_USER; +static const char *_log_level_colors[] = { + "\x1b[1;5;91m", "\x1b[1;91m", "\x1b[91m", "\x1b[31m", "\x1b[33m", "\x1b[34m", "\x1b[32m", "\x1b[36m" +}; +static const char *_log_level_names[] = { + "EMERGENCY", "ALERT", "CRITICAL", "ERROR", "WARNING", "NOTICE", "INFO", "DEBUG" +}; +static uint8_t _log_quiet = 0; +static uint8_t _log_level = LOG_DEBUG; +static uint8_t _log_syslog = 0; -static uint8_t log_open = 0; +static uint8_t _log_pipe = 0; +static char *_log_pipe_file = NULL; +static int _log_pipe_fd = -1; -void logOpen(int options, int facility) +static FILE *_log_file_fp = NULL; + +void logSetQuiet(uint8_t enable) { - openlog(NULL, options, facility); - log_open = 1; + _log_quiet = enable ? 1 : 0; } -void vlogInfo(const char *fmt, va_list args) +void logSetLevel(int level) { - if (!log_open) { - logOpen(log_opts, log_facility); + if (level < LOG_EMERG || level > LOG_DEBUG) { + return; + } + + _log_level = level; +} + +void logSetSyslog(int options, int facility) +{ + openlog(NULL, options, facility); + _log_syslog = 1; +} + +int logSetPipe(char *pipe_file) +{ + if (pipe_file == NULL) { + return -1; + } + + _log_pipe_file = strdup(pipe_file); + if (_log_pipe_file == NULL) { + return -1; + } + + int ret = mkfifo(_log_pipe_file, 0666); + if (ret == 0) { + _log_pipe = 1; + } + + return ret; +} + +int logSetFile(char *file) +{ + if (file == NULL) { + return -1; + } + + _log_file_fp = fopen(file, "a"); + if (_log_file_fp == NULL) { + return errno; + } + + return 0; +} + +void logClose(void) +{ + if (_log_syslog) { + closelog(); + _log_syslog = 0; + } + + if (_log_pipe) { + if (_log_pipe_fd > 0) { + close(_log_pipe_fd); + } + /* remove the FIFO */ + unlink(_log_pipe_file); + _log_pipe = 0; + } + if (_log_pipe_file != NULL) { + free(_log_pipe_file); + _log_pipe_file = NULL; + } + + if (_log_file_fp != NULL) { + fclose(_log_file_fp); + _log_file_fp = NULL; + } +} + +void vlog(int level, const char *fmt, va_list args) +{ + if (_log_level < level) { + return; + } + + if (!_log_quiet || _log_file_fp != NULL) { + /* Get current time */ + time_t t = time(NULL); + struct tm *lt = localtime(&t); + + char buf[16]; + buf[strftime(buf, sizeof(buf), "%b %d %H:%M:%S", lt)] = '\0'; + +#ifdef LOG_DISABLE_COLOR + (void)_log_level_colors; + if (!_log_quiet) { + fprintf(stderr, "%s %-5s ", buf, _log_level_names[level]); + vfprintf(stderr, fmt, args); + } + if (_log_file_fp != NULL) { + vfprintf(_log_file_fp, "%s %-5s ", buf, _log_level_names[level]); + vfprintf(_log_file_fp, fmt, args); + } +#else + if (!_log_quiet) { + fprintf(stderr, "%s %s%-5s\x1b[0m ", buf, _log_level_colors[level], _log_level_names[level]); + vfprintf(stderr, fmt, args); + } + if (_log_file_fp != NULL) { + fprintf(_log_file_fp, "%s %s%-5s\x1b[0m ", buf, _log_level_colors[level], _log_level_names[level]); + vfprintf(_log_file_fp, fmt, args); + } +#endif + } + + if (_log_syslog) { + vsyslog(level, fmt, args); + } + + if (_log_pipe) { + if (_log_pipe_fd < 0) { + _log_pipe_fd = open(_log_pipe_file, O_WRONLY | O_NONBLOCK); + } + if (_log_pipe_fd > 0) { + if (vdprintf(_log_pipe_fd, fmt, args) < 0) { + close(_log_pipe_fd); + _log_pipe_fd = -1; + } + } + } - vsyslog(LOG_INFO, fmt, args); } void #ifdef __GNUC__ __attribute__((format(printf, 1, 2))) #endif -logInfo(const char *fmt, ...) +logEmergency(const char *fmt, ...) { va_list args; va_start(args, fmt); - vlogInfo(fmt, args); + vlog(LOG_EMERG, fmt, args); va_end(args); } -void vlogError(const char *fmt, va_list args) +void +#ifdef __GNUC__ +__attribute__((format(printf, 1, 2))) +#endif +logAlert(const char *fmt, ...) { - if (!log_open) { - logOpen(log_opts, log_facility); - } - vsyslog(LOG_ERR, fmt, args); + va_list args; + + va_start(args, fmt); + vlog(LOG_ALERT, fmt, args); + va_end(args); +} + +void +#ifdef __GNUC__ +__attribute__((format(printf, 1, 2))) +#endif +logCritical(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vlog(LOG_CRIT, fmt, args); + va_end(args); } void @@ -73,60 +225,10 @@ logError(const char *fmt, ...) va_list args; va_start(args, fmt); - vlogError(fmt, args); + vlog(LOG_ERR, 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) -{ - if (!log_open) { - logOpen(log_opts, log_facility); - } - vsyslog(LOG_WARNING, fmt, args); -} - void #ifdef __GNUC__ __attribute__((format(printf, 1, 2))) @@ -136,6 +238,45 @@ logWarning(const char *fmt, ...) va_list args; va_start(args, fmt); - vlogWarning(fmt, args); + vlog(LOG_WARNING, fmt, args); + va_end(args); +} + +void +#ifdef __GNUC__ +__attribute__((format(printf, 1, 2))) +#endif +logNotice(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vlog(LOG_NOTICE, fmt, args); + va_end(args); +} + +void +#ifdef __GNUC__ +__attribute__((format(printf, 1, 2))) +#endif +logInfo(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vlog(LOG_INFO, fmt, args); + va_end(args); +} + +void +#ifdef __GNUC__ +__attribute__((format(printf, 1, 2))) +#endif +logDebug(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vlog(LOG_DEBUG, fmt, args); va_end(args); } diff --git a/drivers/Linux/log.h b/drivers/Linux/log.h index b497580..0cecfc4 100644 --- a/drivers/Linux/log.h +++ b/drivers/Linux/log.h @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2017 Sensnology AB + * Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -21,27 +21,36 @@ #define LOG_H #include +#include +#include +#include #ifdef __cplusplus extern "C" { #endif -extern void logOpen(int options, int facility); +#define vlogError(...) vlog(LOG_ERR, __VA_ARGS__) +#define vlogWarning(...) vlog(LOG_WARNING, __VA_ARGS__) +#define vlogNotice(...) vlog(LOG_NOTICE, __VA_ARGS__) +#define vlogInfo(...) vlog(LOG_INFO, __VA_ARGS__) +#define vlogDebug(...) vlog(LOG_DEBUG, __VA_ARGS__) -extern void vlogInfo(const char *fmt, va_list args); -extern void logInfo(const char *fmt, ...) __attribute__((format(printf,1,2))); +void logSetQuiet(uint8_t enable); +void logSetLevel(int level); +void logSetSyslog(int options, int facility); +int logSetPipe(char *pipe_file); +int logSetFile(char *file); +void logClose(void); -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))); +void vlog(int level, const char *fmt, va_list args); +void logEmergency(const char *fmt, ...) __attribute__((format(printf,1,2))); +void logAlert(const char *fmt, ...) __attribute__((format(printf,1,2))); +void logCritical(const char *fmt, ...) __attribute__((format(printf,1,2))); +void logError(const char *fmt, ...) __attribute__((format(printf,1,2))); +void logWarning(const char *fmt, ...) __attribute__((format(printf,1,2))); +void logNotice(const char *fmt, ...) __attribute__((format(printf,1,2))); +void logInfo(const char *fmt, ...) __attribute__((format(printf,1,2))); +void logDebug(const char *fmt, ...) __attribute__((format(printf,1,2))); #ifdef __cplusplus } diff --git a/examples_linux/mysgw.cpp b/examples_linux/mysgw.cpp index 28024f1..65541a6 100644 --- a/examples_linux/mysgw.cpp +++ b/examples_linux/mysgw.cpp @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2017 Sensnology AB + * Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -24,7 +24,7 @@ // For more options run ./configure --help // Config file -//#define MY_LINUX_CONFIG_FILE "/etc/mysensors.dat" +//#define MY_LINUX_CONFIG_FILE "/etc/mysensors.conf" // How many clients should be able to connect to this gateway (default 1) #define MY_GATEWAY_MAX_CLIENTS 10 diff --git a/hal/architecture/Linux/MyHwLinuxGeneric.cpp b/hal/architecture/Linux/MyHwLinuxGeneric.cpp index 18d0906..8be3de8 100644 --- a/hal/architecture/Linux/MyHwLinuxGeneric.cpp +++ b/hal/architecture/Linux/MyHwLinuxGeneric.cpp @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2017 Sensnology AB + * Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors * * Documentation: http://www.mysensors.org @@ -27,8 +27,9 @@ #include #include "SoftEeprom.h" #include "log.h" +#include "config.h" -static SoftEeprom eeprom = SoftEeprom(MY_LINUX_CONFIG_FILE, 1024); // ATMega328 has 1024 bytes +static SoftEeprom eeprom; static FILE *randomFp = NULL; bool hwInit(void) @@ -43,6 +44,10 @@ bool hwInit(void) #endif #endif + if (eeprom.init(conf.eeprom_file, conf.eeprom_size) != 0) { + exit(1); + } + return true; } diff --git a/hal/architecture/Linux/MyHwLinuxGeneric.h b/hal/architecture/Linux/MyHwLinuxGeneric.h index 40d7950..220a720 100644 --- a/hal/architecture/Linux/MyHwLinuxGeneric.h +++ b/hal/architecture/Linux/MyHwLinuxGeneric.h @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2017 Sensnology AB + * Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors * * Documentation: http://www.mysensors.org diff --git a/hal/architecture/Linux/MyMainLinuxGeneric.cpp b/hal/architecture/Linux/MyMainLinuxGeneric.cpp index 6faf52e..1670978 100644 --- a/hal/architecture/Linux/MyMainLinuxGeneric.cpp +++ b/hal/architecture/Linux/MyMainLinuxGeneric.cpp @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2017 Sensnology AB + * Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -28,6 +28,7 @@ #include #include #include "log.h" +#include "config.h" #include "MySensorsCore.h" void handle_sigint(int sig) @@ -48,7 +49,7 @@ void handle_sigint(int sig) MY_SERIALDEVICE.end(); #endif - closelog(); + logClose(); exit(EXIT_SUCCESS); } @@ -104,17 +105,18 @@ void print_usage() { printf("Usage: mysgw [options]\n\n" \ "Options:\n" \ + " -c, --config-file Config file. [" MY_LINUX_CONFIG_FILE "]\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" + " -q, --quiet Quiet mode, disable log messages written to the terminal.\n" \ + " --daemon Run as a daemon.\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"); } @@ -338,19 +340,21 @@ void set_aes_key(char *key_str) int main(int argc, char *argv[]) { - int opt, log_opts, debug = 0, foreground = 1; - char *key = NULL; + int opt, daemon = 0, quiet = 0; + char *key = NULL, *config_file = NULL; /* register the signal handler */ signal(SIGINT, handle_sigint); signal(SIGTERM, handle_sigint); + signal(SIGPIPE, handle_sigint); hwRandomNumberInit(); static struct option long_options[] = { + {"config-file", required_argument, 0, 'c'}, + {"daemon", no_argument, 0, 'J'}, {"help", no_argument, 0, 'h'}, - {"debug", no_argument, 0, 'd'}, - {"background", no_argument, 0, 'b'}, + {"quiet", no_argument, 0, 'q'}, {"gen-soft-hmac-key", no_argument, 0, 'A'}, {"gen-soft-serial-key", no_argument, 0, 'B'}, {"gen-aes-key", no_argument, 0, 'C'}, @@ -364,16 +368,16 @@ int main(int argc, char *argv[]) }; int long_index = 0; - while ((opt = getopt_long(argc, argv,"hdbABCDEFGHI", long_options, &long_index )) != -1) { + while ((opt = getopt_long(argc, argv,"chqABCDEFGHIJ", long_options, &long_index )) != -1) { switch (opt) { + case 'c': + config_file = strdup(optarg); + break; case 'h': print_usage(); exit(EXIT_SUCCESS); - case 'd': - debug = 1; - break; - case 'b': - foreground = 0; + case 'q': + quiet = 1; break; case 'A': generate_soft_sign_hmac_key(); @@ -405,27 +409,46 @@ int main(int argc, char *argv[]) key = strdup(optarg); set_aes_key(key); exit(EXIT_SUCCESS); + case 'J': + daemon = 1; + break; default: print_usage(); exit(EXIT_SUCCESS); } } - log_opts = LOG_CONS; - if (foreground && isatty(STDIN_FILENO)) { - // Also print syslog to stderror - log_opts |= LOG_PERROR; - } - if (!debug) { - // Ignore debug type messages - setlogmask(LOG_UPTO (LOG_INFO)); - } - logOpen(log_opts, LOG_USER); - - if (!foreground && !debug) { + if (daemon) { if (daemonize() != 0) { exit(EXIT_FAILURE); } + quiet = 1; + } + + if (config_parse(config_file?config_file:MY_LINUX_CONFIG_FILE) != 0) { + exit(EXIT_FAILURE); + } + if (config_file) { + free(config_file); + } + + logSetQuiet(quiet); + logSetLevel(conf.verbose); + + if (conf.log_file) { + if (logSetFile(conf.log_filepath) != 0) { + logError("Failed to open log file.\n"); + } + } + + if (conf.log_pipe) { + if (logSetPipe(conf.log_pipe_file) != 0) { + logError("Failed to open log pipe.\n"); + } + } + + if (conf.syslog) { + logSetSyslog(LOG_CONS, LOG_USER); } logInfo("Starting gateway...\n"); diff --git a/initscripts/mysgw.systemd b/initscripts/mysgw.systemd index 41e7279..d983ab2 100644 --- a/initscripts/mysgw.systemd +++ b/initscripts/mysgw.systemd @@ -3,7 +3,7 @@ Description=MySensors Gateway daemon Requires=network.target [Service] -ExecStart=%gateway_dir%/mysgw +ExecStart=%gateway_dir%/mysgw -q [Install] WantedBy=multi-user.target diff --git a/initscripts/mysgw.sysvinit b/initscripts/mysgw.sysvinit index a511f05..c24fde9 100644 --- a/initscripts/mysgw.sysvinit +++ b/initscripts/mysgw.sysvinit @@ -17,7 +17,7 @@ PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin DESC="MySensors Gateway" NAME=mysgw DAEMON=%gateway_dir%/$NAME -DAEMON_ARGS="-b" +DAEMON_ARGS="--daemon -q" PIDFILE=/var/run/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME From ea6d07cb79394d60b80b1c96933d879509c08598 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Sat, 24 Mar 2018 04:16:44 -0300 Subject: [PATCH 28/60] Linux: Fix stability problem with ethernet (#1091) - Fix a problem where mysgw stops working and consumes a lot of cpu. - Fix bug with tcp sockets where socket descriptor wasn't being freed. --- drivers/Linux/EthernetClient.cpp | 9 +++------ drivers/Linux/EthernetServer.cpp | 4 +--- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/Linux/EthernetClient.cpp b/drivers/Linux/EthernetClient.cpp index c5686e8..446e717 100644 --- a/drivers/Linux/EthernetClient.cpp +++ b/drivers/Linux/EthernetClient.cpp @@ -220,9 +220,8 @@ void EthernetClient::stop() gettimeofday(&startTime, NULL); // wait up to a second for the connection to close - uint8_t s; do { - s = status(); + uint8_t s = status(); if (s == ETHERNETCLIENT_W5100_CLOSED) { break; // exit the loop } @@ -231,10 +230,8 @@ void EthernetClient::stop() } 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); - } + // free up the socket descriptor + ::close(_sock); _sock = -1; } diff --git a/drivers/Linux/EthernetServer.cpp b/drivers/Linux/EthernetServer.cpp index 9bbeb0e..58d0b5c 100644 --- a/drivers/Linux/EthernetServer.cpp +++ b/drivers/Linux/EthernetServer.cpp @@ -155,13 +155,11 @@ size_t EthernetServer::write(uint8_t b) size_t EthernetServer::write(const uint8_t *buffer, size_t size) { size_t n = 0; - size_t i = 0; - while (i < clients.size()) { + for (size_t i = 0; i < clients.size(); ++i) { EthernetClient client(clients[i]); if (client.status() == ETHERNETCLIENT_W5100_ESTABLISHED) { n += client.write(buffer, size); - i++; } } From fb95a84e6f6eaebf91338e1c7bafc64d1f5a1a2c Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Sun, 25 Mar 2018 15:51:41 -0300 Subject: [PATCH 29/60] Linux: Minor log fix (#1092) Use colored log messages only on the terminal. --- drivers/Linux/log.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/drivers/Linux/log.c b/drivers/Linux/log.c index e7bd817..a88bb2d 100644 --- a/drivers/Linux/log.c +++ b/drivers/Linux/log.c @@ -134,29 +134,24 @@ void vlog(int level, const char *fmt, va_list args) time_t t = time(NULL); struct tm *lt = localtime(&t); - char buf[16]; - buf[strftime(buf, sizeof(buf), "%b %d %H:%M:%S", lt)] = '\0'; + char date[16]; + date[strftime(date, sizeof(date), "%b %d %H:%M:%S", lt)] = '\0'; + if (_log_file_fp != NULL) { + fprintf(_log_file_fp, "%s %-5s ", date, _log_level_names[level]); + vfprintf(_log_file_fp, fmt, args); + } + + if (!_log_quiet) { #ifdef LOG_DISABLE_COLOR - (void)_log_level_colors; - if (!_log_quiet) { - fprintf(stderr, "%s %-5s ", buf, _log_level_names[level]); + (void)_log_level_colors; + fprintf(stderr, "%s %-5s ", date, _log_level_names[level]); vfprintf(stderr, fmt, args); - } - if (_log_file_fp != NULL) { - vfprintf(_log_file_fp, "%s %-5s ", buf, _log_level_names[level]); - vfprintf(_log_file_fp, fmt, args); - } #else - if (!_log_quiet) { - fprintf(stderr, "%s %s%-5s\x1b[0m ", buf, _log_level_colors[level], _log_level_names[level]); + fprintf(stderr, "%s %s%-5s\x1b[0m ", date, _log_level_colors[level], _log_level_names[level]); vfprintf(stderr, fmt, args); - } - if (_log_file_fp != NULL) { - fprintf(_log_file_fp, "%s %s%-5s\x1b[0m ", buf, _log_level_colors[level], _log_level_names[level]); - vfprintf(_log_file_fp, fmt, args); - } #endif + } } if (_log_syslog) { From b5a2fc226fe64759f2cb47a255b9b6f34850a968 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Tue, 27 Mar 2018 18:07:57 -0300 Subject: [PATCH 30/60] Linux: RF24 interrupt trigger workaround (#1094) Fix #870 --- drivers/RF24/RF24.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/RF24/RF24.cpp b/drivers/RF24/RF24.cpp index fa048e3..2551faa 100644 --- a/drivers/RF24/RF24.cpp +++ b/drivers/RF24/RF24.cpp @@ -410,11 +410,11 @@ LOCAL int16_t RF24_getSendingRSSI(void) LOCAL void RF24_irqHandler(void) { if (RF24_receiveCallback) { +#if defined(MY_GATEWAY_SERIAL) && !defined(__linux__) // 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 @@ -423,13 +423,28 @@ LOCAL void RF24_irqHandler(void) // 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. +#if defined(__linux__) + // Start checking if RX-FIFO is not empty, as we might end up here from an interrupt + // for a message we've already read. + if (RF24_isDataAvailable()) { + do { + RF24_receiveCallback(); // Must call RF24_readMessage(), which will clear RX_DR IRQ ! + } while (RF24_isDataAvailable()); + } else { + // Occasionally interrupt is triggered but no data is available - clear RX interrupt only + RF24_setStatus(_BV(RF24_RX_DR)); + logNotice("RF24: Recovered from a bad interrupt trigger.\n"); + } +#else // 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. +#endif + #if defined(MY_GATEWAY_SERIAL) && !defined(__linux__) + // Restore our interrupt handler. noInterrupts(); attachInterrupt(digitalPinToInterrupt(MY_RF24_IRQ_PIN), RF24_irqHandler, FALLING); #endif From 4d90c00f984e3af7c1528a4346f7d34ce7c50a71 Mon Sep 17 00:00:00 2001 From: thucar Date: Wed, 4 Apr 2018 17:40:11 +0300 Subject: [PATCH 31/60] MY_GATEWAY_TINYGSM support. GSM gateway using a modem module (#1097) Added TinyGSM driver and GatewayGSMMQTTClient example --- .ci/arduino.groovy | 4 + .ci/doxygen.groovy | 2 +- .mystools/cppcheck/config/suppressions.cfg | 4 +- MyConfig.h | 47 +- MySensors.h | 24 +- core/MyGatewayTransportMQTTClient.cpp | 58 + drivers/TinyGSM/LICENSE | 165 +++ drivers/TinyGSM/TinyGsmClient.h | 67 ++ drivers/TinyGSM/TinyGsmClientA6.h | 843 +++++++++++++ drivers/TinyGSM/TinyGsmClientESP8266.h | 591 +++++++++ drivers/TinyGSM/TinyGsmClientM590.h | 781 ++++++++++++ drivers/TinyGSM/TinyGsmClientSIM800.h | 1057 +++++++++++++++++ drivers/TinyGSM/TinyGsmClientSIM808.h | 163 +++ drivers/TinyGSM/TinyGsmClientU201.h | 789 ++++++++++++ drivers/TinyGSM/TinyGsmClientXBee.h | 752 ++++++++++++ drivers/TinyGSM/TinyGsmCommon.h | 195 +++ drivers/TinyGSM/TinyGsmFifo.h | 152 +++ drivers/TinyGSM/keywords.txt | 26 + .../GatewayGSMMQTTClient.ino | 137 +++ keywords.txt | 11 + 20 files changed, 5862 insertions(+), 6 deletions(-) create mode 100644 drivers/TinyGSM/LICENSE create mode 100644 drivers/TinyGSM/TinyGsmClient.h create mode 100644 drivers/TinyGSM/TinyGsmClientA6.h create mode 100644 drivers/TinyGSM/TinyGsmClientESP8266.h create mode 100644 drivers/TinyGSM/TinyGsmClientM590.h create mode 100644 drivers/TinyGSM/TinyGsmClientSIM800.h create mode 100644 drivers/TinyGSM/TinyGsmClientSIM808.h create mode 100644 drivers/TinyGSM/TinyGsmClientU201.h create mode 100644 drivers/TinyGSM/TinyGsmClientXBee.h create mode 100644 drivers/TinyGSM/TinyGsmCommon.h create mode 100644 drivers/TinyGSM/TinyGsmFifo.h create mode 100644 drivers/TinyGSM/keywords.txt create mode 100644 examples/GatewayGSMMQTTClient/GatewayGSMMQTTClient.ino diff --git a/.ci/arduino.groovy b/.ci/arduino.groovy index b26e72b..ce51237 100644 --- a/.ci/arduino.groovy +++ b/.ci/arduino.groovy @@ -46,6 +46,7 @@ def buildMySensorsMicro(config, sketches, String key) { if (sketches[sketch].path != config.library_root+'examples/GatewayESP8266/GatewayESP8266.ino' && sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' && sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayGSMMQTTClient/GatewayGSMMQTTClient.ino' && sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino') { buildArduino(config, fqbn, sketches[sketch].path, key+'_MySensorsMicro') } @@ -78,6 +79,7 @@ def buildMySensorsGw(config, sketches, String key) { sketches[sketch].path != config.library_root+'examples/GatewayESP8266/GatewayESP8266.ino' && sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' && sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayGSMMQTTClient/GatewayGSMMQTTClient.ino' && sketches[sketch].path != config.library_root+'examples/GatewaySerialRS485/GatewaySerialRS485.ino' && sketches[sketch].path != config.library_root+'examples/MotionSensorRS485/MotionSensorRS485.ino') { buildArduino(config, fqbn, sketches[sketch].path, key+'_MySensorsGw') @@ -206,6 +208,7 @@ def buildEsp8266(config, sketches, String key) { sketches[sketch].path != config.library_root+'examples/GatewaySerialRS485/GatewaySerialRS485.ino' && sketches[sketch].path != config.library_root+'examples/GatewayW5100/GatewayW5100.ino' && sketches[sketch].path != config.library_root+'examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayGSMMQTTClient/GatewayGSMMQTTClient.ino' && sketches[sketch].path != config.library_root+'examples/MotionSensorRS485/MotionSensorRS485.ino' && sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino' && sketches[sketch].path != config.library_root+'examples/SoilMoistSensor/SoilMoistSensor.ino') { @@ -241,6 +244,7 @@ def buildnRF5(config, sketches, String key) { sketches[sketch].path != config.library_root+'examples/DustSensorDSM/DustSensorDSM.ino' && sketches[sketch].path != config.library_root+'examples/GatewayESP8266/GatewayESP8266.ino' && sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayGSMMQTTClient/GatewayGSMMQTTClient.ino' && sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' && sketches[sketch].path != config.library_root+'examples/GatewaySerialRS485/GatewaySerialRS485.ino' && sketches[sketch].path != config.library_root+'examples/GatewayW5100/GatewayW5100.ino' && diff --git a/.ci/doxygen.groovy b/.ci/doxygen.groovy index 5c69ae9..9e68b38 100644 --- a/.ci/doxygen.groovy +++ b/.ci/doxygen.groovy @@ -6,7 +6,7 @@ def call(config) { Documentation/doxygen.sh""" warnings canComputeNew: false, canResolveRelativePaths: false, defaultEncoding: '', - excludePattern: '''.*/sha204_library\\.h,.*/drivers/Linux/.*,.*/cores/esp8266/.*,hardware/.*''', + excludePattern: '''.*/sha204_library\\.h,.*/drivers/Linux/.*,.*/drivers/TinyGSM/.*,.*/cores/esp8266/.*,hardware/.*''', failedTotalAll: '', healthy: '', includePattern: '', messagesPattern: '', parserConfigurations: [[parserName: 'Doxygen', pattern: config.repository_root+'doxygen.log']], unHealthy: '', unstableTotalAll: '0' diff --git a/.mystools/cppcheck/config/suppressions.cfg b/.mystools/cppcheck/config/suppressions.cfg index 6a8b585..9820b3d 100644 --- a/.mystools/cppcheck/config/suppressions.cfg +++ b/.mystools/cppcheck/config/suppressions.cfg @@ -1,4 +1,6 @@ ConfigurationNotChecked unmatchedSuppression // This suppression is because the problem is in an in-lined macro so in-line-suppressions does not appear to take effect -unreadVariable:*/MyHwNRF5.cpp \ No newline at end of file +unreadVariable:*/MyHwNRF5.cpp +uninitMemberVar:*/TinyGsmFifo.h + diff --git a/MyConfig.h b/MyConfig.h index ce73dea..4dd9d3a 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -1344,12 +1344,15 @@ * @brief Define this for Ethernet GW based on the ESP8266. * @def MY_GATEWAY_LINUX * @brief Define this for Ethernet GW based on Linux. + * @def MY_GATEWAY_TINYGSM + * @brief Define this for Ethernet GW based on GSM modems supported by TinyGSM library. */ // The gateway options available //#define MY_GATEWAY_W5100 //#define MY_GATEWAY_ENC28J60 //#define MY_GATEWAY_ESP8266 //#define MY_GATEWAY_LINUX +//#define MY_GATEWAY_TINYGSM /** @@ -1888,7 +1891,7 @@ * MY_IS_GATEWAY is true when @ref MY_GATEWAY_FEATURE is set. * MY_NODE_TYPE contain a string describing the class of sketch/node (gateway/repeater/node). */ -#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) +#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) || defined(MY_GATEWAY_TINYGSM) #define MY_GATEWAY_FEATURE #define MY_IS_GATEWAY (true) #define MY_NODE_TYPE "GW" @@ -2051,9 +2054,51 @@ #define MY_GATEWAY_ENC28J60 #define MY_GATEWAY_ESP8266 #define MY_GATEWAY_LINUX +#define MY_GATEWAY_TINYGSM #define MY_IP_ADDRESS 192,168,178,66 #define MY_USE_UDP #define MY_CONTROLLER_IP_ADDRESS 192,168,178,254 +// TinyGSM +/** + * @def MY_GSM_APN + * @brief APN from your cell carrier / mobile provider. Example: 4g.tele2.se + */ +#define MY_GSM_APN +/** + * @def MY_GSM_BAUDRATE + * @brief Baudrate for your GSM modem. If left undefined, TinyGSM will try to auto detect the correct rate + */ +#define MY_GSM_BAUDRATE +/** + * @def MY_GSM_PIN + * @brief PIN code for your SIM card, if PIN lock is active. + */ +#define MY_GSM_PIN +/** + * @def MY_GSM_PSW + * @brief If using a GSM modem, this is the password supplied by your cell carrier / mobile provider. If using ESP8266 as a WiFi modem, this is your WiFi network password + */ +#define MY_GSM_PSW +/** + * @def MY_GSM_RX + * @brief If defined, uses softSerial using defined pins (must also define MY_GSM_TX) + */ +#define MY_GSM_RX +/** + * @def MY_GSM_SSID + * @brief If using ESP8266 as WiFi modem, this is your network SSID + */ +#define MY_GSM_SSID +/** + * @def MY_GSM_TX + * @brief If defined, uses softSerial using defined pins (must also define MY_GSM_RX) + */ +#define MY_GSM_TX +/** + * @def MY_GSM_USR + * @brief Supplied by your cell carrier / mobile operator. If not required, leave undefined. + */ +#define MY_GSM_USR // LED #define MY_DEFAULT_ERR_LED_PIN #define MY_DEFAULT_TX_LED_PIN diff --git a/MySensors.h b/MySensors.h index dd233e1..3f4facf 100644 --- a/MySensors.h +++ b/MySensors.h @@ -152,11 +152,16 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs #endif // GATEWAY - COMMON FUNCTIONS -// We support MQTT Client using W5100, ESP8266 and Linux -#if !defined(MY_GATEWAY_CLIENT_MODE) +// We support MQTT Client using W5100, ESP8266, GSM modems supported by TinyGSM library and Linux +#if !defined(MY_GATEWAY_CLIENT_MODE) && !defined(MY_GATEWAY_TINYGSM) #error You must specify MY_CONTROLLER_IP_ADDRESS or MY_CONTROLLER_URL_ADDRESS #endif +#if defined(MY_GATEWAY_TINYGSM) && !defined(MY_GATEWAY_MQTT_CLIENT) +// TinyGSM currently only supports MQTTClient mode. +#error MY_GATEWAY_TINYGSM only works with MY_GATEWAY_MQTT_CLIENT +#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 @@ -172,6 +177,10 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs #include "core/MyGatewayTransport.cpp" #include "core/MyProtocolMySensors.cpp" +#if defined(MY_GATEWAY_TINYGSM) +#include "drivers/TinyGSM/TinyGsmClient.h" +#endif + #if defined(MY_GATEWAY_LINUX) #include "drivers/Linux/EthernetClient.h" #include "drivers/Linux/EthernetServer.h" @@ -192,7 +201,7 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs #endif #if !defined(MY_PORT) -#error You must define MY_PORT (controller or gatway port to open) +#error You must define MY_PORT (controller or gateway port to open) #endif #if defined(MY_GATEWAY_ESP8266) // GATEWAY - ESP8266 @@ -307,6 +316,15 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs #include "drivers/AVR/DigitalIO/DigitalIO.h" #endif +// SOFTSERIAL +#if defined(MY_GSM_TX) != defined(MY_GSM_RX) +#error Both, MY_GSM_TX and MY_GSM_RX need to be defined when using SoftSerial +#endif + +#if defined(MY_GATEWAY_TINYGSM) && !defined(SerialAT) && (!defined(MY_GSM_TX) || !defined(MY_GSM_RX)) +#error You need to define either SerialAT or MY_GSM_RX and MY_GSM_TX pins +#endif + // POWER PIN #ifndef DOXYGEN #if defined(MY_RF24_POWER_PIN) || defined(MY_RFM69_POWER_PIN) || defined(MY_RFM95_POWER_PIN) || defined(MY_RADIO_NRF5_ESB) diff --git a/core/MyGatewayTransportMQTTClient.cpp b/core/MyGatewayTransportMQTTClient.cpp index 4a92ae9..d7016bc 100644 --- a/core/MyGatewayTransportMQTTClient.cpp +++ b/core/MyGatewayTransportMQTTClient.cpp @@ -50,8 +50,24 @@ IPAddress _subnetIp(255, 255, 255, 0); uint8_t _MQTT_clientMAC[] = { MY_MAC_ADDRESS }; #endif /* End of MY_GATEWAY_ESP8266 */ +#if defined(MY_GATEWAY_TINYGSM) +#if defined(MY_GSM_RX) && defined(MY_GSM_TX) +SoftwareSerial SerialAT(MY_GSM_RX, MY_GSM_TX); +#endif +static TinyGsm modem(SerialAT); +static TinyGsmClient _MQTT_gsmClient(modem); +static PubSubClient _MQTT_client(_MQTT_gsmClient); +#if defined(MY_GSM_BAUDRATE) +uint32_t rate = MY_GSM_BAUDRATE; +#else /* Else part of MY_GSM_BAUDRATE */ +uint32_t rate = 0; +#endif /* End of MY_GSM_BAUDRATE */ +#else /* Else part of MY_GATEWAY_TINYGSM */ static EthernetClient _MQTT_ethClient; static PubSubClient _MQTT_client(_MQTT_ethClient); +#endif /* End of MY_GATEWAY_TINYGSM */ + + static bool _MQTT_connecting = true; static bool _MQTT_available = false; static MyMessage _MQTT_msg; @@ -114,6 +130,8 @@ bool gatewayTransportConnect(void) #if defined(MY_IP_ADDRESS) _MQTT_ethClient.bind(_MQTT_clientIp); #endif /* End of MY_IP_ADDRESS */ +#elif defined(MY_GATEWAY_TINYGSM) /* Elif part of MY_GATEWAY_ESP8266 */ + GATEWAY_DEBUG(PSTR("GWT:TPC:IP=%s\n"), modem.getLocalIP().c_str()); #else /* Else part of MY_GATEWAY_ESP8266 */ #if defined(MY_IP_ADDRESS) Ethernet.begin(_MQTT_clientMAC, _MQTT_clientIp); @@ -137,6 +155,46 @@ bool gatewayTransportConnect(void) bool gatewayTransportInit(void) { _MQTT_connecting = true; + +#if defined(MY_GATEWAY_TINYGSM) + +#if !defined(MY_GSM_BAUDRATE) + rate = TinyGsmAutoBaud(SerialAT); +#endif /* End of MY_GSM_BAUDRATE */ + + SerialAT.begin(rate); + delay(3000); + + modem.restart(); + +#if defined(MY_GSM_PIN) && !defined(TINY_GSM_MODEM_ESP8266) + modem.simUnlock(MY_GSM_PIN); +#endif /* End of MY_GSM_PIN */ + +#ifndef TINY_GSM_MODEM_ESP8266 + if (!modem.waitForNetwork()) { + GATEWAY_DEBUG(PSTR("!GWT:TIN:ETH FAIL\n")); + while (true); + } + GATEWAY_DEBUG(PSTR("GWT:TIN:ETH OK\n")); + + if (!modem.gprsConnect(MY_GSM_APN, MY_GSM_USR, MY_GSM_PSW)) { + GATEWAY_DEBUG(PSTR("!GWT:TIN:ETH FAIL\n")); + while (true); + } + GATEWAY_DEBUG(PSTR("GWT:TIN:ETH OK\n")); + delay(1000); +#else /* Else part of TINY_GSM_MODEM_ESP8266 */ + if (!modem.networkConnect(MY_GSM_SSID, MY_GSM_PSW)) { + GATEWAY_DEBUG(PSTR("!GWT:TIN:ETH FAIL\n")); + while (true); + } + GATEWAY_DEBUG(PSTR("GWT:TIN:ETH OK\n")); + delay(1000); +#endif /* End of TINY_GSM_MODEM_ESP8266 */ + +#endif /* End of MY_GATEWAY_TINYGSM */ + #if defined(MY_CONTROLLER_IP_ADDRESS) _MQTT_client.setServer(_brokerIp, MY_PORT); #else diff --git a/drivers/TinyGSM/LICENSE b/drivers/TinyGSM/LICENSE new file mode 100644 index 0000000..65c5ca8 --- /dev/null +++ b/drivers/TinyGSM/LICENSE @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/drivers/TinyGSM/TinyGsmClient.h b/drivers/TinyGSM/TinyGsmClient.h new file mode 100644 index 0000000..8badab1 --- /dev/null +++ b/drivers/TinyGSM/TinyGsmClient.h @@ -0,0 +1,67 @@ +/** + * file TinyGsmClient.h + * author Volodymyr Shymanskyy + * license LGPL-3.0 + * copyright Copyright (c) 2016 Volodymyr Shymanskyy + * date Nov 2016 + */ + +#ifndef TinyGsmClient_h +#define TinyGsmClient_h + +#if defined(TINY_GSM_MODEM_SIM800) || defined(TINY_GSM_MODEM_SIM868) || defined(TINY_GSM_MODEM_U201) || defined(TINY_GSM_MODEM_ESP8266) +#define TINY_GSM_MODEM_HAS_SSL +#endif + +#if defined(TINY_GSM_MODEM_SIM808) || defined(TINY_GSM_MODEM_SIM868) || defined(TINY_GSM_MODEM_A7) +#define TINY_GSM_MODEM_HAS_GPS +#endif + +#if defined(TINY_GSM_MODEM_SIM800) || defined(TINY_GSM_MODEM_SIM900) +#define TINY_GSM_MODEM_HAS_GPRS +#include "TinyGsmClientSIM800.h" +typedef TinyGsmSim800 TinyGsm; +typedef TinyGsmSim800::GsmClient TinyGsmClient; +typedef TinyGsmSim800::GsmClientSecure TinyGsmClientSecure; + +#elif defined(TINY_GSM_MODEM_SIM808) || defined(TINY_GSM_MODEM_SIM868) +#define TINY_GSM_MODEM_HAS_GPRS +#include "TinyGsmClientSIM808.h" +typedef TinyGsmSim808 TinyGsm; +typedef TinyGsmSim808::GsmClient TinyGsmClient; +typedef TinyGsmSim808::GsmClientSecure TinyGsmClientSecure; + +#elif defined(TINY_GSM_MODEM_A6) || defined(TINY_GSM_MODEM_A7) +#define TINY_GSM_MODEM_HAS_GPRS +#include "TinyGsmClientA6.h" +typedef TinyGsm::GsmClient TinyGsmClient; + +#elif defined(TINY_GSM_MODEM_M590) +#define TINY_GSM_MODEM_HAS_GPRS +#include "TinyGsmClientM590.h" +typedef TinyGsm::GsmClient TinyGsmClient; + +#elif defined(TINY_GSM_MODEM_U201) +#define TINY_GSM_MODEM_HAS_GPRS +#include "TinyGsmClientU201.h" +typedef TinyGsmU201 TinyGsm; +typedef TinyGsmU201::GsmClient TinyGsmClient; +typedef TinyGsmU201::GsmClientSecure TinyGsmClientSecure; + +#elif defined(TINY_GSM_MODEM_ESP8266) +#define TINY_GSM_MODEM_HAS_WIFI +#include "TinyGsmClientESP8266.h" +typedef TinyGsm::GsmClient TinyGsmClient; +typedef TinyGsm::GsmClientSecure TinyGsmClientSecure; + +#elif defined(TINY_GSM_MODEM_XBEE) +#define TINY_GSM_MODEM_HAS_GPRS +#define TINY_GSM_MODEM_HAS_WIFI +#include "TinyGsmClientXBee.h" +typedef TinyGsm::GsmClient TinyGsmClient; + +#else +#error "Please define GSM modem model" +#endif + +#endif diff --git a/drivers/TinyGSM/TinyGsmClientA6.h b/drivers/TinyGSM/TinyGsmClientA6.h new file mode 100644 index 0000000..7630378 --- /dev/null +++ b/drivers/TinyGSM/TinyGsmClientA6.h @@ -0,0 +1,843 @@ +/** + * file TinyGsmClientA6.h + * author Volodymyr Shymanskyy + * license LGPL-3.0 + * copyright Copyright (c) 2016 Volodymyr Shymanskyy + * date Nov 2016 + */ + +#ifndef TinyGsmClientA6_h +#define TinyGsmClientA6_h + +//#define TINY_GSM_DEBUG Serial + +#if !defined(TINY_GSM_RX_BUFFER) +#define TINY_GSM_RX_BUFFER 256 +#endif + +#define TINY_GSM_MUX_COUNT 8 + +#include "TinyGsmCommon.h" + +#define GSM_NL "\r\n" +static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; +static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; + +enum SimStatus { + SIM_ERROR = 0, + SIM_READY = 1, + SIM_LOCKED = 2, +}; + +enum RegStatus { + REG_UNREGISTERED = 0, + REG_SEARCHING = 2, + REG_DENIED = 3, + REG_OK_HOME = 1, + REG_OK_ROAMING = 5, + REG_UNKNOWN = 4, +}; + + +class TinyGsm +{ + +public: + + class GsmClient : public Client + { + friend class TinyGsm; + typedef TinyGsmFifo RxFifo; + + public: + GsmClient() {} + + GsmClient(TinyGsm& modem) + { + init(&modem); + } + + bool init(TinyGsm* modem) + { + this->at = modem; + this->mux = -1; + sock_connected = false; + + return true; + } + + public: + virtual int connect(const char *host, uint16_t port) + { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + uint8_t newMux = -1; + sock_connected = at->modemConnect(host, port, &newMux); + if (sock_connected) { + mux = newMux; + at->sockets[mux] = this; + } + return sock_connected; + } + + virtual int connect(IPAddress ip, uint16_t port) + { + String host; + host.reserve(16); + host += ip[0]; + host += "."; + host += ip[1]; + host += "."; + host += ip[2]; + host += "."; + host += ip[3]; + return connect(host.c_str(), port); + } + + virtual void stop() + { + TINY_GSM_YIELD(); + at->sendAT(GF("+CIPCLOSE="), mux); + sock_connected = false; + at->waitResponse(); + rx.clear(); + } + + virtual size_t write(const uint8_t *buf, size_t size) + { + TINY_GSM_YIELD(); + //at->maintain(); + return at->modemSend(buf, size, mux); + } + + virtual size_t write(uint8_t c) + { + return write(&c, 1); + } + + virtual int available() + { + TINY_GSM_YIELD(); + if (!rx.size() && sock_connected) { + at->maintain(); + } + return rx.size(); + } + + virtual int read(uint8_t *buf, size_t size) + { + TINY_GSM_YIELD(); + size_t cnt = 0; + while (cnt < size) { + size_t chunk = TinyGsmMin(size-cnt, rx.size()); + if (chunk > 0) { + rx.get(buf, chunk); + buf += chunk; + cnt += chunk; + continue; + } + // TODO: Read directly into user buffer? + if (!rx.size() && sock_connected) { + at->maintain(); + //break; + } + } + return cnt; + } + + virtual int read() + { + uint8_t c; + if (read(&c, 1) == 1) { + return c; + } + return -1; + } + + virtual int peek() + { + return -1; //TODO + } + virtual void flush() + { + at->stream.flush(); + } + + virtual uint8_t connected() + { + if (available()) { + return true; + } + return sock_connected; + } + virtual operator bool() + { + return connected(); + } + + /* + * Extended API + */ + + String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + + private: + TinyGsm* at; + uint8_t mux; + bool sock_connected; + RxFifo rx; + }; + +public: + + explicit TinyGsm(Stream& stream) + : stream(stream) + { + memset(sockets, 0, sizeof(sockets)); + } + + /* + * Basic functions + */ + bool begin() + { + return init(); + } + + bool init() + { + if (!testAT()) { + return false; + } + sendAT(GF("&FZE0")); // Factory + Reset + Echo Off + if (waitResponse() != 1) { + return false; + } + sendAT(GF("+CMEE=0")); + waitResponse(); + + sendAT(GF("+CMER=3,0,0,2")); + waitResponse(); + + getSimStatus(); + return true; + } + + void setBaud(unsigned long baud) + { + sendAT(GF("+IPR="), baud); + } + + bool testAT(unsigned long timeout = 10000L) + { + for (unsigned long start = millis(); millis() - start < timeout; ) { + sendAT(GF("")); + if (waitResponse(200) == 1) { + delay(100); + return true; + } + delay(100); + } + return false; + } + + void maintain() + { + waitResponse(10, NULL, NULL); + } + + bool factoryDefault() + { + sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write + waitResponse(); + sendAT(GF("&W")); // Write configuration + return waitResponse() == 1; + } + + String getModemInfo() + { + sendAT(GF("I")); + String res; + if (waitResponse(1000L, res) != 1) { + return ""; + } + res.replace(GSM_NL "OK" GSM_NL, ""); + res.replace(GSM_NL, " "); + res.trim(); + return res; + } + + bool hasSSL() + { + return false; + } + + /* + * Power functions + */ + + bool restart() + { + if (!testAT()) { + return false; + } + sendAT(GF("+RST=1")); + delay(3000); + return init(); + } + + bool poweroff() + { + sendAT(GF("+CPOF")); + return waitResponse() == 1; + } + + bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED; + + bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; + + /* + * SIM card functions + */ + + bool simUnlock(const char *pin) + { + sendAT(GF("+CPIN=\""), pin, GF("\"")); + return waitResponse() == 1; + } + + String getSimCCID() + { + sendAT(GF("+CCID")); + if (waitResponse(GF(GSM_NL "+SCID: SIM Card ID:")) != 1) { + return ""; + } + String res = stream.readStringUntil('\n'); + waitResponse(); + res.trim(); + return res; + } + + String getIMEI() + { + sendAT(GF("+GSN")); + if (waitResponse(GF(GSM_NL)) != 1) { + return ""; + } + String res = stream.readStringUntil('\n'); + waitResponse(); + res.trim(); + return res; + } + + SimStatus getSimStatus(unsigned long timeout = 10000L) + { + for (unsigned long start = millis(); millis() - start < timeout; ) { + sendAT(GF("+CPIN?")); + if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) { + delay(1000); + continue; + } + int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK")); + waitResponse(); + switch (status) { + case 2: + case 3: + return SIM_LOCKED; + case 1: + return SIM_READY; + default: + return SIM_ERROR; + } + } + return SIM_ERROR; + } + + RegStatus getRegistrationStatus() + { + sendAT(GF("+CREG?")); + if (waitResponse(GF(GSM_NL "+CREG:")) != 1) { + return REG_UNKNOWN; + } + streamSkipUntil(','); // Skip format (0) + int status = stream.readStringUntil('\n').toInt(); + waitResponse(); + return (RegStatus)status; + } + + String getOperator() + { + sendAT(GF("+COPS=3,0")); // Set format + waitResponse(); + + sendAT(GF("+COPS?")); + if (waitResponse(GF(GSM_NL "+COPS:")) != 1) { + return ""; + } + streamSkipUntil('"'); // Skip mode and format + String res = stream.readStringUntil('"'); + waitResponse(); + return res; + } + + /* + * Generic network functions + */ + + int getSignalQuality() + { + sendAT(GF("+CSQ")); + if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) { + return 99; + } + int res = stream.readStringUntil(',').toInt(); + waitResponse(); + return res; + } + + bool isNetworkConnected() + { + RegStatus s = getRegistrationStatus(); + return (s == REG_OK_HOME || s == REG_OK_ROAMING); + } + + bool waitForNetwork(unsigned long timeout = 60000L) + { + for (unsigned long start = millis(); millis() - start < timeout; ) { + if (isNetworkConnected()) { + return true; + } + delay(250); + } + return false; + } + + /* + * GPRS functions + */ + bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) + { + gprsDisconnect(); + + sendAT(GF("+CGATT=1")); + if (waitResponse(60000L) != 1) { + return false; + } + + // TODO: wait AT+CGATT? + + sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"'); + waitResponse(); + + if (!user) { + user = ""; + } + if (!pwd) { + pwd = ""; + } + sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\"")); + if (waitResponse(60000L) != 1) { + return false; + } + + sendAT(GF("+CGACT=1,1")); + waitResponse(60000L); + + sendAT(GF("+CIPMUX=1")); + if (waitResponse() != 1) { + return false; + } + + return true; + } + + bool gprsDisconnect() + { + // Shut the TCP/IP connection + sendAT(GF("+CIPSHUT")); + if (waitResponse(60000L) != 1) { + return false; + } + + for (int i = 0; i<3; i++) { + sendAT(GF("+CGATT=0")); + if (waitResponse(5000L) == 1) { + return true; + } + } + + return false; + } + + bool isGprsConnected() + { + sendAT(GF("+CGATT?")); + if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) { + return false; + } + int res = stream.readStringUntil('\n').toInt(); + waitResponse(); + return (res == 1); + } + + String getLocalIP() + { + sendAT(GF("+CIFSR")); + String res; + if (waitResponse(10000L, res) != 1) { + return ""; + } + res.replace(GSM_NL "OK" GSM_NL, ""); + res.replace(GSM_NL, ""); + res.trim(); + return res; + } + + IPAddress localIP() + { + return TinyGsmIpFromString(getLocalIP()); + } + + /* + * Phone Call functions + */ + + bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE; + + bool callAnswer() + { + sendAT(GF("A")); + return waitResponse() == 1; + } + + // Returns true on pick-up, false on error/busy + bool callNumber(const String& number) + { + if (number == GF("last")) { + sendAT(GF("DLST")); + } else { + sendAT(GF("D\""), number, "\";"); + } + + if (waitResponse(5000L) != 1) { + return false; + } + + if (waitResponse(60000L, + GF(GSM_NL "+CIEV: \"CALL\",1"), + GF(GSM_NL "+CIEV: \"CALL\",0"), + GFP(GSM_ERROR)) != 1) { + return false; + } + + int rsp = waitResponse(60000L, + GF(GSM_NL "+CIEV: \"SOUNDER\",0"), + GF(GSM_NL "+CIEV: \"CALL\",0")); + + int rsp2 = waitResponse(300L, GF(GSM_NL "BUSY" GSM_NL), GF(GSM_NL "NO ANSWER" GSM_NL)); + + return rsp == 1 && rsp2 == 0; + } + + bool callHangup() + { + sendAT(GF("H")); + return waitResponse() == 1; + } + + // 0-9,*,#,A,B,C,D + bool dtmfSend(char cmd, unsigned duration_ms = 100) + { + duration_ms = constrain(duration_ms, 100, 1000); + + // The duration parameter is not working, so we simulate it using delay.. + // TODO: Maybe there's another way... + + //sendAT(GF("+VTD="), duration_ms / 100); + //waitResponse(); + + sendAT(GF("+VTS="), cmd); + if (waitResponse(10000L) == 1) { + delay(duration_ms); + return true; + } + return false; + } + + /* + * Audio functions + */ + + bool audioSetHeadphones() + { + sendAT(GF("+SNFS=0")); + return waitResponse() == 1; + } + + bool audioSetSpeaker() + { + sendAT(GF("+SNFS=1")); + return waitResponse() == 1; + } + + bool audioMuteMic(bool mute) + { + sendAT(GF("+CMUT="), mute); + return waitResponse() == 1; + } + + /* + * Messaging functions + */ + + String sendUSSD(const String& code) + { + sendAT(GF("+CMGF=1")); + waitResponse(); + sendAT(GF("+CSCS=\"HEX\"")); + waitResponse(); + sendAT(GF("+CUSD=1,\""), code, GF("\",15")); + if (waitResponse(10000L) != 1) { + return ""; + } + if (waitResponse(GF(GSM_NL "+CUSD:")) != 1) { + return ""; + } + stream.readStringUntil('"'); + String hex = stream.readStringUntil('"'); + stream.readStringUntil(','); + int dcs = stream.readStringUntil('\n').toInt(); + + if (dcs == 15) { + return TinyGsmDecodeHex7bit(hex); + } else if (dcs == 72) { + return TinyGsmDecodeHex16bit(hex); + } else { + return hex; + } + } + + bool sendSMS(const String& number, const String& text) + { + sendAT(GF("+CMGF=1")); + waitResponse(); + sendAT(GF("+CMGS=\""), number, GF("\"")); + if (waitResponse(GF(">")) != 1) { + return false; + } + stream.print(text); + stream.write((char)0x1A); + stream.flush(); + return waitResponse(60000L) == 1; + } + + + /* + * Location functions + */ + + String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE; + + /* + * Battery functions + */ + + uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE; + + int getBattPercent() + { + sendAT(GF("+CBC?")); + if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { + return false; + } + stream.readStringUntil(','); + int res = stream.readStringUntil('\n').toInt(); + waitResponse(); + return res; + } + +protected: + + bool modemConnect(const char* host, uint16_t port, uint8_t* mux) + { + sendAT(GF("+CIPSTART="), GF("\"TCP"), GF("\",\""), host, GF("\","), port); + + if (waitResponse(75000L, GF(GSM_NL "+CIPNUM:")) != 1) { + return false; + } + int newMux = stream.readStringUntil('\n').toInt(); + + int rsp = waitResponse(75000L, + GF("CONNECT OK" GSM_NL), + GF("CONNECT FAIL" GSM_NL), + GF("ALREADY CONNECT" GSM_NL)); + if (waitResponse() != 1) { + return false; + } + *mux = newMux; + + return (1 == rsp); + } + + int modemSend(const void* buff, size_t len, uint8_t mux) + { + sendAT(GF("+CIPSEND="), mux, ',', len); + if (waitResponse(2000L, GF(GSM_NL ">")) != 1) { + return 0; + } + stream.write((uint8_t*)buff, len); + stream.flush(); + if (waitResponse(10000L, GFP(GSM_OK), GF(GSM_NL "FAIL")) != 1) { + return 0; + } + return len; + } + + bool modemGetConnected(uint8_t mux) + { + sendAT(GF("+CIPSTATUS")); //TODO mux? + int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), GF(",\"CLOSING\""), + GF(",\"INITIAL\"")); + waitResponse(); + return 1 == res; + } + +public: + + /* Utilities */ + + template + void streamWrite(T last) + { + stream.print(last); + } + + template + void streamWrite(T head, Args... tail) + { + stream.print(head); + streamWrite(tail...); + } + + bool streamSkipUntil(char c) //TODO: timeout + { + while (true) { + while (!stream.available()) { + TINY_GSM_YIELD(); + } + if (stream.read() == c) { + return true; + } + } + return false; + } + + template + void sendAT(Args... cmd) + { + streamWrite("AT", cmd..., GSM_NL); + stream.flush(); + TINY_GSM_YIELD(); + //DBG("### AT:", cmd...); + } + + // TODO: Optimize this! + uint8_t waitResponse(uint32_t timeout, String& data, + GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), + GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) + { + /*String r1s(r1); r1s.trim(); + String r2s(r2); r2s.trim(); + String r3s(r3); r3s.trim(); + String r4s(r4); r4s.trim(); + String r5s(r5); r5s.trim(); + DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ + data.reserve(64); + int index = 0; + unsigned long startMillis = millis(); + do { + TINY_GSM_YIELD(); + while (stream.available() > 0) { + int a = stream.read(); + if (a <= 0) { + continue; // Skip 0x00 bytes, just in case + } + data += (char)a; + if (r1 && data.endsWith(r1)) { + index = 1; + goto finish; + } else if (r2 && data.endsWith(r2)) { + index = 2; + goto finish; + } else if (r3 && data.endsWith(r3)) { + index = 3; + goto finish; + } else if (r4 && data.endsWith(r4)) { + index = 4; + goto finish; + } else if (r5 && data.endsWith(r5)) { + index = 5; + goto finish; + } else if (data.endsWith(GF("+CIPRCV:"))) { + int mux = stream.readStringUntil(',').toInt(); + int len = stream.readStringUntil(',').toInt(); + int len_orig = len; + if (len > sockets[mux]->rx.free()) { + DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free()); + } else { + DBG("### Got: ", len, "->", sockets[mux]->rx.free()); + } + while (len--) { + while (!stream.available()) { + TINY_GSM_YIELD(); + } + sockets[mux]->rx.put(stream.read()); + } + if (len_orig > sockets[mux]->available()) { // TODO + DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig); + } + data = ""; + } else if (data.endsWith(GF("+TCPCLOSED:"))) { + int mux = stream.readStringUntil('\n').toInt(); + if (mux >= 0 && mux < TINY_GSM_MUX_COUNT) { + sockets[mux]->sock_connected = false; + } + data = ""; + DBG("### Closed: ", mux); + } + } + } while (millis() - startMillis < timeout); +finish: + if (!index) { + data.trim(); + if (data.length()) { + DBG("### Unhandled:", data); + } + data = ""; + } + return index; + } + + uint8_t waitResponse(uint32_t timeout, + GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), + GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) + { + String data; + return waitResponse(timeout, data, r1, r2, r3, r4, r5); + } + + uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), + GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) + { + return waitResponse(1000, r1, r2, r3, r4, r5); + } + +public: + Stream& stream; + +protected: + GsmClient* sockets[TINY_GSM_MUX_COUNT]; +}; + +#endif diff --git a/drivers/TinyGSM/TinyGsmClientESP8266.h b/drivers/TinyGSM/TinyGsmClientESP8266.h new file mode 100644 index 0000000..76d88ea --- /dev/null +++ b/drivers/TinyGSM/TinyGsmClientESP8266.h @@ -0,0 +1,591 @@ +/** + * file TinyGsmClientESP8266.h + * author Volodymyr Shymanskyy + * license LGPL-3.0 + * copyright Copyright (c) 2016 Volodymyr Shymanskyy + * date Nov 2016 + */ + +#ifndef TinyGsmClientESP8266_h +#define TinyGsmClientESP8266_h + +//#define TINY_GSM_DEBUG Serial + +#if !defined(TINY_GSM_RX_BUFFER) +#define TINY_GSM_RX_BUFFER 512 +#endif + +#define TINY_GSM_MUX_COUNT 5 + +#include "TinyGsmCommon.h" + +#define GSM_NL "\r\n" +static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; +static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; +static unsigned TINY_GSM_TCP_KEEP_ALIVE = 120; + +class TinyGsm +{ + +public: + + class GsmClient : public Client + { + friend class TinyGsm; + typedef TinyGsmFifo RxFifo; + + public: + GsmClient() {} + + GsmClient(TinyGsm& modem, uint8_t mux = 1) + { + init(&modem, mux); + } + + bool init(TinyGsm* modem, uint8_t mux = 1) + { + this->at = modem; + this->mux = mux; + sock_connected = false; + + at->sockets[mux] = this; + + return true; + } + + public: + virtual int connect(const char *host, uint16_t port) + { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux); + return sock_connected; + } + + virtual int connect(IPAddress ip, uint16_t port) + { + String host; + host.reserve(16); + host += ip[0]; + host += "."; + host += ip[1]; + host += "."; + host += ip[2]; + host += "."; + host += ip[3]; + return connect(host.c_str(), port); + } + + virtual void stop() + { + TINY_GSM_YIELD(); + at->sendAT(GF("+CIPCLOSE="), mux); + sock_connected = false; + at->waitResponse(); + rx.clear(); + } + + virtual size_t write(const uint8_t *buf, size_t size) + { + TINY_GSM_YIELD(); + //at->maintain(); + return at->modemSend(buf, size, mux); + } + + virtual size_t write(uint8_t c) + { + return write(&c, 1); + } + + virtual int available() + { + TINY_GSM_YIELD(); + if (!rx.size() && sock_connected) { + at->maintain(); + } + return rx.size(); + } + + virtual int read(uint8_t *buf, size_t size) + { + TINY_GSM_YIELD(); + size_t cnt = 0; + while (cnt < size) { + size_t chunk = TinyGsmMin(size-cnt, rx.size()); + if (chunk > 0) { + rx.get(buf, chunk); + buf += chunk; + cnt += chunk; + continue; + } + // TODO: Read directly into user buffer? + if (!rx.size() && sock_connected) { + at->maintain(); + //break; + } + } + return cnt; + } + + virtual int read() + { + uint8_t c; + if (read(&c, 1) == 1) { + return c; + } + return -1; + } + + virtual int peek() + { + return -1; //TODO + } + virtual void flush() + { + at->stream.flush(); + } + + virtual uint8_t connected() + { + if (available()) { + return true; + } + return sock_connected; + } + virtual operator bool() + { + return connected(); + } + + /* + * Extended API + */ + + String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + + private: + TinyGsm* at; + uint8_t mux; + bool sock_connected; + RxFifo rx; + }; + + class GsmClientSecure : public GsmClient + { + public: + GsmClientSecure() {} + + GsmClientSecure(TinyGsm& modem, uint8_t mux = 1) + : GsmClient(modem, mux) + {} + + public: + virtual int connect(const char *host, uint16_t port) + { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux, true); + return sock_connected; + } + }; + +public: + + explicit TinyGsm(Stream& stream) + : stream(stream) + { + memset(sockets, 0, sizeof(sockets)); + } + + /* + * Basic functions + */ + bool begin() + { + return init(); + } + + bool init() + { + if (!testAT()) { + return false; + } + sendAT(GF("E0")); // Echo Off + if (waitResponse() != 1) { + return false; + } + return true; + } + + void setBaud(unsigned long baud) + { + sendAT(GF("+IPR="), baud); + } + + bool testAT(unsigned long timeout = 10000L) + { + for (unsigned long start = millis(); millis() - start < timeout; ) { + sendAT(GF("")); + if (waitResponse(200) == 1) { + delay(100); + return true; + } + delay(100); + } + return false; + } + + void maintain() + { + waitResponse(10, NULL, NULL); + } + + bool factoryDefault() + { + sendAT(GF("+RESTORE")); + return waitResponse() == 1; + } + + String getModemInfo() + { + sendAT(GF("+GMR")); + String res; + if (waitResponse(1000L, res) != 1) { + return ""; + } + res.replace(GSM_NL "OK" GSM_NL, ""); + res.replace(GSM_NL, " "); + res.trim(); + return res; + } + + bool hasSSL() + { + return true; + } + + /* + * Power functions + */ + + bool restart() + { + if (!testAT()) { + return false; + } + sendAT(GF("+RST")); + if (waitResponse(10000L) != 1) { + return false; + } + if (waitResponse(10000L, GF(GSM_NL "ready" GSM_NL)) != 1) { + return false; + } + delay(500); + return init(); + } + + + /* + * Generic network functions + */ + + int getSignalQuality() + { + sendAT(GF("+CWJAP_CUR?")); + int res1 = waitResponse(GF("No AP"), GF("+CWJAP_CUR:")); + if (res1 != 2) { + waitResponse(); + return 0; + } + streamSkipUntil(','); // Skip SSID + streamSkipUntil(','); // Skip BSSID/MAC address + streamSkipUntil(','); // Skip Chanel number + int res2 = stream.parseInt(); // Read RSSI + waitResponse(); // Returns an OK after the value + return res2; + } + + bool isNetworkConnected() + { + sendAT(GF("+CIPSTATUS")); + int res1 = waitResponse(3000, GF("STATUS:")); + int res2 = 0; + if (res1 == 1) { + res2 = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5")); + } + // status of ESP8266 station interface + // 2 : ESP8266 station connected to an AP and has obtained IP + // 3 : ESP8266 station created a TCP or UDP transmission + // 4 : the TCP or UDP transmission of ESP8266 station disconnected (but AP is connected) + // 5 : ESP8266 station did NOT connect to an AP + waitResponse(); // Returns an OK after the status + if (res2 == 2 || res2 == 3 || res2 == 4) { + return true; + } else { + return false; + } + } + + bool waitForNetwork(unsigned long timeout = 60000L) + { + for (unsigned long start = millis(); millis() - start < timeout; ) { + sendAT(GF("+CIPSTATUS")); + int res1 = waitResponse(3000, GF("busy p..."), GF("STATUS:")); + if (res1 == 2) { + int res2 = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5")); + if (res2 == 2 || res2 == 3 || res2 == 4) { + waitResponse(); + return true; + } + } + delay(250); + } + return false; + } + + /* + * WiFi functions + */ + bool networkConnect(const char* ssid, const char* pwd) + { + + sendAT(GF("+CIPMUX=1")); + if (waitResponse() != 1) { + return false; + } + + sendAT(GF("+CWMODE_CUR=1")); + if (waitResponse() != 1) { + return false; + } + + sendAT(GF("+CWJAP_CUR=\""), ssid, GF("\",\""), pwd, GF("\"")); + if (waitResponse(30000L, GFP(GSM_OK), GF(GSM_NL "FAIL" GSM_NL)) != 1) { + return false; + } + + return true; + } + + bool networkDisconnect() + { + sendAT(GF("+CWQAP")); + bool retVal = waitResponse(10000L) == 1; + waitResponse(GF("WIFI DISCONNECT")); + return retVal; + } + + String getLocalIP() + { + sendAT(GF("+CIPSTA_CUR??")); + int res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:")); + if (res1 != 2) { + return ""; + } + String res2 = stream.readStringUntil('"'); + waitResponse(); + return res2; + } + + IPAddress localIP() + { + return TinyGsmIpFromString(getLocalIP()); + } + +protected: + + bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false) + { + if (ssl) { + sendAT(GF("+CIPSSLSIZE=4096")); + waitResponse(); + } + sendAT(GF("+CIPSTART="), mux, ',', ssl ? GF("\"SSL") : GF("\"TCP"), GF("\",\""), host, GF("\","), + port, GF(","), TINY_GSM_TCP_KEEP_ALIVE); + // TODO: Check mux + int rsp = waitResponse(75000L, + GFP(GSM_OK), + GFP(GSM_ERROR), + GF("ALREADY CONNECT")); + // if (rsp == 3) waitResponse(); // May return "ERROR" after the "ALREADY CONNECT" + return (1 == rsp); + } + + int modemSend(const void* buff, size_t len, uint8_t mux) + { + sendAT(GF("+CIPSEND="), mux, ',', len); + if (waitResponse(GF(">")) != 1) { + return 0; + } + stream.write((uint8_t*)buff, len); + stream.flush(); + if (waitResponse(10000L, GF(GSM_NL "SEND OK" GSM_NL)) != 1) { + return 0; + } + return len; + } + + bool modemGetConnected(uint8_t mux) + { + // TODO: re-check this + sendAT(GF("+CIPSTATUS="), mux); + int res1 = waitResponse(3000, GF("STATUS:")); + int res2; + if (res1 == 1) { + res2 = waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5")); + } + // status of ESP8266 station interface + // 2 : ESP8266 station connected to an AP and has obtained IP + // 3 : ESP8266 station created a TCP or UDP transmission + // 4 : the TCP or UDP transmission of ESP8266 station disconnected (but AP is connected) + // 5 : ESP8266 station did NOT connect to an AP + waitResponse(); // Returns an OK after the status + if (res2 == 2 || res2 == 3 || res2 == 4) { + return true; + } else { + return false; + } + } + +public: + + /* Utilities */ + + template + void streamWrite(T last) + { + stream.print(last); + } + + template + void streamWrite(T head, Args... tail) + { + stream.print(head); + streamWrite(tail...); + } + + bool streamSkipUntil(char c) //TODO: timeout + { + while (true) { + while (!stream.available()) { + TINY_GSM_YIELD(); + } + if (stream.read() == c) { + return true; + } + } + return false; + } + + template + void sendAT(Args... cmd) + { + streamWrite("AT", cmd..., GSM_NL); + stream.flush(); + TINY_GSM_YIELD(); + //DBG("### AT:", cmd...); + } + + // TODO: Optimize this! + uint8_t waitResponse(uint32_t timeout, String& data, + GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), + GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) + { + /*String r1s(r1); r1s.trim(); + String r2s(r2); r2s.trim(); + String r3s(r3); r3s.trim(); + String r4s(r4); r4s.trim(); + String r5s(r5); r5s.trim(); + DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ + data.reserve(64); + int index = 0; + unsigned long startMillis = millis(); + do { + TINY_GSM_YIELD(); + while (stream.available() > 0) { + int a = stream.read(); + if (a <= 0) { + continue; // Skip 0x00 bytes, just in case + } + data += (char)a; + if (r1 && data.endsWith(r1)) { + index = 1; + goto finish; + } else if (r2 && data.endsWith(r2)) { + index = 2; + goto finish; + } else if (r3 && data.endsWith(r3)) { + index = 3; + goto finish; + } else if (r4 && data.endsWith(r4)) { + index = 4; + goto finish; + } else if (r5 && data.endsWith(r5)) { + index = 5; + goto finish; + } else if (data.endsWith(GF(GSM_NL "+IPD,"))) { + int mux = stream.readStringUntil(',').toInt(); + int len = stream.readStringUntil(':').toInt(); + int len_orig = len; + if (len > sockets[mux]->rx.free()) { + DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free()); + } else { + DBG("### Got: ", len, "->", sockets[mux]->rx.free()); + } + while (len--) { + while (!stream.available()) { + TINY_GSM_YIELD(); + } + sockets[mux]->rx.put(stream.read()); + } + if (len_orig > sockets[mux]->available()) { // TODO + DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig); + } + data = ""; + } else if (data.endsWith(GF("CLOSED"))) { + int muxStart = max(0,data.lastIndexOf(GSM_NL, data.length()-8)); + int coma = data.indexOf(',', muxStart); + int mux = data.substring(muxStart, coma).toInt(); + if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { + sockets[mux]->sock_connected = false; + } + data = ""; + DBG("### Closed: ", mux); + } + } + } while (millis() - startMillis < timeout); +finish: + if (!index) { + data.trim(); + if (data.length()) { + DBG("### Unhandled:", data); + } + data = ""; + } + return index; + } + + uint8_t waitResponse(uint32_t timeout, + GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), + GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) + { + String data; + return waitResponse(timeout, data, r1, r2, r3, r4, r5); + } + + uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), + GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) + { + return waitResponse(1000, r1, r2, r3, r4, r5); + } + +public: + Stream& stream; + +protected: + GsmClient* sockets[TINY_GSM_MUX_COUNT]; +}; + +#endif diff --git a/drivers/TinyGSM/TinyGsmClientM590.h b/drivers/TinyGSM/TinyGsmClientM590.h new file mode 100644 index 0000000..5c6288f --- /dev/null +++ b/drivers/TinyGSM/TinyGsmClientM590.h @@ -0,0 +1,781 @@ +/** + * file TinyGsmClientM590.h + * author Volodymyr Shymanskyy + * license LGPL-3.0 + * copyright Copyright (c) 2016 Volodymyr Shymanskyy + * date Nov 2016 + */ + +#ifndef TinyGsmClientM590_h +#define TinyGsmClientM590_h + +//#define TINY_GSM_DEBUG Serial + +#if !defined(TINY_GSM_RX_BUFFER) +#define TINY_GSM_RX_BUFFER 256 +#endif + +#define TINY_GSM_MUX_COUNT 2 + +#include "TinyGsmCommon.h" + +#define GSM_NL "\r\n" +static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; +static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; + +enum SimStatus { + SIM_ERROR = 0, + SIM_READY = 1, + SIM_LOCKED = 2, +}; + +enum RegStatus { + REG_UNREGISTERED = 0, + REG_SEARCHING = 3, + REG_DENIED = 2, + REG_OK_HOME = 1, + REG_OK_ROAMING = 5, + REG_UNKNOWN = 4, +}; + + +class TinyGsm +{ + +public: + + class GsmClient : public Client + { + friend class TinyGsm; + typedef TinyGsmFifo RxFifo; + + public: + GsmClient() {} + + GsmClient(TinyGsm& modem, uint8_t mux = 1) + { + init(&modem, mux); + } + + bool init(TinyGsm* modem, uint8_t mux = 1) + { + this->at = modem; + this->mux = mux; + sock_connected = false; + + at->sockets[mux] = this; + + return true; + } + + public: + virtual int connect(const char *host, uint16_t port) + { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux); + return sock_connected; + } + + virtual int connect(IPAddress ip, uint16_t port) + { + String host; + host.reserve(16); + host += ip[0]; + host += "."; + host += ip[1]; + host += "."; + host += ip[2]; + host += "."; + host += ip[3]; + return connect(host.c_str(), port); + } + + virtual void stop() + { + TINY_GSM_YIELD(); + at->sendAT(GF("+TCPCLOSE="), mux); + sock_connected = false; + at->waitResponse(); + rx.clear(); + } + + virtual size_t write(const uint8_t *buf, size_t size) + { + TINY_GSM_YIELD(); + //at->maintain(); + return at->modemSend(buf, size, mux); + } + + virtual size_t write(uint8_t c) + { + return write(&c, 1); + } + + virtual int available() + { + TINY_GSM_YIELD(); + if (!rx.size() && sock_connected) { + at->maintain(); + } + return rx.size(); + } + + virtual int read(uint8_t *buf, size_t size) + { + TINY_GSM_YIELD(); + size_t cnt = 0; + while (cnt < size) { + size_t chunk = TinyGsmMin(size-cnt, rx.size()); + if (chunk > 0) { + rx.get(buf, chunk); + buf += chunk; + cnt += chunk; + continue; + } + // TODO: Read directly into user buffer? + if (!rx.size() && sock_connected) { + at->maintain(); + //break; + } + } + return cnt; + } + + virtual int read() + { + uint8_t c; + if (read(&c, 1) == 1) { + return c; + } + return -1; + } + + virtual int peek() + { + return -1; //TODO + } + virtual void flush() + { + at->stream.flush(); + } + + virtual uint8_t connected() + { + if (available()) { + return true; + } + return sock_connected; + } + virtual operator bool() + { + return connected(); + } + + /* + * Extended API + */ + + String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + + private: + TinyGsm* at; + uint8_t mux; + bool sock_connected; + RxFifo rx; + }; + +public: + + explicit TinyGsm(Stream& stream) + : stream(stream) + { + memset(sockets, 0, sizeof(sockets)); + } + + /* + * Basic functions + */ + bool begin() + { + return init(); + } + + bool init() + { + if (!testAT()) { + return false; + } + sendAT(GF("&FZE0")); // Factory + Reset + Echo Off + if (waitResponse() != 1) { + return false; + } +#ifdef TINY_GSM_DEBUG + sendAT(GF("+CMEE=2")); + waitResponse(); +#endif + + getSimStatus(); + return true; + } + + void setBaud(unsigned long baud) + { + sendAT(GF("+IPR="), baud); + } + + bool testAT(unsigned long timeout = 10000L) + { + for (unsigned long start = millis(); millis() - start < timeout; ) { + sendAT(GF("")); + if (waitResponse(200) == 1) { + delay(100); + return true; + } + delay(100); + } + return false; + } + + void maintain() + { + //while (stream.available()) { + waitResponse(10, NULL, NULL); + //} + } + + bool factoryDefault() + { + sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write + waitResponse(); + sendAT(GF("+ICF=3,1")); // 8 data 0 parity 1 stop + waitResponse(); + sendAT(GF("+ENPWRSAVE=0")); // Disable PWR save + waitResponse(); + sendAT(GF("+XISP=0")); // Use internal stack + waitResponse(); + sendAT(GF("&W")); // Write configuration + return waitResponse() == 1; + } + + String getModemInfo() + { + sendAT(GF("I")); + String res; + if (waitResponse(1000L, res) != 1) { + return ""; + } + res.replace(GSM_NL "OK" GSM_NL, ""); + res.replace(GSM_NL, " "); + res.trim(); + return res; + } + + bool hasSSL() + { + return false; + } + + /* + * Power functions + */ + + bool restart() + { + if (!testAT()) { + return false; + } + sendAT(GF("+CFUN=15")); + if (waitResponse(10000L) != 1) { + return false; + } + //MODEM:STARTUP + waitResponse(60000L, GF(GSM_NL "+PBREADY" GSM_NL)); + return init(); + } + + bool poweroff() + { + sendAT(GF("+CPWROFF")); + return waitResponse(3000L) == 1; + } + + bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED; + + bool sleepEnable(bool enable = true) + { + sendAT(GF("+ENPWRSAVE="), enable); + return waitResponse() == 1; + } + + /* + * SIM card functions + */ + + bool simUnlock(const char *pin) + { + sendAT(GF("+CPIN=\""), pin, GF("\"")); + return waitResponse() == 1; + } + + String getSimCCID() + { + sendAT(GF("+CCID")); + if (waitResponse(GF(GSM_NL "+CCID:")) != 1) { + return ""; + } + String res = stream.readStringUntil('\n'); + waitResponse(); + res.trim(); + return res; + } + + String getIMEI() + { + sendAT(GF("+GSN")); + if (waitResponse(GF(GSM_NL)) != 1) { + return ""; + } + String res = stream.readStringUntil('\n'); + waitResponse(); + res.trim(); + return res; + } + + SimStatus getSimStatus(unsigned long timeout = 10000L) + { + for (unsigned long start = millis(); millis() - start < timeout; ) { + sendAT(GF("+CPIN?")); + if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) { + delay(1000); + continue; + } + int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK")); + waitResponse(); + switch (status) { + case 2: + case 3: + return SIM_LOCKED; + case 1: + return SIM_READY; + default: + return SIM_ERROR; + } + } + return SIM_ERROR; + } + + RegStatus getRegistrationStatus() + { + sendAT(GF("+CREG?")); + if (waitResponse(GF(GSM_NL "+CREG:")) != 1) { + return REG_UNKNOWN; + } + streamSkipUntil(','); // Skip format (0) + int status = stream.readStringUntil('\n').toInt(); + waitResponse(); + return (RegStatus)status; + } + + String getOperator() + { + sendAT(GF("+COPS?")); + if (waitResponse(GF(GSM_NL "+COPS:")) != 1) { + return ""; + } + streamSkipUntil('"'); // Skip mode and format + String res = stream.readStringUntil('"'); + waitResponse(); + return res; + } + + /* + * Generic network functions + */ + + int getSignalQuality() + { + sendAT(GF("+CSQ")); + if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) { + return 99; + } + int res = stream.readStringUntil(',').toInt(); + waitResponse(); + return res; + } + + bool isNetworkConnected() + { + RegStatus s = getRegistrationStatus(); + return (s == REG_OK_HOME || s == REG_OK_ROAMING); + } + + bool waitForNetwork(unsigned long timeout = 60000L) + { + for (unsigned long start = millis(); millis() - start < timeout; ) { + if (isNetworkConnected()) { + return true; + } + delay(250); + } + return false; + } + + /* + * GPRS functions + */ + bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) + { + gprsDisconnect(); + + sendAT(GF("+XISP=0")); + waitResponse(); + + sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"'); + waitResponse(); + + if (!user) { + user = ""; + } + if (!pwd) { + pwd = ""; + } + sendAT(GF("+XGAUTH=1,1,\""), user, GF("\",\""), pwd, GF("\"")); + waitResponse(); + + sendAT(GF("+XIIC=1")); + waitResponse(); + + const unsigned long timeout = 60000L; + for (unsigned long start = millis(); millis() - start < timeout; ) { + if (isGprsConnected()) { + //goto set_dns; // TODO + return true; + } + delay(500); + } + return false; + +set_dns: + sendAT(GF("+DNSSERVER=1,8.8.8.8")); + waitResponse(); + + sendAT(GF("+DNSSERVER=2,8.8.4.4")); + waitResponse(); + + return true; + } + + bool gprsDisconnect() + { + // TODO: There is no command in AT command set + // XIIC=0 does not work + return true; + } + + bool isGprsConnected() + { + sendAT(GF("+XIIC?")); + if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { + return false; + } + int res = stream.readStringUntil(',').toInt(); + waitResponse(); + return res == 1; + } + + String getLocalIP() + { + sendAT(GF("+XIIC?")); + if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { + return ""; + } + stream.readStringUntil(','); + String res = stream.readStringUntil('\n'); + waitResponse(); + res.trim(); + return res; + } + + IPAddress localIP() + { + return TinyGsmIpFromString(getLocalIP()); + } + + /* + * Phone Call functions + */ + + bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE; + + bool callAnswer() TINY_GSM_ATTR_NOT_AVAILABLE; + + bool callNumber(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE; + + bool callHangup() TINY_GSM_ATTR_NOT_AVAILABLE; + + /* + * Messaging functions + */ + + String sendUSSD(const String& code) + { + sendAT(GF("+CMGF=1")); + waitResponse(); + sendAT(GF("+CSCS=\"HEX\"")); + waitResponse(); + sendAT(GF("D"), code); + if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) { + return ""; + } + stream.readStringUntil('"'); + String hex = stream.readStringUntil('"'); + stream.readStringUntil(','); + int dcs = stream.readStringUntil('\n').toInt(); + + if (waitResponse() != 1) { + return ""; + } + + if (dcs == 15) { + return TinyGsmDecodeHex8bit(hex); + } else if (dcs == 72) { + return TinyGsmDecodeHex16bit(hex); + } else { + return hex; + } + } + + bool sendSMS(const String& number, const String& text) + { + sendAT(GF("+CSCS=\"GSM\"")); + waitResponse(); + sendAT(GF("+CMGF=1")); + waitResponse(); + sendAT(GF("+CMGS=\""), number, GF("\"")); + if (waitResponse(GF(">")) != 1) { + return false; + } + stream.print(text); + stream.write((char)0x1A); + stream.flush(); + return waitResponse(60000L) == 1; + } + + bool sendSMS_UTF16(const String& number, const void* text, size_t len) + TINY_GSM_ATTR_NOT_AVAILABLE; + + /* + * Location functions + */ + + String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE; + + /* + * Battery functions + */ + + uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE; + + int getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE; + +protected: + + bool modemConnect(const char* host, uint16_t port, uint8_t mux) + { + for (int i=0; i<3; i++) { // TODO: no need for loop? + String ip = dnsIpQuery(host); + + sendAT(GF("+TCPSETUP="), mux, GF(","), ip, GF(","), port); + int rsp = waitResponse(75000L, + GF(",OK" GSM_NL), + GF(",FAIL" GSM_NL), + GF("+TCPSETUP:Error" GSM_NL)); + if (1 == rsp) { + return true; + } else if (3 == rsp) { + sendAT(GF("+TCPCLOSE="), mux); + waitResponse(); + } + delay(1000); + } + return false; + } + + int modemSend(const void* buff, size_t len, uint8_t mux) + { + sendAT(GF("+TCPSEND="), mux, ',', len); + if (waitResponse(GF(">")) != 1) { + return 0; + } + stream.write((uint8_t*)buff, len); + stream.write((char)0x0D); + stream.flush(); + if (waitResponse(30000L, GF(GSM_NL "+TCPSEND:")) != 1) { + return 0; + } + stream.readStringUntil('\n'); + return len; + } + + bool modemGetConnected(uint8_t mux) + { + sendAT(GF("+CIPSTATUS="), mux); + int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), GF(",\"CLOSING\""), + GF(",\"INITIAL\"")); + waitResponse(); + return 1 == res; + } + + String dnsIpQuery(const char* host) + { + sendAT(GF("+DNS=\""), host, GF("\"")); + if (waitResponse(10000L, GF(GSM_NL "+DNS:")) != 1) { + return ""; + } + String res = stream.readStringUntil('\n'); + waitResponse(GF("+DNS:OK" GSM_NL)); + res.trim(); + return res; + } + +public: + + /* Utilities */ + + template + void streamWrite(T last) + { + stream.print(last); + } + + template + void streamWrite(T head, Args... tail) + { + stream.print(head); + streamWrite(tail...); + } + + bool streamSkipUntil(char c) //TODO: timeout + { + while (true) { + while (!stream.available()) { + TINY_GSM_YIELD(); + } + if (stream.read() == c) { + return true; + } + } + return false; + } + + template + void sendAT(Args... cmd) + { + streamWrite("AT", cmd..., GSM_NL); + stream.flush(); + TINY_GSM_YIELD(); + //DBG("### AT:", cmd...); + } + + // TODO: Optimize this! + uint8_t waitResponse(uint32_t timeout, String& data, + GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), + GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) + { + /*String r1s(r1); r1s.trim(); + String r2s(r2); r2s.trim(); + String r3s(r3); r3s.trim(); + String r4s(r4); r4s.trim(); + String r5s(r5); r5s.trim(); + DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ + data.reserve(64); + int index = 0; + unsigned long startMillis = millis(); + do { + TINY_GSM_YIELD(); + while (stream.available() > 0) { + int a = stream.read(); + if (a <= 0) { + continue; // Skip 0x00 bytes, just in case + } + data += (char)a; + if (r1 && data.endsWith(r1)) { + index = 1; + goto finish; + } else if (r2 && data.endsWith(r2)) { + index = 2; + goto finish; + } else if (r3 && data.endsWith(r3)) { + index = 3; + goto finish; + } else if (r4 && data.endsWith(r4)) { + index = 4; + goto finish; + } else if (r5 && data.endsWith(r5)) { + index = 5; + goto finish; + } else if (data.endsWith(GF("+TCPRECV:"))) { + int mux = stream.readStringUntil(',').toInt(); + int len = stream.readStringUntil(',').toInt(); + int len_orig = len; + if (len > sockets[mux]->rx.free()) { + DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free()); + } else { + DBG("### Got: ", len, "->", sockets[mux]->rx.free()); + } + while (len--) { + while (!stream.available()) { + TINY_GSM_YIELD(); + } + sockets[mux]->rx.put(stream.read()); + } + if (len_orig > sockets[mux]->available()) { // TODO + DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig); + } + data = ""; + } else if (data.endsWith(GF("+TCPCLOSE:"))) { + int mux = stream.readStringUntil(',').toInt(); + stream.readStringUntil('\n'); + if (mux >= 0 && mux < TINY_GSM_MUX_COUNT) { + sockets[mux]->sock_connected = false; + } + data = ""; + DBG("### Closed: ", mux); + } + } + } while (millis() - startMillis < timeout); +finish: + if (!index) { + data.trim(); + if (data.length()) { + DBG("### Unhandled:", data); + } + data = ""; + } + return index; + } + + uint8_t waitResponse(uint32_t timeout, + GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), + GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) + { + String data; + return waitResponse(timeout, data, r1, r2, r3, r4, r5); + } + + uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), + GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) + { + return waitResponse(1000, r1, r2, r3, r4, r5); + } + +public: + Stream& stream; + +protected: + GsmClient* sockets[TINY_GSM_MUX_COUNT]; +}; + +#endif diff --git a/drivers/TinyGSM/TinyGsmClientSIM800.h b/drivers/TinyGSM/TinyGsmClientSIM800.h new file mode 100644 index 0000000..265bdc0 --- /dev/null +++ b/drivers/TinyGSM/TinyGsmClientSIM800.h @@ -0,0 +1,1057 @@ +/** + * file TinyGsmClientSIM800.h + * author Volodymyr Shymanskyy + * license LGPL-3.0 + * copyright Copyright (c) 2016 Volodymyr Shymanskyy + * date Nov 2016 + */ + +#ifndef TinyGsmClientSIM800_h +#define TinyGsmClientSIM800_h + +//#define TINY_GSM_DEBUG Serial +//#define TINY_GSM_USE_HEX + +#if !defined(TINY_GSM_RX_BUFFER) +#define TINY_GSM_RX_BUFFER 64 +#endif + +#define TINY_GSM_MUX_COUNT 5 + +#include "TinyGsmCommon.h" + +#define GSM_NL "\r\n" +static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; +static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; + +enum SimStatus { + SIM_ERROR = 0, + SIM_READY = 1, + SIM_LOCKED = 2, +}; + +enum RegStatus { + REG_UNREGISTERED = 0, + REG_SEARCHING = 2, + REG_DENIED = 3, + REG_OK_HOME = 1, + REG_OK_ROAMING = 5, + REG_UNKNOWN = 4, +}; + + +class TinyGsmSim800 +{ + +public: + + class GsmClient : public Client + { + friend class TinyGsmSim800; + typedef TinyGsmFifo RxFifo; + + public: + GsmClient() {} + + GsmClient(TinyGsmSim800& modem, uint8_t mux = 1) + { + init(&modem, mux); + } + + bool init(TinyGsmSim800* modem, uint8_t mux = 1) + { + this->at = modem; + this->mux = mux; + sock_available = 0; + prev_check = 0; + sock_connected = false; + got_data = false; + + at->sockets[mux] = this; + + return true; + } + + public: + virtual int connect(const char *host, uint16_t port) + { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux); + return sock_connected; + } + + virtual int connect(IPAddress ip, uint16_t port) + { + String host; + host.reserve(16); + host += ip[0]; + host += "."; + host += ip[1]; + host += "."; + host += ip[2]; + host += "."; + host += ip[3]; + return connect(host.c_str(), port); + } + + virtual void stop() + { + TINY_GSM_YIELD(); + at->sendAT(GF("+CIPCLOSE="), mux); + sock_connected = false; + at->waitResponse(); + rx.clear(); + } + + virtual size_t write(const uint8_t *buf, size_t size) + { + TINY_GSM_YIELD(); + at->maintain(); + return at->modemSend(buf, size, mux); + } + + virtual size_t write(uint8_t c) + { + return write(&c, 1); + } + + virtual int available() + { + TINY_GSM_YIELD(); + if (!rx.size() && sock_connected) { + // Workaround: sometimes SIM800 forgets to notify about data arrival. + // TODO: Currently we ping the module periodically, + // but maybe there's a better indicator that we need to poll + if (millis() - prev_check > 500) { + got_data = true; + prev_check = millis(); + } + at->maintain(); + } + return rx.size() + sock_available; + } + + virtual int read(uint8_t *buf, size_t size) + { + TINY_GSM_YIELD(); + at->maintain(); + size_t cnt = 0; + while (cnt < size && sock_connected) { + size_t chunk = TinyGsmMin(size-cnt, rx.size()); + if (chunk > 0) { + rx.get(buf, chunk); + buf += chunk; + cnt += chunk; + continue; + } + // TODO: Read directly into user buffer? + at->maintain(); + if (sock_available > 0) { + at->modemRead(rx.free(), mux); + } else { + break; + } + } + return cnt; + } + + virtual int read() + { + uint8_t c; + if (read(&c, 1) == 1) { + return c; + } + return -1; + } + + virtual int peek() + { + return -1; //TODO + } + virtual void flush() + { + at->stream.flush(); + } + + virtual uint8_t connected() + { + if (available()) { + return true; + } + return sock_connected; + } + virtual operator bool() + { + return connected(); + } + + /* + * Extended API + */ + + String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + + private: + TinyGsmSim800* at; + uint8_t mux; + uint16_t sock_available; + uint32_t prev_check; + bool sock_connected; + bool got_data; + RxFifo rx; + }; + + class GsmClientSecure : public GsmClient + { + public: + GsmClientSecure() {} + + GsmClientSecure(TinyGsmSim800& modem, uint8_t mux = 1) + : GsmClient(modem, mux) + {} + + public: + virtual int connect(const char *host, uint16_t port) + { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, mux, true); + return sock_connected; + } + }; + +public: + + explicit TinyGsmSim800(Stream& stream) + : stream(stream) + { + memset(sockets, 0, sizeof(sockets)); + } + + /* + * Basic functions + */ + bool begin() + { + return init(); + } + + bool init() + { + if (!testAT()) { + return false; + } + sendAT(GF("&FZ")); // Factory + Reset + waitResponse(); + sendAT(GF("E0")); // Echo Off + if (waitResponse() != 1) { + return false; + } + getSimStatus(); + return true; + } + + void setBaud(unsigned long baud) + { + sendAT(GF("+IPR="), baud); + } + + bool testAT(unsigned long timeout = 10000L) + { + //streamWrite(GF("AAAAA" GSM_NL)); // TODO: extra A's to help detect the baud rate + for (unsigned long start = millis(); millis() - start < timeout; ) { + sendAT(GF("")); + if (waitResponse(200) == 1) { + delay(100); + return true; + } + delay(100); + } + return false; + } + + void maintain() + { + for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) { + GsmClient* sock = sockets[mux]; + if (sock && sock->got_data) { + sock->got_data = false; + sock->sock_available = modemGetAvailable(mux); + } + } + while (stream.available()) { + waitResponse(10, NULL, NULL); + } + } + + bool factoryDefault() + { + sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write + waitResponse(); + sendAT(GF("+IPR=0")); // Auto-baud + waitResponse(); + sendAT(GF("+IFC=0,0")); // No Flow Control + waitResponse(); + sendAT(GF("+ICF=3,3")); // 8 data 0 parity 1 stop + waitResponse(); + sendAT(GF("+CSCLK=0")); // Disable Slow Clock + waitResponse(); + sendAT(GF("&W")); // Write configuration + return waitResponse() == 1; + } + + String getModemInfo() + { + sendAT(GF("I")); + String res; + if (waitResponse(1000L, res) != 1) { + return ""; + } + res.replace(GSM_NL "OK" GSM_NL, ""); + res.replace(GSM_NL, " "); + res.trim(); + return res; + } + + bool hasSSL() + { +#if defined(TINY_GSM_MODEM_SIM900) + return false; +#else + sendAT(GF("+CIPSSL=?")); + if (waitResponse(GF(GSM_NL "+CIPSSL:")) != 1) { + return false; + } + return waitResponse() == 1; +#endif + } + + /* + * Power functions + */ + + bool restart() + { + if (!testAT()) { + return false; + } + sendAT(GF("+CFUN=0")); + if (waitResponse(10000L) != 1) { + return false; + } + sendAT(GF("+CFUN=1,1")); + if (waitResponse(10000L) != 1) { + return false; + } + delay(3000); + return init(); + } + + bool poweroff() + { + sendAT(GF("+CPOWD=1")); + return waitResponse(GF("NORMAL POWER DOWN")) == 1; + } + + bool radioOff() + { + sendAT(GF("+CFUN=0")); + if (waitResponse(10000L) != 1) { + return false; + } + delay(3000); + return true; + } + + /* + During sleep, the SIM800 module has its serial communication disabled. In order to reestablish communication + pull the DRT-pin of the SIM800 module LOW for at least 50ms. Then use this function to disable sleep mode. + The DTR-pin can then be released again. + */ + bool sleepEnable(bool enable = true) + { + sendAT(GF("+CSCLK="), enable); + return waitResponse() == 1; + } + + /* + * SIM card functions + */ + + bool simUnlock(const char *pin) + { + sendAT(GF("+CPIN=\""), pin, GF("\"")); + return waitResponse() == 1; + } + + String getSimCCID() + { + sendAT(GF("+ICCID")); + if (waitResponse(GF(GSM_NL "+ICCID:")) != 1) { + return ""; + } + String res = stream.readStringUntil('\n'); + waitResponse(); + res.trim(); + return res; + } + + String getIMEI() + { + sendAT(GF("+GSN")); + if (waitResponse(GF(GSM_NL)) != 1) { + return ""; + } + String res = stream.readStringUntil('\n'); + waitResponse(); + res.trim(); + return res; + } + + SimStatus getSimStatus(unsigned long timeout = 10000L) + { + for (unsigned long start = millis(); millis() - start < timeout; ) { + sendAT(GF("+CPIN?")); + if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) { + delay(1000); + continue; + } + int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), GF("NOT INSERTED")); + waitResponse(); + switch (status) { + case 2: + case 3: + return SIM_LOCKED; + case 1: + return SIM_READY; + default: + return SIM_ERROR; + } + } + return SIM_ERROR; + } + + RegStatus getRegistrationStatus() + { + sendAT(GF("+CREG?")); + if (waitResponse(GF(GSM_NL "+CREG:")) != 1) { + return REG_UNKNOWN; + } + streamSkipUntil(','); // Skip format (0) + int status = stream.readStringUntil('\n').toInt(); + waitResponse(); + return (RegStatus)status; + } + + String getOperator() + { + sendAT(GF("+COPS?")); + if (waitResponse(GF(GSM_NL "+COPS:")) != 1) { + return ""; + } + streamSkipUntil('"'); // Skip mode and format + String res = stream.readStringUntil('"'); + waitResponse(); + return res; + } + + /* + * Generic network functions + */ + + int getSignalQuality() + { + sendAT(GF("+CSQ")); + if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) { + return 99; + } + int res = stream.readStringUntil(',').toInt(); + waitResponse(); + return res; + } + + bool isNetworkConnected() + { + RegStatus s = getRegistrationStatus(); + return (s == REG_OK_HOME || s == REG_OK_ROAMING); + } + + bool waitForNetwork(unsigned long timeout = 60000L) + { + for (unsigned long start = millis(); millis() - start < timeout; ) { + if (isNetworkConnected()) { + return true; + } + delay(250); + } + return false; + } + + /* + * GPRS functions + */ + bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) + { + gprsDisconnect(); + + // Set the Bearer for the IP + sendAT(GF("+SAPBR=3,1,\"Contype\",\"GPRS\"")); // Set the connection type to GPRS + waitResponse(); + + sendAT(GF("+SAPBR=3,1,\"APN\",\""), apn, '"'); // Set the APN + waitResponse(); + + if (user && strlen(user) > 0) { + sendAT(GF("+SAPBR=3,1,\"USER\",\""), user, '"'); // Set the user name + waitResponse(); + } + if (pwd && strlen(pwd) > 0) { + sendAT(GF("+SAPBR=3,1,\"PWD\",\""), pwd, '"'); // Set the password + waitResponse(); + } + + // Define the PDP context + sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"'); + waitResponse(); + + // Activate the PDP context + sendAT(GF("+CGACT=1,1")); + waitResponse(60000L); + + // Open the definied GPRS bearer context + sendAT(GF("+SAPBR=1,1")); + waitResponse(85000L); + // Query the GPRS bearer context status + sendAT(GF("+SAPBR=2,1")); + if (waitResponse(30000L) != 1) { + return false; + } + + // Attach to GPRS + sendAT(GF("+CGATT=1")); + if (waitResponse(60000L) != 1) { + return false; + } + + // TODO: wait AT+CGATT? + + // Set to multi-IP + sendAT(GF("+CIPMUX=1")); + if (waitResponse() != 1) { + return false; + } + + // Put in "quick send" mode (thus no extra "Send OK") + sendAT(GF("+CIPQSEND=1")); + if (waitResponse() != 1) { + return false; + } + + // Set to get data manually + sendAT(GF("+CIPRXGET=1")); + if (waitResponse() != 1) { + return false; + } + + // Start Task and Set APN, USER NAME, PASSWORD + sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\"")); + if (waitResponse(60000L) != 1) { + return false; + } + + // Bring Up Wireless Connection with GPRS or CSD + sendAT(GF("+CIICR")); + if (waitResponse(60000L) != 1) { + return false; + } + + // Get Local IP Address, only assigned after connection + sendAT(GF("+CIFSR;E0")); + if (waitResponse(10000L) != 1) { + return false; + } + + // Configure Domain Name Server (DNS) + sendAT(GF("+CDNSCFG=\"8.8.8.8\",\"8.8.4.4\"")); + if (waitResponse() != 1) { + return false; + } + + return true; + } + + bool gprsDisconnect() + { + // Shut the TCP/IP connection + sendAT(GF("+CIPSHUT")); + if (waitResponse(60000L) != 1) { + return false; + } + + sendAT(GF("+CGATT=0")); // Deactivate the bearer context + if (waitResponse(60000L) != 1) { + return false; + } + + return true; + } + + bool isGprsConnected() + { + sendAT(GF("+CGATT?")); + if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) { + return false; + } + int res = stream.readStringUntil('\n').toInt(); + waitResponse(); + if (res != 1) { + return false; + } + + sendAT(GF("+CIFSR;E0")); // Another option is to use AT+CGPADDR=1 + if (waitResponse() != 1) { + return false; + } + + return true; + } + + String getLocalIP() + { + sendAT(GF("+CIFSR;E0")); + String res; + if (waitResponse(10000L, res) != 1) { + return ""; + } + res.replace(GSM_NL "OK" GSM_NL, ""); + res.replace(GSM_NL, ""); + res.trim(); + return res; + } + + IPAddress localIP() + { + return TinyGsmIpFromString(getLocalIP()); + } + + /* + * Phone Call functions + */ + + bool setGsmBusy(bool busy = true) + { + sendAT(GF("+GSMBUSY="), busy ? 1 : 0); + return waitResponse() == 1; + } + + bool callAnswer() + { + sendAT(GF("A")); + return waitResponse() == 1; + } + + // Returns true on pick-up, false on error/busy + bool callNumber(const String& number) + { + if (number == GF("last")) { + sendAT(GF("DL")); + } else { + sendAT(GF("D"), number, ";"); + } + int status = waitResponse(60000L, + GFP(GSM_OK), + GF("BUSY" GSM_NL), + GF("NO ANSWER" GSM_NL), + GF("NO CARRIER" GSM_NL)); + switch (status) { + case 1: + return true; + case 2: + case 3: + return false; + default: + return false; + } + } + + bool callHangup() + { + sendAT(GF("H")); + return waitResponse() == 1; + } + + // 0-9,*,#,A,B,C,D + bool dtmfSend(char cmd, int duration_ms = 100) + { + duration_ms = constrain(duration_ms, 100, 1000); + + sendAT(GF("+VTD="), duration_ms / 100); // VTD accepts in 1/10 of a second + waitResponse(); + + sendAT(GF("+VTS="), cmd); + return waitResponse(10000L) == 1; + } + + /* + * Messaging functions + */ + + String sendUSSD(const String& code) + { + sendAT(GF("+CMGF=1")); + waitResponse(); + sendAT(GF("+CSCS=\"HEX\"")); + waitResponse(); + sendAT(GF("+CUSD=1,\""), code, GF("\"")); + if (waitResponse() != 1) { + return ""; + } + if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) { + return ""; + } + stream.readStringUntil('"'); + String hex = stream.readStringUntil('"'); + stream.readStringUntil(','); + int dcs = stream.readStringUntil('\n').toInt(); + + if (dcs == 15) { + return TinyGsmDecodeHex8bit(hex); + } else if (dcs == 72) { + return TinyGsmDecodeHex16bit(hex); + } else { + return hex; + } + } + + bool sendSMS(const String& number, const String& text) + { + sendAT(GF("+CMGF=1")); + waitResponse(); + //Set GSM 7 bit default alphabet (3GPP TS 23.038) + sendAT(GF("+CSCS=\"GSM\"")); + waitResponse(); + sendAT(GF("+CMGS=\""), number, GF("\"")); + if (waitResponse(GF(">")) != 1) { + return false; + } + stream.print(text); + stream.write((char)0x1A); + stream.flush(); + return waitResponse(60000L) == 1; + } + + bool sendSMS_UTF16(const String& number, const void* text, size_t len) + { + sendAT(GF("+CMGF=1")); + waitResponse(); + sendAT(GF("+CSCS=\"HEX\"")); + waitResponse(); + sendAT(GF("+CSMP=17,167,0,8")); + waitResponse(); + + sendAT(GF("+CMGS=\""), number, GF("\"")); + if (waitResponse(GF(">")) != 1) { + return false; + } + + uint16_t* t = (uint16_t*)text; + for (size_t i=0; i> 8; + if (c < 0x10) { + stream.print('0'); + } + stream.print(c, HEX); + c = t[i] & 0xFF; + if (c < 0x10) { + stream.print('0'); + } + stream.print(c, HEX); + } + stream.write((char)0x1A); + stream.flush(); + return waitResponse(60000L) == 1; + } + + + /* + * Location functions + */ + + String getGsmLocation() + { + sendAT(GF("+CIPGSMLOC=1,1")); + if (waitResponse(10000L, GF(GSM_NL "+CIPGSMLOC:")) != 1) { + return ""; + } + String res = stream.readStringUntil('\n'); + waitResponse(); + res.trim(); + return res; + } + + /* + * Battery functions + */ + // Use: float vBatt = modem.getBattVoltage() / 1000.0; + uint16_t getBattVoltage() + { + sendAT(GF("+CBC")); + if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { + return 0; + } + streamSkipUntil(','); // Skip + streamSkipUntil(','); // Skip + + uint16_t res = stream.readStringUntil(',').toInt(); + waitResponse(); + return res; + } + + int getBattPercent() + { + sendAT(GF("+CBC")); + if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { + return false; + } + stream.readStringUntil(','); + int res = stream.readStringUntil(',').toInt(); + waitResponse(); + return res; + } + +protected: + + bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool ssl = false) + { +#if !defined(TINY_GSM_MODEM_SIM900) + sendAT(GF("+CIPSSL="), ssl); + int rsp = waitResponse(); + if (ssl && rsp != 1) { + return false; + } +#endif + sendAT(GF("+CIPSTART="), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), port); + rsp = waitResponse(75000L, + GF("CONNECT OK" GSM_NL), + GF("CONNECT FAIL" GSM_NL), + GF("ALREADY CONNECT" GSM_NL), + GF("ERROR" GSM_NL), + GF("CLOSE OK" GSM_NL) // Happens when HTTPS handshake fails + ); + return (1 == rsp); + } + + int modemSend(const void* buff, size_t len, uint8_t mux) + { + sendAT(GF("+CIPSEND="), mux, ',', len); + if (waitResponse(GF(">")) != 1) { + return 0; + } + stream.write((uint8_t*)buff, len); + stream.flush(); + if (waitResponse(GF(GSM_NL "DATA ACCEPT:")) != 1) { + return 0; + } + streamSkipUntil(','); // Skip mux + return stream.readStringUntil('\n').toInt(); + } + + size_t modemRead(size_t size, uint8_t mux) + { +#ifdef TINY_GSM_USE_HEX + sendAT(GF("+CIPRXGET=3,"), mux, ',', size); + if (waitResponse(GF("+CIPRXGET:")) != 1) { + return 0; + } +#else + sendAT(GF("+CIPRXGET=2,"), mux, ',', size); + if (waitResponse(GF("+CIPRXGET:")) != 1) { + return 0; + } +#endif + streamSkipUntil(','); // Skip mode 2/3 + streamSkipUntil(','); // Skip mux + size_t len = stream.readStringUntil(',').toInt(); + sockets[mux]->sock_available = stream.readStringUntil('\n').toInt(); + + for (size_t i=0; irx.put(c); + } + waitResponse(); + return len; + } + + size_t modemGetAvailable(uint8_t mux) + { + sendAT(GF("+CIPRXGET=4,"), mux); + size_t result = 0; + if (waitResponse(GF("+CIPRXGET:")) == 1) { + streamSkipUntil(','); // Skip mode 4 + streamSkipUntil(','); // Skip mux + result = stream.readStringUntil('\n').toInt(); + waitResponse(); + } + if (!result) { + sockets[mux]->sock_connected = modemGetConnected(mux); + } + return result; + } + + bool modemGetConnected(uint8_t mux) + { + sendAT(GF("+CIPSTATUS="), mux); + int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), GF(",\"CLOSING\""), + GF(",\"INITIAL\"")); + waitResponse(); + return 1 == res; + } + +public: + + /* Utilities */ + + template + void streamWrite(T last) + { + stream.print(last); + } + + template + void streamWrite(T head, Args... tail) + { + stream.print(head); + streamWrite(tail...); + } + + bool streamSkipUntil(char c) //TODO: timeout + { + while (true) { + while (!stream.available()) { + TINY_GSM_YIELD(); + } + if (stream.read() == c) { + return true; + } + } + return false; + } + + template + void sendAT(Args... cmd) + { + streamWrite("AT", cmd..., GSM_NL); + stream.flush(); + TINY_GSM_YIELD(); + //DBG("### AT:", cmd...); + } + + // TODO: Optimize this! + uint8_t waitResponse(uint32_t timeout, String& data, + GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), + GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) + { + /*String r1s(r1); r1s.trim(); + String r2s(r2); r2s.trim(); + String r3s(r3); r3s.trim(); + String r4s(r4); r4s.trim(); + String r5s(r5); r5s.trim(); + DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ + data.reserve(64); + int index = 0; + unsigned long startMillis = millis(); + do { + TINY_GSM_YIELD(); + while (stream.available() > 0) { + int a = stream.read(); + if (a <= 0) { + continue; // Skip 0x00 bytes, just in case + } + data += (char)a; + if (r1 && data.endsWith(r1)) { + index = 1; + goto finish; + } else if (r2 && data.endsWith(r2)) { + index = 2; + goto finish; + } else if (r3 && data.endsWith(r3)) { + index = 3; + goto finish; + } else if (r4 && data.endsWith(r4)) { + index = 4; + goto finish; + } else if (r5 && data.endsWith(r5)) { + index = 5; + goto finish; + } else if (data.endsWith(GF(GSM_NL "+CIPRXGET:"))) { + String mode = stream.readStringUntil(','); + if (mode.toInt() == 1) { + int mux = stream.readStringUntil('\n').toInt(); + if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { + sockets[mux]->got_data = true; + } + data = ""; + } else { + data += mode; + } + } else if (data.endsWith(GF("CLOSED" GSM_NL))) { + int nl = data.lastIndexOf(GSM_NL, data.length()-8); + int coma = data.indexOf(',', nl+2); + int mux = data.substring(nl+2, coma).toInt(); + if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { + sockets[mux]->sock_connected = false; + } + data = ""; + DBG("### Closed: ", mux); + } + } + } while (millis() - startMillis < timeout); +finish: + if (!index) { + data.trim(); + if (data.length()) { + DBG("### Unhandled:", data); + } + data = ""; + } + return index; + } + + uint8_t waitResponse(uint32_t timeout, + GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), + GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) + { + String data; + return waitResponse(timeout, data, r1, r2, r3, r4, r5); + } + + uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), + GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) + { + return waitResponse(1000, r1, r2, r3, r4, r5); + } + +public: + Stream& stream; + +protected: + GsmClient* sockets[TINY_GSM_MUX_COUNT]; +}; + +#endif diff --git a/drivers/TinyGSM/TinyGsmClientSIM808.h b/drivers/TinyGSM/TinyGsmClientSIM808.h new file mode 100644 index 0000000..d6342a1 --- /dev/null +++ b/drivers/TinyGSM/TinyGsmClientSIM808.h @@ -0,0 +1,163 @@ +/** + * file TinyGsmClientSIM808.h + * author Volodymyr Shymanskyy + * license LGPL-3.0 + * copyright Copyright (c) 2016 Volodymyr Shymanskyy + * date Nov 2016 + */ + +#ifndef TinyGsmClientSIM808_h +#define TinyGsmClientSIM808_h + +#include "TinyGsmClientSIM800.h" + +class TinyGsmSim808: public TinyGsmSim800 +{ + +public: + + explicit TinyGsmSim808(Stream& stream) + : TinyGsmSim800(stream) + {} + + /* + * GPS location functions + */ + + // enable GPS + bool enableGPS() + { + uint16_t state; + + sendAT(GF("+CGNSPWR=1")); + if (waitResponse() != 1) { + return false; + } + + return true; + } + + bool disableGPS() + { + uint16_t state; + + sendAT(GF("+CGNSPWR=0")); + if (waitResponse() != 1) { + return false; + } + + return true; + } + + // get the RAW GPS output + // works only with ans SIM808 V2 + String getGPSraw() + { + sendAT(GF("+CGNSINF")); + if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { + return ""; + } + String res = stream.readStringUntil('\n'); + waitResponse(); + res.trim(); + return res; + } + + // get GPS informations + // works only with ans SIM808 V2 + bool getGPS(float *lat, float *lon, float *speed=0, int *alt=0, int *vsat=0, int *usat=0) + { + //String buffer = ""; + char chr_buffer[12]; + bool fix = false; + + sendAT(GF("+CGNSINF")); + if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { + return false; + } + + stream.readStringUntil(','); // mode + if ( stream.readStringUntil(',').toInt() == 1 ) { + fix = true; + } + stream.readStringUntil(','); //utctime + *lat = stream.readStringUntil(',').toFloat(); //lat + *lon = stream.readStringUntil(',').toFloat(); //lon + if (alt != NULL) { + *alt = stream.readStringUntil(',').toFloat(); //lon + } + if (speed != NULL) { + *speed = stream.readStringUntil(',').toFloat(); //speed + } + stream.readStringUntil(','); + stream.readStringUntil(','); + stream.readStringUntil(','); + stream.readStringUntil(','); + stream.readStringUntil(','); + stream.readStringUntil(','); + stream.readStringUntil(','); + if (vsat != NULL) { + *vsat = stream.readStringUntil(',').toInt(); //viewed satelites + } + if (usat != NULL) { + *usat = stream.readStringUntil(',').toInt(); //used satelites + } + stream.readStringUntil('\n'); + + waitResponse(); + + return fix; + } + + // get GPS time + // works only with SIM808 V2 + bool getGPSTime(int *year, int *month, int *day, int *hour, int *minute, int *second) + { + bool fix = false; + char chr_buffer[12]; + sendAT(GF("+CGNSINF")); + if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { + return false; + } + + for (int i = 0; i < 3; i++) { + String buffer = stream.readStringUntil(','); + buffer.toCharArray(chr_buffer, sizeof(chr_buffer)); + switch (i) { + case 0: + //mode + break; + case 1: + //fixstatus + if ( buffer.toInt() == 1 ) { + fix = buffer.toInt(); + } + break; + case 2: + *year = buffer.substring(0,4).toInt(); + *month = buffer.substring(4,6).toInt(); + *day = buffer.substring(6,8).toInt(); + *hour = buffer.substring(8,10).toInt(); + *minute = buffer.substring(10,12).toInt(); + *second = buffer.substring(12,14).toInt(); + break; + + default: + // if nothing else matches, do the default + // default is optional + break; + } + } + String res = stream.readStringUntil('\n'); + waitResponse(); + + if (fix) { + return true; + } else { + return false; + } + } + +}; + +#endif diff --git a/drivers/TinyGSM/TinyGsmClientU201.h b/drivers/TinyGSM/TinyGsmClientU201.h new file mode 100644 index 0000000..d5349ac --- /dev/null +++ b/drivers/TinyGSM/TinyGsmClientU201.h @@ -0,0 +1,789 @@ +/** + * file TinyGsmClientU201.h + * author Volodymyr Shymanskyy + * license LGPL-3.0 + * copyright Copyright (c) 2016 Volodymyr Shymanskyy + * date Nov 2016 + */ + +#ifndef TinyGsmClientU201_h +#define TinyGsmClientU201_h + +//#define TINY_GSM_DEBUG Serial + +#if !defined(TINY_GSM_RX_BUFFER) +#define TINY_GSM_RX_BUFFER 64 +#endif + +#define TINY_GSM_MUX_COUNT 5 + +#include "TinyGsmCommon.h" + +#define GSM_NL "\r\n" +static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; +static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; + +enum SimStatus { + SIM_ERROR = 0, + SIM_READY = 1, + SIM_LOCKED = 2, +}; + +enum RegStatus { + REG_UNREGISTERED = 0, + REG_SEARCHING = 2, + REG_DENIED = 3, + REG_OK_HOME = 1, + REG_OK_ROAMING = 5, + REG_UNKNOWN = 4, +}; + + +class TinyGsmU201 +{ + +public: + + class GsmClient : public Client + { + friend class TinyGsmU201; + typedef TinyGsmFifo RxFifo; + + public: + GsmClient() {} + + GsmClient(TinyGsmU201& modem, uint8_t mux = 1) + { + init(&modem, mux); + } + + bool init(TinyGsmU201* modem, uint8_t mux = 1) + { + this->at = modem; + this->mux = mux; + sock_available = 0; + sock_connected = false; + got_data = false; + + return true; + } + + public: + virtual int connect(const char *host, uint16_t port) + { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, &mux); + at->sockets[mux] = this; + return sock_connected; + } + + virtual int connect(IPAddress ip, uint16_t port) + { + String host; + host.reserve(16); + host += ip[0]; + host += "."; + host += ip[1]; + host += "."; + host += ip[2]; + host += "."; + host += ip[3]; + return connect(host.c_str(), port); + } + + virtual void stop() + { + TINY_GSM_YIELD(); + at->sendAT(GF("+USOCL="), mux); + sock_connected = false; + at->waitResponse(); + rx.clear(); + } + + virtual size_t write(const uint8_t *buf, size_t size) + { + TINY_GSM_YIELD(); + at->maintain(); + return at->modemSend(buf, size, mux); + } + + virtual size_t write(uint8_t c) + { + return write(&c, 1); + } + + virtual int available() + { + TINY_GSM_YIELD(); + if (!rx.size() && sock_connected) { + at->maintain(); + } + return rx.size() + sock_available; + } + + virtual int read(uint8_t *buf, size_t size) + { + TINY_GSM_YIELD(); + at->maintain(); + size_t cnt = 0; + while (cnt < size) { + size_t chunk = TinyGsmMin(size-cnt, rx.size()); + if (chunk > 0) { + rx.get(buf, chunk); + buf += chunk; + cnt += chunk; + continue; + } + // TODO: Read directly into user buffer? + at->maintain(); + if (sock_available > 0) { + at->modemRead(rx.free(), mux); + } else { + break; + } + } + return cnt; + } + + virtual int read() + { + uint8_t c; + if (read(&c, 1) == 1) { + return c; + } + return -1; + } + + virtual int peek() + { + return -1; //TODO + } + virtual void flush() + { + at->stream.flush(); + } + + virtual uint8_t connected() + { + if (available()) { + return true; + } + return sock_connected; + } + virtual operator bool() + { + return connected(); + } + + /* + * Extended API + */ + + String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + + private: + TinyGsmU201* at; + uint8_t mux; + uint16_t sock_available; + bool sock_connected; + bool got_data; + RxFifo rx; + }; + + class GsmClientSecure : public GsmClient + { + public: + GsmClientSecure() {} + + GsmClientSecure(TinyGsmU201& modem, uint8_t mux = 1) + : GsmClient(modem, mux) + {} + + public: + virtual int connect(const char *host, uint16_t port) + { + stop(); + TINY_GSM_YIELD(); + rx.clear(); + sock_connected = at->modemConnect(host, port, &mux, true); + at->sockets[mux] = this; + return sock_connected; + } + }; + +public: + +#ifdef GSM_DEFAULT_STREAM + explicit TinyGsmU201(Stream& stream = GSM_DEFAULT_STREAM) +#else + explicit TinyGsmU201(Stream& stream) +#endif + : stream(stream) + { + memset(sockets, 0, sizeof(sockets)); + } + + /* + * Basic functions + */ + bool begin(const char* pin = NULL) + { + return init(pin); + } + + bool init(const char* pin = NULL) + { + if (!testAT()) { + return false; + } + sendAT(GF("E0")); // Echo Off + if (waitResponse() != 1) { + return false; + } + int ret = getSimStatus(); + if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) { + simUnlock(pin); + } + return (getSimStatus() == SIM_READY); + } + + void setBaud(unsigned long baud) + { + sendAT(GF("+IPR="), baud); + } + + bool testAT(unsigned long timeout = 10000L) + { + for (unsigned long start = millis(); millis() - start < timeout; ) { + sendAT(GF("")); + if (waitResponse(200) == 1) { + delay(100); + return true; + } + delay(100); + } + return false; + } + + void maintain() + { + for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) { + GsmClient* sock = sockets[mux]; + if (sock && sock->got_data) { + sock->got_data = false; + sock->sock_available = modemGetAvailable(mux); + } + } + while (stream.available()) { + waitResponse(10, NULL, NULL); + } + } + + bool factoryDefault() + { + sendAT(GF("+UFACTORY=0,1")); // Factory + Reset + Echo Off + waitResponse(); + sendAT(GF("+CFUN=16")); // Auto-baud + return waitResponse() == 1; + } + + String getModemInfo() TINY_GSM_ATTR_NOT_IMPLEMENTED; + + bool hasSSL() + { + return true; + } + + /* + * Power functions + */ + + bool restart() + { + if (!testAT()) { + return false; + } + sendAT(GF("+CFUN=16")); + if (waitResponse(10000L) != 1) { + return false; + } + delay(3000); + return init(); + } + + bool poweroff() TINY_GSM_ATTR_NOT_IMPLEMENTED; + + /* + * SIM card functions + */ + + bool simUnlock(const char *pin) + { + sendAT(GF("+CPIN=\""), pin, GF("\"")); + return waitResponse() == 1; + } + + String getSimCCID() + { + sendAT(GF("+CCID")); + if (waitResponse(GF(GSM_NL "+CCID:")) != 1) { + return ""; + } + String res = stream.readStringUntil('\n'); + waitResponse(); + res.trim(); + return res; + } + + String getIMEI() + { + sendAT(GF("+CGSN")); + if (waitResponse(GF(GSM_NL)) != 1) { + return ""; + } + String res = stream.readStringUntil('\n'); + waitResponse(); + res.trim(); + return res; + } + + SimStatus getSimStatus(unsigned long timeout = 10000L) + { + for (unsigned long start = millis(); millis() - start < timeout; ) { + sendAT(GF("+CPIN?")); + if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) { + delay(1000); + continue; + } + int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), GF("NOT INSERTED")); + waitResponse(); + switch (status) { + case 2: + case 3: + return SIM_LOCKED; + case 1: + return SIM_READY; + default: + return SIM_ERROR; + } + } + return SIM_ERROR; + } + + RegStatus getRegistrationStatus() + { + sendAT(GF("+CGREG?")); + if (waitResponse(GF(GSM_NL "+CGREG:")) != 1) { + return REG_UNKNOWN; + } + streamSkipUntil(','); // Skip format (0) + int status = stream.readStringUntil('\n').toInt(); + waitResponse(); + return (RegStatus)status; + } + + String getOperator() + { + sendAT(GF("+COPS?")); + if (waitResponse(GF(GSM_NL "+COPS:")) != 1) { + return ""; + } + streamSkipUntil('"'); // Skip mode and format + String res = stream.readStringUntil('"'); + waitResponse(); + return res; + } + + /* + * Generic network functions + */ + + int getSignalQuality() + { + sendAT(GF("+CSQ")); + if (waitResponse(GF(GSM_NL "+CSQ:")) != 1) { + return 99; + } + int res = stream.readStringUntil(',').toInt(); + waitResponse(); + return res; + } + + bool isNetworkConnected() + { + RegStatus s = getRegistrationStatus(); + return (s == REG_OK_HOME || s == REG_OK_ROAMING); + } + + bool waitForNetwork(unsigned long timeout = 60000L) + { + for (unsigned long start = millis(); millis() - start < timeout; ) { + if (isNetworkConnected()) { + return true; + } + delay(250); + } + return false; + } + + /* + * GPRS functions + */ + bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) + { + gprsDisconnect(); + + sendAT(GF("+CGATT=1")); + waitResponse(5000L); + + sendAT(GF("+UPSD=0,1,\""), apn, '"'); + waitResponse(); + + if (user && strlen(user) > 0) { + sendAT(GF("+UPSD=0,2,\""), user, '"'); + waitResponse(); + } + if (pwd && strlen(pwd) > 0) { + sendAT(GF("+UPSD=0,3,\""), pwd, '"'); + waitResponse(); + } + + sendAT(GF("+UPSD=0,7,\"0.0.0.0\"")); // Dynamic IP + waitResponse(); + + sendAT(GF("+UPSDA=0,3")); + waitResponse(6000L); + + // Open a GPRS context + sendAT(GF("+UPSND=0,8")); + if (waitResponse(GF(",8,1")) != 1) { + return false; + } + return true; + } + + bool gprsDisconnect() + { + sendAT(GF("+UPSDA=0,4")); + if (waitResponse(60000L) != 1) { + return false; + } + + sendAT(GF("+CGATT=0")); + if (waitResponse(60000L) != 1) { + return false; + } + + return true; + } + + bool isGprsConnected() + { + sendAT(GF("+CGATT?")); + if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) { + return false; + } + int res = stream.readStringUntil('\n').toInt(); + waitResponse(); + if (res != 1) { + return false; + } + + sendAT(GF("+CIFSR")); + if (waitResponse() != 1) { + return false; + } + + return true; + } + + String getLocalIP() + { + sendAT(GF("+CIFSR;E0")); + String res; + if (waitResponse(10000L, res) != 1) { + return ""; + } + res.trim(); + return res; + } + + IPAddress localIP() + { + return TinyGsmIpFromString(getLocalIP()); + } + + /* + * Phone Call functions + */ + + bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; + + bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED; + + bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED; + + bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED; + + /* + * Messaging functions + */ + + String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED; + + bool sendSMS(const String& number, const String& text) TINY_GSM_ATTR_NOT_IMPLEMENTED; + + bool sendSMS_UTF16(const String& number, const void* text, + size_t len) TINY_GSM_ATTR_NOT_IMPLEMENTED; + + + /* + * Location functions + */ + + String getGsmLocation() + { + sendAT(GF("+ULOC=2,3,0,120,1")); + if (waitResponse(GF(GSM_NL "+UULOC:")) != 1) { + return ""; + } + String res = stream.readStringUntil('\n'); + waitResponse(); + res.trim(); + return res; + } + + /* + * Battery functions + */ + // Use: float vBatt = modem.getBattVoltage() / 1000.0; + uint16_t getBattVoltage() + { + sendAT(GF("+CIND")); + if (waitResponse(GF(GSM_NL "+CIND:")) != 1) { + return 0; + } + + uint16_t res = stream.readStringUntil(',').toInt(); + waitResponse(); + return res; + } + + int getBattPercent() TINY_GSM_ATTR_NOT_IMPLEMENTED; + +protected: + + bool modemConnect(const char* host, uint16_t port, uint8_t* mux, bool ssl = false) + { + sendAT(GF("+USOCR=6")); + if (waitResponse(GF(GSM_NL "+USOCR:")) != 1) { + return false; + } + *mux = stream.readStringUntil('\n').toInt(); + waitResponse(); + + if (ssl) { + sendAT(GF("+USOSEC="), *mux, ",1"); + waitResponse(); + } + + sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port); + int rsp = waitResponse(75000L); + return (1 == rsp); + } + + int modemSend(const void* buff, size_t len, uint8_t mux) + { + sendAT(GF("+USOWR="), mux, ',', len); + if (waitResponse(GF("@")) != 1) { + return -1; + } + // 50ms delay, see AT manual section 25.10.4 + delay(50); + stream.write((uint8_t*)buff, len); + stream.flush(); + if (waitResponse(GF(GSM_NL "+USOWR:")) != 1) { + return -1; + } + streamSkipUntil(','); // Skip mux + return stream.readStringUntil('\n').toInt(); + } + + size_t modemRead(size_t size, uint8_t mux) + { + sendAT(GF("+USORD="), mux, ',', size); + if (waitResponse(GF(GSM_NL "+USORD:")) != 1) { + return 0; + } + streamSkipUntil(','); // Skip mux + size_t len = stream.readStringUntil(',').toInt(); + streamSkipUntil('\"'); + + for (size_t i=0; irx.put(c); + } + streamSkipUntil('\"'); + waitResponse(); + return len; + } + + size_t modemGetAvailable(uint8_t mux) + { + sendAT(GF("+USORD="), mux, ',', 0); + size_t result = 0; + if (waitResponse(GF(GSM_NL "+USORD:")) == 1) { + streamSkipUntil(','); // Skip mux + result = stream.readStringUntil('\n').toInt(); + waitResponse(); + } + if (!result) { + sockets[mux]->sock_connected = modemGetConnected(mux); + } + return result; + } + + bool modemGetConnected(uint8_t mux) + { + sendAT(GF("+USOCTL="), mux, ",10"); + if (waitResponse(GF(GSM_NL "+USOCTL:")) != 1) { + return false; + } + + streamSkipUntil(','); // Skip mux + streamSkipUntil(','); // Skip type + int result = stream.readStringUntil('\n').toInt(); + + return result != 0; + } + +public: + + /* Utilities */ + + template + void streamWrite(T last) + { + stream.print(last); + } + + template + void streamWrite(T head, Args... tail) + { + stream.print(head); + streamWrite(tail...); + } + + bool streamSkipUntil(char c) //TODO: timeout + { + while (true) { + while (!stream.available()) { + TINY_GSM_YIELD(); + } + if (stream.read() == c) { + return true; + } + } + return false; + } + + template + void sendAT(Args... cmd) + { + streamWrite("AT", cmd..., GSM_NL); + stream.flush(); + TINY_GSM_YIELD(); + //DBG("### AT:", cmd...); + } + + // TODO: Optimize this! + uint8_t waitResponse(uint32_t timeout, String& data, + GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), + GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) + { + /*String r1s(r1); r1s.trim(); + String r2s(r2); r2s.trim(); + String r3s(r3); r3s.trim(); + String r4s(r4); r4s.trim(); + String r5s(r5); r5s.trim(); + DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ + data.reserve(64); + int index = 0; + unsigned long startMillis = millis(); + do { + TINY_GSM_YIELD(); + while (stream.available() > 0) { + int a = stream.read(); + if (a < 0) { + continue; + } + data += (char)a; + if (r1 && data.endsWith(r1)) { + index = 1; + goto finish; + } else if (r2 && data.endsWith(r2)) { + index = 2; + goto finish; + } else if (r3 && data.endsWith(r3)) { + index = 3; + goto finish; + } else if (r4 && data.endsWith(r4)) { + index = 4; + goto finish; + } else if (r5 && data.endsWith(r5)) { + index = 5; + goto finish; + } else if (data.endsWith(GF(GSM_NL "+UUSORD:"))) { + int mux = stream.readStringUntil(',').toInt(); + if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { + sockets[mux]->got_data = true; + } + data = ""; + } else if (data.endsWith(GF(GSM_NL "+UUSOCL:"))) { + int mux = stream.readStringUntil('\n').toInt(); + if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { + sockets[mux]->sock_connected = false; + } + data = ""; + DBG("### Closed: ", mux); + } + } + } while (millis() - startMillis < timeout); +finish: + if (!index) { + data.trim(); + if (data.length()) { + DBG("### Unhandled:", data); + } + data = ""; + } + return index; + } + + uint8_t waitResponse(uint32_t timeout, + GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), + GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) + { + String data; + return waitResponse(timeout, data, r1, r2, r3, r4, r5); + } + + uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), + GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) + { + return waitResponse(1000, r1, r2, r3, r4, r5); + } + +public: + Stream& stream; + +protected: + GsmClient* sockets[TINY_GSM_MUX_COUNT]; +}; + +#endif diff --git a/drivers/TinyGSM/TinyGsmClientXBee.h b/drivers/TinyGSM/TinyGsmClientXBee.h new file mode 100644 index 0000000..8efef85 --- /dev/null +++ b/drivers/TinyGSM/TinyGsmClientXBee.h @@ -0,0 +1,752 @@ +/** + * file TinyGsmClientXBee.h + * author Volodymyr Shymanskyy + * license LGPL-3.0 + * copyright Copyright (c) 2016 Volodymyr Shymanskyy + * date Nov 2016 + */ + +#ifndef TinyGsmClientXBee_h +#define TinyGsmClientXBee_h + +//#define TINY_GSM_DEBUG Serial + +#if !defined(TINY_GSM_RX_BUFFER) +#define TINY_GSM_RX_BUFFER 256 +#endif + +#define TINY_GSM_MUX_COUNT 1 // Multi-plexing isn't supported using command mode + +#include "TinyGsmCommon.h" + +#define GSM_NL "\r" +static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; +static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; + +enum SimStatus { + SIM_ERROR = 0, + SIM_READY = 1, + SIM_LOCKED = 2, +}; + +enum XBeeType { + S6B = 0, + LTEC1 = 1, +}; + +enum RegStatus { + REG_UNREGISTERED = 0, + REG_SEARCHING = 2, + REG_DENIED = 3, + REG_OK_HOME = 1, + REG_OK_ROAMING = 5, + REG_UNKNOWN = 4, +}; + + +class TinyGsm +{ + +public: + + class GsmClient : public Client + { + friend class TinyGsm; + + public: + GsmClient() {} + + GsmClient(TinyGsm& modem, uint8_t mux = 0) + { + init(&modem, mux); + } + + bool init(TinyGsm* modem, uint8_t mux = 0) + { + this->at = modem; + this->mux = mux; + sock_connected = false; + + at->sockets[mux] = this; + + return true; + } + + public: + virtual int connect(const char *host, uint16_t port) + { + at->streamClear(); // Empty anything remaining in the buffer; + at->commandMode(); + sock_connected = at->modemConnect(host, port, mux, false); + at->writeChanges(); + at->exitCommand(); + return sock_connected; + } + + virtual int connect(IPAddress ip, uint16_t port) + { + at->streamClear(); // Empty anything remaining in the buffer; + at->commandMode(); + sock_connected = at->modemConnect(ip, port, mux, false); + at->writeChanges(); + at->exitCommand(); + return sock_connected; + } + + // This is a hack to shut the socket by setting the timeout to zero and + // then sending an empty line to the server. + virtual void stop() + { + at->streamClear(); // Empty anything remaining in the buffer; + at->commandMode(); + at->sendAT(GF("TM0")); // Set socket timeout to 0; + at->waitResponse(); + at->writeChanges(); + at->exitCommand(); + at->modemSend("", 1, mux); + at->commandMode(); + at->sendAT(GF("TM64")); // Set socket timeout back to 10seconds; + at->waitResponse(); + at->writeChanges(); + at->exitCommand(); + at->streamClear(); // Empty anything remaining in the buffer; + sock_connected = false; + } + + virtual size_t write(const uint8_t *buf, size_t size) + { + TINY_GSM_YIELD(); + //at->maintain(); + return at->modemSend(buf, size, mux); + } + + virtual size_t write(uint8_t c) + { + return write(&c, 1); + } + + virtual int available() + { + TINY_GSM_YIELD(); + return at->stream.available(); + } + + virtual int read(uint8_t *buf, size_t size) + { + TINY_GSM_YIELD(); + return at->stream.readBytes(buf, size); + } + + virtual int read() + { + TINY_GSM_YIELD(); + return at->stream.read(); + } + + virtual int peek() + { + return at->stream.peek(); + } + virtual void flush() + { + at->stream.flush(); + } + + virtual uint8_t connected() + { + if (available()) { + return true; + } + return sock_connected; + } + virtual operator bool() + { + return connected(); + } + + /* + * Extended API + */ + + String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; + + private: + TinyGsm* at; + uint8_t mux; + bool sock_connected; + }; + + class GsmClientSecure : public GsmClient + { + public: + GsmClientSecure() {} + + GsmClientSecure(TinyGsm& modem, uint8_t mux = 1) + : GsmClient(modem, mux) + {} + + public: + virtual int connect(const char *host, uint16_t port) + { + at->streamClear(); // Empty anything remaining in the buffer; + at->commandMode(); + sock_connected = at->modemConnect(host, port, mux, true); + at->writeChanges(); + at->exitCommand(); + return sock_connected; + } + + virtual int connect(IPAddress ip, uint16_t port) + { + at->streamClear(); // Empty anything remaining in the buffer; + at->commandMode(); + sock_connected = at->modemConnect(ip, port, mux, true); + at->writeChanges(); + at->exitCommand(); + return sock_connected; + } + }; + +public: + + explicit TinyGsm(Stream& stream) + : stream(stream) + { + memset(sockets, 0, sizeof(sockets)); + } + + /* + * Basic functions + */ + bool begin() + { + return init(); + } + + bool init() + { + guardTime = 1100; + commandMode(); + sendAT(GF("AP0")); // Put in transparent mode + waitResponse(); + sendAT(GF("GT64")); // shorten the guard time to 100ms + waitResponse(); + writeChanges(); + sendAT(GF("HS")); // Get the "Hardware Series"; 0x601 for S6B (Wifi) + // wait for the response + unsigned long startMillis = millis(); + while (!stream.available() && millis() - startMillis < 1000) {}; + String res = streamReadUntil('\r'); // Does not send an OK, just the result + exitCommand(); + if (res == "601") { + beeType = S6B; + } else { + beeType = LTEC1; + } + guardTime = 125; + return true; + } + + bool testAT(unsigned long timeout = 10000L) + { + for (unsigned long start = millis(); millis() - start < timeout; ) { + if (commandMode()) { + sendAT(); + if (waitResponse(200) == 1) { + return true; + } + exitCommand(); + } + delay(100); + } + return false; + } + + void maintain() {} + + bool factoryDefault() + { + commandMode(); + sendAT(GF("RE")); + bool ret_val = waitResponse() == 1; + writeChanges(); + exitCommand(); + return ret_val; + } + + bool hasSSL() + { + if (beeType == S6B) { + return false; + } else { + return true; + } + } + + /* + * Power functions + */ + + bool restart() + { + commandMode(); + sendAT(GF("FR")); + if (waitResponse() != 1) { + return false; + } + delay (2000); // Actually resets about 2 seconds later + for (unsigned long start = millis(); millis() - start < 60000L; ) { + if (commandMode()) { + exitCommand(); + return true; + } + } + exitCommand(); + return false;; + } + + void setupPinSleep() + { + commandMode(); + sendAT(GF("SM"),1); + waitResponse(); + if (beeType == S6B) { + sendAT(GF("SO"),200); + waitResponse(); + } + writeChanges(); + exitCommand(); + } + + /* + * SIM card functions + */ + + bool simUnlock(const char *pin) // Not supported + { + return false; + } + + String getSimCCID() + { + commandMode(); + sendAT(GF("S#")); + // wait for the response + unsigned long startMillis = millis(); + while (!stream.available() && millis() - startMillis < 1000) {}; + String res = streamReadUntil('\r'); // Does not send an OK, just the result + exitCommand(); + return res; + } + + String getIMEI() + { + commandMode(); + sendAT(GF("IM")); + // wait for the response + unsigned long startMillis = millis(); + while (!stream.available() && millis() - startMillis < 1000) {}; + String res = streamReadUntil('\r'); // Does not send an OK, just the result + exitCommand(); + return res; + } + + SimStatus getSimStatus(unsigned long timeout = 10000L) + { + return SIM_READY; // unsupported + } + + RegStatus getRegistrationStatus() + { + commandMode(); + sendAT(GF("AI")); + // wait for the response + unsigned long startMillis = millis(); + while (!stream.available() && millis() - startMillis < 1000) {}; + String res = streamReadUntil('\r'); // Does not send an OK, just the result + exitCommand(); + + if(res == GF("0")) { + return REG_OK_HOME; + } + + else if(res == GF("13") || res == GF("2A")) { + return REG_UNREGISTERED; + } + + else if(res == GF("FF") || res == GF("22") || res == GF("23") || + res == GF("40") || res == GF("41") || res == GF("42")) { + return REG_SEARCHING; + } + + else if(res == GF("24") || res == GF("25") || res == GF("27")) { + return REG_DENIED; + } + + else { + return REG_UNKNOWN; + } + } + + String getOperator() + { + commandMode(); + sendAT(GF("MN")); + // wait for the response + unsigned long startMillis = millis(); + while (!stream.available() && millis() - startMillis < 1000) {}; + String res = streamReadUntil('\r'); // Does not send an OK, just the result + exitCommand(); + return res; + } + + /* + * Generic network functions + */ + + int getSignalQuality() + { + commandMode(); + if (beeType == S6B) { + sendAT(GF("LM")); // ask for the "link margin" - the dB above sensitivity + } else { + sendAT(GF("DB")); // ask for the cell strength in dBm + } + // wait for the response + unsigned long startMillis = millis(); + while (!stream.available() && millis() - startMillis < 1000) {}; + char buf[2] = {0}; // Set up buffer for response + buf[0] = streamRead(); + buf[1] = streamRead(); + // DBG(buf[0], buf[1], "\n"); + exitCommand(); + int intr = strtol(buf, 0, 16); + if (beeType == S6B) { + return -93 + intr; // the maximum sensitivity is -93dBm + } else { + return -1*intr; // need to convert to negative number + } + } + + bool isNetworkConnected() + { + RegStatus s = getRegistrationStatus(); + return (s == REG_OK_HOME || s == REG_OK_ROAMING); + } + + bool waitForNetwork(unsigned long timeout = 60000L) + { + for (unsigned long start = millis(); millis() - start < timeout; ) { + if (isNetworkConnected()) { + return true; + } + delay(250); + } + return false; + } + + /* + * WiFi functions + */ + bool networkConnect(const char* ssid, const char* pwd) + { + + commandMode(); + + sendAT(GF("EE"), 2); // Set security to WPA2 + waitResponse(); + + sendAT(GF("ID"), ssid); + if (waitResponse() != 1) { + goto fail; + } + + sendAT(GF("PK"), pwd); + if (waitResponse() != 1) { + goto fail; + } + + writeChanges(); + exitCommand(); + + return true; + +fail: + exitCommand(); + return false; + } + + bool networkDisconnect() + { + return false; // Doesn't support disconnecting + } + + String getLocalIP() + { + commandMode(); + sendAT(GF("MY")); + String IPaddr; + IPaddr.reserve(16); + // wait for the response + unsigned long startMillis = millis(); + while (stream.available() < 8 && millis() - startMillis < 30000) {}; + IPaddr = streamReadUntil('\r'); // read result + return IPaddr; + } + + IPAddress localIP() + { + return TinyGsmIpFromString(getLocalIP()); + } + + /* + * GPRS functions + */ + bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) + { + commandMode(); + sendAT(GF("AN"), apn); // Set the APN + waitResponse(); + writeChanges(); + exitCommand(); + return true; + } + + bool gprsDisconnect() // TODO + { + return false; + } + + /* + * Messaging functions + */ + + String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED; + + bool sendSMS(const String& number, const String& text) + { + commandMode(); + sendAT(GF("IP"), 2); // Put in text messaging mode + waitResponse(); + sendAT(GF("PH"), number); // Set the phone number + waitResponse(); + sendAT(GF("TDD")); // Set the text delimiter to the standard 0x0D (carriabe return) + waitResponse(); + writeChanges(); + exitCommand(); + stream.print(text); + stream.write((char)0x0D); // close off with the carriage return + return true; + } + + +private: + + int modemConnect(const char* host, uint16_t port, uint8_t mux = 0, bool ssl = false) + { + sendAT(GF("LA"), host); + String strIP; + strIP.reserve(16); + // wait for the response + unsigned long startMillis = millis(); + while (stream.available() < 8 && millis() - startMillis < 30000) {}; + strIP = streamReadUntil('\r'); // read result + IPAddress ip = TinyGsmIpFromString(strIP); + return modemConnect(ip, port, mux, ssl); + } + + int modemConnect(IPAddress ip, uint16_t port, uint8_t mux = 0, bool ssl = false) + { + String host; + host.reserve(16); + host += ip[0]; + host += "."; + host += ip[1]; + host += "."; + host += ip[2]; + host += "."; + host += ip[3]; + if (ssl) { + sendAT(GF("IP"), 4); // Put in TCP mode + waitResponse(); + } else { + sendAT(GF("IP"), 1); // Put in TCP mode + waitResponse(); + } + sendAT(GF("DL"), host); // Set the "Destination Address Low" + waitResponse(); + sendAT(GF("DE"), String(port, HEX)); // Set the destination port + int rsp = waitResponse(); + return rsp; + } + + int modemSend(const void* buff, size_t len, uint8_t mux = 0) + { + stream.write((uint8_t*)buff, len); + stream.flush(); + return len; + } + + bool modemGetConnected(uint8_t mux = 0) + { + commandMode(); + sendAT(GF("AI")); + int res = waitResponse(GF("0")); + exitCommand(); + return 1 == res; + } + +public: + + /* Utilities */ + + template + void streamWrite(T last) + { + stream.print(last); + } + + template + void streamWrite(T head, Args... tail) + { + stream.print(head); + streamWrite(tail...); + } + + int streamRead() + { + return stream.read(); + } + + String streamReadUntil(char c) + { + TINY_GSM_YIELD(); + String return_string = stream.readStringUntil(c); + return_string.trim(); + // DBG(return_string, c); + return return_string; + } + + void streamClear(void) + { + while (stream.available()) { + streamRead(); + } + } + + bool commandMode(void) + { + delay(guardTime); // cannot send anything for 1 second before entering command mode + streamWrite(GF("+++")); // enter command mode + // DBG("\r\n+++\r\n"); + return 1 == waitResponse(guardTime*2); + } + + void writeChanges(void) + { + sendAT(GF("WR")); // Write changes to flash + waitResponse(); + sendAT(GF("AC")); // Apply changes + waitResponse(); + } + + void exitCommand(void) + { + sendAT(GF("CN")); // Exit command mode + waitResponse(); + } + + template + void sendAT(Args... cmd) + { + streamWrite("AT", cmd..., GSM_NL); + stream.flush(); + TINY_GSM_YIELD(); + //DBG("### AT:", cmd...); + } + + // TODO: Optimize this! + uint8_t waitResponse(uint32_t timeout, String& data, + GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), + GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) + { + /*String r1s(r1); r1s.trim(); + String r2s(r2); r2s.trim(); + String r3s(r3); r3s.trim(); + String r4s(r4); r4s.trim(); + String r5s(r5); r5s.trim(); + DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ + data.reserve(64); + int index = 0; + unsigned long startMillis = millis(); + do { + TINY_GSM_YIELD(); + while (stream.available() > 0) { + int a = streamRead(); + if (a <= 0) { + continue; // Skip 0x00 bytes, just in case + } + data += (char)a; + if (r1 && data.endsWith(r1)) { + index = 1; + goto finish; + } else if (r2 && data.endsWith(r2)) { + index = 2; + goto finish; + } else if (r3 && data.endsWith(r3)) { + index = 3; + goto finish; + } else if (r4 && data.endsWith(r4)) { + index = 4; + goto finish; + } else if (r5 && data.endsWith(r5)) { + index = 5; + goto finish; + } + } + } while (millis() - startMillis < timeout); +finish: + if (!index) { + data.trim(); + data.replace(GSM_NL GSM_NL, GSM_NL); + data.replace(GSM_NL, "\r\n" " "); + if (data.length()) { + DBG("### Unhandled:", data, "\r\n"); + } else { + DBG("### NO RESPONSE!\r\n"); + } + } else { + data.trim(); + data.replace(GSM_NL GSM_NL, GSM_NL); + data.replace(GSM_NL, "\r\n "); + if (data.length()) { + // DBG("<<< ", data); + } + } + return index; + } + + uint8_t waitResponse(uint32_t timeout, + GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), + GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) + { + String data; + return waitResponse(timeout, data, r1, r2, r3, r4, r5); + } + + uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), + GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) + { + return waitResponse(1000, r1, r2, r3, r4, r5); + } + +public: + Stream& stream; + +protected: + int guardTime; + XBeeType beeType; + GsmClient* sockets[TINY_GSM_MUX_COUNT]; +}; + +#endif diff --git a/drivers/TinyGSM/TinyGsmCommon.h b/drivers/TinyGSM/TinyGsmCommon.h new file mode 100644 index 0000000..458cc90 --- /dev/null +++ b/drivers/TinyGSM/TinyGsmCommon.h @@ -0,0 +1,195 @@ +/** + * file TinyGsmCommon.h + * author Volodymyr Shymanskyy + * license LGPL-3.0 + * copyright Copyright (c) 2016 Volodymyr Shymanskyy + * date Nov 2016 + */ + +#ifndef TinyGsmCommon_h +#define TinyGsmCommon_h + +#if defined(SPARK) || defined(PARTICLE) +#include "Particle.h" +#elif defined(ARDUINO) +#if ARDUINO >= 100 +#include "Arduino.h" +#else +#include "WProgram.h" +#endif +#endif + +#include +#include "TinyGsmFifo.h" + +#ifndef TINY_GSM_YIELD +#define TINY_GSM_YIELD() { delay(0); } +#endif + +#define TINY_GSM_ATTR_NOT_AVAILABLE __attribute__((error("Not available on this modem type"))) +#define TINY_GSM_ATTR_NOT_IMPLEMENTED __attribute__((error("Not implemented"))) + +#if defined(__AVR__) +#define TINY_GSM_PROGMEM PROGMEM +typedef const __FlashStringHelper* GsmConstStr; +#define GFP(x) (reinterpret_cast(x)) +#define GF(x) F(x) +#else +#define TINY_GSM_PROGMEM +typedef const char* GsmConstStr; +#define GFP(x) x +#define GF(x) x +#endif + +#ifdef TINY_GSM_DEBUG +namespace +{ +template +static void DBG(T last) +{ + TINY_GSM_DEBUG.println(last); +} + +template +static void DBG(T head, Args... tail) +{ + TINY_GSM_DEBUG.print(head); + TINY_GSM_DEBUG.print(' '); + DBG(tail...); +} +} +#else +#define DBG(...) +#endif + +template +const T& TinyGsmMin(const T& a, const T& b) +{ + return (b < a) ? b : a; +} + +template +const T& TinyGsmMax(const T& a, const T& b) +{ + return (b < a) ? a : b; +} + +template +uint32_t TinyGsmAutoBaud(T& SerialAT, uint32_t minimum = 9600, uint32_t maximum = 115200) +{ + static uint32_t rates[] = { 115200, 57600, 38400, 19200, 9600, 74400, 74880, 230400, 460800, 2400, 4800, 14400, 28800 }; + + for (unsigned i = 0; i < sizeof(rates)/sizeof(rates[0]); i++) { + uint32_t rate = rates[i]; + if (rate < minimum || rate > maximum) { + continue; + } + + DBG("Trying baud rate", rate, "..."); + SerialAT.begin(rate); + delay(10); + for (int i=0; i<3; i++) { + SerialAT.print("AT\r\n"); + String input = SerialAT.readString(); + if (input.indexOf("OK") >= 0) { + DBG("Modem responded at rate", rate); + return rate; + } + } + } + return 0; +} + +static inline +IPAddress TinyGsmIpFromString(const String& strIP) +{ + int Parts[4] = {0, }; + int Part = 0; + for (uint8_t i=0; i 3) { + return IPAddress(0,0,0,0); + } + continue; + } else if (c >= '0' && c <= '9') { + Parts[Part] *= 10; + Parts[Part] += c - '0'; + } else { + if (Part == 3) { + break; + } + } + } + return IPAddress(Parts[0], Parts[1], Parts[2], Parts[3]); +} + +static inline +String TinyGsmDecodeHex7bit(String &instr) +{ + String result; + byte reminder = 0; + int bitstate = 7; + for (unsigned i=0; i> bitstate; + bitstate--; + if (bitstate == 0) { + char c = reminder; + result += c; + reminder = 0; + bitstate = 7; + } + } + return result; +} + +static inline +String TinyGsmDecodeHex8bit(String &instr) +{ + String result; + for (unsigned i=0; i + +class TinyGsmFifo +{ +public: + + TinyGsmFifo() + { + clear(); + } + + void clear() + { + _r = 0; + _w = 0; + } + + // writing thread/context API + //------------------------------------------------------------- + + bool writeable(void) + { + return free() > 0; + } + + int free(void) + { + int s = _r - _w; + if (s <= 0) { + s += N; + } + return s - 1; + } + + bool put(const T& c) + { + int i = _w; + int j = i; + i = _inc(i); + if (i == _r) { // !writeable() + return false; + } + _b[j] = c; + _w = i; + return true; + } + + int put(const T* p, int n, bool t = false) + { + int c = n; + while (c) { + int f; + while ((f = free()) == 0) { // wait for space + if (!t) { + return n - c; // no more space and not blocking + } + /* nothing / just wait */; + } + // check free space + if (c < f) { + f = c; + } + int w = _w; + int m = N - w; + // check wrap + if (f > m) { + f = m; + } + memcpy(&_b[w], p, f); + _w = _inc(w, f); + c -= f; + p += f; + } + return n - c; + } + + // reading thread/context API + // -------------------------------------------------------- + + bool readable(void) + { + return (_r != _w); + } + + size_t size(void) + { + int s = _w - _r; + if (s < 0) { + s += N; + } + return s; + } + + bool get(T* p) + { + int r = _r; + if (r == _w) { // !readable() + return false; + } + *p = _b[r]; + _r = _inc(r); + return true; + } + + int get(T* p, int n, bool t = false) + { + int c = n; + while (c) { + int f; + for (;;) { // wait for data + f = size(); + if (f) { + break; // free space + } + if (!t) { + return n - c; // no space and not blocking + } + /* nothing / just wait */; + } + // check available data + if (c < f) { + f = c; + } + int r = _r; + int m = N - r; + // check wrap + if (f > m) { + f = m; + } + memcpy(p, &_b[r], f); + _r = _inc(r, f); + c -= f; + p += f; + } + return n - c; + } + +private: + int _inc(int i, int n = 1) + { + return (i + n) % N; + } + + T _b[N]; + int _w; + int _r; +}; + +#endif diff --git a/drivers/TinyGSM/keywords.txt b/drivers/TinyGSM/keywords.txt new file mode 100644 index 0000000..33f98c4 --- /dev/null +++ b/drivers/TinyGSM/keywords.txt @@ -0,0 +1,26 @@ +####################################### +# Data types (KEYWORD1) +####################################### +TinyGsm KEYWORD1 +TinyGsmClient KEYWORD1 +TinyGsmClientSecure KEYWORD1 + +SerialAT KEYWORD1 +SerialMon KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +begin KEYWORD2 +restart KEYWORD2 +waitForNetwork KEYWORD2 +getSimStatus KEYWORD2 +gprsConnect KEYWORD2 +gprsDisconnect KEYWORD2 +isGprsConnected KEYWORD2 +isNetworkConnected KEYWORD2 +factoryReset KEYWORD2 + +####################################### +# Literals (LITERAL1) +####################################### diff --git a/examples/GatewayGSMMQTTClient/GatewayGSMMQTTClient.ino b/examples/GatewayGSMMQTTClient/GatewayGSMMQTTClient.ino new file mode 100644 index 0000000..c9b5728 --- /dev/null +++ b/examples/GatewayGSMMQTTClient/GatewayGSMMQTTClient.ino @@ -0,0 +1,137 @@ +/** + * 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. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - Rait Lotamõis + * + * DESCRIPTION + * The TinyGSM MQTT gateway sends radio network (or locally attached sensors) data to your MQTT broker using a GSM modem or optionally an ESP8266 as a WiFi modem. + * 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 + * - 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 + +// Enables and select radio type (if attached) +#define MY_RADIO_NRF24 +//#define MY_RADIO_RFM69 +//#define MY_RADIO_RFM95 + +#define MY_GATEWAY_MQTT_CLIENT + +// Enable GSM modem support +#define MY_GATEWAY_TINYGSM + +// Define your modem +#define TINY_GSM_MODEM_SIM800 +// #define TINY_GSM_MODEM_SIM808 +// #define TINY_GSM_MODEM_SIM900 +// #define TINY_GSM_MODEM_A6 +// #define TINY_GSM_MODEM_A7 +// #define TINY_GSM_MODEM_M590 +// #define TINY_GSM_ESP8266 + +// leave empty anything that does not apply +#define MY_GSM_APN "internet" +//#define MY_GSM_PIN "1234" +#define MY_GSM_USR "" +//If using a GSM modem, this stands for your GSM connection password. If using WiFi, it's your wireless password. +#define MY_GSM_PSW "" +//#define MY_GSM_SSID "" + +// Use Hardware Serial on Mega, Leonardo, Micro +//#define SerialAT Serial1 +// or Software Serial on Uno, Nano +#include +#define MY_GSM_RX 4 +#define MY_GSM_TX 5 + +// If your Mosquitto is old fashioned and does not support 3.1.1 +//#define MQTT_VERSION MQTT_VERSION_3_1 + +// 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" + +// Set MQTT client id +#define MY_MQTT_CLIENT_ID "mysensors-1" + +// Enable these if your MQTT broker requires usenrame/password +//#define MY_MQTT_USER "username" +//#define MY_MQTT_PASSWORD "password" + +// Enable MY_IP_ADDRESS here if you want a static ip address (no DHCP) +//#define MY_IP_ADDRESS 192,168,32,220 + +// If using static ip you can define Gateway and Subnet address as well +//#define MY_IP_GATEWAY_ADDRESS 192,168,32,1 +//#define MY_IP_SUBNET_ADDRESS 255,255,255,0 + +// MQTT broker ip address or url. Define one or the other. +//#define MY_CONTROLLER_URL_ADDRESS "mymqttbroker.com" +#define MY_CONTROLLER_IP_ADDRESS 192, 168, 178, 68 + +// 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 +//#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 + +// 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 +//#define MY_DEFAULT_TX_LED_PIN 16 // the PCB, on board LED +*/ + +#include + +void setup() +{ + // Setup locally attached sensors +} + +void presentation() +{ + // Present locally attached sensors here +} + +void loop() +{ + // Send locally attached sensors data here +} + diff --git a/keywords.txt b/keywords.txt index 473c5da..476a0ec 100644 --- a/keywords.txt +++ b/keywords.txt @@ -112,6 +112,17 @@ MY_NODE_LOCK_COUNTER_MAX LITERAL1 MY_HW_HAS_GETENTROPY LITERAL1 hwGetentropy KEYWORD2 +# TinyGSM +MY_GATEWAY_TINYGSM LITERAL1 +MY_GSM_APN LITERAL1 +MY_GSM_BAUDRATE LITERAL1 +MY_GSM_PIN LITERAL1 +MY_GSM_PSW LITERAL1 +MY_GSM_RX LITERAL1 +MY_GSM_SSID LITERAL1 +MY_GSM_TX LITERAL1 +MY_GSM_USR LITERAL1 + # SoftSPI MY_SOFTSPI LITERAL1 MY_SOFT_SPI_SCK_PIN LITERAL1 From 3c0b2727a56907277d4d04c985fd72b14e4a483c Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Wed, 4 Apr 2018 15:43:13 -0300 Subject: [PATCH 32/60] Linux: Support keys in config file (#1093) - Signing and encryption keys are set through the configuration file. - SoftEeprom update. --- configure | 60 ++++-- core/MySigning.h | 8 +- drivers/Linux/SoftEeprom.cpp | 37 ++-- drivers/Linux/config.c | 67 ++++++- drivers/Linux/config.h | 3 + hal/architecture/Linux/MyMainLinuxGeneric.cpp | 182 ++++++++++-------- 6 files changed, 230 insertions(+), 127 deletions(-) diff --git a/configure b/configure index c03f3b2..dcca71b 100755 --- a/configure +++ b/configure @@ -113,8 +113,20 @@ MySensors options: EOF } +# Colors +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[1;33m' +LIGHT_BLUE='\033[1;34m' +NO_COLOR='\033[0m' + +OK="${GREEN}[OK]${NO_COLOR}" +ERROR="${RED}[ERROR]${NO_COLOR}" +FAILED="${YELLOW}[FAILED]${NO_COLOR}" +SECTION="${LIGHT_BLUE}[SECTION]${NO_COLOR}" + function die { - echo "[ERROR] $1" + printf "${ERROR} $1 \n" exit $2 } @@ -497,12 +509,12 @@ CC=${CC:-gcc} CXX=${CXX:-g++} if [ -z "${SOC}" ]; then - echo "[SECTION] Detecting target machine." + printf "${SECTION} Detecting target machine.\n" info=($(detect_machine)) SOC=${info[0]} TYPE=${info[1]} CPU=${info[2]} - echo " [OK] machine detected: SoC=${SOC}, Type=${TYPE}, CPU=${CPU}." + printf " ${OK} machine detected: SoC=${SOC}, Type=${TYPE}, CPU=${CPU}.\n" fi if [ -z "${CPUFLAGS}" ]; then @@ -512,23 +524,23 @@ fi if [[ $SOC == "BCM2835" || $SOC == "BCM2836" || $SOC == "BCM2837" ]]; then CPPFLAGS="-DLINUX_ARCH_RASPBERRYPI $CPPFLAGS" else - echo "[SECTION] Checking GPIO Sysfs." + printf "${SECTION} Checking GPIO Sysfs.\n" if [[ $(eval 'ls /sys/class/gpio/export 2>/dev/null') ]]; then - echo " [OK] /sys/class/gpio/export found" + printf " ${OK} /sys/class/gpio/export found.\n" else echo " [WARNING] /sys/class/gpio/export not found." fi fi if [ -z "${SPI_DRIVER}" ]; then - echo "[SECTION] Detecting SPI driver." + printf "${SECTION} Detecting SPI driver.\n" if [[ $SOC == "BCM2835" || $SOC == "BCM2836" || $SOC == "BCM2837" ]]; then SPI_DRIVER=BCM elif [[ $(eval 'ls /dev/spidev* 2>/dev/null') ]]; then SPI_DRIVER=SPIDEV fi if [ -n "${SPI_DRIVER}" ]; then - echo " [OK] SPI driver detected:${SPI_DRIVER}." + printf " ${OK} SPI driver detected:${SPI_DRIVER}.\n" else echo " [WARNING] No supported SPI driver detected. Using SPIDEV." SPI_DRIVER=SPIDEV @@ -551,6 +563,8 @@ if [ -n "${SPI_DRIVER}" ]; then esac fi +printf "${SECTION} Gateway configuration.\n" + if [[ ${debug} == "enable" ]]; then CPPFLAGS="-DMY_DEBUG $CPPFLAGS" fi @@ -567,6 +581,7 @@ elif [[ ${gateway_type} == "mqtt" ]]; then else die "Invalid gateway type." 2 fi +printf " ${OK} Type: ${gateway_type}.\n" if [[ ${transport_type} == "none" ]]; then # Transport disabled @@ -582,20 +597,22 @@ elif [[ ${transport_type} == "rfm95" ]]; then else die "Invalid transport type." 3 fi +printf " ${OK} Transport: ${transport_type}.\n" if [[ ${signing} == "none" ]]; then # Signing disabled - : + printf " ${OK} Signing: Disabled.\n" elif [[ ${signing} == "software" ]]; then CPPFLAGS="-DMY_SIGNING_SOFT $CPPFLAGS" if [[ ${signing_request_signatures} == true ]]; then CPPFLAGS="-DMY_SIGNING_REQUEST_SIGNATURES $CPPFLAGS" fi + printf " ${OK} Signing: Enabled - Using key from config file.\n" elif [[ ${signing} == "password" ]]; then if [ -z "${security_password}" ]; then - die "You need to set the password for signing with --my-security-password= option" 6 + die "You need to set the password for signing with --my-security-password option" 6 fi - echo "Simplified signing using password" + printf " ${OK} Signing: Enabled - Simplified signing using password.\n" CPPFLAGS="-DMY_SIGNING_SIMPLE_PASSWD=\\\"${security_password}\\\" $CPPFLAGS" else die "Invalid signing type." 7 @@ -604,41 +621,44 @@ fi if [[ ${encryption} == true ]]; then # Encryption enabled on some transport if [ -z "${security_password}" ]; then - echo "Encryption key from configuration" + printf " ${OK} Encryption: Enabled - Using key from config file.\n" else - echo "Simplified encryption using password" + printf " ${OK} Encryption: Enabled - Simplified encryption using password.\n" CPPFLAGS="-DMY_ENCRYPTION_SIMPLE_PASSWD=\\\"${security_password}\\\" $CPPFLAGS" fi +else + printf " ${OK} Encryption: Disabled.\n" fi LDFLAGS="-pthread $LDFLAGS" CPPFLAGS="$CPUFLAGS $CPPFLAGS" -echo "[SECTION] Detecting init system." +printf "${SECTION} Detecting init system.\n" if [ "${NO_INIT}" ]; then - echo " [OK] no init system chosen." + printf " ${OK} No init system chosen.\n" elif [ -x /usr/bin/systemctl ] || [ -x /bin/systemctl ]; then INIT_SYSTEM=systemd - echo " [OK] init system detected: systemd." + printf " ${OK} Init system detected: systemd.\n" elif [ -f /etc/init.d/cron ] && [ ! -h /etc/init.d/cron ]; then INIT_SYSTEM=sysvinit - echo " [OK] init system detected: sysvinit." + printf " ${OK} Init system detected: sysvinit.\n" else - echo " [FAILED] unknown init system." + printf " ${FAILED} Unknown init system." fi -echo "[SECTION] Saving configuration." +printf "${SECTION} Saving configuration.\n" echo -n "" > Makefile.inc for param in ${params}; do if [[ ${!param} ]]; then echo "${param}=${!param}" >> Makefile.inc fi done +printf " ${OK} Saved.\n" if [ -z "${NO_CLEAN}" ]; then - echo "[SECTION] Cleaning previous builds." + printf "${SECTION} Cleaning previous builds.\n" make clean >/dev/null fi -echo "[OK] Finished." +printf " ${OK} Finished.\n" diff --git a/core/MySigning.h b/core/MySigning.h index 4c6df24..ecc3b17 100644 --- a/core/MySigning.h +++ b/core/MySigning.h @@ -182,10 +182,10 @@ * * To generate HMAC key @verbatim --gen-soft-hmac-key @endverbatim * * To generate %AES key @verbatim --gen-aes-key @endverbatim * * To generate a soft serial number @verbatim --gen-soft-serial @endverbatim - * 2. Store keys/values to the gateway, execute @c mysgw with arguments - * * To store HMAC key @verbatim --set-soft-hmac-key= @endverbatim - * * To store %AES key @verbatim --set-aes-key= @endverbatim - * * To store soft serial number @verbatim --set-soft-serial-key= @endverbatim + * 2. Update the gateway config file with the generated keys/valeus + * * For HMAC key @verbatim soft_hmac_key= @endverbatim + * * For %AES key @verbatim aes_key= @endverbatim + * * For soft serial number @verbatim soft_serial_key= @endverbatim * * You are now set and ready to use message signing in your network. * As of now, the following restrictions will be applied to your nodes: diff --git a/drivers/Linux/SoftEeprom.cpp b/drivers/Linux/SoftEeprom.cpp index ac00553..f7980c2 100644 --- a/drivers/Linux/SoftEeprom.cpp +++ b/drivers/Linux/SoftEeprom.cpp @@ -60,9 +60,6 @@ int SoftEeprom::init(const char *fileName, size_t length) _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. @@ -72,11 +69,16 @@ int SoftEeprom::init(const char *fileName, size_t length) logError("Unable to create config file %s.\n", _fileName); return -1; } + // Fill the eeprom with 1s + for (size_t i = 0; i < _length; ++i) { + _values[i] = 0xFF; + } myFile.write((const char*)_values, _length); myFile.close(); } else if (fileInfo.st_size < 0 || (size_t)fileInfo.st_size != _length) { logError("EEPROM file %s is not the correct size of %zu. Please remove the file and a new one will be created.\n", _fileName, _length); + destroy(); return -1; } else { //Read config into local memory. @@ -100,27 +102,19 @@ void SoftEeprom::destroy() if (_fileName) { free(_fileName); } + _length = 0; } 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 && length) { - //Read config into local memory. - std::ifstream myFile(_fileName, std::ios::in | std::ios::binary); - if (!myFile) { - logError("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) { + logError("EEPROM being read without being initialized!\n"); + return; } - if (length && offs + length <= _length) { + if (offs + length <= _length) { memcpy(buf, _values+offs, length); } } @@ -129,7 +123,16 @@ void SoftEeprom::writeBlock(void* buf, void* addr, size_t length) { unsigned long int offs = reinterpret_cast(addr); - if (length && offs + length <= _length) { + if (!length) { + logError("EEPROM being written without being initialized!\n"); + return; + } + + if (offs + length <= _length) { + if (memcmp(_values+offs, buf, length) == 0) { + return; + } + memcpy(_values+offs, buf, length); std::ofstream myFile(_fileName, std::ios::out | std::ios::in | std::ios::binary); diff --git a/drivers/Linux/config.c b/drivers/Linux/config.c index db0b7dd..79252ed 100644 --- a/drivers/Linux/config.c +++ b/drivers/Linux/config.c @@ -49,12 +49,15 @@ int config_parse(const char *config_file) return -1; } - conf.verbose = 4; + conf.verbose = 7; conf.log_pipe = 0; conf.log_pipe_file = NULL; conf.syslog = 0; conf.eeprom_file = NULL; - conf.eeprom_size = 1024; + conf.eeprom_size = 0; + conf.soft_hmac_key = NULL; + conf.soft_serial_key = NULL; + conf.aes_key = NULL; while (fgets(buf, 1024, fptr)) { if (buf[0] != '#' && buf[0] != 10 && buf[0] != 13) { @@ -145,6 +148,21 @@ int config_parse(const char *config_file) return -1; } } + } else if (!strncmp(buf, "soft_hmac_key=", 14)) { + if (_config_parse_string(&(buf[14]), "soft_hmac_key", &conf.soft_hmac_key)) { + fclose(fptr); + return -1; + } + } else if (!strncmp(buf, "soft_serial_key=", 16)) { + if (_config_parse_string(&(buf[16]), "soft_serial_key", &conf.soft_serial_key)) { + fclose(fptr); + return -1; + } + } else if (!strncmp(buf, "aes_key=", 8)) { + if (_config_parse_string(&(buf[8]), "aes_key", &conf.aes_key)) { + fclose(fptr); + return -1; + } } else { logWarning("Unknown config option \"%s\".\n", buf); } @@ -172,12 +190,24 @@ int config_parse(const char *config_file) void config_cleanup(void) { - if (conf.eeprom_file) { - free(conf.eeprom_file); + if (conf.log_filepath) { + free(conf.log_filepath); } if (conf.log_pipe_file) { free(conf.log_pipe_file); } + if (conf.eeprom_file) { + free(conf.eeprom_file); + } + if (conf.soft_hmac_key) { + free(conf.soft_hmac_key); + } + if (conf.soft_serial_key) { + free(conf.soft_serial_key); + } + if (conf.aes_key) { + free(conf.aes_key); + } } int _config_create(const char *config_file) @@ -185,12 +215,15 @@ int _config_create(const char *config_file) FILE *myFile; int ret; - const char default_conf[] = "# Logging verbosity: debug,info,notice,warn,err\n" \ + const char default_conf[] = "# Logging\n" \ + "# Verbosity: debug,info,notice,warn,err\n" \ "verbose=debug\n" \ + "\n" \ "# Enable logging to a file.\n" \ "log_file=0\n" \ "# Log file path.\n" \ "log_filepath=/tmp/mysgw.log\n" \ + "\n" \ "# Enable logging to a named pipe.\n" \ "# Use this option to view your gateway's log messages\n" \ "# from the log_pipe_file defined bellow.\n" \ @@ -198,10 +231,32 @@ int _config_create(const char *config_file) "# cat \"log_pipe_file\"\n" \ "log_pipe=0\n" \ "log_pipe_file=/tmp/mysgw.pipe\n" \ + "\n" \ "# Enable logging to syslog.\n" \ "syslog=0\n" \ + "\n" \ + "# EEPROM settings\n" \ "eeprom_file=/etc/mysensors.eeprom\n" \ - "eeprom_size=1024\n"; + "eeprom_size=1024\n" \ + "\n" \ + "# Software signing settings\n" \ + "# Note: The gateway must have been built with signing\n" \ + "# support to use the options below.\n" \ + "#\n" \ + "# To generate a HMAC key run mysgw with: --gen-soft-hmac-key\n" \ + "# copy the new key in the line below and uncomment it.\n" \ + "#soft_hmac_key=\n" \ + "# To generate a serial key run mysgw with: --gen-soft-serial-key\n" \ + "# copy the new key in the line below and uncomment it.\n" \ + "#soft_serial_key=\n" \ + "\n" \ + "# Encryption settings\n" \ + "# Note: The gateway must have been built with encryption\n" \ + "# support to use the options below.\n" \ + "#\n" \ + "# To generate a AES key run mysgw with: --gen-aes-key\n" \ + "# copy the new key in the line below and uncomment it.\n" \ + "#aes_key=\n"; myFile = fopen(config_file, "w"); if (!myFile) { diff --git a/drivers/Linux/config.h b/drivers/Linux/config.h index 5c5dbc5..988cfba 100644 --- a/drivers/Linux/config.h +++ b/drivers/Linux/config.h @@ -33,6 +33,9 @@ struct config { int syslog; char *eeprom_file; int eeprom_size; + char *soft_hmac_key; + char *soft_serial_key; + char *aes_key; } conf; int config_parse(const char *config_file); diff --git a/hal/architecture/Linux/MyMainLinuxGeneric.cpp b/hal/architecture/Linux/MyMainLinuxGeneric.cpp index 1670978..6003f9c 100644 --- a/hal/architecture/Linux/MyMainLinuxGeneric.cpp +++ b/hal/architecture/Linux/MyMainLinuxGeneric.cpp @@ -111,13 +111,7 @@ void print_usage() " --daemon Run as a daemon.\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"); + " --gen-aes-key Generate and print an aes encryption key.\n"); } void print_soft_sign_hmac_key(uint8_t *key_ptr = NULL) @@ -129,7 +123,7 @@ void print_soft_sign_hmac_key(uint8_t *key_ptr = NULL) key_ptr = key; } - printf("SOFT_HMAC_KEY | "); + printf("soft_hmac_key="); for (int i = 0; i < 32; i++) { printf("%02X", key_ptr[i]); } @@ -146,20 +140,26 @@ void print_soft_sign_hmac_key(uint8_t *key_ptr = NULL) printf("\n\n"); } -void generate_soft_sign_hmac_key() +void generate_soft_sign_hmac_key(char *config_file = NULL) { uint8_t key[32]; + printf("Generating key..."); while (hwGetentropy(&key, sizeof(key)) != sizeof(key)); + printf(" done.\n"); + printf("To use the new key, update the value in %s witn:\n", + config_file?config_file:MY_LINUX_CONFIG_FILE); print_soft_sign_hmac_key(key); - printf("To use this key, run mysgw with:\n" - " --set-soft-hmac-key="); - for (int i = 0; i < 32; i++) { - printf("%02X", key[i]); - } - printf("\n"); +#if defined(MY_SIGNING_SIMPLE_PASSWD) + printf("Note: The gateway was built with simplified signing using the password: %s\n" \ + " Any key set with soft_hmac_key option in the config file is ignored.\n\n", + MY_SIGNING_SIMPLE_PASSWD); +#elif !defined(MY_SIGNING_FEATURE) + printf("Note: The gateway was not built with signing support.\n" \ + " Any key set with soft_hmac_key option in the config file is ignored.\n\n"); +#endif } void set_soft_sign_hmac_key(char *key_str) @@ -167,7 +167,7 @@ void set_soft_sign_hmac_key(char *key_str) uint8_t key[32]; if (strlen(key_str) != 64) { - printf("invalid key!\n"); + logWarning("Invalid HMAC key!\n"); } else { for (int i = 0; i < 64; ++i) { int n; @@ -187,7 +187,6 @@ void set_soft_sign_hmac_key(char *key_str) } } hwWriteConfigBlock(&key, reinterpret_castEEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32); - print_soft_sign_hmac_key(); } } @@ -200,7 +199,7 @@ void print_soft_sign_serial_key(uint8_t *key_ptr = NULL) key_ptr = key; } - printf("SOFT_SERIAL | "); + printf("soft_serial_key="); for (int i = 0; i < 9; i++) { printf("%02X", key_ptr[i]); } @@ -217,20 +216,26 @@ void print_soft_sign_serial_key(uint8_t *key_ptr = NULL) printf("\n\n"); } -void generate_soft_sign_serial_key() +void generate_soft_sign_serial_key(char *config_file = NULL) { uint8_t key[9]; + printf("Generating key..."); while (hwGetentropy(&key, sizeof(key)) != sizeof(key)); + printf(" done.\n"); + printf("To use the new key, update the value in %s witn:\n", + config_file?config_file:MY_LINUX_CONFIG_FILE); print_soft_sign_serial_key(key); - printf("To use this key, run mysgw with:\n" - " --set-soft-serial-key="); - for (int i = 0; i < 9; i++) { - printf("%02X", key[i]); - } - printf("\n"); +#if defined(MY_SIGNING_SIMPLE_PASSWD) + printf("Note: The gateway was built with simplified signing using the password: %s\n" \ + " Any key set with soft_serial_key option in the config file is ignored.\n\n", + MY_SIGNING_SIMPLE_PASSWD); +#elif !defined(MY_SIGNING_FEATURE) + printf("Note: The gateway was not built with signing support.\n" \ + " Any key set with soft_serial_key option in the config file is ignored.\n\n"); +#endif } void set_soft_sign_serial_key(char *key_str) @@ -238,7 +243,7 @@ void set_soft_sign_serial_key(char *key_str) uint8_t key[9]; if (strlen(key_str) != 18) { - printf("invalid key!\n"); + logWarning("Invalid soft serial key!\n"); } else { for (int i = 0; i < 18; ++i) { int n; @@ -258,7 +263,6 @@ void set_soft_sign_serial_key(char *key_str) } } hwWriteConfigBlock(&key, reinterpret_castEEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9); - print_soft_sign_serial_key(); } } @@ -267,16 +271,11 @@ void print_aes_key(uint8_t *key_ptr = NULL) uint8_t key[16]; if (key_ptr == NULL) { -#ifdef MY_ENCRYPTION_SIMPLE_PASSWD - memset(key, 0, 16); - memcpy(key, MY_ENCRYPTION_SIMPLE_PASSWD, strnlen(MY_ENCRYPTION_SIMPLE_PASSWD, 16)); -#else hwReadConfigBlock(&key, reinterpret_castEEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); -#endif key_ptr = key; } - printf("AES_KEY | "); + printf("aes_key="); for (int i = 0; i < 16; i++) { printf("%02X", key_ptr[i]); } @@ -293,20 +292,26 @@ void print_aes_key(uint8_t *key_ptr = NULL) printf("\n\n"); } -void generate_aes_key() +void generate_aes_key(char *config_file = NULL) { uint8_t key[16]; + printf("Generating key..."); while (hwGetentropy(&key, sizeof(key)) != sizeof(key)); + printf(" done.\n"); + printf("To use the new key, update the value in %s witn:\n", + config_file?config_file:MY_LINUX_CONFIG_FILE); print_aes_key(key); - printf("To use this key, run mysgw with:\n" - " --set-aes-key="); - for (int i = 0; i < 16; i++) { - printf("%02X", key[i]); - } - printf("\n"); +#if defined(MY_ENCRYPTION_SIMPLE_PASSWD) + printf("Note: The gateway was built with simplified encryption using the password: %s\n" \ + " Any key set with aes_key option in the config file is ignored.\n\n", + MY_ENCRYPTION_SIMPLE_PASSWD); +#elif !defined(MY_ENCRYPTION_FEATURE) + printf("Note: The gateway was not built with encryption support.\n" \ + " Any key set with aes_key option in the config file is ignored.\n\n"); +#endif } void set_aes_key(char *key_str) @@ -314,7 +319,7 @@ void set_aes_key(char *key_str) uint8_t key[16]; if (strlen(key_str) != 32) { - printf("invalid key!\n"); + logWarning("Invalid AES key!\n"); } else { for (int i = 0; i < 32; ++i) { int n; @@ -334,14 +339,16 @@ void set_aes_key(char *key_str) } } hwWriteConfigBlock(&key, reinterpret_castEEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); - print_aes_key(); } } int main(int argc, char *argv[]) { int opt, daemon = 0, quiet = 0; - char *key = NULL, *config_file = NULL; + char *config_file = NULL; + bool gen_soft_sign_hmac_key = false; + bool gen_soft_sign_serial_key = false; + bool gen_aes_key = false; /* register the signal handler */ signal(SIGINT, handle_sigint); @@ -358,17 +365,11 @@ int main(int argc, char *argv[]) {"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,"chqABCDEFGHIJ", long_options, &long_index )) != -1) { + while ((opt = getopt_long(argc, argv,"chqABCJ", long_options, &long_index )) != -1) { switch (opt) { case 'c': config_file = strdup(optarg); @@ -380,35 +381,14 @@ int main(int argc, char *argv[]) quiet = 1; break; case 'A': - generate_soft_sign_hmac_key(); - exit(EXIT_SUCCESS); + gen_soft_sign_hmac_key = true; + break; case 'B': - generate_soft_sign_serial_key(); - exit(EXIT_SUCCESS); + gen_soft_sign_serial_key = true; + break; case 'C': - generate_aes_key(); - exit(EXIT_SUCCESS); - case 'D': - print_soft_sign_hmac_key(); - exit(EXIT_SUCCESS); - case 'E': - print_soft_sign_serial_key(); - exit(EXIT_SUCCESS); - case 'F': - print_aes_key(); - exit(EXIT_SUCCESS); - case 'G': - key = strdup(optarg); - set_soft_sign_hmac_key(key); - exit(EXIT_SUCCESS); - case 'H': - key = strdup(optarg); - set_soft_sign_serial_key(key); - exit(EXIT_SUCCESS); - case 'I': - key = strdup(optarg); - set_aes_key(key); - exit(EXIT_SUCCESS); + gen_aes_key = true; + break; case 'J': daemon = 1; break; @@ -418,6 +398,19 @@ int main(int argc, char *argv[]) } } + if (gen_soft_sign_hmac_key || gen_soft_sign_serial_key || gen_aes_key) { + if (gen_soft_sign_hmac_key) { + generate_soft_sign_hmac_key(config_file); + } + if (gen_soft_sign_serial_key) { + generate_soft_sign_serial_key(config_file); + } + if (gen_aes_key) { + generate_aes_key(config_file); + } + exit(EXIT_SUCCESS); + } + if (daemon) { if (daemonize() != 0) { exit(EXIT_FAILURE); @@ -428,9 +421,6 @@ int main(int argc, char *argv[]) if (config_parse(config_file?config_file:MY_LINUX_CONFIG_FILE) != 0) { exit(EXIT_FAILURE); } - if (config_file) { - free(config_file); - } logSetQuiet(quiet); logSetLevel(conf.verbose); @@ -456,6 +446,38 @@ int main(int argc, char *argv[]) _begin(); // Startup MySensors library + // EEPROM is initialized within _begin() + // any operation on it must be done hereafter + +#if defined(MY_SIGNING_FEATURE) && !defined(MY_SIGNING_SIMPLE_PASSWD) + // Check if we need to update the signing keys in EEPROM + if (conf.soft_hmac_key) { + set_soft_sign_hmac_key(conf.soft_hmac_key); + } else { + logError("soft_hmac_key was not found in %s\n", config_file?config_file:MY_LINUX_CONFIG_FILE); + exit(EXIT_FAILURE); + } + if (conf.soft_serial_key) { + set_soft_sign_serial_key(conf.soft_serial_key); + } else { + logError("soft_serial_key was not found in %s\n", config_file?config_file:MY_LINUX_CONFIG_FILE); + exit(EXIT_FAILURE); + } +#endif +#if defined(MY_ENCRYPTION_FEATURE) && !defined(MY_ENCRYPTION_SIMPLE_PASSWD) + // Check if we need to update the encryption key in EEPROM + if (conf.aes_key) { + set_aes_key(conf.aes_key); + } else { + logError("aes_key was not found in %s\n", config_file?config_file:MY_LINUX_CONFIG_FILE); + exit(EXIT_FAILURE); + } +#endif + + if (config_file) { + free(config_file); + } + for (;;) { _process(); // Process incoming data if (loop) { From 2994d83e53cda2867a80ff413575938ecd6d3ab2 Mon Sep 17 00:00:00 2001 From: tekka Date: Wed, 4 Apr 2018 20:48:36 +0200 Subject: [PATCH 33/60] RF24: Minor power optimization (#1069) --- drivers/RF24/RF24.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/RF24/RF24.cpp b/drivers/RF24/RF24.cpp index 2551faa..58d8c37 100644 --- a/drivers/RF24/RF24.cpp +++ b/drivers/RF24/RF24.cpp @@ -302,13 +302,14 @@ LOCAL bool RF24_sendMessage(const uint8_t recipient, const void *buf, const uint RF24_CMD_WRITE_TX_PAYLOAD, (uint8_t *)buf, len, false ); // go, TX starts after ~10us, CE high also enables PA+LNA on supported HW RF24_ce(HIGH); + delayMicroseconds(10); // datasheet: Pulse CE at least 10us + RF24_ce(LOW); // 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 From 9809eb6270ae6c9a39eed380acd1f0b3308467c4 Mon Sep 17 00:00:00 2001 From: Mikael Falkvidd Date: Thu, 5 Apr 2018 22:25:05 +0200 Subject: [PATCH 34/60] Add missing keywords 2 (#1087) * Add missing keywords and blacklist These keywords already exist in Doxygen and should be highlighted in the Arduino IDE. Some keywords should not be highlighed and are therefore added to the blacklists at end of keywords.txt * Sort keywords in each section * Add blacklist of MY_MQTT_TOPIC_PREFIX --- keywords.txt | 261 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 166 insertions(+), 95 deletions(-) diff --git a/keywords.txt b/keywords.txt index 476a0ec..0a53ed8 100644 --- a/keywords.txt +++ b/keywords.txt @@ -30,83 +30,99 @@ smartSleep KEYWORD2 # Constants (LITERAL1) ####################################### # General -MY_CORE_ONLY LITERAL1 -MY_DISABLE_REMOTE_RESET LITERAL1 -MY_SMART_SLEEP_WAIT_DURATION LITERAL1 MY_BAUD_RATE LITERAL1 +MY_CORE_ONLY LITERAL1 +MY_CORE_MIN_VERSION LITERAL1 +MY_CORE_VERSION LITERAL1 MY_CRITICAL_SECTION LITERAL1 +MY_DISABLE_RAM_ROUTING_TABLE_FEATURE LITERAL1 +MY_DISABLE_REMOTE_RESET LITERAL1 +MY_DISABLED_SERIAL LITERAL1 +MY_INDICATION_HANDLER LITERAL1 MY_RX_MESSAGE_BUFFER_SIZE LITERAL1 MY_RX_MESSAGE_BUFFER_FEATURE LITERAL1 -MY_DISABLED_SERIAL LITERAL1 +MY_SERIAL_OUTPUT_SIZE LITERAL1 +MY_SLEEP_NOT_POSSIBLE LITERAL1 +MY_SMART_SLEEP_WAIT_DURATION LITERAL1 MY_SPLASH_SCREEN_DISABLED LITERAL1 -MY_INDICATION_HANDLER LITERAL1 -MY_DISABLE_RAM_ROUTING_TABLE_FEATURE LITERAL1 +MY_WAKE_UP_BY_TIMER LITERAL1 # transport AUTO LITERAL1 -MY_NODE_ID LITERAL1 +MY_CORE_COMPATIBILITY_CHECK LITERAL1 MY_DEBUG_VERBOSE_TRANSPORT LITERAL1 +MY_NODE_ID LITERAL1 MY_PARENT_NODE_ID LITERAL1 MY_PARENT_NODE_IS_STATIC LITERAL1 -MY_REGISTRATION_FEATURE LITERAL1 -MY_REGISTRATION_DEFAULT LITERAL1 +MY_PASSIVE_NODE LITERAL1 +MY_RAM_ROUTING_TABLE_FEATURE LITERAL1 MY_REGISTRATION_CONTROLLER LITERAL1 -MY_CORE_COMPATIBILITY_CHECK LITERAL1 +MY_REGISTRATION_DEFAULT LITERAL1 +MY_REGISTRATION_FEATURE LITERAL1 +MY_REGISTRATION_RETRIES LITERAL1 +MY_REPEATER_FEATURE LITERAL1 +MY_ROUTING_TABLE_SAVE_INTERVAL_MS LITERAL1 +MY_SIGNAL_REPORT_ENABLED LITERAL1 +MY_SLEEP_TRANSPORT_RECONNECT_TIMEOUT_MS LITERAL1 +MY_SMART_SLEEP_WAIT_DURATION_MS LITERAL1 +MY_TRANSPORT_CHKUPL_INTERVAL_MS LITERAL1 +MY_TRANSPORT_DISCOVERY_INTERVAL_MS LITERAL1 +MY_TRANSPORT_MAX_TSM_FAILURES LITERAL1 +MY_TRANSPORT_MAX_TX_FAILURES LITERAL1 MY_TRANSPORT_SANITY_CHECK LITERAL1 MY_TRANSPORT_SANITY_CHECK_INTERVAL LITERAL1 -MY_TRANSPORT_WAIT_READY_MS LITERAL1 +MY_TRANSPORT_SANITY_CHECK_INTERVAL_MS LITERAL1 +MY_TRANSPORT_STATE_RETRIES LITERAL1 +MY_TRANSPORT_STATE_TIMEOUT_MS LITERAL1 +MY_TRANSPORT_TIMEOUT_EXT_FAILURE_STATE_MS LITERAL1 +MY_TRANSPORT_TIMEOUT_FAILURE_STATE_MS LITERAL1 MY_TRANSPORT_UPLINK_CHECK_DISABLED LITERAL1 -MY_REPEATER_FEATURE LITERAL1 -MY_PASSIVE_NODE LITERAL1 -MY_SIGNAL_REPORT_ENABLED LITERAL1 +MY_TRANSPORT_WAIT_READY_MS LITERAL1 # debug MY_DEBUG LITERAL1 MY_DEBUGDEVICE LITERAL1 -MY_DEBUG_OTA LITERAL1 -MY_DEBUG_OTA_DISABLE_ACK LITERAL1 -MY_SPECIAL_DEBUG LITERAL1 MY_DEBUG_VERBOSE_GATEWAY LITERAL1 +MY_SPECIAL_DEBUG LITERAL1 # OTA -MY_OTA_FIRMWARE_FEATURE LITERAL1 -MY_OTA_FLASH_SS LITERAL1 -MY_OTA_FLASH_JDECID LITERAL1 -MY_SPIFLASH_SST25TYPE LITERAL1 +MY_DEBUG_OTA LITERAL1 +MY_DEBUG_OTA_DISABLE_ACK LITERAL1 MY_DEBUG_VERBOSE_OTA_UPDATE LITERAL1 -MY_WITH_LEDS_BLINKING_INVERSE LITERAL1 +MY_DEFAULT_ERR_LED_PIN LITERAL1 MY_DEFAULT_LED_BLINK_PERIOD LITERAL1 -MY_WITH_LEDS_BLINKING_INVERSE LITERAL1 MY_DEFAULT_RX_LED_PIN LITERAL1 MY_DEFAULT_TX_LED_PIN LITERAL1 -MY_DEFAULT_ERR_LED_PIN LITERAL1 MY_INCLUSION_MODE_FEATURE LITERAL1 MY_INCLUSION_BUTTON_FEATURE LITERAL1 MY_INCLUSION_MODE_BUTTON_PIN LITERAL1 MY_INCLUSION_MODE_DURATION LITERAL1 MY_INCLUSION_LED_PIN LITERAL1 +MY_OTA_FIRMWARE_FEATURE LITERAL1 +MY_OTA_FLASH_SS LITERAL1 +MY_OTA_FLASH_JDECID LITERAL1 MY_OTA_LOG_RECEIVER_FEATURE LITERAL1 MY_OTA_LOG_SENDER_FEATURE LITERAL1 -MY_DEBUG_OTA LITERAL1 -MY_DEBUG_OTA_DISABLE_ACK LITERAL1 MY_OTA_USE_I2C_EEPROM LITERAL1 +MY_SPIFLASH_SST25TYPE LITERAL1 +MY_WITH_LEDS_BLINKING_INVERSE LITERAL1 # Signing MY_DEBUG_VERBOSE_SIGNING LITERAL1 -MY_SECURITY_SIMPLE_PASSWD LITERAL1 -MY_SIGNING_SIMPLE_PASSWD LITERAL1 MY_ENCRYPTION_SIMPLE_PASSWD LITERAL1 -MY_SIGNING_ATSHA204 LITERAL1 -MY_SIGNING_SOFT LITERAL1 -MY_VERIFICATION_TIMEOUT_MS LITERAL1 -MY_SIGNING_NODE_WHITELISTING LITERAL1 -MY_SIGNING_ATSHA204_PIN LITERAL1 -MY_SIGNING_SOFT_RANDOMSEED_PIN LITERAL1 -MY_SIGNING_REQUEST_SIGNATURES LITERAL1 -MY_SIGNING_WEAK_SECURITY LITERAL1 MY_NODE_LOCK_FEATURE LITERAL1 MY_NODE_UNLOCK_PIN LITERAL1 MY_NODE_LOCK_COUNTER_MAX LITERAL1 +MY_SECURITY_SIMPLE_PASSWD LITERAL1 +MY_SIGNING_ATSHA204 LITERAL1 +MY_SIGNING_ATSHA204_PIN LITERAL1 +MY_SIGNING_NODE_WHITELISTING LITERAL1 +MY_SIGNING_SIMPLE_PASSWD LITERAL1 +MY_SIGNING_SOFT LITERAL1 +MY_SIGNING_SOFT_RANDOMSEED_PIN LITERAL1 +MY_SIGNING_REQUEST_SIGNATURES LITERAL1 +MY_SIGNING_WEAK_SECURITY LITERAL1 +MY_VERIFICATION_TIMEOUT_MS LITERAL1 # Random MY_HW_HAS_GETENTROPY LITERAL1 @@ -125,26 +141,25 @@ MY_GSM_USR LITERAL1 # SoftSPI MY_SOFTSPI LITERAL1 -MY_SOFT_SPI_SCK_PIN LITERAL1 MY_SOFT_SPI_MISO_PIN LITERAL1 MY_SOFT_SPI_MOSI_PIN LITERAL1 +MY_SOFT_SPI_SCK_PIN LITERAL1 # RF24 -MY_RADIO_RF24 LITERAL1 MY_DEBUG_VERBOSE_RF24 LITERAL1 +MY_RADIO_RF24 LITERAL1 +MY_RF24_BASE_RADIO_ID LITERAL1 MY_RF24_ENABLE_ENCRYPTION LITERAL1 -MY_RF24_SPI_SPEED LITERAL1 MY_RF24_CE_PIN LITERAL1 +MY_RF24_CHANNEL LITERAL1 MY_RF24_CS_PIN LITERAL1 +MY_RF24_DATARATE LITERAL1 MY_RF24_IRQ_PIN LITERAL1 MY_RF24_PA_LEVEL LITERAL1 -MY_RF24_CHANNEL LITERAL1 -MY_RF24_DATARATE LITERAL1 -MY_RF24_BASE_RADIO_ID LITERAL1 MY_RF24_POWER_PIN LITERAL1 +MY_RF24_SPI_SPEED LITERAL1 # NRF5 -MY_RADIO_NRF5_ESB LITERAL1 MY_DEBUG_VERBOSE_NRF5_ESB LITERAL1 MY_NRF5_ESB_ADDR_WIDTH LITERAL1 MY_NRF5_ESB_BASE_RADIO_ID LITERAL1 @@ -155,103 +170,159 @@ MY_NRF5_ESB_PA_LEVEL LITERAL1 MY_NRF5_ESB_RX_BUFFER_SIZE LITERAL1 MY_NRF5_ESB_REVERSE_ACK_RX LITERAL1 MY_NRF5_ESB_REVERSE_ACK_TX LITERAL1 +MY_RADIO_NRF5_ESB LITERAL1 # RFM95 -MY_RADIO_RFM95 LITERAL1 MY_DEBUG_VERBOSE_RFM95 LITERAL1 -MY_RFM95_MODEM_CONFIGRUATION LITERAL1 -MY_RFM95_FREQUENCY LITERAL1 -MY_RFM95_TX_POWER LITERAL1 +MY_RADIO_RFM95 LITERAL1 +MY_RFM95_ATC_MODE_DISABLED LITERAL1 +MY_RFM95_ATC_TARGET_RSSI LITERAL1 +MY_RFM95_ATC_TARGET_RSSI_DBM LITERAL1 MY_RFM95_CS_PIN LITERAL1 +MY_RFM95_FREQUENCY LITERAL1 +MY_RFM95_IRQ_NUM LITERAL1 +MY_RFM95_IRQ_PIN LITERAL1 +MY_RFM95_MAX_POWER_LEVEL_DBM LITERAL1 +MY_RFM95_MODEM_CONFIGRUATION LITERAL1 +MY_RFM95_POWER_PIN LITERAL1 MY_RFM95_RST_PIN LITERAL1 MY_RFM95_SPI_SPEED LITERAL1 -MY_RFM95_IRQ_PIN LITERAL1 -MY_RFM95_IRQ_NUM LITERAL1 -MY_RFM95_ATC_TARGET_RSSI LITERAL1 -MY_RFM95_ATC_MODE_DISABLED LITERAL1 -MY_RFM95_ATC_TARGET_RSSI_DBM LITERAL1 -MY_RFM95_MAX_POWER_LEVEL_DBM LITERAL1 -MY_RFM95_POWER_PIN LITERAL1 MY_RFM95_TCXO LITERAL1 +MY_RFM95_TX_POWER LITERAL1 # RFM69 -MY_RADIO_RFM69 LITERAL1 MY_DEBUG_VERBOSE_RFM69 LITERAL1 MY_DEBUG_VERBOSE_RFM69_REGISTERS LITERAL1 -MY_RFM69_FREQUENCY LITERAL1 -MY_IS_RFM69HW LITERAL1 -MY_RFM69_NEW_DRIVER LITERAL1 -MY_RFM69_TX_POWER_DBM LITERAL1 -MY_RFM69_ATC_TARGET_RSSI_DBM LITERAL1 +MY_IS_RFM69HW LITERAL1 LITERAL1 +MY_RADIO_RFM69 LITERAL1 LITERAL1 MY_RFM69_ATC_MODE_DISABLED LITERAL1 -MY_RFM69_MAX_POWER_LEVEL_DBM LITERAL1 -MY_RFM69_NETWORKID LITERAL1 -MY_RFM69_RST_PIN LITERAL1 -MY_RFM69_IRQ_PIN LITERAL1 -MY_RFM69_IRQ_NUM LITERAL1 -MY_RFM69_CS_PIN LITERAL1 -MY_RFM69_ENABLE_ENCRYPTION LITERAL1 -MY_RFM69_ENABLE_LISTENMODE LITERAL1 -MY_RFM69_DEFAULT_LISTEN_RX_US LITERAL1 -MY_RFM69_DEFAULT_LISTEN_IDLE_US LITERAL1 -MY_RFM69_SPI_SPEED LITERAL1 -MY_RFM69_BITRATE_MSB LITERAL1 +MY_RFM69_ATC_TARGET_RSSI_DBM LITERAL1 MY_RFM69_BITRATE_LSB LITERAL1 +MY_RFM69_BITRATE_MSB LITERAL1 +MY_RFM69_CS_PIN LITERAL1 MY_RFM69_CSMA_ADD_DELAY_BASE LITERAL1 MY_RFM69_CSMA_ADD_DELAY_COUNT LITERAL1 -MY_RFM69_POWER_PIN LITERAL1 +MY_RFM69_DEFAULT_LISTEN_IDLE_US LITERAL1 +MY_RFM69_DEFAULT_LISTEN_RX_US LITERAL1 +MY_RFM69_ENABLE_ENCRYPTION LITERAL1 +MY_RFM69_ENABLE_LISTENMODE LITERAL1 +MY_RFM69_FREQUENCY LITERAL1 +MY_RFM69_IRQ_NUM LITERAL1 +MY_RFM69_IRQ_PIN LITERAL1 +MY_RFM69_MAX_POWER_LEVEL_DBM LITERAL1 MY_RFM69_MODEM_CONFIGURATION LITERAL1 +MY_RFM69_NETWORKID LITERAL1 +MY_RFM69_NEW_DRIVER LITERAL1 +MY_RFM69_POWER_PIN LITERAL1 +MY_RFM69_RST_PIN LITERAL1 +MY_RFM69_SPI_SPEED LITERAL1 +MY_RFM69_TX_POWER_DBM LITERAL1 # RS485 MY_RS485 LITERAL1 MY_RS485_BAUD_RATE LITERAL1 -MY_RS485_MAX_MESSAGE_LENGTH LITERAL1 -MY_RS485_HWSERIAL LITERAL1 MY_RS485_DE_PIN LITERAL1 +MY_RS485_HWSERIAL LITERAL1 +MY_RS485_MAX_MESSAGE_LENGTH LITERAL1 MY_RS485_SOH_COUNT LITERAL1 # Gateway / MQTT -MY_GATEWAY_SERIAL LITERAL1 -MY_GATEWAY_W5100 LITERAL1 -MY_W5100_SPI_EN LITERAL1 +MY_GATEWAY_CLIENT_MODE LITERAL1 MY_GATEWAY_ENC28J60 LITERAL1 MY_GATEWAY_ESP8266 LITERAL1 -MY_INCLUSION_BUTTON_EXTERNAL_PULLUP LITERAL1 -MY_MQTT_SUBSCRIBE_TOPIC_PREFIX LITERAL1 -MY_MQTT_PUBLISH_TOPIC_PREFIX LITERAL1 -MY_MQTT_CLIENT_ID LITERAL1 MY_GATEWAY_MQTT_CLIENT LITERAL1 +MY_GATEWAY_SERIAL LITERAL1 +MY_GATEWAY_W5100 LITERAL1 +MY_INCLUSION_BUTTON_EXTERNAL_PULLUP LITERAL1 +MY_MQTT_CLIENT_ID LITERAL1 MY_MQTT_CLIENT_PUBLISH_RETAIN LITERAL1 +MY_MQTT_PUBLISH_TOPIC_PREFIX LITERAL1 +MY_MQTT_SUBSCRIBE_TOPIC_PREFIX LITERAL1 +MY_W5100_SPI_EN LITERAL1 # Ethernet -MY_PORT LITERAL1 -MY_IP_ADDRESS LITERAL1 -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 +MY_GATEWAY_MAX_SEND_LENGTH LITERAL1 +MY_IP_ADDRESS LITERAL1 MY_IP_GATEWAY_ADDRESS LITERAL1 +MY_IP_RENEWAL_INTERVAL LITERAL1 +MY_IP_RENEWAL_INTERVAL_MS LITERAL1 MY_IP_SUBNET_ADDRESS LITERAL1 +MY_MAC_ADDRESS LITERAL1 +MY_PORT LITERAL1 +MY_USE_UDP LITERAL1 # ESP8266 -MY_ESP8266_SSID LITERAL1 -MY_ESP8266_PASSWORD LITERAL1 MY_ESP8266_BSSID LITERAL1 MY_ESP8266_HOSTNAME LITERAL1 +MY_ESP8266_PASSWORD LITERAL1 MY_ESP8266_SERIAL_MODE LITERAL1 +MY_ESP8266_SSID LITERAL1 # Blacklist - autodefines that are used internally and should not be highlighted, hence commented. -# MY_SIGNING_FEATURE +# MY_CAP_ARCH +# MY_CAP_ENCR +# MY_CAP_OTA_FW +# MY_CAP_RADIO +# MY_CAP_RESET +# MY_CAP_RXBUF +# MY_CAP_SIGN +# MY_CAP_TYPE +# MY_CAPABILITIES +# MY_DEBUG_VERBOSE_CORE +# MY_GATEWAY_FEATURE +# MY_RAM_ROUTING_TABLE_ENABLED +# MY_SENSOR_NETWORK + +# Blacklist - defined in ArduinoHwSAMD and therefore not responsibility of the MySensors library +# MY_BAT_DETECT + +# Blacklist - used by the Security Personalizer, not meant to be used in any other sketch +# MY_AES_KEY # MY_ENCRYPTION_FEATURE +# MY_HMAC_KEY # MY_LOCK_DEVICE +# MY_LOCK_MCU +# MY_SIGNING_FEATURE +# MY_SOFT_SERIAL + +# Blacklist - internal, not meant to be used by users +# MY_EXT_EEPROM_PAGE_SIZE +# MY_EXT_EEPROM_SIZE +# MY_EXT_EEPROM_TWI_CLOCK +# MY_HW_ERR_LED_PIN +# MY_HW_RTC +# MY_HW_RTC_IRQ_HANDLER +# MY_HW_RTC_IRQN +# MY_HW_TX_LED_PIN +# MY_HWID_PADDING_BYTE +# MY_INCLUSION_BUTTON_PRESSED +# MY_IS_GATEWAY +# MY_NODE_TYPE +# MY_OTA_BOOTLOADER_MAJOR_VERSION +# MY_OTA_BOOTLOADER_MINOR_VERSION +# MY_OTA_BOOTLOADER_VERSION +# MY_OTA_RETRY +# MY_OTA_RETRY_DELAY +# MY_SDCARD_CS + +# Blacklist - used by the Raspberry Pi gateway and not meant to be used by users +# MY_GATEWAY_LINUX +# MY_LINUX_CONFIG_FILE +# MY_LINUX_IS_SERIAL_PTY +# MY_LINUX_SERIAL_GROUPNAME +# MY_LINUX_SERIAL_IS_PTY # MY_LINUX_SERIAL_PORT -# MY_LINUX_SERIAL_IS_PTY -# MY_LINUX_SERIAL_GROUPNAME # MY_LINUX_SERIAL_PTY -# MY_LINUX_IS_SERIAL_PTY -# MY_GATEWAY_LINUX + +# Blacklist - deprecated and should therefore not be highlighted anymore +# MY_LEDS_BLINKING_FEATURE +# MY_TRANSPORT_DONT_CARE_MODE + +# Blacklist - descriptional only +# MY_XYZ_POWER_PIN +# MY_MQTT_TOPIC_PREFIX From d1aa419efe612bfd00256ed3259d123a3efe95d5 Mon Sep 17 00:00:00 2001 From: Mikael Falkvidd Date: Sat, 7 Apr 2018 10:42:52 +0200 Subject: [PATCH 35/60] Remove faulty wiring instructions from ESP gateways (#1100) This fixes https://github.com/mysensors/MySensors/issues/1096 https://www.mysensors.org/build/connect_radio has been updated to include GPIOn instructions (in addition to the existing Dn instructions). Thanks to RWoerz for reporting this discrepancy. Also, the "barebone" boot wiring has been moved to http://bit.do/stupidurl --- examples/GatewayESP8266/GatewayESP8266.ino | 28 +++++------------ .../GatewayESP8266MQTTClient.ino | 29 +++++------------- .../GatewayESP8266OTA/GatewayESP8266OTA.ino | 30 +++++-------------- 3 files changed, 23 insertions(+), 64 deletions(-) diff --git a/examples/GatewayESP8266/GatewayESP8266.ino b/examples/GatewayESP8266/GatewayESP8266.ino index 54af4dc..b7fef14 100644 --- a/examples/GatewayESP8266/GatewayESP8266.ino +++ b/examples/GatewayESP8266/GatewayESP8266.ino @@ -30,34 +30,20 @@ * * 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. - * E.g. If you want to use the defualt values in this sketch enter: 192.168.178.66:5003 + * E.g. If you want to use the default values in this sketch enter: 192.168.178.66:5003 * * LED purposes: * - 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 + * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation received * - 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 receive crc error * - * See http://www.mysensors.org/build/esp8266_gateway for wiring instructions. - * nRF24L01+ ESP8266 - * VCC VCC - * CE GPIO4 - * CSN/CS GPIO15 - * SCK GPIO14 - * MISO GPIO12 - * MOSI GPIO13 - * GND GND + * See https://www.mysensors.org/build/connect_radio for wiring instructions. * - * 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: - * - Connect REST (reset) via 10K pullup resistor to VCC, and via switch to GND ('reset switch') - * - Connect GPIO15 via 10K pulldown resistor to GND - * - 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') + * If you are using a "barebone" ESP8266, see + * https://www.mysensors.org/build/esp8266_gateway#wiring-for-barebone-esp8266 * - * Inclusion mode button: + * Inclusion mode button: * - Connect GPIO5 (=D1) via switch to GND ('inclusion switch') * * Hardware SHA204 signing is currently not supported! diff --git a/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino b/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino index 57fff44..9d2b49b 100644 --- a/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino +++ b/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino @@ -27,29 +27,16 @@ * * LED purposes: * - 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 + * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation received * - 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 receive crc error * - * See http://www.mysensors.org/build/esp8266_gateway for wiring instructions. - * nRF24L01+ ESP8266 - * VCC VCC - * CE GPIO4 - * CSN/CS GPIO15 - * SCK GPIO14 - * MISO GPIO12 - * MOSI GPIO13 + * See https://www.mysensors.org/build/connect_radio for wiring instructions. * - * 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: - * - Connect REST (reset) via 10K pullup resistor to VCC, and via switch to GND ('reset switch') - * - Connect GPIO15 via 10K pulldown resistor to GND - * - 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') + * If you are using a "barebone" ESP8266, see + * https://www.mysensors.org/build/esp8266_gateway#wiring-for-barebone-esp8266 * - * Inclusion mode button: + * Inclusion mode button: * - Connect GPIO5 (=D1) via switch to GND ('inclusion switch') * * Hardware SHA204 signing is currently not supported! @@ -78,7 +65,7 @@ // Set MQTT client id #define MY_MQTT_CLIENT_ID "mysensors-1" -// Enable these if your MQTT broker requires usenrame/password +// Enable these if your MQTT broker requires username/password //#define MY_MQTT_USER "username" //#define MY_MQTT_PASSWORD "password" @@ -138,6 +125,6 @@ void presentation() void loop() { - // Send locally attech sensors data here + // Send locally attached sensors data here } diff --git a/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino b/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino index 76badfd..4a485f8 100644 --- a/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino +++ b/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino @@ -31,34 +31,20 @@ * * 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. - * E.g. If you want to use the defualt values in this sketch enter: 192.168.178.66:5003 + * E.g. If you want to use the default 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 + * - RX (green) - blink fast on radio message recieved. In inclusion mode will blink fast only on presentation received * - 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 receive crc error * - * See http://www.mysensors.org/build/esp8266_gateway for wiring instructions. - * nRF24L01+ ESP8266 - * VCC VCC - * CE GPIO4 - * CSN/CS GPIO15 - * SCK GPIO14 - * MISO GPIO12 - * MOSI GPIO13 - * GND GND + * See https://www.mysensors.org/build/connect_radio for wiring instructions. * - * 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: - * - Connect REST (reset) via 10K pullup resistor to VCC, and via switch to GND ('reset switch') - * - Connect GPIO15 via 10K pulldown resistor to GND - * - 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') + * If you are using a "barebone" ESP8266, see + * https://www.mysensors.org/build/esp8266_gateway#wiring-for-barebone-esp8266 * - * Inclusion mode button: + * Inclusion mode button: * - Connect GPIO5 via switch to GND ('inclusion switch') * * Hardware SHA204 signing is currently not supported! @@ -170,7 +156,7 @@ void presentation() void loop() { - // Send locally attech sensors data here + // Send locally attached sensors data here ArduinoOTA.handle(); } From eaf1b9452bef48f22e1b9b5e7efd607e3a1a23fc Mon Sep 17 00:00:00 2001 From: tekka Date: Sat, 7 Apr 2018 14:46:01 +0200 Subject: [PATCH 36/60] ESP32: Support HW (#865) This fixes https://github.com/mysensors/MySensors/issues/968 --- .ci/arduino.groovy | 66 ++++++- .ci/pipeline.groovy | 10 +- MyConfig.h | 19 +- MySensors.h | 10 +- core/MyCapabilities.h | 2 + core/MyGatewayTransportEthernet.cpp | 44 +++-- core/MyGatewayTransportMQTTClient.cpp | 24 ++- core/MySensorsCore.cpp | 1 + core/MySigningAtsha204Soft.cpp | 2 +- core/MyTransport.cpp | 2 +- drivers/AES/AES_config.h | 2 + drivers/RF24/RF24.h | 2 +- drivers/RFM69/new/RFM69_new.h | 3 +- drivers/RFM69/old/RFM69_old.h | 3 +- drivers/RFM95/RFM95.cpp | 1 - drivers/RFM95/RFM95.h | 3 +- examples/GatewayESP32/GatewayESP32.ino | 76 ++++++++ .../GatewayESP32MQTTClient.ino | 90 ++++++++++ hal/architecture/ESP32/MyHwESP32.cpp | 168 ++++++++++++++++++ hal/architecture/ESP32/MyHwESP32.h | 89 ++++++++++ hal/architecture/ESP32/MyMainESP32.cpp | 49 +++++ keywords.txt | 7 + 22 files changed, 643 insertions(+), 30 deletions(-) create mode 100644 examples/GatewayESP32/GatewayESP32.ino create mode 100644 examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino create mode 100644 hal/architecture/ESP32/MyHwESP32.cpp create mode 100644 hal/architecture/ESP32/MyHwESP32.h create mode 100644 hal/architecture/ESP32/MyMainESP32.cpp diff --git a/.ci/arduino.groovy b/.ci/arduino.groovy index ce51237..da74a5d 100644 --- a/.ci/arduino.groovy +++ b/.ci/arduino.groovy @@ -26,7 +26,9 @@ def parseWarnings(String key) { excludePattern: '''.*/EEPROM\\.h,.*/Dns\\.cpp,.*/socket\\.cpp,.*/util\\.h,.*/Servo\\.cpp, .*/Adafruit_NeoPixel\\.cpp,.*/UIPEthernet.*,.*/SoftwareSerial\\.cpp, .*/pins_arduino\\.h,.*/Stream\\.cpp,.*/USBCore\\.cpp,.*/Wire\\.cpp, - .*/hardware/STM32F1.*,.*/hardware/esp8266.*,.*/libraries/SD/.*''', + .*/hardware/STM32F1.*,.*/hardware/esp8266.*,.*/hardware/espressif/esp32.*, + .*/libraries/SD/.*''', + healthy: '', includePattern: '', messagesPattern: '', parserConfigurations: [[parserName: 'Arduino/AVR', pattern: 'compiler_'+key+'.log']], unHealthy: '', unstableNewAll: '0', unstableTotalAll: '0' @@ -47,6 +49,8 @@ def buildMySensorsMicro(config, sketches, String key) { sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' && sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' && sketches[sketch].path != config.library_root+'examples/GatewayGSMMQTTClient/GatewayGSMMQTTClient.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayESP32/GatewayESP32.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino' && sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino') { buildArduino(config, fqbn, sketches[sketch].path, key+'_MySensorsMicro') } @@ -80,6 +84,8 @@ def buildMySensorsGw(config, sketches, String key) { sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' && sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' && sketches[sketch].path != config.library_root+'examples/GatewayGSMMQTTClient/GatewayGSMMQTTClient.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayESP32/GatewayESP32.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino' && sketches[sketch].path != config.library_root+'examples/GatewaySerialRS485/GatewaySerialRS485.ino' && sketches[sketch].path != config.library_root+'examples/MotionSensorRS485/MotionSensorRS485.ino') { buildArduino(config, fqbn, sketches[sketch].path, key+'_MySensorsGw') @@ -112,6 +118,8 @@ def buildArduinoUno(config, sketches, String key) { if (sketches[sketch].path != config.library_root+'examples/GatewayESP8266/GatewayESP8266.ino' && sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' && sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayESP32/GatewayESP32.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino' && sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino') { buildArduino(config, fqbn, sketches[sketch].path, key+'_ArduinoUno') } @@ -143,6 +151,8 @@ def buildArduinoMega(config, sketches, String key) { if (sketches[sketch].path != config.library_root+'examples/GatewayESP8266/GatewayESP8266.ino' && sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' && sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayESP32/GatewayESP32.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino' && sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino') { buildArduino(config, fqbn, sketches[sketch].path, key+'_ArduinoMega') } @@ -174,6 +184,8 @@ def buildSTM32F1(config, sketches, String key) { if (sketches[sketch].path != config.library_root+'examples/GatewayESP8266/GatewayESP8266.ino' && sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' && sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayESP32/GatewayESP32.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino' && sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino') { buildArduino(config, fqbn, sketches[sketch].path, key+'_STM32F1') } @@ -209,6 +221,8 @@ def buildEsp8266(config, sketches, String key) { sketches[sketch].path != config.library_root+'examples/GatewayW5100/GatewayW5100.ino' && sketches[sketch].path != config.library_root+'examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino' && sketches[sketch].path != config.library_root+'examples/GatewayGSMMQTTClient/GatewayGSMMQTTClient.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayESP32/GatewayESP32.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino' && sketches[sketch].path != config.library_root+'examples/MotionSensorRS485/MotionSensorRS485.ino' && sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino' && sketches[sketch].path != config.library_root+'examples/SoilMoistSensor/SoilMoistSensor.ino') { @@ -234,6 +248,54 @@ def buildEsp8266(config, sketches, String key) { } } +def buildEsp32(config, sketches, String key) { + def fqbn = '-fqbn espressif:esp32:node32s -warnings=default -prefs build.f_cpu=80000000 -prefs build.mcu=esp32' + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (ESP32 - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/') + try { + for (sketch = 0; sketch < sketches.size(); sketch++) { + if (sketches[sketch].path != config.library_root+'examples/BatteryPoweredSensor/BatteryPoweredSensor.ino' && + sketches[sketch].path != config.library_root+'examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino' && + sketches[sketch].path != config.library_root+'examples/CO2Sensor/CO2Sensor.ino' && + sketches[sketch].path != config.library_root+'examples/DustSensor/DustSensor.ino' && + sketches[sketch].path != config.library_root+'examples/DustSensorDSM/DustSensorDSM.ino' && + sketches[sketch].path != config.library_root+'examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino' && + sketches[sketch].path != config.library_root+'examples/LightSensor/LightSensor.ino' && + sketches[sketch].path != config.library_root+'examples/LogOTANode/LogOTANode.ino' && + sketches[sketch].path != config.library_root+'examples/MotionSensor/MotionSensor.ino' && + sketches[sketch].path != config.library_root+'examples/MotionSensorRS485/MotionSensorRS485.ino' && + sketches[sketch].path != config.library_root+'examples/PassiveNode/PassiveNode.ino' && + sketches[sketch].path != config.library_root+'examples/GatewaySerialRS485/GatewaySerialRS485.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayW5100/GatewayW5100.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayGSMMQTTClient/GatewayGSMMQTTClient.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayESP8266/GatewayESP8266.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' && + sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino' && + sketches[sketch].path != config.library_root+'examples/MotionSensorRS485/MotionSensorRS485.ino' && + sketches[sketch].path != config.library_root+'examples/SoilMoistSensor/SoilMoistSensor.ino') { + buildArduino(config, '-prefs build.flash_freq=80m -prefs build.flash_size=4MB '+fqbn, sketches[sketch].path, key+'_Esp32') + } + } + } catch (ex) { + echo "Build failed with: "+ ex.toString() + config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (ESP32 - '+key+')', 'Build error', '${BUILD_URL}') + throw ex + } finally { + parseWarnings(key+'_Esp32') + } + if (currentBuild.currentResult == 'UNSTABLE') { + config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (ESP32 - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new') + if (config.is_pull_request) { + error 'Termiated due to warnings found' + } + } else if (currentBuild.currentResult == 'FAILURE') { + config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (ESP32 - '+key+')', 'Build error', '${BUILD_URL}') + } else { + config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (ESP32 - '+key+')', 'Pass', '') + } +} + def buildnRF5(config, sketches, String key) { def fqbn = '-fqbn sandeepmistry:nRF5:Generic_nRF52832 -prefs build.f_cpu=16000000 -prefs build.mcu=cortex-m4' config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (nRF5 - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/') @@ -246,6 +308,8 @@ def buildnRF5(config, sketches, String key) { sketches[sketch].path != config.library_root+'examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino' && sketches[sketch].path != config.library_root+'examples/GatewayGSMMQTTClient/GatewayGSMMQTTClient.ino' && sketches[sketch].path != config.library_root+'examples/GatewayESP8266OTA/GatewayESP8266OTA.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayESP32/GatewayESP32.ino' && + sketches[sketch].path != config.library_root+'examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino' && sketches[sketch].path != config.library_root+'examples/GatewaySerialRS485/GatewaySerialRS485.ino' && sketches[sketch].path != config.library_root+'examples/GatewayW5100/GatewayW5100.ino' && sketches[sketch].path != config.library_root+'examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino' && diff --git a/.ci/pipeline.groovy b/.ci/pipeline.groovy index 36b9951..e59d78a 100644 --- a/.ci/pipeline.groovy +++ b/.ci/pipeline.groovy @@ -97,6 +97,9 @@ def call(Closure body) { stage('MySensorsGW (tests)') { arduino.buildMySensorsGw(config, config.tests, 'Tests') } + stage('ESP32 (tests)') { + arduino.buildEsp32(config, config.tests, 'Tests') + } stage('nRF52832 (tests)') { arduino.buildnRF52832(config, config.tests, 'Tests') } @@ -142,11 +145,16 @@ def call(Closure body) { stage('ESP8266 (examples)') { arduino.buildEsp8266(config, config.examples, 'Examples') } + // No point in building examples for ESP32 yet + /* + stage('ESP32 (examples)') { + arduino.buildEsp32(config, config.examples, 'Examples') + } + */ // No point in building examples for STM32F1 yet /* stage('STM32F1 (Examples)') { arduino.buildSTM32F1(config, config.tests, 'Examples') - } */ stage('ArduinoUno (examples)') { arduino.buildArduinoUno(config, config.examples, 'Examples') diff --git a/MyConfig.h b/MyConfig.h index 4dd9d3a..9cfb2f7 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -1342,6 +1342,8 @@ * @brief Define this for Ethernet GW based on the ENC28J60 module. * @def MY_GATEWAY_ESP8266 * @brief Define this for Ethernet GW based on the ESP8266. + * @def MY_GATEWAY_ESP32 + * @brief Define this for Ethernet GW based on the ESP32. * @def MY_GATEWAY_LINUX * @brief Define this for Ethernet GW based on Linux. * @def MY_GATEWAY_TINYGSM @@ -1351,6 +1353,7 @@ //#define MY_GATEWAY_W5100 //#define MY_GATEWAY_ENC28J60 //#define MY_GATEWAY_ESP8266 +//#define MY_GATEWAY_ESP32 //#define MY_GATEWAY_LINUX //#define MY_GATEWAY_TINYGSM @@ -1823,6 +1826,19 @@ #endif /** @}*/ // End of ESP8266SettingGrpPub group +/** +* @defgroup ESP32SettingGrpPub ESP32 +* @ingroup PlatformSettingGrpPub +* @brief These options control ESP32 specific configurations. +* @{ +*/ + +// +// no ESP32 settings +// + +/** @}*/ // End of ESP32SettingGrpPub group + /** * @defgroup LinuxSettingGrpPub Linux * @ingroup PlatformSettingGrpPub @@ -1891,7 +1907,7 @@ * MY_IS_GATEWAY is true when @ref MY_GATEWAY_FEATURE is set. * MY_NODE_TYPE contain a string describing the class of sketch/node (gateway/repeater/node). */ -#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) || defined(MY_GATEWAY_TINYGSM) +#if defined(MY_GATEWAY_SERIAL) || defined(MY_GATEWAY_W5100) || defined(MY_GATEWAY_ENC28J60) || defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32)|| defined(MY_GATEWAY_LINUX) || defined(MY_GATEWAY_MQTT_CLIENT) || defined(MY_GATEWAY_TINYGSM) #define MY_GATEWAY_FEATURE #define MY_IS_GATEWAY (true) #define MY_NODE_TYPE "GW" @@ -2053,6 +2069,7 @@ #define MY_GATEWAY_W5100 #define MY_GATEWAY_ENC28J60 #define MY_GATEWAY_ESP8266 +#define MY_GATEWAY_ESP32 #define MY_GATEWAY_LINUX #define MY_GATEWAY_TINYGSM #define MY_IP_ADDRESS 192,168,178,66 diff --git a/MySensors.h b/MySensors.h index 3f4facf..31d6ddf 100644 --- a/MySensors.h +++ b/MySensors.h @@ -59,6 +59,8 @@ #include "hal/architecture/MyHw.h" #if defined(ARDUINO_ARCH_ESP8266) #include "hal/architecture/ESP8266/MyHwESP8266.cpp" +#elif defined(ARDUINO_ARCH_ESP32) +#include "hal/architecture/ESP32/MyHwESP32.cpp" #elif defined(ARDUINO_ARCH_AVR) #include "drivers/AVR/DigitalWriteFast/digitalWriteFast.h" #include "hal/architecture/AVR/MyHwAVR.cpp" @@ -203,8 +205,8 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs #if !defined(MY_PORT) #error You must define MY_PORT (controller or gateway port to open) #endif -#if defined(MY_GATEWAY_ESP8266) -// GATEWAY - ESP8266 +#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32) +// GATEWAY - ESP8266 / ESP32 #include "core/MyGatewayTransportEthernet.cpp" #elif defined(MY_GATEWAY_LINUX) // GATEWAY - Generic Linux @@ -286,7 +288,7 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs // 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(ARDUINO_ARCH_NRF5) || defined(ARDUINO_ARCH_STM32F1) || defined(TEENSYDUINO) || defined(__linux__) +#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_NRF5) || defined(ARDUINO_ARCH_STM32F1) || defined(TEENSYDUINO) || defined(__linux__) #define MY_RAM_ROUTING_TABLE_ENABLED #elif defined(ARDUINO_ARCH_AVR) #if defined(__avr_atmega1280__) || defined(__avr_atmega1284__) || defined(__avr_atmega2560__) @@ -416,6 +418,8 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs #include "hal/architecture/ESP8266/MyMainESP8266.cpp" #elif defined(ARDUINO_ARCH_NRF5) #include "hal/architecture/NRF5/MyMainNRF5.cpp" +#elif defined(ARDUINO_ARCH_ESP32) +#include "hal/architecture/ESP32/MyMainESP32.cpp" #elif defined(__linux__) #include "hal/architecture/Linux/MyMainLinuxGeneric.cpp" #elif defined(ARDUINO_ARCH_STM32F1) diff --git a/core/MyCapabilities.h b/core/MyCapabilities.h index 6840898..d83875c 100644 --- a/core/MyCapabilities.h +++ b/core/MyCapabilities.h @@ -160,6 +160,8 @@ #define MY_CAP_ARCH "N" #elif defined(ARDUINO_ARCH_ESP8266) #define MY_CAP_ARCH "E" +#elif defined(ARDUINO_ARCH_ESP32) +#define MY_CAP_ARCH "F" #elif defined(ARDUINO_ARCH_AVR) #define MY_CAP_ARCH "A" #elif defined(ARDUINO_ARCH_STM32F1) diff --git a/core/MyGatewayTransportEthernet.cpp b/core/MyGatewayTransportEthernet.cpp index 9ec4512..7676613 100644 --- a/core/MyGatewayTransportEthernet.cpp +++ b/core/MyGatewayTransportEthernet.cpp @@ -30,14 +30,14 @@ IPAddress _ethernetControllerIP(MY_CONTROLLER_IP_ADDRESS); IPAddress _ethernetGatewayIP(MY_IP_ADDRESS); #if defined(MY_IP_GATEWAY_ADDRESS) IPAddress _gatewayIp(MY_IP_GATEWAY_ADDRESS); -#elif defined(MY_GATEWAY_ESP8266) /* Elif part of MY_IP_GATEWAY_ADDRESS */ +#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32) // Assume the gateway will be the machine on the same network as the local IP // but with last octet being '1' IPAddress _gatewayIp(_ethernetGatewayIP[0], _ethernetGatewayIP[1], _ethernetGatewayIP[2], 1); #endif /* End of MY_IP_GATEWAY_ADDRESS */ #if defined(MY_IP_SUBNET_ADDRESS) IPAddress _subnetIp(MY_IP_SUBNET_ADDRESS); -#elif defined(MY_GATEWAY_ESP8266) /* Elif part of MY_IP_SUBNET_ADDRESS */ +#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32) IPAddress _subnetIp(255, 255, 255, 0); #endif /* End of MY_IP_SUBNET_ADDRESS */ #endif /* End of MY_IP_ADDRESS */ @@ -57,12 +57,12 @@ typedef struct { uint8_t idx; } inputBuffer; -#if defined(MY_GATEWAY_ESP8266) +#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32) // Some re-defines to make code more readable below #define EthernetServer WiFiServer #define EthernetClient WiFiClient #define EthernetUDP WiFiUDP -#endif /* End of MY_GATEWAY_ESP8266 */ +#endif #if defined(MY_GATEWAY_CLIENT_MODE) #if defined(MY_USE_UDP) @@ -81,7 +81,7 @@ static inputBuffer inputString; #else static EthernetClient client = EthernetClient(); #endif /* End of MY_USE_UDP */ -#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX) /* Elif part of MY_GATEWAY_CLIENT_MODE */ +#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32) || 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]; @@ -136,9 +136,29 @@ bool gatewayTransportInit(void) } GATEWAY_DEBUG(PSTR("GWT:TIN:IP=%s\n"), WiFi.localIP().toString().c_str()); #endif /* End of MY_ESP8266_SSID */ -#elif defined(MY_GATEWAY_LINUX) /* Elif part of MY_GATEWAY_ESP8266 */ +#elif defined(MY_GATEWAY_ESP32) +#if defined(MY_ESP32_SSID) + // Turn off access point + WiFi.mode(WIFI_STA); +#if defined(MY_ESP32_HOSTNAME) + WiFi.setHostname(MY_ESP32_HOSTNAME); +#endif +#ifdef MY_IP_ADDRESS + WiFi.config(_ethernetGatewayIP, _gatewayIp, _subnetIp); +#endif +#ifndef MY_ESP32_BSSID +#define MY_ESP32_BSSID NULL +#endif + (void)WiFi.begin(MY_ESP32_SSID, MY_ESP32_PASSWORD, 0, MY_ESP32_BSSID); + while (WiFi.waitForConnectResult() != WL_CONNECTED) { + wait(500); + GATEWAY_DEBUG(PSTR(".")); + } + GATEWAY_DEBUG(PSTR("IP: %s\n"), WiFi.localIP().toString().c_str()); +#endif +#elif defined(MY_GATEWAY_LINUX) // Nothing to do here -#else /* Else part of MY_GATEWAY_ESP8266 */ +#else #if defined(MY_IP_GATEWAY_ADDRESS) && defined(MY_IP_SUBNET_ADDRESS) // DNS server set to gateway ip Ethernet.begin(_ethernetGatewayMAC, _ethernetGatewayIP, _gatewayIp, _gatewayIp, _subnetIp); @@ -157,7 +177,7 @@ bool gatewayTransportInit(void) Ethernet.localIP()[1], Ethernet.localIP()[2], Ethernet.localIP()[3]); // give the Ethernet interface a second to initialize delay(1000); -#endif /* End of MY_GATEWAY_ESP8266 */ +#endif /* MY_GATEWAY_ESP8266 / MY_GATEWAY_ESP32 */ #if defined(MY_GATEWAY_CLIENT_MODE) #if defined(MY_USE_UDP) @@ -236,7 +256,7 @@ bool gatewayTransportSend(MyMessage &message) #endif /* End of MY_USE_UDP */ #else /* Else part of MY_GATEWAY_CLIENT_MODE */ // Send message to connected clients -#if defined(MY_GATEWAY_ESP8266) +#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32) 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)); @@ -253,7 +273,7 @@ bool gatewayTransportSend(MyMessage &message) #if defined(MY_USE_UDP) // Nothing to do here #else -#if (defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX)) && !defined(MY_GATEWAY_CLIENT_MODE) +#if (defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32) || defined(MY_GATEWAY_LINUX)) && !defined(MY_GATEWAY_CLIENT_MODE) bool _readFromClient(uint8_t i) { while (clients[i].connected() && clients[i].available()) { @@ -366,7 +386,7 @@ bool gatewayTransportAvailable(void) } #endif /* End of MY_USE_UDP */ #else /* Else part of MY_GATEWAY_CLIENT_MODE */ -#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_LINUX) +#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32) || 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; @@ -443,7 +463,7 @@ MyMessage& gatewayTransportReceive(void) return _ethernetMsg; } -#if !defined(MY_IP_ADDRESS) && !defined(MY_GATEWAY_ESP8266) && !defined(MY_GATEWAY_LINUX) +#if !defined(MY_IP_ADDRESS) && !defined(MY_GATEWAY_ESP8266) && !defined(MY_GATEWAY_ESP32) && !defined(MY_GATEWAY_LINUX) void gatewayTransportRenewIP(void) { /* renew/rebind IP address diff --git a/core/MyGatewayTransportMQTTClient.cpp b/core/MyGatewayTransportMQTTClient.cpp index d7016bc..e3bf94f 100644 --- a/core/MyGatewayTransportMQTTClient.cpp +++ b/core/MyGatewayTransportMQTTClient.cpp @@ -30,19 +30,20 @@ IPAddress _brokerIp(MY_CONTROLLER_IP_ADDRESS); IPAddress _MQTT_clientIp(MY_IP_ADDRESS); #if defined(MY_IP_GATEWAY_ADDRESS) IPAddress _gatewayIp(MY_IP_GATEWAY_ADDRESS); -#elif defined(MY_GATEWAY_ESP8266) /* Elif part of MY_IP_GATEWAY_ADDRESS */ +#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32) // Assume the gateway will be the machine on the same network as the local IP // but with last octet being '1' IPAddress _gatewayIp(_MQTT_clientIp[0], _MQTT_clientIp[1], _MQTT_clientIp[2], 1); #endif /* End of MY_IP_GATEWAY_ADDRESS */ + #if defined(MY_IP_SUBNET_ADDRESS) IPAddress _subnetIp(MY_IP_SUBNET_ADDRESS); -#elif defined(MY_GATEWAY_ESP8266) /* Elif part of MY_IP_SUBNET_ADDRESS */ +#elif defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32) IPAddress _subnetIp(255, 255, 255, 0); #endif /* End of MY_IP_SUBNET_ADDRESS */ #endif /* End of MY_IP_ADDRESS */ -#if defined(MY_GATEWAY_ESP8266) +#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32) #define EthernetClient WiFiClient #elif defined(MY_GATEWAY_LINUX) // Nothing to do here @@ -120,7 +121,7 @@ bool reconnectMQTT(void) bool gatewayTransportConnect(void) { -#if defined(MY_GATEWAY_ESP8266) +#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32) while (WiFi.status() != WL_CONNECTED) { wait(500); GATEWAY_DEBUG(PSTR("GWT:TPC:CONNECTING...\n")); @@ -216,7 +217,20 @@ bool gatewayTransportInit(void) #define MY_ESP8266_BSSID NULL #endif (void)WiFi.begin(MY_ESP8266_SSID, MY_ESP8266_PASSWORD, 0, MY_ESP8266_BSSID); -#endif /* End of MY_GATEWAY_ESP8266 */ +#elif defined(MY_GATEWAY_ESP32) + // Turn off access point + WiFi.mode(WIFI_STA); +#if defined(MY_ESP32_HOSTNAME) + WiFi.setHostname(MY_ESP32_HOSTNAME); +#endif /* End of MY_ESP32_HOSTNAME */ +#if defined(MY_IP_ADDRESS) + WiFi.config(_MQTT_clientIp, _gatewayIp, _subnetIp); +#endif /* End of MY_IP_ADDRESS */ +#ifndef MY_ESP32_BSSID +#define MY_ESP32_BSSID NULL +#endif + (void)WiFi.begin(MY_ESP32_SSID, MY_ESP32_PASSWORD, 0, MY_ESP32_BSSID); +#endif gatewayTransportConnect(); diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index fcb6939..6b92b99 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -32,6 +32,7 @@ #endif // message buffers + MyMessage _msg; // Buffer for incoming messages MyMessage _msgTmp; // Buffer for temporary messages (acks and nonces among others) diff --git a/core/MySigningAtsha204Soft.cpp b/core/MySigningAtsha204Soft.cpp index 19c5f65..acd7bca 100644 --- a/core/MySigningAtsha204Soft.cpp +++ b/core/MySigningAtsha204Soft.cpp @@ -1,4 +1,4 @@ -/* +/* * The MySensors Arduino library handles the wireless radio link and protocol * between your home built sensors/actuators and HA controller of choice. * The sensors forms a self healing radio network with optional repeaters. Each diff --git a/core/MyTransport.cpp b/core/MyTransport.cpp index 5059510..06f0c14 100644 --- a/core/MyTransport.cpp +++ b/core/MyTransport.cpp @@ -1,4 +1,4 @@ -/* +/* * The MySensors Arduino library handles the wireless radio link and protocol * between your home built sensors/actuators and HA controller of choice. * The sensors forms a self healing radio network with optional repeaters. Each diff --git a/drivers/AES/AES_config.h b/drivers/AES/AES_config.h index ab38489..aa608a1 100644 --- a/drivers/AES/AES_config.h +++ b/drivers/AES/AES_config.h @@ -31,6 +31,8 @@ typedef unsigned char byte; #define PSTR(x) (x) #elif defined(ARDUINO_ARCH_ESP8266) #include +#elif defined(ARDUINO_ARCH_ESP32) +#include #elif defined(ARDUINO_ARCH_SAMD) #define printf_P printf #else diff --git a/drivers/RF24/RF24.h b/drivers/RF24/RF24.h index cecaf7c..4b182b7 100644 --- a/drivers/RF24/RF24.h +++ b/drivers/RF24/RF24.h @@ -67,7 +67,7 @@ #elif defined(ARDUINO_ARCH_ESP8266) #define DEFAULT_RF24_CE_PIN (4) //!< DEFAULT_RF24_CE_PIN #elif defined(ARDUINO_ARCH_ESP32) -#warning not implemented yet +#define DEFAULT_RF24_CE_PIN (17) //!< DEFAULT_RF24_CE_PIN #elif defined(ARDUINO_ARCH_SAMD) #define DEFAULT_RF24_CE_PIN (27) //!< DEFAULT_RF24_CE_PIN #elif defined(LINUX_ARCH_RASPBERRYPI) diff --git a/drivers/RFM69/new/RFM69_new.h b/drivers/RFM69/new/RFM69_new.h index 5b74c38..1f08b08 100644 --- a/drivers/RFM69/new/RFM69_new.h +++ b/drivers/RFM69/new/RFM69_new.h @@ -80,7 +80,8 @@ #elif defined(ARDUINO_ARCH_ESP8266) #define DEFAULT_RFM69_IRQ_PIN (5) //!< DEFAULT_RFM69_IRQ_PIN #elif defined(ARDUINO_ARCH_ESP32) -#warning not implemented yet +#define DEFAULT_RFM69_IRQ_PIN (16) //!< DEFAULT_RFM69_IRQ_PIN +#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM #elif defined(ARDUINO_ARCH_SAMD) #define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN #elif defined(LINUX_ARCH_RASPBERRYPI) diff --git a/drivers/RFM69/old/RFM69_old.h b/drivers/RFM69/old/RFM69_old.h index 42a1aaa..9e56b6a 100644 --- a/drivers/RFM69/old/RFM69_old.h +++ b/drivers/RFM69/old/RFM69_old.h @@ -46,7 +46,8 @@ #define DEFAULT_RFM69_IRQ_PIN (5) //!< DEFAULT_RFM69_IRQ_PIN #define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(MY_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM #elif defined(ARDUINO_ARCH_ESP32) -#warning not implemented yet +#define DEFAULT_RFM69_IRQ_PIN (16) //!< DEFAULT_RFM69_IRQ_PIN +#define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM #elif defined(ARDUINO_ARCH_SAMD) #define DEFAULT_RFM69_IRQ_PIN (2) //!< DEFAULT_RFM69_IRQ_PIN #define DEFAULT_RFM69_IRQ_NUM digitalPinToInterrupt(MY_RFM69_IRQ_PIN) //!< DEFAULT_RFM69_IRQ_NUM diff --git a/drivers/RFM95/RFM95.cpp b/drivers/RFM95/RFM95.cpp index 903d5e4..8fcb589 100644 --- a/drivers/RFM95/RFM95.cpp +++ b/drivers/RFM95/RFM95.cpp @@ -214,7 +214,6 @@ LOCAL bool RFM95_initialise(const uint32_t frequencyHz) RFM95_setFrequency(frequencyHz); (void)RFM95_setTxPowerLevel(MY_RFM95_TX_POWER_DBM); - if (!RFM95_sanityCheck()) { // sanity check failed, check wiring or replace module RFM95_DEBUG(PSTR("!RFM95:INIT:SANCHK FAIL\n")); diff --git a/drivers/RFM95/RFM95.h b/drivers/RFM95/RFM95.h index a302ac6..4db4a5a 100644 --- a/drivers/RFM95/RFM95.h +++ b/drivers/RFM95/RFM95.h @@ -91,7 +91,8 @@ #elif defined(ARDUINO_ARCH_ESP8266) #define DEFAULT_RFM95_IRQ_PIN (5) //!< DEFAULT_RFM95_IRQ_PIN #elif defined(ARDUINO_ARCH_ESP32) -#warning not implemented yet +#define DEFAULT_RFM95_IRQ_PIN (16) //!< DEFAULT_RFM95_IRQ_PIN +#define DEFAULT_RFM95_IRQ_NUM digitalPinToInterrupt(DEFAULT_RFM95_IRQ_PIN) //!< DEFAULT_RFM95_IRQ_NUM #elif defined(ARDUINO_ARCH_SAMD) #define DEFAULT_RFM95_IRQ_PIN (2) //!< DEFAULT_RFM95_IRQ_PIN #elif defined(LINUX_ARCH_RASPBERRYPI) diff --git a/examples/GatewayESP32/GatewayESP32.ino b/examples/GatewayESP32/GatewayESP32.ino new file mode 100644 index 0000000..6bd440f --- /dev/null +++ b/examples/GatewayESP32/GatewayESP32.ino @@ -0,0 +1,76 @@ +/** + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2018 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. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - tekka + * + * DESCRIPTION + * The ESP32 gateway 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. + * + * Make sure to fill in your ssid and WiFi password below. + */ + +// Enable debug prints to serial monitor +#define MY_DEBUG + +// Enables and select radio type (if attached) +#define MY_RADIO_NRF24 +//#define MY_RADIO_RFM69 +//#define MY_RADIO_RFM95 + +#define MY_GATEWAY_ESP32 + +#define MY_ESP32_SSID "MySSID" +#define MY_ESP32_PASSWORD "MyVerySecretPassword" + +// Set the hostname for the WiFi Client. This is the hostname +// it will pass to the DHCP server if not static. +#define MY_ESP32_HOSTNAME "ESP32_GW" + +// Enable MY_IP_ADDRESS here if you want a static ip address (no DHCP) +//#define MY_IP_ADDRESS 192,168,1,100 + +// If using static ip you can define Gateway and Subnet address as well +//#define MY_IP_GATEWAY_ADDRESS 192,168,1,1 +//#define MY_IP_SUBNET_ADDRESS 255,255,255,0 + +// 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 + +void setup() +{ + // Setup locally attached sensors +} + +void presentation() +{ + // Present locally attached sensors here +} + +void loop() +{ + // Send locally attached sensors data here +} diff --git a/examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino b/examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino new file mode 100644 index 0000000..9d58793 --- /dev/null +++ b/examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino @@ -0,0 +1,90 @@ +/** + * 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-2018 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. + * + ******************************* + * + * REVISION HISTORY + * Version 1.0 - tekka + * + * DESCRIPTION + * The ESP32 gateway 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. + * + * Make sure to fill in your ssid and WiFi password below. + */ + +// Enable debug prints to serial monitor +#define MY_DEBUG + +// Enables and select radio type (if attached) +#define MY_RADIO_NRF24 +//#define MY_RADIO_RFM69 +//#define MY_RADIO_RFM95 + +#define MY_GATEWAY_MQTT_CLIENT +#define MY_GATEWAY_ESP32 + +// 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" + +// Set MQTT client id +#define MY_MQTT_CLIENT_ID "mysensors-1" + +// Enable these if your MQTT broker requires usenrame/password +//#define MY_MQTT_USER "username" +//#define MY_MQTT_PASSWORD "password" + +// Set WIFI SSID and password +#define MY_ESP32_SSID "MySSID" +#define MY_ESP32_PASSWORD "MyVerySecretPassword" + +// Set the hostname for the WiFi Client. This is the hostname +// it will pass to the DHCP server if not static. +#define MY_ESP32_HOSTNAME "ESP32_MQTT_GW" + +// Enable MY_IP_ADDRESS here if you want a static ip address (no DHCP) +//#define MY_IP_ADDRESS 192,168,178,87 + +// If using static ip you can define Gateway and Subnet address as well +//#define MY_IP_GATEWAY_ADDRESS 192,168,178,1 +//#define MY_IP_SUBNET_ADDRESS 255,255,255,0 + +// MQTT broker ip address. +#define MY_CONTROLLER_IP_ADDRESS 192, 168, 1, 5 + +// The MQTT broker port to to open +#define MY_PORT 1883 + +#include + +void setup() +{ + // Setup locally attached sensors +} + +void presentation() +{ + // Present locally attached sensors here +} + +void loop() +{ + // Send locally attech sensors data here +} + diff --git a/hal/architecture/ESP32/MyHwESP32.cpp b/hal/architecture/ESP32/MyHwESP32.cpp new file mode 100644 index 0000000..25578fc --- /dev/null +++ b/hal/architecture/ESP32/MyHwESP32.cpp @@ -0,0 +1,168 @@ +/* + * 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-2018 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. + * + * Arduino core for ESP32: https://github.com/espressif/arduino-esp32 + * + * MySensors ESP32 implementation, Copyright (C) 2017-2018 Olivier Mauti + * + */ + +#include "MyHwESP32.h" + +bool hwInit(void) +{ +#if !defined(MY_DISABLED_SERIAL) + MY_SERIALDEVICE.begin(MY_BAUD_RATE, SERIAL_8N1); +#endif + return EEPROM.begin(MY_EEPROM_SIZE); +} + +void hwReadConfigBlock(void *buf, void *addr, size_t length) +{ + uint8_t *dst = static_cast(buf); + int offs = reinterpret_cast(addr); + while (length-- > 0) { + *dst++ = EEPROM.read(offs++); + } +} + +void hwWriteConfigBlock(void *buf, void *addr, size_t length) +{ + uint8_t *src = static_cast(buf); + int offs = reinterpret_cast(addr); + while (length-- > 0) { + EEPROM.write(offs++, *src++); + } + EEPROM.commit(); +} + +uint8_t hwReadConfig(const int addr) +{ + uint8_t value; + hwReadConfigBlock(&value, reinterpret_cast(addr), 1); + return value; +} + +void hwWriteConfig(const int addr, uint8_t value) +{ + if (hwReadConfig(addr) != value) { + hwWriteConfigBlock(&value, reinterpret_cast(addr), 1); + } +} + +bool hwUniqueID(unique_id_t *uniqueID) +{ + uint64_t val = ESP.getEfuseMac(); + (void)memcpy((void *)uniqueID, (void *)&val, 8); + (void)memset((void *)(uniqueID + 8), MY_HWID_PADDING_BYTE, 8); // padding + return true; +} + +ssize_t hwGetentropy(void *__buffer, size_t __length) +{ + // cut length if > 256 + if (__length > 256) { + __length = 256; + } + uint8_t *dst = (uint8_t *)__buffer; + // get random numbers + for (size_t i = 0; i < __length; i++) { + dst[i] = (uint8_t)esp_random(); + } + return __length; +} + +int8_t hwSleep(uint32_t ms) +{ + // TODO: Not supported! + (void)ms; + return MY_SLEEP_NOT_POSSIBLE; +} + +int8_t hwSleep(const uint8_t interrupt, const uint8_t mode, uint32_t ms) +{ + // TODO: Not supported! + (void)interrupt; + (void)mode; + (void)ms; + return MY_SLEEP_NOT_POSSIBLE; +} + +int8_t hwSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, + const uint8_t mode2, + uint32_t ms) +{ + // TODO: Not supported! + (void)interrupt1; + (void)mode1; + (void)interrupt2; + (void)mode2; + (void)ms; + return MY_SLEEP_NOT_POSSIBLE; +} + +uint16_t hwCPUVoltage(void) +{ + // in mV + return FUNCTION_NOT_SUPPORTED; +} + +uint16_t hwCPUFrequency(void) +{ + // in 1/10Mhz + return static_cast(ESP.getCpuFreqMHz() * 10); +} + +uint8_t hwCPUTemperature(void) +{ + // CPU temperature in °C + return static_cast(temperatureRead()); +} + +uint16_t hwFreeMem(void) +{ + return static_cast(ESP.getFreeHeap()); +} + +void hwDebugPrint(const char *fmt, ...) +{ + char fmtBuffer[MY_SERIAL_OUTPUT_SIZE]; +#ifdef MY_GATEWAY_SERIAL + // 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;%lu "), C_INTERNAL, I_LOG_MESSAGE, + millis()); + MY_SERIALDEVICE.print(fmtBuffer); +#else + // prepend timestamp + MY_SERIALDEVICE.print(millis()); + MY_SERIALDEVICE.print(" "); +#endif + va_list args; + va_start(args, fmt); +#ifdef MY_GATEWAY_SERIAL + // 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/hal/architecture/ESP32/MyHwESP32.h b/hal/architecture/ESP32/MyHwESP32.h new file mode 100644 index 0000000..64d6ac7 --- /dev/null +++ b/hal/architecture/ESP32/MyHwESP32.h @@ -0,0 +1,89 @@ +/* + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2018 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. + * + * Arduino core for ESP32: https://github.com/espressif/arduino-esp32 + * + * MySensors ESP32 implementation, Copyright (C) 2017-2018 Olivier Mauti + * + * Radio wiring ESP32(Node32s): RF24, RFM69, RFM95: + * + * | IO | RF24 | RFM69 | RFM95 | + * |------|------|-------|-------| + * | MOSI | 23 | 23 | 23 | + * | MISO | 19 | 19 | 19 | + * | SCK | 18 | 18 | 18 | + * | CSN | 5 | 5 | 5 | + * | CE | 17 | - | - | + * | RST | - | 17 | 17 | + * | IRQ | 16* | 16 | 16 | + * * = optional + * + */ + +#ifndef MyHwESP32_h +#define MyHwESP32_h + +#include +#include "EEPROM.h" + +#ifdef __cplusplus +#include +#endif + +#define MY_SERIALDEVICE Serial + +#define min(a,b) ((a)<(b)?(a):(b)) +#define max(a,b) ((a)>(b)?(a):(b)) + +#define MIN min +#define MAX max + +#define MY_EEPROM_SIZE 1024 + +#define hwDigitalWrite(__pin, __value) digitalWrite(__pin, __value) +#define hwDigitalRead(__pin) digitalRead(__pin) +#define hwPinMode(__pin, __value) pinMode(__pin, __value) +#define hwWatchdogReset() +#define hwReboot() ESP.restart() +#define hwMillis() millis() +#define hwMicros() micros() +#define hwRandomNumberInit() randomSeed(esp_random()) + +bool hwInit(void); +void hwReadConfigBlock(void *buf, void *addr, size_t length); +void hwWriteConfigBlock(void *buf, void *addr, size_t length); +void hwWriteConfig(const int addr, uint8_t value); +uint8_t hwReadConfig(const int addr); +ssize_t hwGetentropy(void *__buffer, size_t __length); +#define MY_HW_HAS_GETENTROPY + +/** +* Restore interrupt state. +* Helper function for MY_CRITICAL_SECTION. +*/ +static __inline__ void __psRestore(const uint32_t *__s) +{ + XTOS_RESTORE_INTLEVEL(*__s); +} + +#ifndef DOXYGEN +#define MY_CRITICAL_SECTION for ( uint32_t __psSaved __attribute__((__cleanup__(__psRestore))) = XTOS_DISABLE_ALL_INTERRUPTS, __ToDo = 1; __ToDo ; __ToDo = 0 ) +#endif /* DOXYGEN */ + + +#endif diff --git a/hal/architecture/ESP32/MyMainESP32.cpp b/hal/architecture/ESP32/MyMainESP32.cpp new file mode 100644 index 0000000..99be171 --- /dev/null +++ b/hal/architecture/ESP32/MyMainESP32.cpp @@ -0,0 +1,49 @@ +/* +* 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-2018 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 "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "Arduino.h" + +#if CONFIG_AUTOSTART_ARDUINO + +#if CONFIG_FREERTOS_UNICORE +#define ARDUINO_RUNNING_CORE 0 +#else +#define ARDUINO_RUNNING_CORE 1 +#endif + +void MySensorsTask(void *pvParameters) +{ + _begin(); // Startup MySensors library + for (;;) { + micros(); // update overflow + _process(); // Process incoming data + loop(); // Call sketch loop + } +} + +extern "C" void app_main() +{ + initArduino(); + xTaskCreatePinnedToCore(MySensorsTask, "MySensorsTask", 8192, NULL, 1, NULL, ARDUINO_RUNNING_CORE); +} + +#endif diff --git a/keywords.txt b/keywords.txt index 0a53ed8..917d3f5 100644 --- a/keywords.txt +++ b/keywords.txt @@ -229,6 +229,7 @@ MY_RS485_SOH_COUNT LITERAL1 # Gateway / MQTT MY_GATEWAY_CLIENT_MODE LITERAL1 MY_GATEWAY_ENC28J60 LITERAL1 +MY_GATEWAY_ESP32 LITERAL1 MY_GATEWAY_ESP8266 LITERAL1 MY_GATEWAY_MQTT_CLIENT LITERAL1 MY_GATEWAY_SERIAL LITERAL1 @@ -255,6 +256,12 @@ MY_MAC_ADDRESS LITERAL1 MY_PORT LITERAL1 MY_USE_UDP LITERAL1 +# ESP32 +MY_ESP32_SSID LITERAL1 +MY_ESP32_PASSWORD LITERAL1 +MY_ESP32_BSSID LITERAL1 +MY_ESP32_HOSTNAME LITERAL1 + # ESP8266 MY_ESP8266_BSSID LITERAL1 MY_ESP8266_HOSTNAME LITERAL1 From bb80732eada04434ed94a6a21891db1a06cbf2fa Mon Sep 17 00:00:00 2001 From: Mikael Falkvidd Date: Mon, 9 Apr 2018 23:27:19 +0200 Subject: [PATCH 37/60] Add keywords that already have Doxygen (#1108) Found some keywords that already have Doxygen comments but were not present in keywords.txt --- keywords.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/keywords.txt b/keywords.txt index 917d3f5..bfb8503 100644 --- a/keywords.txt +++ b/keywords.txt @@ -148,6 +148,7 @@ MY_SOFT_SPI_SCK_PIN LITERAL1 # RF24 MY_DEBUG_VERBOSE_RF24 LITERAL1 MY_RADIO_RF24 LITERAL1 +MY_RF24_ADDR_WIDTH LITERAL1 MY_RF24_BASE_RADIO_ID LITERAL1 MY_RF24_ENABLE_ENCRYPTION LITERAL1 MY_RF24_CE_PIN LITERAL1 @@ -189,6 +190,8 @@ MY_RFM95_RST_PIN LITERAL1 MY_RFM95_SPI_SPEED LITERAL1 MY_RFM95_TCXO LITERAL1 MY_RFM95_TX_POWER LITERAL1 +MY_RFM95_TX_POWER_DBM LITERAL1 +MY_RFM95_TX_TIMEOUT_MS LITERAL1 # RFM69 MY_DEBUG_VERBOSE_RFM69 LITERAL1 @@ -202,6 +205,8 @@ MY_RFM69_BITRATE_MSB LITERAL1 MY_RFM69_CS_PIN LITERAL1 MY_RFM69_CSMA_ADD_DELAY_BASE LITERAL1 MY_RFM69_CSMA_ADD_DELAY_COUNT LITERAL1 +MY_RFM69_CSMA_LIMIT_DBM LITERAL1 +MY_RFM69_CSMA_TIMEOUT_MS LITERAL1 MY_RFM69_DEFAULT_LISTEN_IDLE_US LITERAL1 MY_RFM69_DEFAULT_LISTEN_RX_US LITERAL1 MY_RFM69_ENABLE_ENCRYPTION LITERAL1 @@ -216,6 +221,7 @@ MY_RFM69_NEW_DRIVER LITERAL1 MY_RFM69_POWER_PIN LITERAL1 MY_RFM69_RST_PIN LITERAL1 MY_RFM69_SPI_SPEED LITERAL1 +MY_RFM69_TX_TIMEOUT_MS LITERAL1 MY_RFM69_TX_POWER_DBM LITERAL1 # RS485 @@ -282,10 +288,14 @@ MY_ESP8266_SSID LITERAL1 # MY_DEBUG_VERBOSE_CORE # MY_GATEWAY_FEATURE # MY_RAM_ROUTING_TABLE_ENABLED +# MY_RF24_CONFIGURATION +# MY_RFM69HW # MY_SENSOR_NETWORK # Blacklist - defined in ArduinoHwSAMD and therefore not responsibility of the MySensors library # MY_BAT_DETECT +# MY_SWC1 +# MY_SWC2 # Blacklist - used by the Security Personalizer, not meant to be used in any other sketch # MY_AES_KEY @@ -297,6 +307,8 @@ MY_ESP8266_SSID LITERAL1 # MY_SOFT_SERIAL # Blacklist - internal, not meant to be used by users +# MY_EEPROM_SIZE +# MY_EXT_EEPROM_I2C_ADDRESS # MY_EXT_EEPROM_PAGE_SIZE # MY_EXT_EEPROM_SIZE # MY_EXT_EEPROM_TWI_CLOCK @@ -327,6 +339,11 @@ MY_ESP8266_SSID LITERAL1 # Blacklist - deprecated and should therefore not be highlighted anymore # MY_LEDS_BLINKING_FEATURE +# MY_RADIO_NRF24 +# MY_RF69_IRQ_NUM +# MY_RF69_IRQ_PIN +# MY_RF69_RESET +# MY_RF69_SPI_CS # MY_TRANSPORT_DONT_CARE_MODE # Blacklist - descriptional only From f2d9f72cf488b86c04ec7a37ac69cbc147da0638 Mon Sep 17 00:00:00 2001 From: Mikael Falkvidd Date: Mon, 9 Apr 2018 23:31:50 +0200 Subject: [PATCH 38/60] Fix spelling mistakes (#1104) --- drivers/NRF5/Radio_ESB.cpp | 2 +- examples/AirQualitySensor/AirQualitySensor.ino | 10 +++++----- .../BinarySwitchSleepSensor.ino | 2 +- examples/CO2Sensor/CO2Sensor.ino | 2 +- examples/DimmableLEDActuator/DimmableLEDActuator.ino | 2 +- examples/DimmableLight/DimmableLight.ino | 4 ++-- examples/DustSensor/DustSensor.ino | 2 +- .../EnergyMeterPulseSensor.ino | 12 ++++++------ examples/GatewayESP8266/GatewayESP8266.ino | 2 +- .../GatewayESP8266MQTTClient.ino | 2 +- examples/GatewayESP8266OTA/GatewayESP8266OTA.ino | 2 +- examples/GatewaySerial/GatewaySerial.ino | 8 ++++---- examples/GatewaySerialRS485/GatewaySerialRS485.ino | 4 ++-- examples/GatewayW5100/GatewayW5100.ino | 6 +++--- .../GatewayW5100MQTTClient.ino | 4 ++-- examples/LightSensor/LightSensor.ino | 2 +- examples/LogOTAGateway/LogOTAGateway.ino | 8 ++++---- examples/MockMySensors/MockMySensors.ino | 12 ++++++------ examples/PingPongSensor/PingPongSensor.ino | 6 +++--- examples/RepeaterNode/RepeaterNode.ino | 2 +- examples/SecretKnockSensor/SecretKnockSensor.ino | 2 +- .../SensebenderGatewaySerial.ino | 10 +++++----- examples/SoilMoistSensor/SoilMoistSensor.ino | 4 ++-- .../WaterMeterPulseSensor/WaterMeterPulseSensor.ino | 12 ++++++------ 24 files changed, 61 insertions(+), 61 deletions(-) diff --git a/drivers/NRF5/Radio_ESB.cpp b/drivers/NRF5/Radio_ESB.cpp index 03472cf..3b0a929 100644 --- a/drivers/NRF5/Radio_ESB.cpp +++ b/drivers/NRF5/Radio_ESB.cpp @@ -637,7 +637,7 @@ extern "C" { (NRF_RADIO->STATE == RADIO_STATE_STATE_RxDisable) or (NRF_RADIO->STATE == RADIO_STATE_STATE_TxRu)) { if (NRF_RADIO->CRCSTATUS) { - // Ensure no ACK package is recieved + // Ensure no ACK package is received if (NRF_RADIO->RXMATCH != NRF5_ESB_TX_ADDR) { // calculate a package id uint32_t pkgid = rx_buffer.pid << 16 | NRF_RADIO->RXCRC; diff --git a/examples/AirQualitySensor/AirQualitySensor.ino b/examples/AirQualitySensor/AirQualitySensor.ino index 9986272..ca3a59d 100644 --- a/examples/AirQualitySensor/AirQualitySensor.ino +++ b/examples/AirQualitySensor/AirQualitySensor.ino @@ -53,10 +53,10 @@ //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 +#define CALIBRATION_SAMPLE_INTERVAL (500) //define the time interval(in milliseconds) between each samples in the +//calibration 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 interval(in milliseconds) between each samples in //normal operation /**********************Application Related Macros**********************************/ #define GAS_LPG (0) @@ -165,8 +165,8 @@ float MQCalibration(int mq_pin) /***************************** MQRead ********************************************* Input: mq_pin - analog channel Output: Rs of the sensor -Remarks: This function use MQResistanceCalculation to caculate the sensor resistenc (Rs). - The Rs changes as the sensor is in the different consentration of the target +Remarks: This function use MQResistanceCalculation to calculate the sensor resistance (Rs). + The Rs changes as the sensor is in the different concentration of the target gas. The sample times and the time interval between samples could be configured by changing the definition of the macros. ************************************************************************************/ diff --git a/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino b/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino index 8ba3e01..c02262a 100644 --- a/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino +++ b/examples/BinarySwitchSleepSensor/BinarySwitchSleepSensor.ino @@ -23,7 +23,7 @@ * Interrupt driven binary switch example with dual interrupts * Author: Patrick 'Anticimex' Fallberg * Connect one button or door/window reed switch between - * digitial I/O pin 3 (BUTTON_PIN below) and GND and the other + * digital I/O pin 3 (BUTTON_PIN below) and GND and the other * one in similar fashion on digital I/O pin 2. * This example is designed to fit Arduino Nano/Pro Mini * diff --git a/examples/CO2Sensor/CO2Sensor.ino b/examples/CO2Sensor/CO2Sensor.ino index 7b3bf2e..ba78acf 100644 --- a/examples/CO2Sensor/CO2Sensor.ino +++ b/examples/CO2Sensor/CO2Sensor.ino @@ -28,7 +28,7 @@ * Pad 6: PWM output ==> pin 6 * * From: http://davidegironi.blogspot.fr/2014/01/co2-meter-using-ndir-infrared-mh-z14.html - * MH-Z14 has a PWM output, with a sensitivity range of 0ppm to 2000ppm CO2, an accurancy of ±200ppm. + * MH-Z14 has a PWM output, with a sensitivity range of 0ppm to 2000ppm CO2, an accuracy of ±200ppm. * The cycle is 1004ms±5%, given the duty cicle Th (pulse high), Tl is 1004-Th, we can convert it to CO2 value using the formula: * CO2ppm = 2000 * (Th - 2ms) /(Th + Tl - 4ms) * From: http://airqualityegg.wikispaces.com/Sensor+Tests diff --git a/examples/DimmableLEDActuator/DimmableLEDActuator.ino b/examples/DimmableLEDActuator/DimmableLEDActuator.ino index d64de95..167be9d 100644 --- a/examples/DimmableLEDActuator/DimmableLEDActuator.ino +++ b/examples/DimmableLEDActuator/DimmableLEDActuator.ino @@ -62,7 +62,7 @@ MyMessage lightMsg(0, V_LIGHT); */ void setup() { - // Pull the gateway's current dim level - restore light level upon sendor node power-up + // Pull the gateway's current dim level - restore light level upon node power-up request( 0, V_DIMMER ); } diff --git a/examples/DimmableLight/DimmableLight.ino b/examples/DimmableLight/DimmableLight.ino index 4d18d6c..c67b6a9 100644 --- a/examples/DimmableLight/DimmableLight.ino +++ b/examples/DimmableLight/DimmableLight.ino @@ -48,7 +48,7 @@ #define LIGHT_OFF 0 #define LIGHT_ON 1 -#define SN "Dimable Light" +#define SN "Dimmable Light" #define SV "1.0" int16_t LastLightState=LIGHT_OFF; @@ -70,7 +70,7 @@ void setup() } } - //Here you actualy switch on/off the light with the last known dim level + //Here you actually switch on/off the light with the last known dim level SetCurrentState2Hardware(); Serial.println( "Node ready to receive messages..." ); diff --git a/examples/DustSensor/DustSensor.ino b/examples/DustSensor/DustSensor.ino index 1ccf552..eb250ac 100644 --- a/examples/DustSensor/DustSensor.ino +++ b/examples/DustSensor/DustSensor.ino @@ -83,7 +83,7 @@ void loop() // recover voltage calcVoltage = voMeasured * (5.0 / 1024.0); - // linear eqaution taken from http://www.howmuchsnow.com/arduino/airquality/ + // linear equation taken from http://www.howmuchsnow.com/arduino/airquality/ // Chris Nafis (c) 2012 dustDensity = (0.17 * calcVoltage - 0.1)*1000; diff --git a/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino b/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino index f14a1cf..512d75d 100644 --- a/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino +++ b/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino @@ -46,13 +46,13 @@ #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 +#define PULSE_FACTOR 1000 // Number of blinks per KWH of your meeter #define SLEEP_MODE false // Watt-value can only be reported when sleep mode is false. -#define MAX_WATT 10000 // Max watt value to report. This filetrs outliers. +#define MAX_WATT 10000 // Max watt value to report. This filters outliers. #define CHILD_ID 1 // Id of the sensor child uint32_t SEND_FREQUENCY = - 20000; // Minimum time between send (in milliseconds). We don't wnat to spam the gateway. + 20000; // Minimum time between send (in milliseconds). We don't want to spam the gateway. double ppwh = ((double)PULSE_FACTOR)/1000; // Pulses per watt hour bool pcReceived = false; volatile uint32_t pulseCount = 0; @@ -97,8 +97,8 @@ void loop() 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 + // Check that we don't get unreasonable large watt value. + // could happen when long wraps or false interrupt triggered if (watt<((uint32_t)MAX_WATT)) { send(wattMsg.set(watt)); // Send watt value to gw } @@ -151,4 +151,4 @@ void onPulse() lastBlink = newBlink; } pulseCount++; -} \ No newline at end of file +} diff --git a/examples/GatewayESP8266/GatewayESP8266.ino b/examples/GatewayESP8266/GatewayESP8266.ino index b7fef14..6532b53 100644 --- a/examples/GatewayESP8266/GatewayESP8266.ino +++ b/examples/GatewayESP8266/GatewayESP8266.ino @@ -34,7 +34,7 @@ * * LED purposes: * - 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 received + * - RX (green) - blink fast on radio message received. In inclusion mode will blink fast only on presentation received * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly * - ERR (red) - fast blink on error during transmission error or receive crc error * diff --git a/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino b/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino index 9d2b49b..b1d10ab 100644 --- a/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino +++ b/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino @@ -27,7 +27,7 @@ * * LED purposes: * - 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 received + * - RX (green) - blink fast on radio message received. In inclusion mode will blink fast only on presentation received * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly * - ERR (red) - fast blink on error during transmission error or receive crc error * diff --git a/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino b/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino index 4a485f8..6a0bb79 100644 --- a/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino +++ b/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino @@ -35,7 +35,7 @@ * * 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 received + * - RX (green) - blink fast on radio message received. In inclusion mode will blink fast only on presentation received * - TX (yellow) - blink fast on radio message transmitted. In inclusion mode will blink slowly * - ERR (red) - fast blink on error during transmission error or receive crc error * diff --git a/examples/GatewaySerial/GatewaySerial.ino b/examples/GatewaySerial/GatewaySerial.ino index f7bc2f3..3913bc2 100644 --- a/examples/GatewaySerial/GatewaySerial.ino +++ b/examples/GatewaySerial/GatewaySerial.ino @@ -20,7 +20,7 @@ * * 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 gateway accepts input on serial which will be sent out on radio network. * * The GW code is designed for Arduino Nano 328p / 16MHz * @@ -30,9 +30,9 @@ * * 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 +* - RX (green) - blink fast on radio message received. In inclusion mode will blink fast only on presentation received * - 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 receive crc error * */ @@ -53,7 +53,7 @@ // 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) +// Define a lower baud rate for Arduinos running on 8 MHz (Arduino Pro Mini 3.3V & SenseBender) #if F_CPU == 8000000L #define MY_BAUD_RATE 38400 #endif diff --git a/examples/GatewaySerialRS485/GatewaySerialRS485.ino b/examples/GatewaySerialRS485/GatewaySerialRS485.ino index 1cca1b0..36750eb 100644 --- a/examples/GatewaySerialRS485/GatewaySerialRS485.ino +++ b/examples/GatewaySerialRS485/GatewaySerialRS485.ino @@ -28,9 +28,9 @@ * - 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 +* - RX (green) - blink fast on radio message received. In inclusion mode will blink fast only on presentation received * - 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 receive crc error * * If your Arduino board has additional serial ports * you can use to connect the RS485 module. diff --git a/examples/GatewayW5100/GatewayW5100.ino b/examples/GatewayW5100/GatewayW5100.ino index f423529..6d7a488 100644 --- a/examples/GatewayW5100/GatewayW5100.ino +++ b/examples/GatewayW5100/GatewayW5100.ino @@ -33,9 +33,9 @@ * * LED purposes: * - 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 + * - RX (green) - blink fast on radio message received. In inclusion mode will blink fast only on presentation received * - 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 receive crc error * * See http://www.mysensors.org/build/ethernet_gateway for wiring instructions. * @@ -96,7 +96,7 @@ // 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. +// Note that most of the Arduino examples use "DEAD BEEF FEED" for the MAC address. #define MY_MAC_ADDRESS 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED // Enable inclusion mode diff --git a/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino b/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino index df270f7..0b6d66f 100644 --- a/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino +++ b/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino @@ -27,9 +27,9 @@ * * 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 + * - RX (green) - blink fast on radio message received. In inclusion mode will blink fast only on presentation received * - 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 receive crc error * * See http://www.mysensors.org/build/esp8266_gateway for wiring instructions. * nRF24L01+ ESP8266 diff --git a/examples/LightSensor/LightSensor.ino b/examples/LightSensor/LightSensor.ino index 505bc8c..3716ffd 100644 --- a/examples/LightSensor/LightSensor.ino +++ b/examples/LightSensor/LightSensor.ino @@ -22,7 +22,7 @@ * Version 1.0 - Henrik EKblad * * DESCRIPTION - * Example sketch showing how to measue light level using a LM393 photo-resistor + * Example sketch showing how to measure light level using a LM393 photo-resistor * http://www.mysensors.org/build/light */ diff --git a/examples/LogOTAGateway/LogOTAGateway.ino b/examples/LogOTAGateway/LogOTAGateway.ino index 7d8a80a..c1e62d7 100644 --- a/examples/LogOTAGateway/LogOTAGateway.ino +++ b/examples/LogOTAGateway/LogOTAGateway.ino @@ -20,7 +20,7 @@ * * 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 gateway accepts input on serial which will be sent out on radio network. * * The GW code is designed for Arduino Nano 328p / 16MHz * @@ -30,9 +30,9 @@ * * 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 +* - RX (green) - blink fast on radio message received. In inclusion mode will blink fast only on presentation received * - 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 receive crc error * * OTA DEBUG MESSAGES * - Add the OTADebugReceive(message) into receive(const MyMessage &message) on a serial connected node @@ -59,7 +59,7 @@ // 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) +// Define a lower baud rate for Arduinos running on 8 MHz (Arduino Pro Mini 3.3V & SenseBender) #if F_CPU == 8000000L #define MY_BAUD_RATE 38400 #endif diff --git a/examples/MockMySensors/MockMySensors.ino b/examples/MockMySensors/MockMySensors.ino index 158deff..1eeeafa 100644 --- a/examples/MockMySensors/MockMySensors.ino +++ b/examples/MockMySensors/MockMySensors.ino @@ -45,7 +45,7 @@ // will make the sketch too large for a pro mini's memory so it's probably best to try // one at a time. -#define ID_S_ARMED 0 // dummy to controll armed stated for several sensors +#define ID_S_ARMED 0 // dummy to control armed stated for several sensors #define ID_S_DOOR 1 //#define ID_S_MOTION 2 //#define ID_S_SMOKE 3 @@ -91,7 +91,7 @@ bool metric = true; long randNumber; -//Instanciate Messages objects +//Instantiate Messages objects #ifdef ID_S_ARMED bool isArmed; @@ -857,7 +857,7 @@ void temp() void hum() { - Serial.print("Humitidty is: " ); + Serial.print("Humidity is: " ); Serial.println(randNumber); send(msg_S_HUM.set(randNumber)); @@ -873,7 +873,7 @@ void baro() long pressure = map(randNumber,1,100,870,1086);// hPa? int forecast = map(randNumber,1,100,0,5); - Serial.print("Atmosferic Pressure is: " ); + Serial.print("Atmospheric Pressure is: " ); Serial.println(pressure); send(msg_S_BARO_P.set(pressure)); @@ -907,7 +907,7 @@ void wind() void rain() { - Serial.print("Rain ammount is: " ); + Serial.print("Rain amount is: " ); Serial.println(randNumber); send(msg_S_RAIN_A.set(randNumber)); @@ -1488,7 +1488,7 @@ void receive(const MyMessage &message) #endif default: - Serial.print("Unknown/UnImplemented message type: "); + Serial.print("Unknown/Unimplemented message type: "); Serial.println(message.type); } diff --git a/examples/PingPongSensor/PingPongSensor.ino b/examples/PingPongSensor/PingPongSensor.ino index 593757b..0fd8461 100644 --- a/examples/PingPongSensor/PingPongSensor.ino +++ b/examples/PingPongSensor/PingPongSensor.ino @@ -1,7 +1,7 @@ /*** - * This is a simple sketch used to demenstrate and test node-to-node MySensor's communication. + * This is a simple sketch used to demonstrate and test node-to-node MySensors communication. * To use this sketch, assemble MySensors nodes - they need nothing more than a radio - * 1. Flash each node with the same sketch, open the console and type either 0 or 1 to the respective nodes to set thei ID + * 1. Flash each node with the same sketch, open the console and type either 0 or 1 to the respective nodes to set their ID * 2. You only need to set the node id once, and restart the nodes * 3. To being a ping-pong test, simply type T in the console for one of the nodes. * @@ -47,7 +47,7 @@ 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. + // Entering T on either node will initiate a ping-pong test. if (Serial.available()) { byte inChar = Serial.read(); uint8_t node = getNodeId(); diff --git a/examples/RepeaterNode/RepeaterNode.ino b/examples/RepeaterNode/RepeaterNode.ino index bee56d3..768b555 100644 --- a/examples/RepeaterNode/RepeaterNode.ino +++ b/examples/RepeaterNode/RepeaterNode.ino @@ -22,7 +22,7 @@ * Version 1.0 - Henrik Ekblad * * DESCRIPTION - * Example sketch showing how to create a node thay repeates messages + * Example sketch showing how to create a node that repeats 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. diff --git a/examples/SecretKnockSensor/SecretKnockSensor.ino b/examples/SecretKnockSensor/SecretKnockSensor.ino index 2bdf79c..d626b7f 100644 --- a/examples/SecretKnockSensor/SecretKnockSensor.ino +++ b/examples/SecretKnockSensor/SecretKnockSensor.ino @@ -139,7 +139,7 @@ void loop() 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. + } else { // If we are in programming mode, turn it off. programModeActive = false; digitalWrite(ledPin, LOW); chirp(500, 1000); // Turn off the programming LED and play a sad note. diff --git a/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino b/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino index d0a9637..1c682ac 100644 --- a/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino +++ b/examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino @@ -20,7 +20,7 @@ * * 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 gateway accepts input on serial which will be sent out on radio network. * * This GW code is designed for Sensebender GateWay / (Arduino Zero variant) * @@ -29,9 +29,9 @@ * * 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 +* - Yellow: RX - Blink fast on radio message received. In inclusion mode will blink fast only on presentation received * - 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 +* - Red : ERR - Fast blink on error during transmission error or receive crc error * - Blue : free - (use with LED_BLUE macro) * */ @@ -53,7 +53,7 @@ // 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) +// Define a lower baud rate for Arduinos running on 8 MHz (Arduino Pro Mini 3.3V & Sensebender) #if F_CPU == 8000000L #define MY_BAUD_RATE 38400 #endif @@ -135,7 +135,7 @@ void preHwInit() digitalWrite(LED_BLUE, LOW); if (Serial) { Serial.println("Sensebender GateWay test routine"); - Serial.print("Mysensors core version : "); + Serial.print("MySensors core version : "); Serial.println(MYSENSORS_LIBRARY_VERSION); Serial.print("GateWay sketch version : "); Serial.println(SKETCH_VERSION); diff --git a/examples/SoilMoistSensor/SoilMoistSensor.ino b/examples/SoilMoistSensor/SoilMoistSensor.ino index bc76be3..c4900ba 100644 --- a/examples/SoilMoistSensor/SoilMoistSensor.ino +++ b/examples/SoilMoistSensor/SoilMoistSensor.ino @@ -36,8 +36,8 @@ * 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 + * D6, D7: alternative powering to avoid sensor degradation + * A0, A1: alternative resistance measuring * * Based on: * "Vinduino" portable soil moisture sensor code V3.00 diff --git a/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino b/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino index 3f70756..1afd45a 100644 --- a/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino +++ b/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino @@ -23,7 +23,7 @@ * Version 1.1 - GizMoCuz * * DESCRIPTION - * Use this sensor to measure volume and flow of your house watermeter. + * Use this sensor to measure volume and flow of your house water meter. * 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. @@ -47,7 +47,7 @@ #define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your sensor. (Only 2 and 3 generates interrupt!) -#define PULSE_FACTOR 1000 // Nummber of blinks per m3 of your meter (One rotation/liter) +#define PULSE_FACTOR 1000 // Number of blinks per m3 of your meter (One rotation/liter) #define SLEEP_MODE false // flowvalue can only be reported when sleep mode is false. @@ -96,7 +96,7 @@ void presentation() // Send the sketch version information to the gateway and Controller sendSketchInfo("Water Meter", "1.1"); - // Register this device as Waterflow sensor + // Register this device as Water flow sensor present(CHILD_ID, S_WATER); } @@ -120,8 +120,8 @@ void loop() 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 + // Check that we don't get unreasonable large flow value. + // could happen when long wraps or false interrupt triggered if (flow<((uint32_t)MAX_FLOW)) { send(flowMsg.set(flow, 2)); // Send flow value to gw } @@ -178,7 +178,7 @@ void onPulse() if (interval!=0) { lastPulse = millis(); if (interval<500000L) { - // Sometimes we get interrupt on RISING, 500000 = 0.5sek debounce ( max 120 l/min) + // Sometimes we get interrupt on RISING, 500000 = 0.5 second debounce ( max 120 l/min) return; } flow = (60000000.0 /interval) / ppl; From df1bb7fcc538a0c95ca6985868edbfc4c2af5a9a Mon Sep 17 00:00:00 2001 From: Mikael Falkvidd Date: Tue, 10 Apr 2018 07:56:17 +0200 Subject: [PATCH 39/60] Add Doxygen for MQTT_USER and MQTT_PASSWORD (#1105) This fixes https://github.com/mysensors/MySensors/issues/1088 --- MyConfig.h | 22 ++++++++++++++++++++++ keywords.txt | 2 ++ 2 files changed, 24 insertions(+) diff --git a/MyConfig.h b/MyConfig.h index 9cfb2f7..df83bb0 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -1382,6 +1382,26 @@ */ //#define MY_MQTT_CLIENT_PUBLISH_RETAIN +/** + * @def MY_MQTT_PASSWORD + * @brief Used for authenticated MQTT connections. + * + * Set if your MQTT broker requires username/password. + * Example: @code #define MY_MQTT_PASSWORD "secretpassword" @endcode + * @see MY_MQTT_USER + */ +//#define MY_MQTT_PASSWORD "secretpassword" + +/** + * @def MY_MQTT_USER + * @brief Used for authenticated MQTT connections. + * + * Set if your MQTT broker requires username/password. + * Example: @code #define MY_MQTT_USER "username" @endcode + * @see MY_MQTT_PASSWORD + */ +//#define MY_MQTT_USER "username" + /** * @def MY_IP_ADDRESS * @brief Static ip address of gateway (if this is not defined, DHCP will be used). @@ -2053,6 +2073,8 @@ #define MY_REPEATER_FEATURE #define MY_PASSIVE_NODE #define MY_MQTT_CLIENT_PUBLISH_RETAIN +#define MY_MQTT_PASSWORD +#define MY_MQTT_USER #define MY_SIGNAL_REPORT_ENABLED // general #define MY_WITH_LEDS_BLINKING_INVERSE diff --git a/keywords.txt b/keywords.txt index bfb8503..494e979 100644 --- a/keywords.txt +++ b/keywords.txt @@ -243,8 +243,10 @@ MY_GATEWAY_W5100 LITERAL1 MY_INCLUSION_BUTTON_EXTERNAL_PULLUP LITERAL1 MY_MQTT_CLIENT_ID LITERAL1 MY_MQTT_CLIENT_PUBLISH_RETAIN LITERAL1 +MY_MQTT_PASSWORD LITERAL1 MY_MQTT_PUBLISH_TOPIC_PREFIX LITERAL1 MY_MQTT_SUBSCRIBE_TOPIC_PREFIX LITERAL1 +MY_MQTT_USER LITERAL1 MY_W5100_SPI_EN LITERAL1 # Ethernet From a8429868e770ce89bf4e467b3b926ce80a3ba20f Mon Sep 17 00:00:00 2001 From: Mikael Falkvidd Date: Tue, 10 Apr 2018 14:58:11 +0200 Subject: [PATCH 40/60] Clarify default defines (#1106) Moved example values after the @brief portion of Doxygen, so the default (empty/undefined) values are visible in Doxygen. --- MyConfig.h | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/MyConfig.h b/MyConfig.h index df83bb0..b8d7e95 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -243,6 +243,8 @@ /** * @def MY_RS485_HWSERIAL * @brief Define this if RS485 is connected to a hardware serial port. + * + * Example: @code #define MY_RS485_HWSERIAL Serial1 @endcode */ //#define MY_RS485_HWSERIAL (Serial1) /** @}*/ // End of RS485SettingGrpPub group @@ -1404,7 +1406,9 @@ /** * @def MY_IP_ADDRESS - * @brief Static ip address of gateway (if this is not defined, DHCP will be used). + * @brief Static ip address of gateway. If not defined, DHCP will be used. + * + * Example: @code #define MY_IP_ADDRESS 192,168,178,66 @endcode */ //#define MY_IP_ADDRESS 192,168,178,66 @@ -1437,6 +1441,8 @@ * @brief If this is defined, gateway will act as a client trying to contact controller on * @ref MY_PORT using this IP address. * + * Example: @code #define MY_CONTROLLER_IP_ADDRESS 192,168,178,254 @endcode + * * If left un-defined, gateway acts as server allowing incoming connections. */ //#define MY_CONTROLLER_IP_ADDRESS 192,168,178,254 @@ -1535,6 +1541,8 @@ * @brief Enables SW backed signing functionality and encryption functionality in library and uses * provided password as key. * + * Example: @code #define MY_SECURITY_SIMPLE_PASSWD "MyInsecurePassword" @endcode + * * For details on the effects, see the references. * @see MY_SIGNING_SIMPLE_PASSWD, MY_ENCRYPTION_SIMPLE_PASSWD */ @@ -1582,6 +1590,8 @@ * to accommodate the key size in question. A 32 character password is the maximum length. Any * password longer than that will be truncated. * + * Example: @code #define MY_SIGNING_SIMPLE_PASSWD "MyInsecurePassword" @endcode + * * @see MY_SECURITY_SIMPLE_PASSWD * */ @@ -1659,6 +1669,8 @@ * the signed message. * * It is legal to only have one node with a whitelist for this reason but it is not required. + * + * Example: @code #define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01}}} @endcode */ //#define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01}}} @@ -1731,6 +1743,8 @@ * to accommodate the key size in question. A 16 character password is the maximum length. Any * password longer than that will be truncated. * + * Example: @code #define MY_ENCRYPTION_SIMPLE_PASSWD "MyInsecurePassword" @endcode + * * @see MY_SECURITY_SIMPLE_PASSWD */ //#define MY_ENCRYPTION_SIMPLE_PASSWD "MyInsecurePassword" @@ -2094,9 +2108,9 @@ #define MY_GATEWAY_ESP32 #define MY_GATEWAY_LINUX #define MY_GATEWAY_TINYGSM -#define MY_IP_ADDRESS 192,168,178,66 +#define MY_IP_ADDRESS #define MY_USE_UDP -#define MY_CONTROLLER_IP_ADDRESS 192,168,178,254 +#define MY_CONTROLLER_IP_ADDRESS // TinyGSM /** * @def MY_GSM_APN @@ -2143,14 +2157,14 @@ #define MY_DEFAULT_TX_LED_PIN #define MY_DEFAULT_RX_LED_PIN // signing -#define MY_SECURITY_SIMPLE_PASSWD "MyInsecurePassword" -#define MY_SIGNING_SIMPLE_PASSWD "MyInsecurePassword" -#define MY_ENCRYPTION_SIMPLE_PASSWD "MyInsecurePassword" +#define MY_SECURITY_SIMPLE_PASSWD +#define MY_SIGNING_SIMPLE_PASSWD +#define MY_ENCRYPTION_SIMPLE_PASSWD #define MY_SIGNING_ATSHA204 #define MY_SIGNING_SOFT #define MY_SIGNING_REQUEST_SIGNATURES #define MY_SIGNING_WEAK_SECURITY -#define MY_SIGNING_NODE_WHITELISTING {{.nodeId = GATEWAY_ADDRESS,.serial = {0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x01}}} +#define MY_SIGNING_NODE_WHITELISTING #define MY_DEBUG_VERBOSE_SIGNING #define MY_SIGNING_FEATURE #define MY_ENCRYPTION_FEATURE @@ -2159,7 +2173,7 @@ #define MY_OTA_USE_I2C_EEPROM // RS485 #define MY_RS485 -#define MY_RS485_HWSERIAL (Serial1) +#define MY_RS485_HWSERIAL // RF24 #define MY_RADIO_RF24 #define MY_DEBUG_VERBOSE_RF24 From e0988e6d9e368f1b619641c1e8e2328dcb809bf1 Mon Sep 17 00:00:00 2001 From: Mikael Falkvidd Date: Tue, 10 Apr 2018 20:22:39 +0200 Subject: [PATCH 41/60] Add more missing keywords (#1111) This fixes https://github.com/mysensors/MySensors/issues/1089 and also adds Doxygen and syntax highlighting for the following keywords: MY_GATEWAY_MQTT_CLIENT MY_GATEWAY_SERIAL MY_IP_GATEWAY_ADDRESS MY_IP_SUBNET_ADDRESS MY_MQTT_CLIENT_ID MY_MQTT_PUBLISH_TOPIC_PREFIX MY_MQTT_SUBSCRIBE_TOPIC_PREFIX --- MyConfig.h | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/MyConfig.h b/MyConfig.h index b8d7e95..5b1d84a 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -1350,6 +1350,10 @@ * @brief Define this for Ethernet GW based on Linux. * @def MY_GATEWAY_TINYGSM * @brief Define this for Ethernet GW based on GSM modems supported by TinyGSM library. + * @def MY_GATEWAY_MQTT_CLIENT + * @brief Define this for MQTT client GW. + * @def MY_GATEWAY_SERIAL + * @brief Define this for Serial GW. */ // The gateway options available //#define MY_GATEWAY_W5100 @@ -1358,6 +1362,8 @@ //#define MY_GATEWAY_ESP32 //#define MY_GATEWAY_LINUX //#define MY_GATEWAY_TINYGSM +//#define MY_GATEWAY_MQTT_CLIENT +//#define MY_GATEWAY_SERIAL /** @@ -1404,6 +1410,33 @@ */ //#define MY_MQTT_USER "username" +/** + * @def MY_MQTT_CLIENT_ID + * @brief Set client ID for MQTT connections + * + * This define is mandatory for all MQTT client gateways. + * Example: @code #define MY_MQTT_CLIENT_ID "mysensors-1" @endcode + */ +//#define MY_MQTT_CLIENT_ID "mysensors-1" + +/** + * @def MY_MQTT_PUBLISH_TOPIC_PREFIX + * @brief Set prefix for MQTT topic to publish to. + * + * This define is mandatory for all MQTT client gateways. + * Example: @code #define MY_MQTT_PUBLISH_TOPIC_PREFIX "mygateway1-out" @endcode + */ +//#define MY_MQTT_PUBLISH_TOPIC_PREFIX "mygateway1-out" + +/** + * @def MY_MQTT_SUBSCRIBE_TOPIC_PREFIX + * @brief Set prefix for MQTT topic to subscribe to. + * + * This define is mandatory for all MQTT client gateways. + * Example: @code #define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX "mygateway1-in" @endcode + */ +//#define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX "mygateway1-in" + /** * @def MY_IP_ADDRESS * @brief Static ip address of gateway. If not defined, DHCP will be used. @@ -1412,6 +1445,22 @@ */ //#define MY_IP_ADDRESS 192,168,178,66 +/** + * @def MY_IP_GATEWAY_ADDRESS + * @brief IP address of your broadband router/gateway, if not using DHCP. + * + * Example: @code #define MY_IP_GATEWAY_ADDRESS 192,168,1,1 @endcode + */ +//#define MY_IP_GATEWAY_ADDRESS 192,168,1,1 + +/** + * @def MY_IP_SUBNET_ADDRESS + * @brief Subnet address of your local network, if not using DHCP. + * + * Example: @code #define MY_IP_SUBNET_ADDRESS 255,255,255,0 @endcode + */ +//#define MY_IP_SUBNET_ADDRESS 255,255,255,0 + /** * @def MY_USE_UDP * @brief Enables UDP mode for Ethernet gateway. @@ -1444,8 +1493,22 @@ * Example: @code #define MY_CONTROLLER_IP_ADDRESS 192,168,178,254 @endcode * * If left un-defined, gateway acts as server allowing incoming connections. + * @see MY_CONTROLLER_URL_ADDRESS */ //#define MY_CONTROLLER_IP_ADDRESS 192,168,178,254 + +/** + * @def MY_CONTROLLER_URL_ADDRESS + * @brief If this is defined, gateway will act as a client (ethernet or MQTT) trying to + * contact controller on the given URL. + * + * If left un-defined, gateway acts as server allowing incoming connections. + * Example: @code #define MY_CONTROLLER_URL_ADDRESS "test.mosquitto.org" @endcode + * @see MY_CONTROLLER_IP_ADDRESS + * @see MY_GATEWAY_MQTT_CLIENT + */ +//#define MY_CONTROLLER_URL_ADDRESS "test.mosquitto.org" + /** @}*/ // End of GatewaySettingGrpPub group /** @@ -2089,6 +2152,9 @@ #define MY_MQTT_CLIENT_PUBLISH_RETAIN #define MY_MQTT_PASSWORD #define MY_MQTT_USER +#define MY_MQTT_CLIENT_ID +#define MY_MQTT_PUBLISH_TOPIC_PREFIX +#define MY_MQTT_SUBSCRIBE_TOPIC_PREFIX #define MY_SIGNAL_REPORT_ENABLED // general #define MY_WITH_LEDS_BLINKING_INVERSE @@ -2108,9 +2174,14 @@ #define MY_GATEWAY_ESP32 #define MY_GATEWAY_LINUX #define MY_GATEWAY_TINYGSM +#define MY_GATEWAY_MQTT_CLIENT +#define MY_GATEWAY_SERIAL #define MY_IP_ADDRESS +#define MY_IP_GATEWAY_ADDRESS +#define MY_IP_SUBNET_ADDRESS #define MY_USE_UDP #define MY_CONTROLLER_IP_ADDRESS +#define MY_CONTROLLER_URL_ADDRESS // TinyGSM /** * @def MY_GSM_APN From bb7766197c982eb36410da2e2aab82c58b0a66aa Mon Sep 17 00:00:00 2001 From: tekka Date: Tue, 1 May 2018 16:54:43 +0200 Subject: [PATCH 42/60] Consolidate WiFi defines (#1110) Great work @tekka007 --- MyConfig.h | 30 +++++++- core/MyGatewayTransportEthernet.cpp | 73 +++++++++++-------- core/MyGatewayTransportMQTTClient.cpp | 59 +++++++++++---- examples/GatewayESP32/GatewayESP32.ino | 8 +- .../GatewayESP32MQTTClient.ino | 8 +- examples/GatewayESP8266/GatewayESP8266.ino | 6 +- .../GatewayESP8266MQTTClient.ino | 6 +- .../GatewayESP8266OTA/GatewayESP8266OTA.ino | 6 +- keywords.txt | 16 ++-- 9 files changed, 140 insertions(+), 72 deletions(-) diff --git a/MyConfig.h b/MyConfig.h index 5b1d84a..c08b1f2 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -6,7 +6,7 @@ * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad - * Copyright (C) 2013-2017 Sensnology AB + * Copyright (C) 2013-2018 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org @@ -1372,6 +1372,30 @@ */ //#define MY_DEBUG_VERBOSE_GATEWAY +/** +* @def MY_WIFI_SSID +* @brief SSID of your WiFi network +*/ +//#define MY_WIFI_SSID "MySSID" + +/** +* @def MY_WIFI_BSSID +* @brief BSSID of your WiFi network +*/ +//#define MY_WIFI_BSSID "MyBSSID" + +/** +* @def MY_WIFI_PASSWORD +* @brief Password of your WiFi network +*/ +//#define MY_WIFI_PASSWORD "MyVerySecretPassword" + +/** +* @def MY_HOSTNAME +* @brief Hostname of your device +*/ +//#define MY_HOSTNAME "MyHostname" + /** * @def MY_PORT * @brief The Ethernet TCP/UDP port to open on controller or gateway. @@ -2172,6 +2196,10 @@ #define MY_GATEWAY_ENC28J60 #define MY_GATEWAY_ESP8266 #define MY_GATEWAY_ESP32 +#define MY_WIFI_SSID +#define MY_WIFI_BSSID +#define MY_WIFI_PASSWORD +#define MY_HOSTNAME #define MY_GATEWAY_LINUX #define MY_GATEWAY_TINYGSM #define MY_GATEWAY_MQTT_CLIENT diff --git a/core/MyGatewayTransportEthernet.cpp b/core/MyGatewayTransportEthernet.cpp index 7676613..ac17394 100644 --- a/core/MyGatewayTransportEthernet.cpp +++ b/core/MyGatewayTransportEthernet.cpp @@ -22,6 +22,35 @@ // global variables extern MyMessage _msgTmp; +// housekeeping, remove for 3.0.0 +#ifdef MY_ESP8266_SSID +#warning MY_ESP8266_SSID is deprecated, use MY_WIFI_SSID instead! +#define MY_WIFI_SSID MY_ESP8266_SSID +#undef MY_ESP8266_SSID // cleanup +#endif + +#ifdef MY_ESP8266_PASSWORD +#warning MY_ESP8266_PASSWORD is deprecated, use MY_WIFI_PASSWORD instead! +#define MY_WIFI_PASSWORD MY_ESP8266_PASSWORD +#undef MY_ESP8266_PASSWORD // cleanup +#endif + +#ifdef MY_ESP8266_BSSID +#warning MY_ESP8266_BSSID is deprecated, use MY_WIFI_BSSID instead! +#define MY_WIFI_BSSID MY_ESP8266_BSSID +#undef MY_ESP8266_BSSID // cleanup +#endif + +#ifdef MY_ESP8266_HOSTNAME +#warning MY_ESP8266_HOSTNAME is deprecated, use MY_HOSTNAME instead! +#define MY_HOSTNAME MY_ESP8266_HOSTNAME +#undef MY_ESP8266_HOSTNAME // cleanup +#endif + +#ifndef MY_WIFI_BSSID +#define MY_WIFI_BSSID NULL +#endif + #if defined(MY_CONTROLLER_IP_ADDRESS) IPAddress _ethernetControllerIP(MY_CONTROLLER_IP_ADDRESS); #endif @@ -116,45 +145,27 @@ void _w5100_spi_en(bool enable) bool gatewayTransportInit(void) { _w5100_spi_en(true); + +#if defined(MY_GATEWAY_ESP8266) || defined(MY_GATEWAY_ESP32) +#if defined(MY_WIFI_SSID) + // Turn off access point + WiFi.mode(WIFI_STA); +#if defined(MY_HOSTNAME) #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 /* End of MY_ESP8266_HOSTNAME */ -#if defined(MY_IP_ADDRESS) - WiFi.config(_ethernetGatewayIP, _gatewayIp, _subnetIp); -#endif /* End of MY_IP_ADDRESS */ -#ifndef MY_ESP8266_BSSID -#define MY_ESP8266_BSSID NULL -#endif - (void)WiFi.begin(MY_ESP8266_SSID, MY_ESP8266_PASSWORD, 0, MY_ESP8266_BSSID); - while (WiFi.status() != WL_CONNECTED) { - wait(500); - GATEWAY_DEBUG(PSTR("GWT:TIN:CONNECTING...\n")); - } - GATEWAY_DEBUG(PSTR("GWT:TIN:IP=%s\n"), WiFi.localIP().toString().c_str()); -#endif /* End of MY_ESP8266_SSID */ + WiFi.hostname(MY_HOSTNAME) #elif defined(MY_GATEWAY_ESP32) -#if defined(MY_ESP32_SSID) - // Turn off access point - WiFi.mode(WIFI_STA); -#if defined(MY_ESP32_HOSTNAME) - WiFi.setHostname(MY_ESP32_HOSTNAME); + WiFi.setHostname(MY_HOSTNAME) +#endif #endif #ifdef MY_IP_ADDRESS WiFi.config(_ethernetGatewayIP, _gatewayIp, _subnetIp); #endif -#ifndef MY_ESP32_BSSID -#define MY_ESP32_BSSID NULL -#endif - (void)WiFi.begin(MY_ESP32_SSID, MY_ESP32_PASSWORD, 0, MY_ESP32_BSSID); - while (WiFi.waitForConnectResult() != WL_CONNECTED) { + (void)WiFi.begin(MY_WIFI_SSID, MY_WIFI_PASSWORD, 0, MY_WIFI_BSSID); + while (WiFi.status() != WL_CONNECTED) { wait(500); - GATEWAY_DEBUG(PSTR(".")); + GATEWAY_DEBUG(PSTR("GWT:TIN:CONNECTING...\n")); } - GATEWAY_DEBUG(PSTR("IP: %s\n"), WiFi.localIP().toString().c_str()); + GATEWAY_DEBUG(PSTR("GWT:TIN:IP: %s\n"), WiFi.localIP().toString().c_str()); #endif #elif defined(MY_GATEWAY_LINUX) // Nothing to do here diff --git a/core/MyGatewayTransportMQTTClient.cpp b/core/MyGatewayTransportMQTTClient.cpp index e3bf94f..1c96dab 100644 --- a/core/MyGatewayTransportMQTTClient.cpp +++ b/core/MyGatewayTransportMQTTClient.cpp @@ -22,6 +22,35 @@ #include "MyGatewayTransport.h" +// housekeeping, remove for 3.0.0 +#ifdef MY_ESP8266_SSID +#warning MY_ESP8266_SSID is deprecated, use MY_WIFI_SSID instead! +#define MY_WIFI_SSID MY_ESP8266_SSID +#undef MY_ESP8266_SSID // cleanup +#endif + +#ifdef MY_ESP8266_PASSWORD +#warning MY_ESP8266_PASSWORD is deprecated, use MY_WIFI_PASSWORD instead! +#define MY_WIFI_PASSWORD MY_ESP8266_PASSWORD +#undef MY_ESP8266_PASSWORD // cleanup +#endif + +#ifdef MY_ESP8266_BSSID +#warning MY_ESP8266_BSSID is deprecated, use MY_WIFI_BSSID instead! +#define MY_WIFI_BSSID MY_ESP8266_BSSID +#undef MY_ESP8266_BSSID // cleanup +#endif + +#ifdef MY_ESP8266_HOSTNAME +#warning MY_ESP8266_HOSTNAME is deprecated, use MY_HOSTNAME instead! +#define MY_HOSTNAME MY_ESP8266_HOSTNAME +#undef MY_ESP8266_HOSTNAME // cleanup +#endif + +#ifndef MY_WIFI_BSSID +#define MY_WIFI_BSSID NULL +#endif + #if defined MY_CONTROLLER_IP_ADDRESS IPAddress _brokerIp(MY_CONTROLLER_IP_ADDRESS); #endif @@ -127,13 +156,13 @@ bool gatewayTransportConnect(void) GATEWAY_DEBUG(PSTR("GWT:TPC:CONNECTING...\n")); } GATEWAY_DEBUG(PSTR("GWT:TPC:IP=%s\n"),WiFi.localIP().toString().c_str()); -#elif defined(MY_GATEWAY_LINUX) /* Elif part of MY_GATEWAY_ESP8266 */ +#elif defined(MY_GATEWAY_LINUX) #if defined(MY_IP_ADDRESS) _MQTT_ethClient.bind(_MQTT_clientIp); #endif /* End of MY_IP_ADDRESS */ -#elif defined(MY_GATEWAY_TINYGSM) /* Elif part of MY_GATEWAY_ESP8266 */ +#elif defined(MY_GATEWAY_TINYGSM) GATEWAY_DEBUG(PSTR("GWT:TPC:IP=%s\n"), modem.getLocalIP().c_str()); -#else /* Else part of MY_GATEWAY_ESP8266 */ +#else #if defined(MY_IP_ADDRESS) Ethernet.begin(_MQTT_clientMAC, _MQTT_clientIp); #else /* Else part of MY_IP_ADDRESS */ @@ -149,7 +178,7 @@ bool gatewayTransportConnect(void) Ethernet.localIP()[1], Ethernet.localIP()[2], Ethernet.localIP()[3]); // give the Ethernet interface a second to initialize delay(1000); -#endif /* End of MY_GATEWAY_ESP8266 */ +#endif return true; } @@ -207,29 +236,29 @@ bool gatewayTransportInit(void) #if defined(MY_GATEWAY_ESP8266) // Turn off access point WiFi.mode(WIFI_STA); -#if defined(MY_ESP8266_HOSTNAME) - WiFi.hostname(MY_ESP8266_HOSTNAME); +#if defined(MY_HOSTNAME) + WiFi.hostname(MY_HOSTNAME); #endif /* End of MY_ESP8266_HOSTNAME */ #if defined(MY_IP_ADDRESS) WiFi.config(_MQTT_clientIp, _gatewayIp, _subnetIp); #endif /* End of MY_IP_ADDRESS */ -#ifndef MY_ESP8266_BSSID -#define MY_ESP8266_BSSID NULL +#ifndef MY_WIFI_BSSID +#define MY_WIFI_BSSID NULL #endif - (void)WiFi.begin(MY_ESP8266_SSID, MY_ESP8266_PASSWORD, 0, MY_ESP8266_BSSID); + (void)WiFi.begin(MY_WIFI_SSID, MY_WIFI_PASSWORD, 0, MY_WIFI_BSSID); #elif defined(MY_GATEWAY_ESP32) // Turn off access point WiFi.mode(WIFI_STA); -#if defined(MY_ESP32_HOSTNAME) - WiFi.setHostname(MY_ESP32_HOSTNAME); -#endif /* End of MY_ESP32_HOSTNAME */ +#if defined(MY_HOSTNAME) + WiFi.setHostname(MY_HOSTNAME); +#endif /* End of MY_HOSTNAME */ #if defined(MY_IP_ADDRESS) WiFi.config(_MQTT_clientIp, _gatewayIp, _subnetIp); #endif /* End of MY_IP_ADDRESS */ -#ifndef MY_ESP32_BSSID -#define MY_ESP32_BSSID NULL +#ifndef MY_WIFI_BSSID +#define MY_WIFI_BSSID NULL #endif - (void)WiFi.begin(MY_ESP32_SSID, MY_ESP32_PASSWORD, 0, MY_ESP32_BSSID); + (void)WiFi.begin(MY_WIFI_SSID, MY_WIFI_PASSWORD, 0, MY_WIFI_BSSID); #endif gatewayTransportConnect(); diff --git a/examples/GatewayESP32/GatewayESP32.ino b/examples/GatewayESP32/GatewayESP32.ino index 6bd440f..c2d1f99 100644 --- a/examples/GatewayESP32/GatewayESP32.ino +++ b/examples/GatewayESP32/GatewayESP32.ino @@ -32,18 +32,18 @@ #define MY_DEBUG // Enables and select radio type (if attached) -#define MY_RADIO_NRF24 +#define MY_RADIO_RF24 //#define MY_RADIO_RFM69 //#define MY_RADIO_RFM95 #define MY_GATEWAY_ESP32 -#define MY_ESP32_SSID "MySSID" -#define MY_ESP32_PASSWORD "MyVerySecretPassword" +#define MY_WIFI_SSID "MySSID" +#define MY_WIFI_PASSWORD "MyVerySecretPassword" // Set the hostname for the WiFi Client. This is the hostname // it will pass to the DHCP server if not static. -#define MY_ESP32_HOSTNAME "ESP32_GW" +#define MY_HOSTNAME "ESP32_GW" // Enable MY_IP_ADDRESS here if you want a static ip address (no DHCP) //#define MY_IP_ADDRESS 192,168,1,100 diff --git a/examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino b/examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino index 9d58793..9783ddd 100644 --- a/examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino +++ b/examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino @@ -32,7 +32,7 @@ #define MY_DEBUG // Enables and select radio type (if attached) -#define MY_RADIO_NRF24 +#define MY_RADIO_RF24 //#define MY_RADIO_RFM69 //#define MY_RADIO_RFM95 @@ -51,12 +51,12 @@ //#define MY_MQTT_PASSWORD "password" // Set WIFI SSID and password -#define MY_ESP32_SSID "MySSID" -#define MY_ESP32_PASSWORD "MyVerySecretPassword" +#define MY_WIFI_SSID "MySSID" +#define MY_WIFI_PASSWORD "MyVerySecretPassword" // Set the hostname for the WiFi Client. This is the hostname // it will pass to the DHCP server if not static. -#define MY_ESP32_HOSTNAME "ESP32_MQTT_GW" +#define MY_HOSTNAME "ESP32_MQTT_GW" // Enable MY_IP_ADDRESS here if you want a static ip address (no DHCP) //#define MY_IP_ADDRESS 192,168,178,87 diff --git a/examples/GatewayESP8266/GatewayESP8266.ino b/examples/GatewayESP8266/GatewayESP8266.ino index 6532b53..32bbf33 100644 --- a/examples/GatewayESP8266/GatewayESP8266.ino +++ b/examples/GatewayESP8266/GatewayESP8266.ino @@ -64,15 +64,15 @@ #define MY_GATEWAY_ESP8266 -#define MY_ESP8266_SSID "MySSID" -#define MY_ESP8266_PASSWORD "MyVerySecretPassword" +#define MY_WIFI_SSID "MySSID" +#define MY_WIFI_PASSWORD "MyVerySecretPassword" // Enable UDP communication //#define MY_USE_UDP // If using UDP you need to set MY_CONTROLLER_IP_ADDRESS below // Set the hostname for the WiFi Client. This is the hostname // it will pass to the DHCP server if not static. -//#define MY_ESP8266_HOSTNAME "sensor-gateway" +//#define MY_HOSTNAME "sensor-gateway" // Enable MY_IP_ADDRESS here if you want a static ip address (no DHCP) //#define MY_IP_ADDRESS 192,168,178,87 diff --git a/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino b/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino index b1d10ab..f517cb5 100644 --- a/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino +++ b/examples/GatewayESP8266MQTTClient/GatewayESP8266MQTTClient.ino @@ -70,12 +70,12 @@ //#define MY_MQTT_PASSWORD "password" // Set WIFI SSID and password -#define MY_ESP8266_SSID "MySSID" -#define MY_ESP8266_PASSWORD "MyVerySecretPassword" +#define MY_WIFI_SSID "MySSID" +#define MY_WIFI_PASSWORD "MyVerySecretPassword" // Set the hostname for the WiFi Client. This is the hostname // it will pass to the DHCP server if not static. -// #define MY_ESP8266_HOSTNAME "mqtt-sensor-gateway" +// #define MY_HOSTNAME "mqtt-sensor-gateway" // Enable MY_IP_ADDRESS here if you want a static ip address (no DHCP) //#define MY_IP_ADDRESS 192,168,178,87 diff --git a/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino b/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino index 6a0bb79..f83fe52 100644 --- a/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino +++ b/examples/GatewayESP8266OTA/GatewayESP8266OTA.ino @@ -65,12 +65,12 @@ #define MY_GATEWAY_ESP8266 -#define MY_ESP8266_SSID "MySSID" -#define MY_ESP8266_PASSWORD "MyVerySecretPassword" +#define MY_WIFI_SSID "MySSID" +#define MY_WIFI_PASSWORD "MyVerySecretPassword" // Set the hostname for the WiFi Client. This is the hostname // it will pass to the DHCP server if not static. -// #define MY_ESP8266_HOSTNAME "sensor-ota-gateway" +// #define MY_HOSTNAME "sensor-ota-gateway" // Enable UDP communication //#define MY_USE_UDP // If using UDP you need to set MY_CONTROLLER_IP_ADDRESS below diff --git a/keywords.txt b/keywords.txt index 494e979..b22e5fd 100644 --- a/keywords.txt +++ b/keywords.txt @@ -240,6 +240,7 @@ MY_GATEWAY_ESP8266 LITERAL1 MY_GATEWAY_MQTT_CLIENT LITERAL1 MY_GATEWAY_SERIAL LITERAL1 MY_GATEWAY_W5100 LITERAL1 +MY_HOSTNAME LITERAL1 MY_INCLUSION_BUTTON_EXTERNAL_PULLUP LITERAL1 MY_MQTT_CLIENT_ID LITERAL1 MY_MQTT_CLIENT_PUBLISH_RETAIN LITERAL1 @@ -248,6 +249,9 @@ MY_MQTT_PUBLISH_TOPIC_PREFIX LITERAL1 MY_MQTT_SUBSCRIBE_TOPIC_PREFIX LITERAL1 MY_MQTT_USER LITERAL1 MY_W5100_SPI_EN LITERAL1 +MY_WIFI_SSID LITERAL1 +MY_WIFI_BSSID LITERAL1 +MY_WIFI_PASSWORD LITERAL1 # Ethernet MY_CONTROLLER_IP_ADDRESS LITERAL1 @@ -265,17 +269,9 @@ MY_PORT LITERAL1 MY_USE_UDP LITERAL1 # ESP32 -MY_ESP32_SSID LITERAL1 -MY_ESP32_PASSWORD LITERAL1 -MY_ESP32_BSSID LITERAL1 -MY_ESP32_HOSTNAME LITERAL1 # ESP8266 -MY_ESP8266_BSSID LITERAL1 -MY_ESP8266_HOSTNAME LITERAL1 -MY_ESP8266_PASSWORD LITERAL1 MY_ESP8266_SERIAL_MODE LITERAL1 -MY_ESP8266_SSID LITERAL1 # Blacklist - autodefines that are used internally and should not be highlighted, hence commented. # MY_CAP_ARCH @@ -347,6 +343,10 @@ MY_ESP8266_SSID LITERAL1 # MY_RF69_RESET # MY_RF69_SPI_CS # MY_TRANSPORT_DONT_CARE_MODE +# MY_ESP8266_BSSID LITERAL1 +# MY_ESP8266_HOSTNAME LITERAL1 +# MY_ESP8266_PASSWORD LITERAL1 +# MY_ESP8266_SSID LITERAL1 # Blacklist - descriptional only # MY_XYZ_POWER_PIN From 6c9be97fa32f19f7c88767619003fa9727961a66 Mon Sep 17 00:00:00 2001 From: flopp999 <21694965+flopp999@users.noreply.github.com> Date: Tue, 1 May 2018 16:57:37 +0200 Subject: [PATCH 43/60] Word corrections (#1114) * Word corrections * Removed an enter Thanks @flopp999 ! --- .../EnergyMeterPulseSensor.ino | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino b/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino index 512d75d..9486260 100644 --- a/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino +++ b/examples/EnergyMeterPulseSensor/EnergyMeterPulseSensor.ino @@ -19,18 +19,18 @@ ******************************* * * REVISION HISTORY - * Version 1.0 - Henrik EKblad + * Version 1.0 - Henrik Ekblad * * DESCRIPTION - * 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. + * This sketch provides an example how to implement a LM393 PCB + * Use this sensor to measure kWh and Watt of your house meter + * You need to set the correct pulsefactor of your meter (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 - * to calculate/report watt-number. + * to calculate/report watt value. * http://www.mysensors.org/build/pulse_power */ @@ -46,8 +46,8 @@ #include #define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your light sensor. (Only 2 and 3 generates interrupt!) -#define PULSE_FACTOR 1000 // Number of blinks per KWH of your meeter -#define SLEEP_MODE false // Watt-value can only be reported when sleep mode is false. +#define PULSE_FACTOR 1000 // Number of blinks per of your meter +#define SLEEP_MODE false // Watt value can only be reported when sleep mode is false. #define MAX_WATT 10000 // Max watt value to report. This filters outliers. #define CHILD_ID 1 // Id of the sensor child @@ -60,10 +60,10 @@ volatile uint32_t lastBlink = 0; volatile uint32_t watt = 0; uint32_t oldPulseCount = 0; uint32_t oldWatt = 0; -double oldKwh; +double oldkWh; uint32_t lastSend; MyMessage wattMsg(CHILD_ID,V_WATT); -MyMessage kwhMsg(CHILD_ID,V_KWH); +MyMessage kWhMsg(CHILD_ID,V_KWH); MyMessage pcMsg(CHILD_ID,V_VAR1); @@ -107,19 +107,19 @@ void loop() oldWatt = watt; } - // Pulse cout has changed + // Pulse count value has changed if (pulseCount != oldPulseCount) { send(pcMsg.set(pulseCount)); // Send pulse count value to gw - double kwh = ((double)pulseCount/((double)PULSE_FACTOR)); + double kWh = ((double)pulseCount/((double)PULSE_FACTOR)); oldPulseCount = pulseCount; - if (kwh != oldKwh) { - send(kwhMsg.set(kwh, 4)); // Send kwh value to gw - oldKwh = kwh; + 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 + // No pulse count value received. Try requesting it again request(CHILD_ID, V_VAR1); lastSend=now; } @@ -133,7 +133,7 @@ void receive(const MyMessage &message) { if (message.type==V_VAR1) { pulseCount = oldPulseCount = message.getLong(); - Serial.print("Received last pulse count from gw:"); + Serial.print("Received last pulse count value from gw:"); Serial.println(pulseCount); pcReceived = true; } From 1c5853ce79fb62bbcf9d497342f7acb153abd1f0 Mon Sep 17 00:00:00 2001 From: Tombula <38461340+Tombula@users.noreply.github.com> Date: Tue, 1 May 2018 16:59:04 +0200 Subject: [PATCH 44/60] Add sleep forever by sleep(0); (#1113) For battery powered sensors which wake up by the RST Pin its useful to sleep the cpu forever. When using this command: sleep(INTERRUPT_NOT_DEFINED, MODE_NOT_DEFINED, 0, false); the code will be stripped down to hwSleep(0);. But this will not sleep the cpu forever. --- hal/architecture/AVR/MyHwAVR.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/hal/architecture/AVR/MyHwAVR.cpp b/hal/architecture/AVR/MyHwAVR.cpp index 2083fc3..de3ff86 100644 --- a/hal/architecture/AVR/MyHwAVR.cpp +++ b/hal/architecture/AVR/MyHwAVR.cpp @@ -141,8 +141,23 @@ void hwInternalSleep(uint32_t ms) int8_t hwSleep(uint32_t ms) { - hwInternalSleep(ms); - return MY_WAKE_UP_BY_TIMER; + // Return what woke the mcu. + // Default: no interrupt triggered, timer wake up + int8_t ret = MY_WAKE_UP_BY_TIMER; + if (ms > 0u) { + // sleep for defined time + hwInternalSleep(ms); + } else { + // sleep until ext interrupt triggered + hwPowerDown(WDTO_SLEEP_FOREVER); + } + 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; } int8_t hwSleep(const uint8_t interrupt, const uint8_t mode, uint32_t ms) From 3c07390323fb104ec5eb632070c2dda096e90f11 Mon Sep 17 00:00:00 2001 From: tekka Date: Tue, 1 May 2018 22:31:16 +0200 Subject: [PATCH 45/60] Fix RFMxx deadlock and minor optimization (#1099) --- drivers/RFM69/new/RFM69_new.cpp | 8 +++----- drivers/RFM95/RFM95.cpp | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/RFM69/new/RFM69_new.cpp b/drivers/RFM69/new/RFM69_new.cpp index 5a952cb..c1a065a 100644 --- a/drivers/RFM69/new/RFM69_new.cpp +++ b/drivers/RFM69/new/RFM69_new.cpp @@ -224,8 +224,6 @@ LOCAL bool RFM69_initialise(const uint32_t frequencyHz) RFM69_DEBUG(PSTR("!RFM69:INIT:SANCHK FAIL\n")); return false; } - // clear FIFO and flags - RFM69_clearFIFO(); // IRQ RFM69_irq = false; hwPinMode(MY_RFM69_IRQ_PIN, INPUT); @@ -235,7 +233,7 @@ LOCAL bool RFM69_initialise(const uint32_t frequencyHz) LOCAL void RFM69_clearFIFO(void) { - (void)RFM69_writeReg(RFM69_REG_IRQFLAGS2, 0x10u); + (void)RFM69_writeReg(RFM69_REG_IRQFLAGS2, RFM69_IRQFLAGS2_FIFOOVERRUN); } // IRQ handler: PayloadReady (RX) & PacketSent (TX) mapped to DI0 LOCAL void RFM69_interruptHandler(void) @@ -621,7 +619,7 @@ LOCAL bool RFM69_sendWithRetry(const uint8_t recipient, const void *buffer, } // radio is in RX const uint32_t enterMS = hwMillis(); - while (hwMillis() - enterMS < retryWaitTimeMS) { + while (hwMillis() - enterMS < retryWaitTimeMS && !RFM69.dataReceived) { RFM69_handler(); if (RFM69.ackReceived) { // radio is in stdby @@ -719,7 +717,7 @@ LOCAL void RFM69_setConfiguration(void) { RFM69_REG_AFCBW, rfm69_modem_config[5] }, // same as rxbw, experimental, based on datasheet //{ RFM69_REG_DIOMAPPING1, RFM69_DIOMAPPING1_DIO0_01 }, { RFM69_REG_DIOMAPPING2, RFM69_DIOMAPPING2_CLKOUT_OFF }, - { RFM69_REG_IRQFLAGS2, RFM69_IRQFLAGS2_FIFOOVERRUN }, + { RFM69_REG_IRQFLAGS2, RFM69_IRQFLAGS2_FIFOOVERRUN }, // clear FIFO and flags { RFM69_REG_RSSITHRESH, RFM69_RSSITHRESH_VALUE }, { RFM69_REG_PREAMBLEMSB, RFM69_PREAMBLESIZE_MSB_VALUE }, { RFM69_REG_PREAMBLELSB, RFM69_PREAMBLESIZE_LSB_VALUE }, diff --git a/drivers/RFM95/RFM95.cpp b/drivers/RFM95/RFM95.cpp index 8fcb589..a8e7dee 100644 --- a/drivers/RFM95/RFM95.cpp +++ b/drivers/RFM95/RFM95.cpp @@ -550,7 +550,7 @@ LOCAL bool RFM95_sendWithRetry(const uint8_t recipient, const void *buffer, return true; } const uint32_t enterMS = hwMillis(); - while (hwMillis() - enterMS < retryWaitTime) { + while (hwMillis() - enterMS < retryWaitTime && !RFM95.dataReceived) { RFM95_handler(); if (RFM95.ackReceived) { const uint8_t sender = RFM95.currentPacket.header.sender; From 153850de808023ece9a09b21e847ea546c45239f Mon Sep 17 00:00:00 2001 From: tekka Date: Tue, 1 May 2018 22:33:26 +0200 Subject: [PATCH 46/60] Add transport sanity check before entering loop() (#1116) --- core/MySensorsCore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/MySensorsCore.cpp b/core/MySensorsCore.cpp index 6b92b99..eb1f1ab 100644 --- a/core/MySensorsCore.cpp +++ b/core/MySensorsCore.cpp @@ -177,7 +177,7 @@ void _begin(void) setup(); } #if defined(MY_SENSOR_NETWORK) - CORE_DEBUG(PSTR("MCO:BGN:INIT OK,TSP=%" PRIu8 "\n"), isTransportReady()); + CORE_DEBUG(PSTR("MCO:BGN:INIT OK,TSP=%" PRIu8 "\n"), isTransportReady() && transportSanityCheck()); #else // no sensor network defined, call presentation & registration _callbackTransportReady(); From d9e05eb39c387ce3c94af063416e23722bb547c7 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Fri, 4 May 2018 09:38:24 +0200 Subject: [PATCH 47/60] Kill Gitler and make way for The Butler (#1124) The Butler is a more polite and helpful replacement to the grumpy old Gitler. The Butler will do his utmost to assist new (and old) contributors to the MySensors cause. --- .ci/arduino.groovy | 20 ++++---- .ci/{gitler.groovy => butler.groovy} | 36 ++++++++------ .ci/{gitler.sh => butler.sh} | 73 ++++++++++++++-------------- .ci/linux.groovy | 6 +-- .ci/pipeline.groovy | 41 +++++++++++----- 5 files changed, 98 insertions(+), 78 deletions(-) rename .ci/{gitler.groovy => butler.groovy} (80%) rename .ci/{gitler.sh => butler.sh} (55%) diff --git a/.ci/arduino.groovy b/.ci/arduino.groovy index da74a5d..47a69f3 100644 --- a/.ci/arduino.groovy +++ b/.ci/arduino.groovy @@ -65,7 +65,7 @@ def buildMySensorsMicro(config, sketches, String key) { if (currentBuild.currentResult == 'UNSTABLE') { config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (MySensorsMicro - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new') if (config.is_pull_request) { - error 'Termiated due to warnings found' + error 'Terminated due to warnings found' } } else if (currentBuild.currentResult == 'FAILURE') { config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (MySensorsMicro - '+key+')', 'Build error', '${BUILD_URL}') @@ -101,7 +101,7 @@ def buildMySensorsGw(config, sketches, String key) { if (currentBuild.currentResult == 'UNSTABLE') { config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (MySensorsGW - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new') if (config.is_pull_request) { - error 'Termiated due to warnings found' + error 'Terminated due to warnings found' } } else if (currentBuild.currentResult == 'FAILURE') { config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (MySensorsGW - '+key+')', 'Build error', '${BUILD_URL}') @@ -134,7 +134,7 @@ def buildArduinoUno(config, sketches, String key) { if (currentBuild.currentResult == 'UNSTABLE') { config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (Arduino Uno - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new') if (config.is_pull_request) { - error 'Termiated due to warnings found' + error 'Terminated due to warnings found' } } else if (currentBuild.currentResult == 'FAILURE') { config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Arduino Uno - '+key+')', 'Build error', '${BUILD_URL}') @@ -167,7 +167,7 @@ def buildArduinoMega(config, sketches, String key) { if (currentBuild.currentResult == 'UNSTABLE') { config.pr.setBuildStatus(config, config, 'ERROR', 'Toll gate (Arduino Mega - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new') if (config.is_pull_request) { - error 'Termiated due to warnings found' + error 'Terminated due to warnings found' } } else if (currentBuild.currentResult == 'FAILURE') { config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Arduino Mega - '+key+')', 'Build error', '${BUILD_URL}') @@ -200,7 +200,7 @@ def buildSTM32F1(config, sketches, String key) { if (currentBuild.currentResult == 'UNSTABLE') { config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (STM32F1 - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new') if (config.is_pull_request) { - error 'Termiated due to warnings found' + error 'Terminated due to warnings found' } } else if (currentBuild.currentResult == 'FAILURE') { config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (STM32F1 - '+key+')', 'Build error', '${BUILD_URL}') @@ -239,7 +239,7 @@ def buildEsp8266(config, sketches, String key) { if (currentBuild.currentResult == 'UNSTABLE') { config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (ESP8266 - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new') if (config.is_pull_request) { - error 'Termiated due to warnings found' + error 'Terminated due to warnings found' } } else if (currentBuild.currentResult == 'FAILURE') { config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (ESP8266 - '+key+')', 'Build error', '${BUILD_URL}') @@ -287,7 +287,7 @@ def buildEsp32(config, sketches, String key) { if (currentBuild.currentResult == 'UNSTABLE') { config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (ESP32 - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new') if (config.is_pull_request) { - error 'Termiated due to warnings found' + error 'Terminated due to warnings found' } } else if (currentBuild.currentResult == 'FAILURE') { config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (ESP32 - '+key+')', 'Build error', '${BUILD_URL}') @@ -328,7 +328,7 @@ def buildnRF5(config, sketches, String key) { if (currentBuild.currentResult == 'UNSTABLE') { config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (nRF5 - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new') if (config.is_pull_request) { - error 'Termiated due to warnings found' + error 'Terminated due to warnings found' } } else if (currentBuild.currentResult == 'FAILURE') { config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (nRF5 - '+key+')', 'Build error', '${BUILD_URL}') @@ -352,7 +352,7 @@ def buildnRF52832(config, sketches, String key) { if (currentBuild.currentResult == 'UNSTABLE') { config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (nRF52832 - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new') if (config.is_pull_request) { - error 'Termiated due to warnings found' + error 'Terminated due to warnings found' } } else if (currentBuild.currentResult == 'FAILURE') { config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (nRF52832 - '+key+')', 'Build error', '${BUILD_URL}') @@ -376,7 +376,7 @@ def buildnRF51822(config, sketches, String key) { if (currentBuild.currentResult == 'UNSTABLE') { config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (nRF51822 - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new') if (config.is_pull_request) { - error 'Termiated due to warnings found' + error 'Terminated due to warnings found' } } else if (currentBuild.currentResult == 'FAILURE') { config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (nRF51822 - '+key+')', 'Build error', '${BUILD_URL}') diff --git a/.ci/gitler.groovy b/.ci/butler.groovy similarity index 80% rename from .ci/gitler.groovy rename to .ci/butler.groovy index 00e4e79..3bfa97c 100644 --- a/.ci/gitler.groovy +++ b/.ci/butler.groovy @@ -1,6 +1,6 @@ #!groovy def call(config) { - config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Gitler)', 'Checking...', '${BUILD_URL}flowGraphTable/') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Butler)', 'Checking...', '${BUILD_URL}flowGraphTable/') if (env.CHANGE_TARGET == 'master' && (env.CHANGE_AUTHOR != 'bblacey' && env.CHANGE_AUTHOR != 'd00616' && env.CHANGE_AUTHOR != 'fallberg' && env.CHANGE_AUTHOR != 'henrikekblad' && @@ -9,7 +9,7 @@ def call(config) { env.CHANGE_AUTHOR != 'tekka007' && env.CHANGE_AUTHOR != 'user2684' && env.CHANGE_AUTHOR != 'Yveaux')) { - config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Gitler)', 'This pull request targets master. That is not permitted for '+env.CHANGE_AUTHOR, '') + config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Butler)', 'Sir, This pull request targets master. I am afraid that is not permitted for '+env.CHANGE_AUTHOR, '') error "This pull request targets master. That is not permitted!" } else if (env.CHANGE_TARGET == 'master') @@ -48,7 +48,7 @@ def call(config) { ]) } - config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Gitler)', 'Pass', '') + config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Butler)', 'Pass - Well done Master!', '') config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Release changelog)', '', '${BUILD_URL}execution/node/3/ws/MySensors/ReleaseNotes.md/*view*/') return } @@ -115,31 +115,35 @@ def call(config) { ret = sh(returnStatus: true, script:"""#!/bin/bash cd ${config.repository_root}/.ci - ./gitler.sh""") + ./butler.sh""") if (fileExists(config.repository_root+'restyling.patch')) { emailext ( - subject: "Job '${env.JOB_NAME} #${env.BUILD_NUMBER} [PR#${env.CHANGE_ID}]' failed due to bad code styling", - body: """

Job '${env.JOB_NAME} [PR#${env.CHANGE_ID} - ${env.CHANGE_TITLE}]' failed because code style does not follow the standards.

- A patch to rectify the errors is attached. You apply the patch using:
+ subject: "PR#${env.CHANGE_ID} - ${env.CHANGE_TITLE} has unfortunate code styling", + body: """

Greetings Sir!

+ I am afraid your pull request does not follow the MySensors standards with respect to coding style.

+ That is ok, you are perhaps a first time committer to this repository. Please read the code contribution guidelines for help on how to format your code.

+ To assist you, I have prepared a patch for you that will reformat the code according to the coding style required.
+ The patch is attached. You may apply the patch using:
git apply restyling.patch

- If you disagree to this, please discuss it here.

- Yours sincerely, Gitler, on behalf of Jenkins""", - mimeType: 'text/html', to: '${env.CHANGE_AUTHOR_EMAIL}', + If you disagree with me, please discuss it here.

+ --
+ Yours sincerely, The Butler, serving the MySensors community""", + mimeType: 'text/html', to: env.CHANGE_AUTHOR_EMAIL, attachLog: false, compressLog: false, attachmentsPattern: config.repository_root+'restyling.patch' ) } publishHTML([allowMissing: true, alwaysLinkToLastBuild: false, keepAll: true, reportDir: config.repository_root, - reportFiles: 'gitler.html', reportName: 'Gitler report', reportTitles: '']) + reportFiles: 'butler.html', reportName: 'The Butler report', reportTitles: '']) if (ret == 1) { - config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Gitler)', 'Commit(s) does not meet coding standards', '${BUILD_URL}Gitler_report/gitler.html') + config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Butler)', 'I am afraid the commit(s) needs some touchup, please check the details...', '${BUILD_URL}The_20Butler_20report/butler.html') currentBuild.currentResult == 'FAILURE' - echo "Termiated due to Gitler assert" // For BFA - echo "You can read the detailed error report here: "+env.BUILD_URL+"Gitler_report/" - error 'Termiated due to Gitler assert' + echo "Terminated due to Butler assert" // For BFA + echo "You can read the detailed error report here: "+env.BUILD_URL+"The_20Butler_20report/" + error 'Terminated due to Butler assert' } else { - config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Gitler)', 'Pass', '') + config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Butler)', 'Pass - Well done Sir!', '${BUILD_URL}The_20Butler_20report/butler.html') } } diff --git a/.ci/gitler.sh b/.ci/butler.sh similarity index 55% rename from .ci/gitler.sh rename to .ci/butler.sh index 9c5a78d..d4deeaf 100755 --- a/.ci/gitler.sh +++ b/.ci/butler.sh @@ -9,6 +9,7 @@ echo "No subjects with leading lower case characters
" > leading_lowercases.t echo "No subjects with trailing periods
" > trailing_periods.txt echo "No body lines are too wide
" > too_long_body_lines.txt echo "No keywords are missing in keywords.txt
" > missing_keywords.txt +echo "No occurences of the deprecated boolean data type
" >> booleans.txt too_long_subjects=`awk 'length > 72' subjects.txt` if [ -n "$too_long_subjects" ]; then @@ -48,56 +49,54 @@ if [ -n "$missing_keywords" ]; then result=1 fi +# Evaluate if there exists booleans in the code tree (not counting this file) +if git grep -q boolean -- `git ls-files | grep -v butler.sh`; then + echo "You have added at least one occurence of the deprecated boolean data type. Please use bool instead.
" > booleans.txt + result=1 +fi -printf "%s" "" > gitler.html -awk 'FNR==1{print "
"}1' too_long_subjects.txt leading_lowercases.txt trailing_periods.txt too_long_body_lines.txt missing_keywords.txt >> gitler.html -echo "
" >> gitler.html +printf "%s" "" > butler.html +echo "Greetings Sir! Here is my evaluation of your pull request:
" >> butler.html +awk 'FNR==1{print "
"}1' too_long_subjects.txt leading_lowercases.txt trailing_periods.txt too_long_body_lines.txt missing_keywords.txt booleans.txt >> butler.html +echo "
" >> butler.html if [ $result -ne 0 ]; then - echo "You should follow this guide when writing your commit messages.
" >> gitler.html - echo "
" >> gitler.html - echo "To change the commit message for a single-commit pull request:
" >> gitler.html - echo "git checkout <your_branch>
" >> gitler.html - echo "git commit --amend
" >> gitler.html - echo "git push origin HEAD:<your_branch_on_github> -f
" >> gitler.html - echo "
" >> gitler.html - echo "To change the commit messages for a multiple-commit pull request:
" >> gitler.html - echo "git checkout <your_branch>
" >> gitler.html - echo "git rebase -i <sha_of_parent_to_the_earliest_commit_you_want_to_change>
" >> gitler.html - echo "Replace \"pick\" with \"r\" or \"reword\" on the commits you need to change message for
" >> gitler.html - echo "git push origin HEAD:<your_branch_on_github> -f
" >> gitler.html - echo "
" >> gitler.html + echo "I am afraid there are some issues with your commit messages and/or use of keywords.
" >> butler.html + echo "I highly recommend reading this guide for tips on how to write a good commit message.
" >> butler.html + echo "More specifically, MySensors have some code contribution guidelines that I am afraid all contributers need to follow.
" >> butler.html + echo "
" >> butler.html + echo "I can help guide you in how to change the commit message for a single-commit pull request:
" >> butler.html + echo "git checkout <your_branch>
" >> butler.html + echo "git commit --amend
" >> butler.html + echo "git push origin HEAD:<your_branch_on_github> -f
" >> butler.html + echo "
" >> butler.html + echo "To change the commit messages for a multiple-commit pull request:
" >> butler.html + echo "git checkout <your_branch>
" >> butler.html + echo "git rebase -i <sha_of_parent_to_the_earliest_commit_you_want_to_change>
" >> butler.html + echo "Replace \"pick\" with \"r\" or \"reword\" on the commits you need to change message for
" >> butler.html + echo "git push origin HEAD:<your_branch_on_github> -f
" >> butler.html + echo "
" >> butler.html fi # Evaluate coding style astyle --options=.mystools/astyle/config/style.cfg -nq --recursive "*.h" "*.c" "*.cpp" git diff > restyling.patch if [ -s restyling.patch ]; then - echo "This commit is not meeting the coding standards, a mail with a patch has been sent to you that if applied to your PR, will make it meet the coding standards.
" >> gitler.html - echo "You apply the patch using:
" >> gitler.html - echo "git apply restyling.patch
" >> gitler.html - echo "
" >> gitler.html + echo "I am afraid your coding style is not entirely in line with the MySensors preffered style.
A mail with a patch has been sent to you that, if applied to your PR, will make it follow the MySensors coding standards.

" >> butler.html + echo "You can apply the patch using:
" >> butler.html + echo "git apply restyling.patch
" >> butler.html + echo "
" >> butler.html result=1 else - echo "This commit is meeting the coding standards, congratulations!
" >> gitler.html - echo "
" >> gitler.html + echo "This commit is meeting the coding standards, well done Sir!
" >> butler.html + echo "
" >> butler.html rm restyling.patch fi -# Evaluate if there exists booleans in the code tree (not counting this file) -if git grep -q boolean -- `git ls-files | grep -v gitler.sh` -then - echo "This repository currently contain the boolean keyword. This should be avoided.
" >> gitler.html - echo "
" >> gitler.html - result=1 -else - echo "This repository does not contain any boolean keywords. This is good.
" >> gitler.html - echo "
" >> gitler.html -fi - if [ $result -ne 0 ]; then - echo "If you disagree to this, please discuss it in the GitHub pull request thread.
" >> gitler.html - echo "
" >> gitler.html + echo "If you have any questions, please first read the code contribution guidelines.
" >> butler.html + echo "If you disagree to this, please discuss it in the GitHub pull request thread.
" >> butler.html + echo "
" >> butler.html fi -echo "Yours sincerely, Gitler, on behalf of Jenkins
" >> gitler.html -printf "%s" "" >> gitler.html +echo "Yours sincerely, The Butler, serving the MySensors community
" >> butler.html +printf "%s" "" >> butler.html exit $result diff --git a/.ci/linux.groovy b/.ci/linux.groovy index 672a530..991fed1 100644 --- a/.ci/linux.groovy +++ b/.ci/linux.groovy @@ -34,7 +34,7 @@ def buildSerial(config) { buildLinux(config, '--my-debug=disable --my-transport=none --my-gateway=serial', 'Serial') if (currentBuild.currentResult == 'UNSTABLE') { config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (Linux builds - Serial GW)', 'Warnings found', '${BUILD_URL}warnings28Result/new') - error 'Termiated due to warnings found' + error 'Terminated due to warnings found' } else if (currentBuild.currentResult == 'FAILURE') { config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Linux builds - Serial GW)', 'Build error', '${BUILD_URL}') } else { @@ -47,7 +47,7 @@ def buildEthernet(config) { buildLinux(config, '--my-debug=enable --my-transport=rs485 --my-gateway=ethernet', 'Ethernet') if (currentBuild.currentResult == 'UNSTABLE') { config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (Linux builds - Ethernet GW)', 'Warnings found', '${BUILD_URL}warnings28Result/new') - error 'Termiated due to warnings found' + error 'Terminated due to warnings found' } else if (currentBuild.currentResult == 'FAILURE') { config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Linux builds - Ethernet GW)', 'Build error', '${BUILD_URL}') } else { @@ -60,7 +60,7 @@ def buildMQTT(config) { buildLinux(config, '--my-debug=disable --my-transport=none --my-gateway=mqtt', 'MQTT') if (currentBuild.currentResult == 'UNSTABLE') { config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (Linux builds - MQTT GW)', 'Warnings found', '${BUILD_URL}warnings28Result/new') - error 'Termiated due to warnings found' + error 'Terminated due to warnings found' } else if (currentBuild.currentResult == 'FAILURE') { config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Linux builds - MQTT GW)', 'Build error', '${BUILD_URL}') } else { diff --git a/.ci/pipeline.groovy b/.ci/pipeline.groovy index e59d78a..8eb4761 100644 --- a/.ci/pipeline.groovy +++ b/.ci/pipeline.groovy @@ -12,7 +12,7 @@ def call(Closure body) { if (env.CHANGE_ID) { config.is_pull_request = true - echo "Building pull request: #"+env.CHANGE_ID+"\nTarget branch: "+env.CHANGE_TARGET + echo "Building pull request: #"+env.CHANGE_ID+"\nTarget branch: "+env.CHANGE_TARGET+"\nAuthor: "+env.CHANGE_AUTHOR+" ("+env.CHANGE_AUTHOR_EMAIL+")" config.git_sha = sh(returnStdout: true, script: """#!/bin/bash cd ${config.repository_root} @@ -30,9 +30,9 @@ def call(Closure body) { try { ansiColor('xterm') { if (config.is_pull_request) { - def gitler = load(config.repository_root+'.ci/gitler.groovy') - stage('Gitler') { - gitler(config) + def butler = load(config.repository_root+'.ci/butler.groovy') + stage('Butler') { + butler(config) } } @@ -174,20 +174,37 @@ def call(Closure body) { config.pr.setBuildStatus(config, 'ERROR', 'Toll gate', 'Failed', '${BUILD_URL}flowGraphTable/') if (config.is_pull_request) { slackSend color: 'danger', - message: "Job '${env.JOB_NAME} <${env.BUILD_URL}|#${env.BUILD_NUMBER}> <${env.CHANGE_URL}|PR#${env.CHANGE_ID} - ${env.CHANGE_TITLE}>' failed with result ${currentBuild.result}." + message: "Failed to build <${env.CHANGE_URL}|PR#${env.CHANGE_ID} - ${env.CHANGE_TITLE}>. Job <${env.BUILD_URL}|${env.JOB_NAME} #${env.BUILD_NUMBER}> ended with ${currentBuild.result}." emailext ( - subject: "Job '${env.JOB_NAME} #${env.BUILD_NUMBER}' failed", - body: """Job '${env.JOB_NAME} #${env.BUILD_NUMBER} (PR#${env.CHANGE_ID} - ${env.CHANGE_TITLE})' ended with result ${currentBuild.result}. -
Check attached console output or here for a hint on what the problem might be.""", + subject: "PR#${env.CHANGE_ID} - ${env.CHANGE_TITLE} failed to build", + body: '''Greetings Sir!

+ I am The Butler. My task is to help you create a pull request that fit the MySensors organizations coding style and builds for all supported platforms.

+ I am afraid I failed to validate your pull request. Result was '''+currentBuild.result+'''. +
Please check the attached build log or here for a hint on what the problem might be.

+ If you have difficulties determining the cause for the failure, feel free to ask questions here.

+ Changes:
+ ${CHANGES}

+ Notable build log lines:
+ ${BUILD_LOG_REGEX, regex="^.*?Terminated.*?$", linesBefore=0, linesAfter=0, maxMatches=5, showTruncatedLines=false, escapeHtml=true}

+ My personal evaluation of your pull request is available here.

+ --
+ Yours sincerely, The Butler, serving the MySensors community''', mimeType: 'text/html', to: env.CHANGE_AUTHOR_EMAIL, attachLog: true, compressLog: false ) } else { slackSend color: 'danger', - message: "Job '${env.JOB_NAME} <${env.BUILD_URL}|#${env.BUILD_NUMBER}> ${env.BRANCH_NAME}]' failed with result ${currentBuild.result}." + message: "Failed to build branch ${env.BRANCH_NAME}. Job <${env.BUILD_URL}|${env.JOB_NAME} #${env.BUILD_NUMBER}> ended with ${currentBuild.result}." emailext ( - subject: "Job '${env.JOB_NAME} #${env.BUILD_NUMBER} ${env.BRANCH_NAME}' failed", - body: """Job '${env.JOB_NAME} #${env.BUILD_NUMBER} (${env.BRANCH_NAME})' ended with result ${currentBuild.result}. -
Check attached console output or here for a hint on what the problem might be.""", + subject: "MySensors branch ${env.BRANCH_NAME} failed to build", + body: '''Sir, I am afraid I failed to build branch ${BRANCH_NAME}. Result was '''+currentBuild.result+'''. +
Please check the attached build log or here for a hint on what the problem might be.

+ Changes:
+ ${CHANGES}

+ Notable build log lines:
+ ${BUILD_LOG_REGEX, regex="^.*?Terminated.*?$", linesBefore=0, linesAfter=0, maxMatches=5, showTruncatedLines=false, escapeHtml=true}

+ My personal evaluation of your pull request is available here.

+ --
+ Yours sincerely, The Butler, serving the MySensors community''', mimeType: 'text/html', to: 'builds@mysensors.org', attachLog: true, compressLog: false ) } From c08b80cb90b434ca142ca28983a5ebb69233375c Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Fri, 4 May 2018 18:35:00 +0200 Subject: [PATCH 48/60] Remove use of titles by CI Butler (#1125) --- .ci/butler.groovy | 10 +++++----- .ci/butler.sh | 4 ++-- .ci/pipeline.groovy | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.ci/butler.groovy b/.ci/butler.groovy index 3bfa97c..6ae3deb 100644 --- a/.ci/butler.groovy +++ b/.ci/butler.groovy @@ -9,7 +9,7 @@ def call(config) { env.CHANGE_AUTHOR != 'tekka007' && env.CHANGE_AUTHOR != 'user2684' && env.CHANGE_AUTHOR != 'Yveaux')) { - config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Butler)', 'Sir, This pull request targets master. I am afraid that is not permitted for '+env.CHANGE_AUTHOR, '') + config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (Butler)', 'This pull request targets master. I am afraid that is not permitted for '+env.CHANGE_AUTHOR, '') error "This pull request targets master. That is not permitted!" } else if (env.CHANGE_TARGET == 'master') @@ -48,7 +48,7 @@ def call(config) { ]) } - config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Butler)', 'Pass - Well done Master!', '') + config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Butler)', 'Pass - Well done!', '') config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Release changelog)', '', '${BUILD_URL}execution/node/3/ws/MySensors/ReleaseNotes.md/*view*/') return } @@ -85,7 +85,7 @@ def call(config) { createFileTemplateContent: ''' {{#commits}} {{#messageBodyItems}} -{{.}} +{{.}} {{/messageBodyItems}} {{/commits}} ''', @@ -120,7 +120,7 @@ def call(config) { if (fileExists(config.repository_root+'restyling.patch')) { emailext ( subject: "PR#${env.CHANGE_ID} - ${env.CHANGE_TITLE} has unfortunate code styling", - body: """

Greetings Sir!

+ body: """

Greetings!

I am afraid your pull request does not follow the MySensors standards with respect to coding style.

That is ok, you are perhaps a first time committer to this repository. Please read the code contribution guidelines for help on how to format your code.

To assist you, I have prepared a patch for you that will reformat the code according to the coding style required.
@@ -143,7 +143,7 @@ def call(config) { echo "You can read the detailed error report here: "+env.BUILD_URL+"The_20Butler_20report/" error 'Terminated due to Butler assert' } else { - config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Butler)', 'Pass - Well done Sir!', '${BUILD_URL}The_20Butler_20report/butler.html') + config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Butler)', 'Pass - Well done!', '${BUILD_URL}The_20Butler_20report/butler.html') } } diff --git a/.ci/butler.sh b/.ci/butler.sh index d4deeaf..3fdce17 100755 --- a/.ci/butler.sh +++ b/.ci/butler.sh @@ -56,7 +56,7 @@ if git grep -q boolean -- `git ls-files | grep -v butler.sh`; then fi printf "%s" "" > butler.html -echo "Greetings Sir! Here is my evaluation of your pull request:
" >> butler.html +echo "Greetings! Here is my evaluation of your pull request:
" >> butler.html awk 'FNR==1{print "
"}1' too_long_subjects.txt leading_lowercases.txt trailing_periods.txt too_long_body_lines.txt missing_keywords.txt booleans.txt >> butler.html echo "
" >> butler.html if [ $result -ne 0 ]; then @@ -87,7 +87,7 @@ if [ -s restyling.patch ]; then echo "
" >> butler.html result=1 else - echo "This commit is meeting the coding standards, well done Sir!
" >> butler.html + echo "This commit is meeting the coding standards, well done!
" >> butler.html echo "
" >> butler.html rm restyling.patch fi diff --git a/.ci/pipeline.groovy b/.ci/pipeline.groovy index 8eb4761..d50e44d 100644 --- a/.ci/pipeline.groovy +++ b/.ci/pipeline.groovy @@ -58,7 +58,7 @@ def call(Closure body) { config.tests = findFiles(glob: config.library_root+'tests/**/*.ino') config.examples = findFiles(glob: config.library_root+'examples/**/*.ino') - + } parallel Doxygen: { @@ -177,7 +177,7 @@ def call(Closure body) { message: "Failed to build <${env.CHANGE_URL}|PR#${env.CHANGE_ID} - ${env.CHANGE_TITLE}>. Job <${env.BUILD_URL}|${env.JOB_NAME} #${env.BUILD_NUMBER}> ended with ${currentBuild.result}." emailext ( subject: "PR#${env.CHANGE_ID} - ${env.CHANGE_TITLE} failed to build", - body: '''Greetings Sir!

+ body: '''Greetings!

I am The Butler. My task is to help you create a pull request that fit the MySensors organizations coding style and builds for all supported platforms.

I am afraid I failed to validate your pull request. Result was '''+currentBuild.result+'''.
Please check the attached build log or here for a hint on what the problem might be.

@@ -196,7 +196,7 @@ def call(Closure body) { message: "Failed to build branch ${env.BRANCH_NAME}. Job <${env.BUILD_URL}|${env.JOB_NAME} #${env.BUILD_NUMBER}> ended with ${currentBuild.result}." emailext ( subject: "MySensors branch ${env.BRANCH_NAME} failed to build", - body: '''Sir, I am afraid I failed to build branch ${BRANCH_NAME}. Result was '''+currentBuild.result+'''. + body: '''I am afraid I failed to build branch ${BRANCH_NAME}. Result was '''+currentBuild.result+'''.
Please check the attached build log or here for a hint on what the problem might be.

Changes:
${CHANGES}

@@ -215,4 +215,4 @@ def call(Closure body) { } } } -return this \ No newline at end of file +return this From f5ed26c778c18107d1516bd86704f8c8f99ff571 Mon Sep 17 00:00:00 2001 From: Marco Bakera Date: Sun, 6 May 2018 20:22:56 +0200 Subject: [PATCH 49/60] Fixed some minor typos in comments (#1082) * Fixed typo in the username --- examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino | 2 +- examples_linux/mysgw.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino b/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino index 0b6d66f..3f1cad0 100644 --- a/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino +++ b/examples/GatewayW5100MQTTClient/GatewayW5100MQTTClient.ino @@ -96,7 +96,7 @@ #define MY_RF24_CS_PIN 6 #endif -// Enable these if your MQTT broker requires usenrame/password +// Enable these if your MQTT broker requires username/password //#define MY_MQTT_USER "username" //#define MY_MQTT_PASSWORD "password" diff --git a/examples_linux/mysgw.cpp b/examples_linux/mysgw.cpp index 65541a6..22771a8 100644 --- a/examples_linux/mysgw.cpp +++ b/examples_linux/mysgw.cpp @@ -45,7 +45,7 @@ //#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 +// Enable these if your MQTT broker requires username/password //#define MY_MQTT_USER "username" //#define MY_MQTT_PASSWORD "password" From 0b9af6d713aaa17295020f666a31425f1588b3de Mon Sep 17 00:00:00 2001 From: Mikael Falkvidd Date: Mon, 14 May 2018 21:32:11 +0200 Subject: [PATCH 50/60] Update cast in msg.set (#1130) A while ago, MySensors changed to use int32_t instead of long int (and similar for other data types). This change was not applied to all examples, causing some examples to fail compilation for ESP8266 with the following message: call of overloaded 'set(long int)' is ambiguous This update changes the casts to match the new style. This fixes https://github.com/mysensors/MySensors/issues/1129 Thanks to https://github.com/henfri for reporting. --- examples/CO2Sensor/CO2Sensor.ino | 2 +- examples/DustSensorDSM/DustSensorDSM.ino | 4 ++-- examples/SoilMoistSensor/SoilMoistSensor.ino | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/CO2Sensor/CO2Sensor.ino b/examples/CO2Sensor/CO2Sensor.ino index ba78acf..f19940a 100644 --- a/examples/CO2Sensor/CO2Sensor.ino +++ b/examples/CO2Sensor/CO2Sensor.ino @@ -95,7 +95,7 @@ void loop() long co2ppm = 2 * ((duration/1000) - 2); //Serial.print(co2ppm); if ((co2ppm != lastAIQ)&&(abs(co2ppm-lastAIQ)>=10)) { - send(msg.set((long)ceil(co2ppm))); + send(msg.set((int32_t)ceil(co2ppm))); lastAIQ = ceil(co2ppm); } diff --git a/examples/DustSensorDSM/DustSensorDSM.ino b/examples/DustSensorDSM/DustSensorDSM.ino index 7564973..418c7ae 100644 --- a/examples/DustSensorDSM/DustSensorDSM.ino +++ b/examples/DustSensorDSM/DustSensorDSM.ino @@ -95,7 +95,7 @@ void loop() Serial.print("\n"); if ((concentrationPM25 != lastDUSTPM25)&&(concentrationPM25>0)) { - send(dustMsgPM25.set((long)ceil(concentrationPM25))); + send(dustMsgPM25.set((int32_t)ceil(concentrationPM25))); lastDUSTPM25 = ceil(concentrationPM25); } @@ -110,7 +110,7 @@ void loop() long ppmv=(concentrationPM10*0.0283168/100/1000) * (0.08205*temp)/0.01; if ((ceil(concentrationPM10) != lastDUSTPM10)&&((long)concentrationPM10>0)) { - send(dustMsgPM10.set((long)ppmv)); + send(dustMsgPM10.set((int32_t)ppmv)); lastDUSTPM10 = ceil(concentrationPM10); } diff --git a/examples/SoilMoistSensor/SoilMoistSensor.ino b/examples/SoilMoistSensor/SoilMoistSensor.ino index c4900ba..719d8ce 100644 --- a/examples/SoilMoistSensor/SoilMoistSensor.ino +++ b/examples/SoilMoistSensor/SoilMoistSensor.ino @@ -138,7 +138,7 @@ void loop() Serial.println (); //send back the values - send(msg.set((long int)ceil(sensor1))); + send(msg.set((int32_t)ceil(sensor1))); // delay until next measurement (msec) sleep(SLEEP_TIME); } From ba7027ce1d4ba81eed150a5be61d73db5e7c3ff5 Mon Sep 17 00:00:00 2001 From: Avamander Date: Wed, 16 May 2018 11:34:14 +0300 Subject: [PATCH 51/60] Add error message when HAL is undefined (#1131) --- MySensors.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MySensors.h b/MySensors.h index 31d6ddf..0033d5d 100644 --- a/MySensors.h +++ b/MySensors.h @@ -77,6 +77,8 @@ #include "hal/architecture/Teensy3/MyHwTeensy3.cpp" #elif defined(__linux__) #include "hal/architecture/Linux/MyHwLinuxGeneric.cpp" +#else +#error Hardware abstraction not defined (unsupported platform) #endif // OTA Debug second part, depends on HAL From 4e1d69dbb232bd81d12b83e57bade8ba6ae0fcd9 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Fri, 18 May 2018 08:35:43 +0200 Subject: [PATCH 52/60] Refine cppcheck analysis (#1133) - Details link on github for cppcheck now goes straight to the report - Removed umatched suppression from the cppcheck suppression file --- .ci/static_analysis.groovy | 2 +- .mystools/cppcheck/config/suppressions.cfg | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.ci/static_analysis.groovy b/.ci/static_analysis.groovy index fbd3fe5..642176e 100644 --- a/.ci/static_analysis.groovy +++ b/.ci/static_analysis.groovy @@ -29,7 +29,7 @@ def cppCheck(config) { "grep -q \"0total\" cppcheck-avr_cppcheck_reports/index.html || exit_code=\$?\n"+ "exit \$((exit_code == 0 ? 0 : 1))") if (ret == 1) { - config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (Code analysis - Cppcheck)', 'Issues found', '${BUILD_URL}CppCheck_AVR/index.html') + config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (Code analysis - Cppcheck)', 'Issues found', '${BUILD_URL}CppCheck_20AVR/index.html') error 'Terminating due to Cppcheck error' } else { config.pr.setBuildStatus(config, 'SUCCESS', 'Toll gate (Code analysis - Cppcheck)', 'Pass', '') diff --git a/.mystools/cppcheck/config/suppressions.cfg b/.mystools/cppcheck/config/suppressions.cfg index 9820b3d..18171c4 100644 --- a/.mystools/cppcheck/config/suppressions.cfg +++ b/.mystools/cppcheck/config/suppressions.cfg @@ -2,5 +2,3 @@ ConfigurationNotChecked unmatchedSuppression // This suppression is because the problem is in an in-lined macro so in-line-suppressions does not appear to take effect unreadVariable:*/MyHwNRF5.cpp -uninitMemberVar:*/TinyGsmFifo.h - From 59b15f5824bf060fa153b30065d089b04fff77c7 Mon Sep 17 00:00:00 2001 From: Mikael Falkvidd Date: Fri, 18 May 2018 15:46:12 +0200 Subject: [PATCH 53/60] Fix syntax error in MyGatewayTransportEthernet (#1132) Code doesn't compile very well if statements are missing a semicolon at the end. This error snuck in in https://github.com/mysensors/MySensors/pull/1110 --- core/MyGatewayTransportEthernet.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/MyGatewayTransportEthernet.cpp b/core/MyGatewayTransportEthernet.cpp index ac17394..6d1f576 100644 --- a/core/MyGatewayTransportEthernet.cpp +++ b/core/MyGatewayTransportEthernet.cpp @@ -152,9 +152,9 @@ bool gatewayTransportInit(void) WiFi.mode(WIFI_STA); #if defined(MY_HOSTNAME) #if defined(MY_GATEWAY_ESP8266) - WiFi.hostname(MY_HOSTNAME) + WiFi.hostname(MY_HOSTNAME); #elif defined(MY_GATEWAY_ESP32) - WiFi.setHostname(MY_HOSTNAME) + WiFi.setHostname(MY_HOSTNAME); #endif #endif #ifdef MY_IP_ADDRESS From bbaa9399d6e68f1342173c886baae4d8bd51afb3 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Wed, 30 May 2018 00:09:24 +0200 Subject: [PATCH 54/60] Add software AES encryption to RFM95 transport HAL (#1054) Also clean up capabilities flags a bit and fix test-sketch for rfm95 to use proper encryption flag. --- MyConfig.h | 25 ++++++++-- configure | 8 ++++ core/MyCapabilities.h | 4 +- hal/transport/RFM95/MyTransportRFM95.cpp | 47 ++++++++++++++++++- keywords.txt | 1 + ...ning_whitelisting_full_debug_rfm95_rsa.ino | 2 +- 6 files changed, 79 insertions(+), 8 deletions(-) diff --git a/MyConfig.h b/MyConfig.h index c08b1f2..8a48503 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -817,6 +817,18 @@ */ //#define MY_DEBUG_VERBOSE_RFM95 +/** + * @def MY_RFM95_ENABLE_ENCRYPTION + * @brief Define this to enable software based %AES encryption. + * + * All nodes and gateway must have this enabled, and all must be personalized with the same %AES + * key. + * @see @ref personalization + * + * @warning This driver always sets the initialization vector to 0 so encryption is weak. + */ +//#define MY_RFM95_ENABLE_ENCRYPTION + /** * @def MY_RFM95_FREQUENCY * @brief The frequency to use. @@ -1799,7 +1811,7 @@ /** * @def MY_SIGNING_FEATURE * @ingroup internals - * @brief Helper flag to indicate that some signing feature is enabled + * @brief Helper flag to indicate that some signing feature is enabled, set automatically */ #if defined(MY_SIGNING_ATSHA204) || defined(MY_SIGNING_SOFT) #define MY_SIGNING_FEATURE @@ -1812,7 +1824,7 @@ * @brief These options control encryption related configurations. * * Note that encryption is toggled on a per-radio basis. - * @see MY_RF24_ENABLE_ENCRYPTION, MY_RFM69_ENABLE_ENCRYPTION, MY_NRF5_ESB_ENABLE_ENCRYPTION + * @see MY_RF24_ENABLE_ENCRYPTION, MY_RFM69_ENABLE_ENCRYPTION, MY_NRF5_ESB_ENABLE_ENCRYPTION, MY_RFM95_ENABLE_ENCRYPTION * @{ */ @@ -1845,14 +1857,18 @@ #ifndef MY_NRF5_ESB_ENABLE_ENCRYPTION #define MY_NRF5_ESB_ENABLE_ENCRYPTION #endif +#ifndef MY_RFM95_ENABLE_ENCRYPTION +#define MY_RFM95_ENABLE_ENCRYPTION +#endif #endif /** * @def MY_ENCRYPTION_FEATURE * @ingroup internals - * @brief Helper flag to indicate that some encryption feature is enabled + * @brief Helper flag to indicate that some encryption feature is enabled, set automatically + * @see MY_RF24_ENABLE_ENCRYPTION, MY_RFM69_ENABLE_ENCRYPTION, MY_NRF5_ESB_ENABLE_ENCRYPTION, MY_RFM95_ENABLE_ENCRYPTION */ -#if defined(MY_RF24_ENABLE_ENCRYPTION) || defined(MY_RFM69_ENABLE_ENCRYPTION) || defined(MY_NRF5_ESB_ENABLE_ENCRYPTION) +#if defined(MY_RF24_ENABLE_ENCRYPTION) || defined(MY_RFM69_ENABLE_ENCRYPTION) || defined(MY_NRF5_ESB_ENABLE_ENCRYPTION) || defined(MY_RFM95_ENABLE_ENCRYPTION) #define MY_ENCRYPTION_FEATURE #endif /** @}*/ // End of EncryptionSettingGrpPub group @@ -2303,6 +2319,7 @@ // RFM95 #define MY_RADIO_RFM95 #define MY_DEBUG_VERBOSE_RFM95 +#define MY_RFM95_ENABLE_ENCRYPTION #define MY_RFM95_ATC_MODE_DISABLED #define MY_RFM95_RST_PIN #define MY_RFM95_MODEM_CONFIGRUATION diff --git a/configure b/configure index dcca71b..b545e29 100755 --- a/configure +++ b/configure @@ -85,6 +85,10 @@ MySensors options: Enables RFM69 encryption. All nodes and gateway must have this enabled, and all must be personalized with the same AES key. + --my-rfm95-encryption-enabled + Enables RFM95 encryption. + All nodes and gateway must have this enabled, and all must be + personalized with the same AES key. --my-rs485-serial-port= RS485 serial port. You must provide a port. --my-rs485-baudrate= RS485 baudrate. [9600] @@ -450,6 +454,10 @@ for opt do encryption=true CPPFLAGS="-DMY_RFM69_ENABLE_ENCRYPTION $CPPFLAGS" ;; + --my-rfm95-encryption-enabled*) + encryption=true + CPPFLAGS="-DMY_RFM95_ENABLE_ENCRYPTION $CPPFLAGS" + ;; --my-rs485-serial-port=*) CPPFLAGS="-DMY_RS485_HWSERIAL=\\\"${optarg}\\\" $CPPFLAGS" ;; diff --git a/core/MyCapabilities.h b/core/MyCapabilities.h index d83875c..629ea6b 100644 --- a/core/MyCapabilities.h +++ b/core/MyCapabilities.h @@ -218,14 +218,14 @@ * @def MY_CAP_ENCR * @brief Indicate the encryption setting. * - * @see MY_RF24_ENABLE_ENCRYPTION, MY_RFM69_ENABLE_ENCRYPTION, MY_NRF5_ESB_ENABLE_ENCRYPTION + * @see MY_ENCRYPTION_FEATURE * * | Setting | Indicator * |------------|---------- * | Enabled | X * | Disabled | - */ -#if defined(MY_RF24_ENABLE_ENCRYPTION) || defined(MY_RFM69_ENABLE_ENCRYPTION) || defined (MY_NRF5_ESB_ENABLE_ENCRYPTION) +#if defined(MY_ENCRYPTION_FEATURE) #define MY_CAP_ENCR "X" #else #define MY_CAP_ENCR "-" diff --git a/hal/transport/RFM95/MyTransportRFM95.cpp b/hal/transport/RFM95/MyTransportRFM95.cpp index 7003012..5e3bd64 100644 --- a/hal/transport/RFM95/MyTransportRFM95.cpp +++ b/hal/transport/RFM95/MyTransportRFM95.cpp @@ -18,6 +18,14 @@ */ #include "drivers/RFM95/RFM95.h" +#if defined(MY_RFM95_ENABLE_ENCRYPTION) +#include "drivers/AES/AES.h" +#endif + +#if defined(MY_RFM95_ENABLE_ENCRYPTION) +AES RFM95_aes; +uint8_t RFM95_dataenc[32] = {0}; +#endif #if defined(MY_RFM95_ENABLE_ENCRYPTION) #include "drivers/AES/AES.cpp" @@ -25,6 +33,20 @@ bool transportInit(void) { +#if defined(MY_RFM95_ENABLE_ENCRYPTION) + uint8_t RFM95_psk[16]; +#ifdef MY_SIGNING_SIMPLE_PASSWD + memset(RFM95_psk, 0, 16); + memcpy(RFM95_psk, MY_SIGNING_SIMPLE_PASSWD, strnlen(MY_SIGNING_SIMPLE_PASSWD, 16)); +#else + hwReadConfigBlock((void*)RFM95_psk, (void*)EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16); +#endif + //set up AES-key + RFM95_aes.set_key(RFM95_psk, 16); + // Make sure it is purged from memory when set + memset(RFM95_psk, 0, 16); +#endif + const bool result = RFM95_initialise(MY_RFM95_FREQUENCY); #if defined(MY_RFM95_TCXO) RFM95_enableTCXO(); @@ -48,11 +70,26 @@ uint8_t transportGetAddress(void) bool transportSend(const uint8_t to, const void *data, const uint8_t len, const bool noACK) { +#if defined(MY_RFM95_ENABLE_ENCRYPTION) + // copy input data because it is read-only + (void)memcpy(RFM95_dataenc,data,len); + // has to be adjusted, WIP! + RFM95_aes.set_IV(0); + const uint8_t finalLength = len > 16 ? 32 : 16; + //encrypt data + RFM95_aes.cbc_encrypt(RFM95_dataenc, RFM95_dataenc, finalLength /16); + if (noACK) { + (void)RFM95_sendWithRetry(to, RFM95_dataenc, finalLength, 0, 0); + return true; + } + return RFM95_sendWithRetry(to, RFM95_dataenc, finalLength); +#else if (noACK) { (void)RFM95_sendWithRetry(to, data, len, 0, 0); return true; } return RFM95_sendWithRetry(to, data, len); +#endif } bool transportAvailable(void) @@ -68,7 +105,15 @@ bool transportSanityCheck(void) uint8_t transportReceive(void *data) { - const uint8_t len = RFM95_receive((uint8_t *)data, MAX_MESSAGE_LENGTH); + uint8_t len = RFM95_receive((uint8_t*)data, MAX_MESSAGE_LENGTH); +#if defined(MY_RFM95_ENABLE_ENCRYPTION) + // has to be adjusted, WIP! + RFM95_aes.set_IV(0); + // decrypt data + if (RFM95_aes.cbc_decrypt((uint8_t*)(data), (uint8_t*)(data), len > 16 ? 2 : 1) != AES_SUCCESS) { + len = 0; + } +#endif return len; } diff --git a/keywords.txt b/keywords.txt index b22e5fd..2643bae 100644 --- a/keywords.txt +++ b/keywords.txt @@ -192,6 +192,7 @@ MY_RFM95_TCXO LITERAL1 MY_RFM95_TX_POWER LITERAL1 MY_RFM95_TX_POWER_DBM LITERAL1 MY_RFM95_TX_TIMEOUT_MS LITERAL1 +MY_RFM95_ENABLE_ENCRYPTION LITERAL1 # RFM69 MY_DEBUG_VERBOSE_RFM69 LITERAL1 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 index 510c72c..67fc11e 100644 --- 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 @@ -33,6 +33,6 @@ #ifndef MY_SIGNING_ATSHA204_PIN #define MY_SIGNING_ATSHA204_PIN 17 #endif -#define MY_RFM69_ENABLE_ENCRYPTION +#define MY_RFM95_ENABLE_ENCRYPTION #include From 9f987a98f9517728b61913cec19db307909de230 Mon Sep 17 00:00:00 2001 From: per1234 Date: Fri, 8 Jun 2018 01:29:06 -0700 Subject: [PATCH 55/60] Remove redundant keyword identifiers (#1140) The third field of keywords.txt is used to provide Arduino Language Reference links, which are accessed from the Arduino IDE by highlighting the keyword and then selecting "Find in Reference" from the Help or right click menu. Adding values to this field that do not match any existing reference pages results in a "Could not open the URL" error. --- keywords.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/keywords.txt b/keywords.txt index 2643bae..3361eec 100644 --- a/keywords.txt +++ b/keywords.txt @@ -197,8 +197,8 @@ MY_RFM95_ENABLE_ENCRYPTION LITERAL1 # RFM69 MY_DEBUG_VERBOSE_RFM69 LITERAL1 MY_DEBUG_VERBOSE_RFM69_REGISTERS LITERAL1 -MY_IS_RFM69HW LITERAL1 LITERAL1 -MY_RADIO_RFM69 LITERAL1 LITERAL1 +MY_IS_RFM69HW LITERAL1 +MY_RADIO_RFM69 LITERAL1 MY_RFM69_ATC_MODE_DISABLED LITERAL1 MY_RFM69_ATC_TARGET_RSSI_DBM LITERAL1 MY_RFM69_BITRATE_LSB LITERAL1 From fc99db60e0f870d46eb2f049d2bddb7a46ff4bc8 Mon Sep 17 00:00:00 2001 From: tekka Date: Sun, 10 Jun 2018 10:59:48 +0200 Subject: [PATCH 56/60] Jenkins: Update ESP8266 board defs 2.4.1 (#1143) --- .ci/arduino.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.ci/arduino.groovy b/.ci/arduino.groovy index 47a69f3..e7faeef 100644 --- a/.ci/arduino.groovy +++ b/.ci/arduino.groovy @@ -210,7 +210,7 @@ def buildSTM32F1(config, sketches, String key) { } def buildEsp8266(config, sketches, String key) { - def fqbn = '-fqbn esp8266:esp8266:generic -prefs build.f_cpu=80000000 -prefs build.mcu=esp8266' + def fqbn = '-fqbn=esp8266:esp8266:generic:CpuFrequency=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,FlashSize=512K0,led=2,LwIPVariant=v2mss536,Debug=Disabled,DebugLevel=None____,FlashErase=none,UploadSpeed=115200' config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (ESP8266 - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/') try { for (sketch = 0; sketch < sketches.size(); sketch++) { @@ -226,7 +226,7 @@ def buildEsp8266(config, sketches, String key) { sketches[sketch].path != config.library_root+'examples/MotionSensorRS485/MotionSensorRS485.ino' && sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino' && sketches[sketch].path != config.library_root+'examples/SoilMoistSensor/SoilMoistSensor.ino') { - buildArduino(config, '-prefs build.flash_ld=eagle.flash.512k0.ld -prefs build.flash_freq=40 -prefs build.flash_size=512K '+fqbn, sketches[sketch].path, key+'_Esp8266') + buildArduino(config, fqbn, sketches[sketch].path, key+'_Esp8266') } } } catch (ex) { From f934d7c46f92f51004af888412e362604de0e357 Mon Sep 17 00:00:00 2001 From: tekka Date: Sun, 10 Jun 2018 13:05:47 +0200 Subject: [PATCH 57/60] Jenkins: Update CI scripts + Arduino IDE 1.8.5 (#1144) --- .ci/arduino.groovy | 40 ++++++++++++++++++++-------------------- .ci/pipeline.groovy | 8 ++++---- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/.ci/arduino.groovy b/.ci/arduino.groovy index e7faeef..7037309 100644 --- a/.ci/arduino.groovy +++ b/.ci/arduino.groovy @@ -1,16 +1,16 @@ #!groovy def buildArduino(config, String buildFlags, String sketch, String key) { - def root = '/opt/arduino-1.8.2/' + def root = '/opt/arduino-1.8.5/' if (config.nightly_arduino_ide) { root = '/opt/arduino-nightly/' } - def esp8266_tools = '/opt/arduino-nightly/hardware/esp8266com/esp8266/tools' + //def esp8266_tools = '/opt/arduino-nightly/hardware/esp8266com/esp8266/tools' def jenkins_root = '/var/lib/jenkins/' def builder = root+'arduino-builder' - def standard_args = ' -warnings="all"' //-verbose=true + def standard_args = ' -warnings=all' //-verbose=true def builder_specifics = ' -hardware '+root+'hardware -tools '+root+'hardware/tools/avr -tools '+ - root+'tools-builder -tools '+esp8266_tools+' -built-in-libraries '+root+'libraries' + root+'tools-builder -built-in-libraries '+root+'libraries' def jenkins_packages = jenkins_root+'.arduino15/packages' def site_specifics = ' -hardware '+jenkins_packages+' -tools '+jenkins_packages def repo_specifics = ' -hardware hardware -libraries . ' @@ -41,7 +41,7 @@ def parseWarnings(String key) { } def buildMySensorsMicro(config, sketches, String key) { - def fqbn = '-fqbn MySensors:avr:MysensorsMicro -prefs build.f_cpu=1000000 -prefs build.mcu=atmega328p' + def fqbn = '-fqbn=MySensors:avr:MysensorsMicro:cpu=1Mhz' config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (MySensorsMicro - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/') try { for (sketch = 0; sketch < sketches.size(); sketch++) { @@ -75,7 +75,7 @@ def buildMySensorsMicro(config, sketches, String key) { } def buildMySensorsGw(config, sketches, String key) { - def fqbn = '-fqbn MySensors:samd:mysensors_gw_native -prefs build.f_cpu=48000000 -prefs build.mcu=cortex-m0plus' + def fqbn = '-fqbn MySensors:samd:mysensors_gw_native' config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (MySensorsGW - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/') try { for (sketch = 0; sketch < sketches.size(); sketch++) { @@ -88,7 +88,7 @@ def buildMySensorsGw(config, sketches, String key) { sketches[sketch].path != config.library_root+'examples/GatewayESP32MQTTClient/GatewayESP32MQTTClient.ino' && sketches[sketch].path != config.library_root+'examples/GatewaySerialRS485/GatewaySerialRS485.ino' && sketches[sketch].path != config.library_root+'examples/MotionSensorRS485/MotionSensorRS485.ino') { - buildArduino(config, fqbn, sketches[sketch].path, key+'_MySensorsGw') + buildArduino(config, fqbn, sketches[sketch].path, key+'_MySensorsGW') } } } catch (ex) { @@ -96,7 +96,7 @@ def buildMySensorsGw(config, sketches, String key) { config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (MySensorsGW - '+key+')', 'Build error', '${BUILD_URL}') throw ex } finally { - parseWarnings(key+'_MySensorsGw') + parseWarnings(key+'_MySensorsGW') } if (currentBuild.currentResult == 'UNSTABLE') { config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (MySensorsGW - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new') @@ -111,7 +111,7 @@ def buildMySensorsGw(config, sketches, String key) { } def buildArduinoUno(config, sketches, String key) { - def fqbn = '-fqbn arduino:avr:uno -prefs build.f_cpu=16000000 -prefs build.mcu=atmega328p' + def fqbn = '-fqbn arduino:avr:uno' config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Arduino Uno - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/') try { for (sketch = 0; sketch < sketches.size(); sketch++) { @@ -144,7 +144,7 @@ def buildArduinoUno(config, sketches, String key) { } def buildArduinoMega(config, sketches, String key) { - def fqbn = '-fqbn arduino:avr:mega -prefs build.f_cpu=16000000 -prefs build.mcu=atmega2560' + def fqbn = '-fqbn arduino:avr:mega:cpu=atmega2560' config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Arduino Mega - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/') try { for (sketch = 0; sketch < sketches.size(); sketch++) { @@ -209,7 +209,7 @@ def buildSTM32F1(config, sketches, String key) { } } -def buildEsp8266(config, sketches, String key) { +def buildESP8266(config, sketches, String key) { def fqbn = '-fqbn=esp8266:esp8266:generic:CpuFrequency=80,ResetMethod=ck,CrystalFreq=26,FlashFreq=40,FlashMode=qio,FlashSize=512K0,led=2,LwIPVariant=v2mss536,Debug=Disabled,DebugLevel=None____,FlashErase=none,UploadSpeed=115200' config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (ESP8266 - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/') try { @@ -226,7 +226,7 @@ def buildEsp8266(config, sketches, String key) { sketches[sketch].path != config.library_root+'examples/MotionSensorRS485/MotionSensorRS485.ino' && sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino' && sketches[sketch].path != config.library_root+'examples/SoilMoistSensor/SoilMoistSensor.ino') { - buildArduino(config, fqbn, sketches[sketch].path, key+'_Esp8266') + buildArduino(config, fqbn, sketches[sketch].path, key+'_ESP8266') } } } catch (ex) { @@ -234,7 +234,7 @@ def buildEsp8266(config, sketches, String key) { config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (ESP8266 - '+key+')', 'Build error', '${BUILD_URL}') throw ex } finally { - parseWarnings(key+'_Esp8266') + parseWarnings(key+'_ESP8266') } if (currentBuild.currentResult == 'UNSTABLE') { config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (ESP8266 - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new') @@ -248,8 +248,8 @@ def buildEsp8266(config, sketches, String key) { } } -def buildEsp32(config, sketches, String key) { - def fqbn = '-fqbn espressif:esp32:node32s -warnings=default -prefs build.f_cpu=80000000 -prefs build.mcu=esp32' +def buildESP32(config, sketches, String key) { + def fqbn = '-fqbn espressif:esp32:esp32:PartitionScheme=default,FlashMode=qio,FlashFreq=80,FlashSize=4M,UploadSpeed=921600,DebugLevel=none -warnings=default' config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (ESP32 - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/') try { for (sketch = 0; sketch < sketches.size(); sketch++) { @@ -274,7 +274,7 @@ def buildEsp32(config, sketches, String key) { sketches[sketch].path != config.library_root+'examples/SensebenderGatewaySerial/SensebenderGatewaySerial.ino' && sketches[sketch].path != config.library_root+'examples/MotionSensorRS485/MotionSensorRS485.ino' && sketches[sketch].path != config.library_root+'examples/SoilMoistSensor/SoilMoistSensor.ino') { - buildArduino(config, '-prefs build.flash_freq=80m -prefs build.flash_size=4MB '+fqbn, sketches[sketch].path, key+'_Esp32') + buildArduino(config, fqbn, sketches[sketch].path, key+'_ESP32') } } } catch (ex) { @@ -282,7 +282,7 @@ def buildEsp32(config, sketches, String key) { config.pr.setBuildStatus(config, 'FAILURE', 'Toll gate (ESP32 - '+key+')', 'Build error', '${BUILD_URL}') throw ex } finally { - parseWarnings(key+'_Esp32') + parseWarnings(key+'_ESP32') } if (currentBuild.currentResult == 'UNSTABLE') { config.pr.setBuildStatus(config, 'ERROR', 'Toll gate (ESP32 - '+key+')', 'Warnings found', '${BUILD_URL}warnings2Result/new') @@ -297,7 +297,7 @@ def buildEsp32(config, sketches, String key) { } def buildnRF5(config, sketches, String key) { - def fqbn = '-fqbn sandeepmistry:nRF5:Generic_nRF52832 -prefs build.f_cpu=16000000 -prefs build.mcu=cortex-m4' + def fqbn = '-fqbn sandeepmistry:nRF5:Generic_nRF52832:softdevice=none,lfclk=lfxo' config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (nRF5 - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/') try { for (sketch = 0; sketch < sketches.size(); sketch++) { @@ -338,7 +338,7 @@ def buildnRF5(config, sketches, String key) { } def buildnRF52832(config, sketches, String key) { - def fqbn = '-fqbn=MySensors:nRF5:MyBoard_nRF52832:bootcode=none,lfclk=lfxo,reset=notenable -prefs build.f_cpu=16000000 -prefs build.mcu=cortex-m4' + def fqbn = '-fqbn=MySensors:nRF5:MyBoard_nRF52832:bootcode=none,lfclk=lfxo,reset=notenable' config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (nRF52832 - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/') try { buildArduino(config, fqbn, 'hardware/MySensors/nRF5/libraries/MyBoardNRF5/examples/MyBoardNRF5/MyBoardNRF5.ino', key+'_nRF52832') @@ -362,7 +362,7 @@ def buildnRF52832(config, sketches, String key) { } def buildnRF51822(config, sketches, String key) { - def fqbn = '-fqbn=MySensors:nRF5:MyBoard_nRF51822:chip=xxaa,bootcode=none,lfclk=lfxo -prefs build.f_cpu=16000000 -prefs build.mcu=cortex-m0' + def fqbn = '-fqbn=MySensors:nRF5:MyBoard_nRF51822:chip=xxaa,bootcode=none,lfclk=lfxo' config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (nRF51822 - '+key+')', 'Building...', '${BUILD_URL}flowGraphTable/') try { buildArduino(config, fqbn, 'hardware/MySensors/nRF5/libraries/MyBoardNRF5/examples/MyBoardNRF5/MyBoardNRF5.ino', key+'_nRF51822') diff --git a/.ci/pipeline.groovy b/.ci/pipeline.groovy index d50e44d..73e0e9a 100644 --- a/.ci/pipeline.groovy +++ b/.ci/pipeline.groovy @@ -98,7 +98,7 @@ def call(Closure body) { arduino.buildMySensorsGw(config, config.tests, 'Tests') } stage('ESP32 (tests)') { - arduino.buildEsp32(config, config.tests, 'Tests') + arduino.buildESP32(config, config.tests, 'Tests') } stage('nRF52832 (tests)') { arduino.buildnRF52832(config, config.tests, 'Tests') @@ -110,7 +110,7 @@ def call(Closure body) { arduino.buildnRF5(config, config.tests, 'Tests') } stage('ESP8266 (tests)') { - arduino.buildEsp8266(config, config.tests, 'Tests') + arduino.buildESP8266(config, config.tests, 'Tests') } stage('STM32F1 (tests)') { arduino.buildSTM32F1(config, config.tests, 'Tests') @@ -143,12 +143,12 @@ def call(Closure body) { arduino.buildnRF5(config, config.examples, 'Examples') } stage('ESP8266 (examples)') { - arduino.buildEsp8266(config, config.examples, 'Examples') + arduino.buildESP8266(config, config.examples, 'Examples') } // No point in building examples for ESP32 yet /* stage('ESP32 (examples)') { - arduino.buildEsp32(config, config.examples, 'Examples') + arduino.buildESP32(config, config.examples, 'Examples') } */ // No point in building examples for STM32F1 yet From a28b7036caa787f7c32193c92b2b8ab70cc41f16 Mon Sep 17 00:00:00 2001 From: seeers Date: Sat, 16 Jun 2018 13:32:10 +0200 Subject: [PATCH 58/60] Avoid data array overflow (#1142) Occurs through packet collisions. Sometimes a wrong length is received. --- hal/transport/RS485/MyTransportRS485.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hal/transport/RS485/MyTransportRS485.cpp b/hal/transport/RS485/MyTransportRS485.cpp index 2cbe8d9..00e8695 100644 --- a/hal/transport/RS485/MyTransportRS485.cpp +++ b/hal/transport/RS485/MyTransportRS485.cpp @@ -155,6 +155,12 @@ bool _serialProcess() _recPhase = 1; _recPos = 0; + //Avoid _data[] overflow + if (_recLen >= MY_RS485_MAX_MESSAGE_LENGTH) { + _serialReset(); + break; + } + //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 From 88a0d70e4d669848f362012a0089a41419b983b9 Mon Sep 17 00:00:00 2001 From: Patrick Fallberg Date: Sat, 16 Jun 2018 16:41:37 +0200 Subject: [PATCH 59/60] Pre-register PR build statuses on GitHub (#1145) This enables GitHub to show all statuses planned for execution. --- .ci/pipeline.groovy | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/.ci/pipeline.groovy b/.ci/pipeline.groovy index 73e0e9a..78e36e3 100644 --- a/.ci/pipeline.groovy +++ b/.ci/pipeline.groovy @@ -17,6 +17,38 @@ def call(Closure body) { script: """#!/bin/bash cd ${config.repository_root} git log -n 1 --pretty=format:'%H' refs/remotes/origin/PR-${env.CHANGE_ID}""").trim() + // Pre-register all build statues so github shows what is going to happen + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate', 'Validating...', '${BUILD_URL}flowGraphTable/') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Butler)', 'Not run yet...', '') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Code analysis - Cppcheck)', 'Not run yet...', '') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Documentation)', 'Not run yet...', '') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Linux builds - Serial GW)', 'Not run yet...', '') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Linux builds - Ethernet GW)', 'Not run yet...', '') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Linux builds - MQTT GW)', 'Not run yet...', '') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (MySensorsMicro - Tests)', 'Not run yet...', '') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (MySensorsGW - Tests)', 'Not run yet...', '') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (ESP32 - Tests)', 'Not run yet...', '') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (nRF52832 - Tests)', 'Not run yet...', '') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (nRF51822 - Tests)', 'Not run yet...', '') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (nRF5 - Tests)', 'Not run yet...', '') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (ESP8266 - Tests)', 'Not run yet...', '') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (STM32F1 - Tests)', 'Not run yet...', '') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Arduino Uno - Tests)', 'Not run yet...', '') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Arduino Mega - Tests)', 'Not run yet...', '') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (MySensorsMicro - Examples)', 'Not run yet...', '') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (MySensorsGW - Examples)', 'Not run yet...', '') +/* + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (nRF52832 - Examples)', 'Not run yet...', '') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (nRF51822 - Examples)', 'Not run yet...', '') +*/ + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (nRF5 - Examples)', 'Not run yet...', '') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (ESP8266 - Examples)', 'Not run yet...', '') +/* + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (ESP32 - Examples)', 'Not run yet...', '') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (STM32F1 - Examples)', 'Not run yet...', '') +*/ + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Arduino Uno - Examples)', 'Not run yet...', '') + config.pr.setBuildStatus(config, 'PENDING', 'Toll gate (Arduino Mega - Examples)', 'Not run yet...', '') } else { config.is_pull_request = false echo "Building branch: "+env.BRANCH_NAME @@ -24,7 +56,6 @@ def call(Closure body) { script: """#!/bin/bash cd ${config.repository_root} git log -n 1 --pretty=format:'%H' refs/remotes/origin/${env.BRANCH_NAME}""").trim() - config.pr.setBuildStatus(config, 'PENDING', 'Toll gate', 'Validating...', '${BUILD_URL}flowGraphTable/') } try { From b84cd6ac4ecacddf305c83412a5b1be1020478e2 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Sat, 16 Jun 2018 14:19:32 -0300 Subject: [PATCH 60/60] Linux: Add rfm95 configure options (#1135) --- MyConfig.h | 1 + configure | 27 ++++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/MyConfig.h b/MyConfig.h index 8a48503..5c20987 100644 --- a/MyConfig.h +++ b/MyConfig.h @@ -602,6 +602,7 @@ * @def MY_RFM69_FREQUENCY * @brief The frequency to use. * + * - RFM69_315MHZ * - RFM69_433MHZ * - RFM69_868MHZ * - RFM69_915MHZ diff --git a/configure b/configure index b545e29..ddf7666 100755 --- a/configure +++ b/configure @@ -85,7 +85,11 @@ MySensors options: Enables RFM69 encryption. All nodes and gateway must have this enabled, and all must be personalized with the same AES key. - --my-rfm95-encryption-enabled + --my-rfm95-frequency=[169|315|434|868|915] + RFM95 Module Frequency. [868] + --my-rfm95-irq-pin= Pin number connected to RFM95 IRQ pin. + --my-rfm95-cs-pin= Pin number to use for RFM95 Chip-Select. + --my-rfm95-encryption-enabled Enables RFM95 encryption. All nodes and gateway must have this enabled, and all must be personalized with the same AES key. @@ -454,6 +458,27 @@ for opt do encryption=true CPPFLAGS="-DMY_RFM69_ENABLE_ENCRYPTION $CPPFLAGS" ;; + --my-rfm95-frequency=*) + if [[ ${optarg} == "169" ]]; then + CPPFLAGS="-DMY_RFM95_FREQUENCY=RFM95_169MHZ $CPPFLAGS" + elif [[ ${optarg} == "315" ]]; then + CPPFLAGS="-DMY_RFM95_FREQUENCY=RFM95_315MHZ $CPPFLAGS" + elif [[ ${optarg} == "434" ]]; then + CPPFLAGS="-DMY_RFM95_FREQUENCY=RFM95_434MHZ $CPPFLAGS" + elif [[ ${optarg} == "868" ]]; then + CPPFLAGS="-DMY_RFM95_FREQUENCY=RFM95_868MHZ $CPPFLAGS" + elif [[ ${optarg} == "915" ]]; then + CPPFLAGS="-DMY_RFM95_FREQUENCY=RFM95_915MHZ $CPPFLAGS" + else + echo "[WARNING] Illegal value for --my-rfm95-frequency=${optarg}, ignored" + fi + ;; + --my-rfm95-irq-pin=*) + CPPFLAGS="-DMY_RFM95_IRQ_NUM=${optarg} $CPPFLAGS" + ;; + --my-rfm95-cs-pin=*) + CPPFLAGS="-DMY_RFM95_CS_PIN=${optarg} $CPPFLAGS" + ;; --my-rfm95-encryption-enabled*) encryption=true CPPFLAGS="-DMY_RFM95_ENABLE_ENCRYPTION $CPPFLAGS"