diff --git a/SerialGateway/SerialGateway.ino b/SerialGateway/SerialGateway.ino index 8bb48c1..5206306 100644 --- a/SerialGateway/SerialGateway.ino +++ b/SerialGateway/SerialGateway.ino @@ -47,6 +47,8 @@ void setup() // reserve bytes for the inputString. RadioId;ChildId;VAR=VALUE inputString.reserve(MAX_RECEIVE_LENGTH); gw.begin(); + gw.setPALevel(RF24_PA_HIGH); //Adjust PA-level: MIN, LOW, HIGH, MAX (MAX can sometimes cause problems when using amplified NRF24L01) + // C++ classes and interrupts really sucks. Need to attach interrupt // outside thw Gateway class due to language shortcomings! Gah! diff --git a/libraries/MySensors/Gateway.cpp b/libraries/MySensors/Gateway.cpp index 01e9185..603d1f0 100644 --- a/libraries/MySensors/Gateway.cpp +++ b/libraries/MySensors/Gateway.cpp @@ -13,11 +13,13 @@ Gateway::Gateway(uint8_t _cepin, uint8_t _cspin, uint8_t _inclusion_time) : Relay(_cepin, _cspin) { ledMode = false; + isRelay = true; inclusionTime = _inclusion_time; } Gateway::Gateway(uint8_t _cepin, uint8_t _cspin, uint8_t _inclusion, uint8_t _inclusion_time, uint8_t _rx, uint8_t _tx, uint8_t _er) : Relay(_cepin, _cspin) { ledMode = true; + isRelay = true; pinInclusion = _inclusion; inclusionTime = _inclusion_time; pinRx = _rx; @@ -169,8 +171,8 @@ void Gateway::setInclusionMode(boolean newMode) { // Override normal validate to add error blink if crc check fails -uint8_t Gateway::validate() { - uint8_t res = Sensor::validate(); +uint8_t Gateway::validate(uint8_t length) { + uint8_t res = Sensor::validate(length); if (res == VALIDATE_BAD_CRC) { errBlink(1); } diff --git a/libraries/MySensors/Gateway.h b/libraries/MySensors/Gateway.h index 88bd3df..aaa3846 100644 --- a/libraries/MySensors/Gateway.h +++ b/libraries/MySensors/Gateway.h @@ -67,7 +67,7 @@ class Gateway : public Relay uint8_t pinEr; void serial(const char *fmt, ... ); - uint8_t validate(); + uint8_t validate(uint8_t length); void serial(message_s msg); void interruptStartInclusion(); void checkButtonTriggeredInclusion(); diff --git a/libraries/MySensors/Relay.cpp b/libraries/MySensors/Relay.cpp index 432ab1c..ad33cc6 100644 --- a/libraries/MySensors/Relay.cpp +++ b/libraries/MySensors/Relay.cpp @@ -23,9 +23,6 @@ void Relay::begin(uint8_t _radioId) { for (int i=0;i20) { + if (failedTransmissions > FIND_RELAY_RETRIES) { findRelay(); } failedTransmissions++; @@ -217,27 +214,45 @@ boolean Sensor::send(message_s message, int length) { boolean Sensor::sendWrite(uint8_t dest, message_s message, int length) { - // Add current radioId to last-field and calculate crc - message.header.last = radioId; - message.header.crc = crc8Message(message); - debug(PSTR("Tx: f=%d,t=%d,p=%d,n=%d,c=%d,mt=%d,t=%d,x=%d: %s\n"), - message.header.from,message.header.to, message.header.last, dest, message.header.childId, message.header.messageType, message.header.type, message.header.crc, message.data); + message.header.last = radioId; + message.header.crc = crc8Message(message, length); + debug(PSTR("Tx: fr=%d,to=%d,la=%d,ne=%d,ci=%d,mt=%d,ty=%d,cr=%d: %s\n"), + message.header.from,message.header.to, message.header.last, dest, message.header.childId, message.header.messageType, message.header.type, message.header.crc, message.data); + + bool ok = true; + bool broadcast = message.header.messageType == M_INTERNAL && message.header.type == I_PING; + int retry = WRITE_RETRY; RF24::stopListening(); - bool ok = false; - RF24::openWritingPipe(BASE_RADIO_ID+ dest); - int retry = 5; - do { - ok = RF24::write(&message, min(MAX_MESSAGE_LENGTH, sizeof(message.header) + length)); - } - while ( !ok && --retry ); + RF24::openWritingPipe(TO_ADDR(dest)); + RF24::write(&message, min(MAX_MESSAGE_LENGTH, sizeof(message.header) + length), broadcast); RF24::startListening(); -// RF24::openReadingPipe(CURRENT_NODE_PIPE, BASE_RADIO_ID+radioId); + RF24::closeReadingPipe(WRITE_PIPE); // Stop listening to write-pipe after transmit + + if (!broadcast) { + // ---------------- WAIT FOR ACK ------------------ + unsigned long startedWaiting = millis(); + bool timeout = false; + // Wait max 100 ms + while ( !RF24::available() && !timeout ) { + if (millis() - startedWaiting > 100 ) { + timeout = true; + ok = false; + } + } + // Check payload size and content + if ( !timeout && RF24::getDynamicPayloadSize()==sizeof(uint8_t)) { + uint8_t idest; + RF24::read( &idest, sizeof(uint8_t)); + if (dest != idest) { ok == false; } + } else { ok = false; } + //-------------------- + } if (ok) { debug(PSTR("Sent successfully\n")); } else { - debug(PSTR("Send failed. No ack received.\n")); + debug(PSTR("Send failed.\n")); } return ok; } @@ -381,9 +396,7 @@ boolean Sensor::messageAvailable() { if (available && pipe<7) { - readMessage(); - boolean ok = validate() == VALIDATE_OK; - debug(PSTR("Mess crc %s.\n"),ok?"ok":"error"); + boolean ok = readMessage(); if (ok && msg.header.to == radioId) { // This message is addressed to this node debug(PSTR("Message addressed for this node.\n")); @@ -414,106 +427,81 @@ message_s Sensor::getMessage() { } -message_s Sensor::readMessage() { +boolean Sensor::readMessage() { uint8_t len = RF24::getDynamicPayloadSize(); - bool done = RF24::read(&msg, len); - // Make sure string gets terminated ok. + boolean done = RF24::read(&msg, len); + + if (!(msg.header.messageType==M_INTERNAL && msg.header.type == I_PING_ACK)) { + RF24::stopListening(); + RF24::openWritingPipe(TO_ADDR(msg.header.last)); + RF24::write(&radioId, sizeof(uint8_t)); + RF24::startListening(); + RF24::closeReadingPipe(WRITE_PIPE); // Stop listening to write-pipe after transmit + } + uint8_t cb = msg.header.crc; + uint8_t valid = validate(len-sizeof(header_s)); + boolean ok = valid == VALIDATE_OK; + + + // Make sure string gets terminated ok for full sized messages. msg.data[len - sizeof(header_s) ] = '\0'; - debug(PSTR("Rx: f=%d,t=%d,l=%d,c=%d,mt=%d,t=%d,x=%d: %s\n"), - msg.header.from,msg.header.to, msg.header.last, msg.header.childId, msg.header.messageType, msg.header.type,msg.header.crc, msg.data); - return msg; + debug(PSTR("Rx: fr=%d,to=%d,la=%d,ci=%d,mt=%d,t=%d,cr=%d(%s): %s\n"), + msg.header.from,msg.header.to, msg.header.last, msg.header.childId, msg.header.messageType, msg.header.type, msg.header.crc, valid==0?"ok":valid==1?"ec":"ev", msg.data); + return ok; } -/* - * raw CRC 8 bit calculation - */ -uint8_t Sensor::crc8Raw ( uint8_t *data_in, uint8_t number_of_bytes_to_read ) -{ - uint8_t crc; - uint8_t loop_count; - uint8_t bit_counter; - uint8_t data; - uint8_t feedback_bit; - - crc = CRC8INIT; - - for (loop_count = 0; loop_count != number_of_bytes_to_read; loop_count++) - { - data = data_in[loop_count]; - - bit_counter = 8; - do { - feedback_bit = (crc ^ data) & 0x01; - - if ( feedback_bit == 0x01 ) { - crc = crc ^ CRC8POLY; - } - crc = (crc >> 1) & 0x7F; - if ( feedback_bit == 0x01 ) { - crc = crc | 0x80; - } - - data = data >> 1; - bit_counter--; - - } while (bit_counter > 0); - } - return crc; -} /* * calculate CRC8 on message_s data taking care of data structure and protocol version */ -uint8_t Sensor::crc8Message(message_s var_msg) { +uint8_t Sensor::crc8Message(message_s var_msg, uint8_t len) { + uint8_t crc = 0x00; + uint8_t loop_count; + uint8_t bit_counter; + uint8_t data; + uint8_t feedback_bit; + uint8_t number_of_bytes_to_read = (uint8_t)sizeof(var_msg); + // Must set crc to a constant value. var_msg.header.crc = 0; + // fill unused space by zeroes for string data only - if(!var_msg.header.binary) { - uint8_t len = strlen(var_msg.data); - if(len < sizeof(var_msg.data)-1) { - memset(&var_msg.data[len], 0, sizeof(var_msg.data) - 1 - len); - } + if(len>=0 && len < sizeof(var_msg.data)-1) { + memset(&var_msg.data[len], 0, sizeof(var_msg.data) - 1 - len); } - return crc8Raw((uint8_t*)&var_msg, (uint8_t)sizeof(var_msg)); + + + for (loop_count = 0; loop_count != number_of_bytes_to_read; loop_count++) + { + data = ((uint8_t*)&var_msg)[loop_count]; + + bit_counter = 8; + do { + feedback_bit = (crc ^ data) & 0x01; + + if ( feedback_bit == 0x01 ) { + crc = crc ^ 0x18; //0X18 = X^8+X^5+X^4+X^0 + } + crc = (crc >> 1) & 0x7F; + if ( feedback_bit == 0x01 ) { + crc = crc | 0x80; + } + + data = data >> 1; + bit_counter--; + + } while (bit_counter > 0); + } + return crc; } -/* -uint8_t Sensor::crc8Message(message_s var_msg) { - struct { - message_s msg; - uint8_t protocol_version; - } crc_data; - memcpy(&crc_data, &var_msg, sizeof(var_msg)); - crc_data.protocol_version = PROTOCOL_VERSION; - // some clean up needed for repeated result - crc_data.msg.header.crc = 0; - // fill unused space by zeroes for string data only - if(!crc_data.msg.header.binary) { - uint8_t len = strlen(crc_data.msg.data); - if(len < sizeof(crc_data.msg.data)-1) { - memset(&crc_data.msg.data[len], 0, sizeof(crc_data.msg.data) - 1 - len); - } - } - return crc8Raw((uint8_t*)&crc_data, (uint8_t)sizeof(crc_data)); -} */ +uint8_t Sensor::validate(uint8_t length) { + uint8_t oldCrc = msg.header.crc; + uint8_t newCrc = crc8Message(msg, length); + if(!(msg.header.version == PROTOCOL_VERSION)) return VALIDATE_BAD_VERSION; -/* - * true if message is consistent * - */ -bool Sensor::checkCRC(message_s var_msg) { - uint8_t oldCrc = var_msg.header.crc; - - //debug(PSTR("CRC: in %d, calc %d\n"),oldCrc, crc8Message(var_msg)); - - return (oldCrc == crc8Message(var_msg))?true:false; -} - -uint8_t Sensor::validate() { - bool crc_check = checkCRC(msg); - bool version_check = (msg.header.version == PROTOCOL_VERSION); - if(!version_check) return VALIDATE_BAD_VERSION; - if(!crc_check) return VALIDATE_BAD_CRC; + if(!(oldCrc == newCrc)) return VALIDATE_BAD_CRC; return VALIDATE_OK; } diff --git a/libraries/MySensors/Sensor.h b/libraries/MySensors/Sensor.h index 13e23a1..b011e9b 100644 --- a/libraries/MySensors/Sensor.h +++ b/libraries/MySensors/Sensor.h @@ -45,15 +45,18 @@ #define BASE_RADIO_ID ((uint64_t)0xABCDABC000LL) #define GATEWAY_ADDRESS ((uint8_t)0) #define BROADCAST_ADDRESS ((uint8_t)0xFF) +#define TO_ADDR(x) (BASE_RADIO_ID + x) -#define MAX_MESSAGE_LENGTH 32 - +#define WRITE_PIPE ((uint8_t)0) #define CURRENT_NODE_PIPE ((uint8_t)1) #define BROADCAST_PIPE ((uint8_t)2) -#define RELAY_PIPE ((uint8_t)3) -#define CRC8INIT 0x00 -#define CRC8POLY 0x18 //0X18 = X^8+X^5+X^4+X^0 + +#define WRITE_RETRY 5 +#define FIND_RELAY_RETRIES 20 + + +#define MAX_MESSAGE_LENGTH 32 // Message types typedef enum { @@ -235,7 +238,7 @@ class Sensor : public RF24 /** * Validates consistency of the message including CRC and protocol version */ - uint8_t validate(); + uint8_t validate(uint8_t length); #ifdef DEBUG @@ -257,7 +260,7 @@ class Sensor : public RF24 void findRelay(); boolean send(message_s message, int length); boolean sendWrite(uint8_t dest, message_s message, int length); - message_s readMessage(void); + boolean readMessage(); void buildMsg(uint8_t from, uint8_t to, uint8_t childId, uint8_t messageType, uint8_t type, const char *data, uint8_t length, boolean binary); void sendInternal(uint8_t variableType, const char *value); boolean sendVariableAck(); @@ -269,9 +272,7 @@ class Sensor : public RF24 message_s ack; // Buffer for ack messages. void initializeRadioId(); - uint8_t crc8Raw(uint8_t *data_in, uint8_t number_of_bytes_to_read); - uint8_t crc8Message(message_s); - bool checkCRC(message_s); + uint8_t crc8Message(message_s, uint8_t length); char* get(uint8_t nodeId, uint8_t childId, uint8_t sendType, uint8_t receiveType, uint8_t variableType); char *getInternal(uint8_t variableType); };