From fe4b07074dc53a9825e6110a67068f07fb0b1c41 Mon Sep 17 00:00:00 2001 From: Henrik Ekblad Date: Thu, 19 Feb 2015 16:59:38 +0100 Subject: [PATCH 01/24] Revert "check for invalid input on gateway" --- libraries/MySensors/MyGateway.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libraries/MySensors/MyGateway.cpp b/libraries/MySensors/MyGateway.cpp index 740683d..c65978f 100644 --- a/libraries/MySensors/MyGateway.cpp +++ b/libraries/MySensors/MyGateway.cpp @@ -180,9 +180,6 @@ void MyGateway::parseAndSend(char *commandBuffer) { } i++; } - // Check for invalid input - if (i != 6) - return; if (destination==GATEWAY_ADDRESS && command==C_INTERNAL) { // Handle messages directed to gateway From 3133a7ba0cf3cc21b9a651b6fb91c171e7ba2840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Mon, 23 Feb 2015 21:31:22 +0100 Subject: [PATCH 02/24] Updated library to use getHumidityPercentage, instead of getHumidityBasisPoints() in combined humidity/temperature reader --- libraries/SI7021/SI7021.cpp | 2 +- libraries/SI7021/SI7021.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/SI7021/SI7021.cpp b/libraries/SI7021/SI7021.cpp index 2bde080..c51ab6b 100644 --- a/libraries/SI7021/SI7021.cpp +++ b/libraries/SI7021/SI7021.cpp @@ -128,7 +128,7 @@ void SI7021::setHeater(bool on) { // get humidity, then get temperature reading from humidity measurement struct si7021_env SI7021::getHumidityAndTemperature() { si7021_env ret = {0, 0, 0}; - ret.humidityBasisPoints = getHumidityBasisPoints(); + ret.humidityPercent = getHumidityPercent(); ret.celsiusHundredths = _getCelsiusPostHumidity(); ret.fahrenheitHundredths = (1.8 * ret.celsiusHundredths) + 3200; return ret; diff --git a/libraries/SI7021/SI7021.h b/libraries/SI7021/SI7021.h index 5aa9f4b..d577900 100644 --- a/libraries/SI7021/SI7021.h +++ b/libraries/SI7021/SI7021.h @@ -23,7 +23,7 @@ This program is licensed under the GNU GPL v2 typedef struct si7021_env { int celsiusHundredths; int fahrenheitHundredths; - unsigned int humidityBasisPoints; + unsigned int humidityPercent; } si7021_env; class SI7021 From c6efc23de384248f881aded9287da1c8c22ceb89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Mon, 23 Feb 2015 21:32:38 +0100 Subject: [PATCH 03/24] Updated MysensorMicro to use combined humidity and temperature readings from Si7021, in order to save current --- .../examples/MysensorMicro/MysensorMicro.ino | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino index 11bf608..feb6dd6 100644 --- a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino +++ b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino @@ -26,6 +26,9 @@ #define MEASURE_INTERVAL 60000 +// FORCE_TRANSMIT_INTERVAL, this number of times of wakeup, the sensor is forced to report all values to the controller +#define FORCE_TRANSMIT_INTERVAL 30 + SI7021 humiditySensor; MySensor gw; @@ -45,7 +48,6 @@ long lastBattery = -100; void setup() { - Serial.begin(115200); pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, LOW); @@ -73,6 +75,7 @@ void setup() { gw.present(CHILD_ID_HUM,S_HUM); gw.present(CHILD_ID_BATT, S_POWER); + switchClock(1< 30) {// Every 60th time we wake up, force a transmission on all sensors. + if (measureCount > FORCE_TRANSMIT_INTERVAL + ) {// Every 60th time we wake up, force a transmission on all sensors. forceTransmit = true; measureCount = 0; } @@ -106,23 +110,19 @@ void sendTempHumidityMeasurements(bool force) lastTemperature = -100; } - float temperature = humiditySensor.getCelsiusHundredths()/10; + si7021_env data = humiditySensor.getHumidityAndTemperature(); - temperature = temperature / 10; - - int humidity = humiditySensor.getHumidityPercent(); + float temperature = data.celsiusHundredths/100; + + int humidity = data.humidityPercent; if (lastTemperature != temperature) { gw.send(msgTemp.set(temperature,1)); lastTemperature = temperature; - Serial.print("temperature "); - Serial.println(temperature); } if (lastHumidity != humidity) { gw.send(msgHum.set(humidity)); lastHumidity = humidity; - Serial.print("Humidity "); - Serial.println(humidity); } } @@ -155,7 +155,7 @@ long readVcc() { #elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) ADMUX = _BV(MUX5) | _BV(MUX0); #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) - ADMUX = _BV(MUX3) | _BV(MUX2); + ADcdMUX = _BV(MUX3) | _BV(MUX2); #else ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); #endif @@ -188,4 +188,11 @@ void resetEEP() } } - +void switchClock(unsigned char clk) +{ + cli(); + + CLKPR = 1< Date: Thu, 26 Feb 2015 18:23:31 -0300 Subject: [PATCH 04/24] MQTTGateway: fix garbage in MQTT payload --- .../examples/MQTTGateway/MQTTGateway.ino | 73 +++++++++++-------- 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino index bbd44dd..90abe03 100644 --- a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino +++ b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino @@ -61,14 +61,14 @@ http://forum.mysensors.org/topic/303/mqtt-broker-gateway #include #include - // * Use this for IBOARD modded to use standard MISO/MOSI/SCK, see note *1 above! /* #define RADIO_CE_PIN 3 // radio chip enable #define RADIO_SPI_SS_PIN 8 // radio SPI serial select #define RADIO_ERROR_LED_PIN A2 // Error led pin #define RADIO_RX_LED_PIN A1 // Receive led pin -#define RADIO_TX_LED_PIN A0 // the PCB, on board LED*/ +#define RADIO_TX_LED_PIN A0 // the PCB, on board LED +*/ // * Use this for default configured pro mini / nano etc : ///* @@ -88,42 +88,57 @@ EthernetServer server = EthernetServer(TCP_PORT); MyMQTT gw(RADIO_CE_PIN, RADIO_SPI_SS_PIN); void processEthernetMessages() { - char inputString[MQTT_MAX_PACKET_SIZE] = ""; - uint8_t inputSize = 0; - EthernetClient client = server.available(); - if (client) { - while (client.available()) { - char inChar = client.read(); - inputString[inputSize] = inChar; - inputSize++; - } + char inputString[MQTT_MAX_PACKET_SIZE] = ""; + uint8_t inputSize = 0; + uint8_t readCnt = 0; + uint8_t length = 0; + + EthernetClient client = server.available(); + if (client) { + while (client.available()) { + uint8_t inChar = client.read(); + readCnt++; + + if (inputSize < MQTT_MAX_PACKET_SIZE-1) { + inputString[inputSize] = (char)inChar; + inputSize++; + } + + if (readCnt == 2) { + length = (inChar & 127) * 1; + } + if (readCnt == (length+2)) { + break; + } + } + inputString[inputSize] = 0; #ifdef TCPDUMP - Serial.print("<<"); - char buf[4]; - for (uint8_t a=0; a>"); - char buf[4]; - for (uint8_t a=0; a<*writeSize; a++) { sprintf(buf,"%02X ",(uint8_t)writeBuffer[a]); Serial.print(buf); } Serial.println(""); + Serial.print(">>"); + char buf[4]; + for (uint8_t a=0; a<*writeSize; a++) { sprintf(buf,"%02X ",(uint8_t)writeBuffer[a]); Serial.print(buf); } Serial.println(); #endif - server.write((const uint8_t *)writeBuffer, *writeSize); + server.write((const uint8_t *)writeBuffer, *writeSize); } int main(void) { - init(); - Ethernet.begin(TCP_MAC, TCP_IP); - delay(1000); // Wait for Ethernet to get configured. - gw.begin(RF24_PA_LEVEL_GW, RF24_CHANNEL, RF24_DATARATE, writeEthernet, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN); - server.begin(); - while (1) { - processEthernetMessages(); - gw.processRadioMessage(); - } + init(); + Ethernet.begin(TCP_MAC, TCP_IP); + delay(1000); // Wait for Ethernet to get configured. + gw.begin(RF24_PA_LEVEL_GW, RF24_CHANNEL, RF24_DATARATE, writeEthernet, RADIO_RX_LED_PIN, RADIO_TX_LED_PIN, RADIO_ERROR_LED_PIN); + server.begin(); + while (1) { + processEthernetMessages(); + gw.processRadioMessage(); + } } From 0d1c061dc9751a0cdac21172799065d3958059ab Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Thu, 26 Feb 2015 20:33:14 -0300 Subject: [PATCH 05/24] add DigitalIO.h for SOFTSPI in MQTTGateway.ino --- libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino index 90abe03..161a926 100644 --- a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino +++ b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino @@ -56,6 +56,7 @@ http://forum.mysensors.org/topic/303/mqtt-broker-gateway */ +#include #include #include #include @@ -130,7 +131,6 @@ void writeEthernet(const char *writeBuffer, uint8_t *writeSize) { server.write((const uint8_t *)writeBuffer, *writeSize); } - int main(void) { init(); Ethernet.begin(TCP_MAC, TCP_IP); From 8d3f24424dc8fa1be3aba3159cfb4f5b6ada2ec3 Mon Sep 17 00:00:00 2001 From: Marcelo Aquino Date: Thu, 26 Feb 2015 21:19:47 -0300 Subject: [PATCH 06/24] fix mqtt gateway doesn't distribute node ids --- libraries/MySensors/MyMQTT.cpp | 226 ++++++++++-------- libraries/MySensors/MyMQTT.h | 2 +- .../examples/MQTTGateway/MQTTGateway.ino | 3 +- 3 files changed, 129 insertions(+), 102 deletions(-) diff --git a/libraries/MySensors/MyMQTT.cpp b/libraries/MySensors/MyMQTT.cpp index 610414e..fca2eea 100755 --- a/libraries/MySensors/MyMQTT.cpp +++ b/libraries/MySensors/MyMQTT.cpp @@ -13,7 +13,7 @@ version 2 as published by the Free Software Foundation. #include "utility/MsTimer2.h" char V_0[] PROGMEM = "TEMP"; //V_TEMP -char V_1[] PROGMEM = "HUM"; //V_HUM +char V_1[] PROGMEM = "HUM"; //V_HUM char V_2[] PROGMEM = "LIGHT"; //V_LIGHT char V_3[] PROGMEM = "DIMMER"; //V_DIMMER char V_4[] PROGMEM = "PRESSURE"; //V_PRESSURE @@ -23,7 +23,7 @@ char V_7[] PROGMEM = "RAINRATE"; //V_RAINRATE char V_8[] PROGMEM = "WIND"; //V_WIND char V_9[] PROGMEM = "GUST"; //V_GUST char V_10[] PROGMEM = "DIRECTON"; //V_DIRECTON -char V_11[] PROGMEM = "UV"; //V_UV +char V_11[] PROGMEM = "UV"; //V_UV char V_12[] PROGMEM = "WEIGHT"; //V_WEIGHT char V_13[] PROGMEM = "DISTANCE"; //V_DISTANCE char V_14[] PROGMEM = "IMPEDANCE"; //V_IMPEDANCE @@ -35,20 +35,20 @@ char V_19[] PROGMEM = "SCENE_ON"; //V_SCENE_ON char V_20[] PROGMEM = "SCENE_OFF"; //V_SCENE_OFF char V_21[] PROGMEM = "HEATER"; //V_HEATER char V_22[] PROGMEM = "HEATER_SW"; //V_HEATER_SW -char V_23[] PROGMEM = "LIGHT_LEVEL"; //V_LIGHT_LEVEL +char V_23[] PROGMEM = "LIGHT_LEVEL";//V_LIGHT_LEVEL char V_24[] PROGMEM = "VAR1"; //V_VAR1 char V_25[] PROGMEM = "VAR2"; //V_VAR2 char V_26[] PROGMEM = "VAR3"; //V_VAR3 char V_27[] PROGMEM = "VAR4"; //V_VAR4 char V_28[] PROGMEM = "VAR5"; //V_VAR5 -char V_29[] PROGMEM = "UP"; //V_UP +char V_29[] PROGMEM = "UP"; //V_UP char V_30[] PROGMEM = "DOWN"; //V_DOWN char V_31[] PROGMEM = "STOP"; //V_STOP char V_32[] PROGMEM = "IR_SEND"; //V_IR_SEND char V_33[] PROGMEM = "IR_RECEIVE"; //V_IR_RECEIVE char V_34[] PROGMEM = "FLOW"; //V_FLOW char V_35[] PROGMEM = "VOLUME"; //V_VOLUME -char V_36[] PROGMEM = "LOCK_STATUS"; //V_LOCK_STATUS +char V_36[] PROGMEM = "LOCK_STATUS";//V_LOCK_STATUS char V_37[] PROGMEM = "DUST_LEVEL"; //V_DUST_LEVEL char V_38[] PROGMEM = "VOLTAGE"; //V_VOLTAGE char V_39[] PROGMEM = "CURRENT"; //V_CURRENT @@ -72,10 +72,10 @@ char V_56[] PROGMEM = ""; // char V_57[] PROGMEM = ""; // char V_58[] PROGMEM = ""; // char V_59[] PROGMEM = ""; // -char V_60[] PROGMEM = "Started!\n"; //Custom for MQTTGateway +char V_60[] PROGMEM = "Started!\n"; //Custom for MQTTGateway char V_61[] PROGMEM = "SKETCH_NAME"; //Custom for MQTTGateway char V_62[] PROGMEM = "SKETCH_VERSION"; //Custom for MQTTGateway -char V_63[] PROGMEM = "UNKNOWN"; //Custom for MQTTGateway +char V_63[] PROGMEM = "UNKNOWN"; //Custom for MQTTGateway ////////////////////////////////////////////////////////////////// @@ -89,7 +89,6 @@ PROGMEM const char *vType[] = { V_61, V_62, V_63 }; - char broker[] PROGMEM = MQTT_BROKER_PREFIX; #define S_FIRSTCUSTOM 60 @@ -132,7 +131,7 @@ void MyMQTT::begin(rf24_pa_dbm_e paLevel, uint8_t channel, rf24_datarate_e dataR Serial.begin(BAUD_RATE); repeaterMode = true; isGateway = true; - MQTTClientConnected = false; + MQTTClients = 0; setupRepeaterMode(); dataCallback = inDataCallback; @@ -163,77 +162,120 @@ void MyMQTT::processRadioMessage() { if (process()) { // A new message was received from one of the sensors MyMessage message = getLastMessage(); - // Pass along the message from sensors to serial line rxBlink(1); - SendMQTT(message); - } + if (msg.isAck()) { + Serial.println("msg is ack!"); + if (msg.sender == 255 && mGetCommand(msg) == C_INTERNAL && msg.type == I_ID_REQUEST) { + // TODO: sending ACK request on id_response fucks node up. doesn't work. + // The idea was to confirm id and save to EEPROM_LATEST_NODE_ADDRESS. + } + } else { + // we have to check every message if its a newly assigned id or not. + // Ack on I_ID_RESPONSE does not work, and checking on C_PRESENTATION isn't reliable. + uint8_t newNodeID = loadState(EEPROM_LATEST_NODE_ADDRESS)+1; + if (newNodeID <= MQTT_FIRST_SENSORID) { + newNodeID = MQTT_FIRST_SENSORID; + } + if (msg.sender == newNodeID) { + saveState(EEPROM_LATEST_NODE_ADDRESS,newNodeID); + } + + if (mGetCommand(msg) == C_INTERNAL) { + if (msg.type == I_CONFIG) { + txBlink(1); + if (!sendRoute(build(msg, GATEWAY_ADDRESS, msg.sender, 255, C_INTERNAL, I_CONFIG, 0).set("M"))) { + errBlink(1); + } + } else if (msg.type == I_ID_REQUEST && msg.sender == 255) { + uint8_t newNodeID = loadState(EEPROM_LATEST_NODE_ADDRESS)+1; + if (newNodeID <= MQTT_FIRST_SENSORID) { + newNodeID = MQTT_FIRST_SENSORID; + } + if (newNodeID >= MQTT_LAST_SENSORID) { + // Sorry no more id's left :( + newNodeID = AUTO; + } + txBlink(1); + if (!sendRoute(build(msg, GATEWAY_ADDRESS, msg.sender, 255, C_INTERNAL, I_ID_RESPONSE, 0).set(newNodeID))) { + errBlink(1); + } + } + } else if (mGetCommand(msg)!= C_PRESENTATION) { + // Pass along the message from sensors to MQTT + SendMQTT(message); + } + } + } } void MyMQTT::processMQTTMessage(char *inputString, uint8_t inputPos) { - char *str, *p; + char *str, *p, *payload=NULL; uint8_t i = 0; buffer[0]= 0; buffsize = 0; + uint8_t mqttMsgType = (uint8_t)inputString[0] >> 4; - if ((uint8_t)inputString[0] >> 4 == MQTTCONNECT) { + if (mqttMsgType == MQTTCONNECT) { buffer[buffsize++] = MQTTCONNACK << 4; buffer[buffsize++] = 0x02; // Remaining length buffer[buffsize++] = 0x00; // Connection accepted buffer[buffsize++] = 0x00; // Reserved - MQTTClientConnected=true; // We have connection! - } - if ((uint8_t)inputString[0] >> 4 == MQTTPINGREQ) { + MQTTClients++; // We have a new client connected! + } else if (mqttMsgType == MQTTPINGREQ) { buffer[buffsize++] = MQTTPINGRESP << 4; buffer[buffsize++] = 0x00; - } - if ((uint8_t)inputString[0] >> 4 == MQTTSUBSCRIBE) { - buffer[buffsize++] = MQTTSUBACK << 4; // Just ack everything, we actually dont really care! - buffer[buffsize++] = 0x03; // Remaining length + } else if (mqttMsgType == MQTTSUBSCRIBE) { + buffer[buffsize++] = MQTTSUBACK << 4; // Just ack everything, we actually dont really care! + buffer[buffsize++] = 0x03; // Remaining length buffer[buffsize++] = (uint8_t)inputString[2]; // Message ID MSB buffer[buffsize++] = (uint8_t)inputString[3]; // Message ID LSB - buffer[buffsize++] = MQTTQOS0; // QOS level - } - if ((uint8_t)inputString[0] >> 4 == MQTTUNSUBSCRIBE) { + buffer[buffsize++] = MQTTQOS0; // QOS level + } else if (mqttMsgType == MQTTUNSUBSCRIBE) { buffer[buffsize++] = MQTTUNSUBACK << 4; - buffer[buffsize++] = 0x02; // Remaining length + buffer[buffsize++] = 0x02; // Remaining length buffer[buffsize++] = (uint8_t)inputString[2]; // Message ID MSB buffer[buffsize++] = (uint8_t)inputString[3]; // Message ID LSB + } else if (mqttMsgType == MQTTDISCONNECT) { + MQTTClients--; // Client disconnected! } - if ((uint8_t)inputString[0] >> 4 == MQTTDISCONNECT) { - MQTTClientConnected=false; // We lost connection! - } + if (buffsize > 0) { - dataCallback(buffer,&buffsize); + dataCallback(buffer, &buffsize); } // We publish everything we get, we dont care if its subscribed or not! - if ((uint8_t)inputString[0] >> 4 == MQTTPUBLISH || (MQTT_SEND_SUBSCRIPTION && (uint8_t)inputString[0] >> 4 == MQTTSUBSCRIBE)) { - buffer[0]= 0; + if (mqttMsgType == MQTTPUBLISH || (MQTT_SEND_SUBSCRIPTION && mqttMsgType == MQTTSUBSCRIBE)) { + buffer[0] = 0; buffsize = 0; // Cut out address and payload depending on message type. - if ((uint8_t)inputString[0] >> 4 == MQTTSUBSCRIBE) { - strncat(buffer,inputString+6,inputString[5]); + if (mqttMsgType == MQTTSUBSCRIBE) { + strncat(buffer, inputString+6, inputString[5]); } else { - strncat(buffer,inputString+4,inputString[3]); + strncat(buffer, inputString+4, inputString[3]); } // TODO: Check if we should send ack or not. - for (str = strtok_r(buffer,"/",&p) ; str && i<4 ; str = strtok_r(NULL,"/",&p)) { + for (str = strtok_r(buffer, "/", &p) ; str && i<4 ; str = strtok_r(NULL, "/", &p)) { if (i == 0) { - if (strcmp_P(str,broker)!=0) { //look for MQTT_BROKER_PREFIX - return; //Message not for us or malformatted! + //look for MQTT_BROKER_PREFIX + if (strcmp_P(str, broker) != 0) { + //Message not for us or malformatted! + return; } } else if (i==1) { - msg.destination = atoi(str); //NodeID + //NodeID + msg.destination = atoi(str); } else if (i==2) { - msg.sensor = atoi(str); //SensorID + //SensorID + msg.sensor = atoi(str); } else if (i==3) { - char match=0; //SensorType - //strcpy(str,(char*)&str[2]); //Strip V_ + //SensorType + char match=0; for (uint8_t j=0; strcpy_P(convBuf, (char*)pgm_read_word(&(vType[j]))) ; j++) { - if (strcmp((char*)&str[2],convBuf)==0) { //Strip V_ and compare + //Strip V_ and compare + if (strcmp((char*)&str[2], convBuf)==0) { match=j; break; } @@ -245,70 +287,58 @@ void MyMQTT::processMQTTMessage(char *inputString, uint8_t inputPos) { msg.type = match; } i++; - } //Check if packge has payload - if ((uint8_t)inputString[1] > (uint8_t)(inputString[3]+2) && !((uint8_t)inputString[0] >> 4 == MQTTSUBSCRIBE)) { - strcpy(convBuf,inputString+(inputString[3]+4)); - msg.set(convBuf); //Payload - } else { - msg.set(""); //No payload } + + // Check if package has payload + if (mqttMsgType == MQTTPUBLISH) { + uint8_t length = (uint8_t)inputString[1] - (uint8_t)(inputString[3]+2); + if (length && length < MAX_PAYLOAD*2) { + // Payload + memcpy(convBuf, inputString+(inputString[3]+4), length); + convBuf[length] = 0; + payload = convBuf; + } + } + msg.set(payload); + txBlink(1); if (!sendRoute(build(msg, GATEWAY_ADDRESS, msg.destination, msg.sensor, C_SET, msg.type, 0))) errBlink(1); - } } void MyMQTT::SendMQTT(MyMessage &msg) { buffsize = 0; - if (!MQTTClientConnected) return; //We have no connections - return - if (msg.isAck()) { - Serial.println("msg is ack!"); - if (msg.sender==255 && mGetCommand(msg)==C_INTERNAL && msg.type==I_ID_REQUEST) { - // TODO: sending ACK request on id_response fucks node up. doesn't work. - // The idea was to confirm id and save to EEPROM_LATEST_NODE_ADDRESS. - } - } else { - // we have to check every message if its a newly assigned id or not. - // Ack on I_ID_RESPONSE does not work, and checking on C_PRESENTATION isn't reliable. - uint8_t newNodeID = loadState(EEPROM_LATEST_NODE_ADDRESS)+1; - if (newNodeID <= MQTT_FIRST_SENSORID) newNodeID = MQTT_FIRST_SENSORID; - if (msg.sender==newNodeID) { - saveState(EEPROM_LATEST_NODE_ADDRESS,newNodeID); - } - if (mGetCommand(msg)==C_INTERNAL) { - if (msg.type==I_CONFIG) { - txBlink(1); - if (!sendRoute(build(msg, GATEWAY_ADDRESS, msg.sender, 255, C_INTERNAL, I_CONFIG, 0).set("M"))) errBlink(1); - } else if (msg.type==I_ID_REQUEST && msg.sender==255) { - uint8_t newNodeID = loadState(EEPROM_LATEST_NODE_ADDRESS)+1; - if (newNodeID <= MQTT_FIRST_SENSORID) newNodeID = MQTT_FIRST_SENSORID; - if (newNodeID >= MQTT_LAST_SENSORID) return; // Sorry no more id's left :( - txBlink(1); - if (!sendRoute(build(msg, GATEWAY_ADDRESS, msg.sender, 255, C_INTERNAL, I_ID_RESPONSE, 0).set(newNodeID))) errBlink(1); - } - } else if (mGetCommand(msg)!=0) { - if (mGetCommand(msg)==3) msg.type=msg.type+(S_FIRSTCUSTOM-10); //Special message - - buffer[buffsize++] = MQTTPUBLISH << 4; // 0: - buffer[buffsize++] = 0x09; // 1: Remaining length with no payload, we'll set this later to correct value, buffsize -2 - buffer[buffsize++] = 0x00; // 2: Length MSB (Remaing length can never exceed ff,so MSB must be 0!) - buffer[buffsize++] = 0x08; // 3: Length LSB (ADDR), We'll set this later - if (msg.type > V_TOTAL) msg.type=V_TOTAL;// If type > defined types set to unknown. - strcpy_P(buffer+4, broker); - buffsize+=strlen_P(broker); - buffsize+=sprintf(&buffer[buffsize],"/%i/%i/V_%s",msg.sender,msg.sensor,getType(convBuf, &vType[msg.type])); - buffer[3]=buffsize-4; // Set correct address length on byte 4. -#ifdef DEBUG - Serial.println((char*)&buffer[4]); -#endif - msg.getString(convBuf); - for (uint8_t a=0; a V_TOTAL) { + // If type > defined types set to unknown. + msg.type=V_TOTAL; + } + strcpy_P(buffer+4, broker); + buffsize+=strlen_P(broker); + buffsize+=sprintf(&buffer[buffsize], "/%i/%i/V_%s", msg.sender, msg.sensor, getType(convBuf, &vType[msg.type])); + buffer[3]=buffsize-4; // Set correct address length on byte 4. +#ifdef DEBUG + Serial.println((char*)&buffer[4]); +#endif + msg.getString(convBuf); + for (uint8_t a=0; a Date: Fri, 27 Feb 2015 16:23:07 -0300 Subject: [PATCH 07/24] fix multiple mqtt clients with openhab There is probably a better solution for this, this was the simplest I came up with. Changed some variables types from uint8_t to byte to make simple for common arduino user. --- .../examples/MQTTGateway/MQTTGateway.ino | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino index 10f0211..ba3104a 100644 --- a/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino +++ b/libraries/MySensors/examples/MQTTGateway/MQTTGateway.ino @@ -81,32 +81,35 @@ http://forum.mysensors.org/topic/303/mqtt-broker-gateway #define TCP_PORT 1883 // Set your MQTT Broker Listening port. IPAddress TCP_IP ( 192, 168, 0, 234 ); // Configure your static ip-address here -uint8_t TCP_MAC[] = { 0x02, 0xDE, 0xAD, 0x00, 0x00, 0x42 }; // Mac-address - You should change this! see note *2 above! +byte TCP_MAC[] = { 0x02, 0xDE, 0xAD, 0x00, 0x00, 0x42 }; // Mac-address - You should change this! see note *2 above! ////////////////////////////////////////////////////////////////// EthernetServer server = EthernetServer(TCP_PORT); +EthernetClient *currentClient = NULL; MyMQTT gw(RADIO_CE_PIN, RADIO_SPI_SS_PIN); void processEthernetMessages() { char inputString[MQTT_MAX_PACKET_SIZE] = ""; - uint8_t inputSize = 0; - uint8_t readCnt = 0; - uint8_t length = 0; + byte inputSize = 0; + byte readCnt = 0; + byte length = 0; EthernetClient client = server.available(); if (client) { while (client.available()) { - uint8_t inChar = client.read(); + // Save the current client we are talking with + currentClient = &client; + byte inByte = client.read(); readCnt++; if (inputSize < MQTT_MAX_PACKET_SIZE) { - inputString[inputSize] = (char)inChar; + inputString[inputSize] = (char)inByte; inputSize++; } if (readCnt == 2) { - length = (inChar & 127) * 1; + length = (inByte & 127) * 1; } if (readCnt == (length+2)) { break; @@ -115,19 +118,24 @@ void processEthernetMessages() { #ifdef TCPDUMP Serial.print("<<"); char buf[4]; - for (uint8_t a=0; a>"); char buf[4]; - for (uint8_t a=0; a<*writeSize; a++) { sprintf(buf,"%02X ",(uint8_t)writeBuffer[a]); Serial.print(buf); } Serial.println(); + for (byte a=0; a<*writeSize; a++) { sprintf(buf,"%02X ",(byte)writeBuffer[a]); Serial.print(buf); } Serial.println(); #endif - server.write((const uint8_t *)writeBuffer, *writeSize); + // Check whether to respond to a single client or write to all + if (currentClient != NULL) + currentClient->write((const byte *)writeBuffer, *writeSize); + else + server.write((const byte *)writeBuffer, *writeSize); } int main(void) { From 0fed6838e5e186963789c543be63d1464a1c6398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Thu, 12 Mar 2015 20:32:51 +0100 Subject: [PATCH 08/24] Initial testmode implemented. --- .../examples/MysensorMicro/MysensorMicro.ino | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino index feb6dd6..24ce5ce 100644 --- a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino +++ b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino @@ -10,6 +10,7 @@ #include #include #include +#include #include // Define a static node address, remove if you want auto address assignment @@ -21,6 +22,7 @@ #define CHILD_ID_BATT 199 //Pin definitions +#define TEST_PIN A0 #define RESET_CFG_PIN A1 #define LED_PIN A2 @@ -30,6 +32,8 @@ #define FORCE_TRANSMIT_INTERVAL 30 SI7021 humiditySensor; +SPIFlash flash(8, 0xEF30); + MySensor gw; // Sensor messages @@ -53,10 +57,13 @@ void setup() { // First check if we should boot into clear eeprom mode pinMode(RESET_CFG_PIN, INPUT); + pinMode(TEST_PIN,INPUT); digitalWrite(RESET_CFG_PIN, HIGH); // Enable pullup + digitalWrite(TEST_PIN, HIGH); + if (!digitalRead(TEST_PIN)) testMode(); if (!digitalRead(RESET_CFG_PIN)) resetEEP(); digitalWrite(RESET_CFG_PIN, LOW); - + digitalWrite(TEST_PIN,LOW); digitalWrite(LED_PIN, HIGH); #ifdef NODE_ADDRESS @@ -196,3 +203,28 @@ void switchClock(unsigned char clk) CLKPR = clk; sei(); } + +void testMode() +{ + if (humiditySensor.begin()) + if (flash.initialize()) + { + while (1) + { + digitalWrite(LED_PIN, HIGH); + delay(800); + digitalWrite(LED_PIN, LOW); + delay(200); + } + } + else + { + while (1) + { + digitalWrite(LED_PIN, HIGH); + delay(200); + digitalWrite(LED_PIN, LOW); + delay(200); + } + } +} From adeca1c41c115d126f8130b93494e2ea4372632f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Sat, 14 Mar 2015 11:01:41 +0100 Subject: [PATCH 09/24] Updated testmode, removed clearEEP function as it's not needed in production. --- .../examples/MysensorMicro/MysensorMicro.ino | 60 +++++++++++-------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino index 24ce5ce..8c10883 100644 --- a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino +++ b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino @@ -12,6 +12,8 @@ #include #include #include +//#include + // Define a static node address, remove if you want auto address assignment //#define NODE_ADDRESS 3 @@ -23,8 +25,8 @@ //Pin definitions #define TEST_PIN A0 -#define RESET_CFG_PIN A1 #define LED_PIN A2 +#define ATSHA204_PIN 17 // A3 #define MEASURE_INTERVAL 60000 @@ -56,13 +58,9 @@ void setup() { digitalWrite(LED_PIN, LOW); // First check if we should boot into clear eeprom mode - pinMode(RESET_CFG_PIN, INPUT); pinMode(TEST_PIN,INPUT); - digitalWrite(RESET_CFG_PIN, HIGH); // Enable pullup digitalWrite(TEST_PIN, HIGH); if (!digitalRead(TEST_PIN)) testMode(); - if (!digitalRead(RESET_CFG_PIN)) resetEEP(); - digitalWrite(RESET_CFG_PIN, LOW); digitalWrite(TEST_PIN,LOW); digitalWrite(LED_PIN, HIGH); @@ -82,7 +80,7 @@ void setup() { gw.present(CHILD_ID_HUM,S_HUM); gw.present(CHILD_ID_BATT, S_POWER); - switchClock(1< Si7021 FAILED!"); + } + if (flash.initialize()) { - while (1) + Serial.println("flash OK!"); + tests ++; + } + else + { + Serial.println("---> flash failed!"); + } + + Serial.println("Test finished"); + + if (tests == 2) + { + Serial.println("Selftest ok!"); + while (1) // Blink OK pattern! { digitalWrite(LED_PIN, HIGH); delay(800); @@ -219,7 +230,8 @@ void testMode() } else { - while (1) + Serial.println("----> Selftest failed!"); + while (1) // Blink FAILED pattern! Rappidly blinking.. { digitalWrite(LED_PIN, HIGH); delay(200); From 9b41d2a8e65e4f076e5c8ea5920fa010beda8c1e Mon Sep 17 00:00:00 2001 From: tekka Date: Sat, 14 Mar 2015 13:46:24 +0100 Subject: [PATCH 10/24] MYSBootloader 1.1 Enhancements: static parent, bootloader commands, updated delay funtion for more precise timing and minor improvements --- MYSBootloader/MYSBootloader.c | 209 ++++---- MYSBootloader/MYSBootloader.h | 20 +- MYSBootloader/MYSBootloader.hex | 241 +++++---- MYSBootloader/MYSBootloaderHW.h | 47 +- MYSBootloader/MYSBootloaderRF24.h | 56 +- MYSBootloader/boot.h | 848 ++++++++++++++++++++++++++++++ 6 files changed, 1149 insertions(+), 272 deletions(-) create mode 100644 MYSBootloader/boot.h diff --git a/MYSBootloader/MYSBootloader.c b/MYSBootloader/MYSBootloader.c index 462d99c..1efd459 100644 --- a/MYSBootloader/MYSBootloader.c +++ b/MYSBootloader/MYSBootloader.c @@ -1,17 +1,15 @@ /* MYSBootloader: OTA bootloader for Mysensor nodes (www.mysensors.org) - Code based on OTA bootloader by ToSa + Original OTA bootloader code by ToSa Optimized and extended by tekka - Version 1.0 / 20150206 - Size: 1834 bytes + Version 1.1 / 20150314 + Size: 2002 bytes - Tested with Atmega328P, 16Mhz 3.3V and 5V and MYSController 0.1.2.266 (goo.gl/9DCWNo) + Tested with MYSController 0.1.2.276 (goo.gl/9DCWNo) - MCU: atmega328 - clock: 16Mhz (prescaler: off/1) + MCU: Atmega328p bootsz: 1024W - fuses for ISP: EX = 0xFE (use 0x06 for Arduino IDE, boards.txt) HI = 0xDA @@ -23,9 +21,20 @@ Successfully tested with: - 16Mhz extXTAL, 3.3V - 1Mhz intRC (8Mhz + DIV8), 3.3V - 128kHz intRC, 3.3V + 16Mhz extXTAL, 3.3V & 5V + 8Mhz intRC, 3.3V & 5V + 1Mhz intRC, 3.3 & 5V + 128kHz intRC, 3.3V & 5V + + * Version 1.1 + - use eeprom_update instead of eeprom_write to reduce wear out + - bootloader commands: erase eeprom, set node id + - verify incoming FW blocks for type & address + - communicate over static parent (if set and found) else broadcast to find nearest node + - adjusted timings + + * Version 1.0 + Initial release This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -36,45 +45,63 @@ #define MYSBOOTLOADER_MAJVER 1 -#define MYSBOOTLOADER_MINVER 0 +#define MYSBOOTLOADER_MINVER 1 #define MYSBOOTLOADER_VERSION (MYSBOOTLOADER_MINVER * 256 + MYSBOOTLOADER_MAJVER) -//#define USE_PRESCALER #define MAX_RESEND 5 // procedures and functions -int main(void) __attribute__ ((OS_main)) __attribute__ ((section (".init9"))); +static void programPage(uint16_t page, uint8_t *buf); static uint16_t calcCRCrom (const void* ptr, uint16_t len); static uint8_t IsFirmwareValid(); static void reboot(); static void startup(); -static void programPage(uint32_t page, uint8_t *buf); static boolean sendWrite(MyMessage message); static bool sendAndWait(uint8_t reqType, uint8_t resType); +int main(void) __attribute__ ((OS_main)) __attribute__ ((section (".init9"))); + + +static void programPage(uint16_t page, uint8_t *buf) { + // these function calls use "out" commands: save some bytes and cycles :) + __boot_page_erase_short(page); + boot_spm_busy_wait(); + for (uint16_t i = 0; i < SPM_PAGESIZE; i += 2) { + uint16_t data_word = *buf++; + data_word += (*buf++) << 8; + __boot_page_fill_short(page + i, data_word); + } + __boot_page_write_short(page); + boot_spm_busy_wait(); + __boot_rww_enable_short(); +} + static uint16_t calcCRCrom (const void* ptr, uint16_t len) { // init 0xFFFF uint16_t crc = ~0; - for (uint16_t i = 0; i < len; ++i) { + for (uint16_t i = 0; i < len; i++) { crc = _crc16_update(crc, pgm_read_byte((uint16_t) ptr + i)); } return crc; } + static uint8_t IsFirmwareValid () { return calcCRCrom(0, fc.blocks * FIRMWARE_BLOCK_SIZE) == fc.crc; } + + static void reboot() { - // any pending eeprom activities? + // wait for pending eeprom activities eeprom_busy_wait(); // trigger watchdog ASAP watchdogConfig(WATCHDOG_16MS); - // wait until WD triggers + // endless loop while (1); } @@ -82,13 +109,7 @@ static void startup() { if (IsFirmwareValid()) { // WD off watchdogConfig(WATCHDOG_OFF); - - #ifdef USE_PRESCALER - // reset prescaler - clock_prescale_set(orgClockDiv); - #endif - - // start sketch + // run sketch ((void(*)()) 0)(); } else { @@ -96,20 +117,7 @@ static void startup() { } } -static void programPage(uint32_t page, uint8_t *buf) { - // using out commands, saves some bytes :) - __boot_page_erase_short(page); - boot_spm_busy_wait(); - for (uint16_t i = 0; i < SPM_PAGESIZE; i += 2) { - uint16_t w = *buf++; - // generate word - w += (*buf++) << 8; - __boot_page_fill_short(page + i, w); - } - __boot_page_write_short(page); - boot_spm_busy_wait(); - __boot_rww_enable_short(); -} + static boolean sendWrite(MyMessage message) { @@ -121,38 +129,45 @@ static bool sendAndWait(uint8_t reqType, uint8_t resType) { // outer loop, retries for (uint8_t i = 0; i < MAX_RESEND; i++) { sendWrite(outMsg); - // loop 20 times, wait time 0.1ms if no/wrong data => 2s + // loop 20 times, wait time 0.1s if no/wrong data => 2s for (uint8_t j = 0; j < 20; j++) { // loop 100 times, wait 1ms if no/wrong data => 0.1s for (uint8_t k = 0; k < 100; k++) { watchdogReset(); // Tx FIFO data available? (we don't care about the pipe here) if (available(NULL)) { - // read message from FIFO - readMessage(inMsg.array); - // protocol compatible? if not ignore msg - if ((mGetVersion(inMsg) != PROTOCOL_VERSION)) { - continue; - } - if (inMsg.destination == nc.nodeId) { - // msg for us - if ((mGetCommand(inMsg) == C_INTERNAL) && (inMsg.type == I_FIND_PARENT_RESPONSE)) { - if (inMsg.bValue < nc.distance - 1) { - // got new routing info, update settings - nc.distance = inMsg.bValue + 1; - nc.parentNodeId = inMsg.sender; + // read message from FIFO, skip if size = 0 + if (readMessage(inMsg.array) > 0) { + // protocol compatible? if not ignore msg + if ((mGetVersion(inMsg) != PROTOCOL_VERSION)) { + continue; + } + // msg for us? + if (inMsg.destination == nc.nodeId) { + // internal command: find parent + if ((mGetCommand(inMsg) == C_INTERNAL) && (inMsg.type == I_FIND_PARENT_RESPONSE)) { + // static parent found? + if (configuredParentID == inMsg.sender) { + configuredParentFound = true; + } + if ( ((inMsg.bValue < nc.distance - 1) && ( !configuredParentFound) ) || (configuredParentID == inMsg.sender)) { + // got new routing info, update settings + nc.distance = inMsg.bValue + 1; + nc.parentNodeId = inMsg.sender; + } + } + // did we receive expected reply? + if ((mGetCommand(inMsg) == mGetCommand(outMsg)) && (inMsg.type == resType)) { + return true; } - } - // did we receive expected reply? - if ((mGetCommand(inMsg) == mGetCommand(outMsg)) && (inMsg.type == resType)) { - return true; - } + } } - } else { + } else { // wait 1ms if no data available - delaym(10); + _delay_ms(1); } + } } } @@ -169,13 +184,6 @@ int main(void) { // reset MCU status register MCUSR = 0; - #ifdef USE_PRESCALER - // get current prescale - orgClockDiv = clock_prescale_get(); - //switch to 4 MHz on 16Mhz crystal - clock_prescale_set(F_CPU_DIV); - #endif - // enable watchdog to avoid deadlock watchdogConfig(WATCHDOG_8S); @@ -190,11 +198,10 @@ int main(void) { // Read firmware config from EEPROM, i.e. type, version, CRC, blocks eeprom_read_block((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); - // bootloader should find closest node during each reboot - - // invalidate parent node settings, since we have to re-discover them for every single reboot + // find nearest node during reboot: invalidate parent node settings, since we have to re-discover them for every single reboot + configuredParentID = nc.parentNodeId; + // nc.parentNodeId = 0xFF; nc.distance = 0xFF; - nc.parentNodeId = 0xFF; // prepare for I_FIND_PARENTS outMsg.sender = nc.nodeId; @@ -202,6 +209,7 @@ int main(void) { outMsg.sensor = 0xFF; outMsg.destination = BROADCAST_ADDRESS; + // set header mSetVersion(outMsg, PROTOCOL_VERSION); mSetLength(outMsg, 0); mSetCommand(outMsg, C_INTERNAL); @@ -211,7 +219,7 @@ int main(void) { // set reading & writing pipe address setAddress(nc.nodeId); - // network up?, get neighbors, else startup + // network up? get neighbors, else startup if (!sendAndWait(I_FIND_PARENT, I_FIND_PARENT_RESPONSE)) { startup(); } @@ -225,9 +233,9 @@ int main(void) { openReadingPipe(CURRENT_NODE_PIPE, TO_ADDR(BROADCAST_ADDRESS)); if (sendAndWait(I_ID_REQUEST, I_ID_RESPONSE)) { // save id to eeprom - eeprom_write_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, atoi(inMsg.data)); + eeprom_update_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, atoi(inMsg.data)); } - // we could go on and set everything right here, but rebooting will take care of that - saves bytes :) + // we could go on and set everything right here, but rebooting will take care of that - and saves some bytes :) reboot(); } @@ -250,6 +258,23 @@ int main(void) { NodeFirmwareConfig *firmwareConfigResponse = (NodeFirmwareConfig *)inMsg.data; + // bootloader commands + if (firmwareConfigResponse->blocks == 0) { + // verify flag + if (firmwareConfigResponse->crc == 0xDA7A){ + // cmd 0x01 clear eeprom + if(firmwareConfigResponse->bl_command == 0x01) { + for(uint16_t i = 0; i < EEPROM_SIZE; i++) eeprom_update_byte((uint8_t *)i,0xFF); + } else + // cmd 0x02 set id + if(firmwareConfigResponse->bl_command == 0x02) { + eeprom_update_byte((uint8_t*)EEPROM_NODE_ID_ADDRESS, (uint8_t)firmwareConfigResponse->bl_data); + } + } + // final step + reboot(); + } + // compare with current node configuration, if equal startup if (!memcmp(&fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig))) { startup(); @@ -260,7 +285,7 @@ int main(void) { // invalidate current CRC fc.crc = 0xFFFF; // write fetched type and version in case OTA fails (BL will reboot and re-request FW with stored settings) - eeprom_write_block(&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS,sizeof(NodeFirmwareConfig)); + eeprom_update_block(&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS,sizeof(NodeFirmwareConfig)); // copy new FW config memcpy(&fc,firmwareConfigResponse,sizeof(NodeFirmwareConfig)); @@ -270,33 +295,39 @@ int main(void) { firmwareRequest->type = fc.type; firmwareRequest->version = fc.version; - // request FW from controller - for (uint16_t block = fc.blocks; block > 0; block--) { - firmwareRequest->block = (block - 1); + // request FW from controller, load FW counting backwards + uint16_t block = fc.blocks; + do { + firmwareRequest->block = block - 1; + // request FW block if (!sendAndWait(ST_FIRMWARE_REQUEST, ST_FIRMWARE_RESPONSE)) { reboot(); } ReplyFWBlock *firmwareResponse = (ReplyFWBlock *)inMsg.data; - // calculate page offset - uint8_t offset = ((block - 1) * FIRMWARE_BLOCK_SIZE) % SPM_PAGESIZE; - // write to buffer - memcpy(progBuf + offset, firmwareResponse->data, FIRMWARE_BLOCK_SIZE); - // program if page full - if (offset == 0) { - programPage(((block - 1) * FIRMWARE_BLOCK_SIZE), progBuf); - } - } - + + // did we receive requested block? + if (!memcmp(firmwareRequest,firmwareResponse,sizeof(RequestFWBlock))) { + // calculate page offset + uint8_t offset = ((block - 1) * FIRMWARE_BLOCK_SIZE) % SPM_PAGESIZE; + // write to buffer + memcpy(progBuf + offset, firmwareResponse->data, FIRMWARE_BLOCK_SIZE); + // program if page full + if (offset == 0) { + programPage(((block - 1) * FIRMWARE_BLOCK_SIZE), progBuf); + } + block--; + } + } while (block); + // wuff watchdogReset(); // all blocks transmitted, calc CRC and write to eeprom if valid if (IsFirmwareValid()) { // if FW is valid, write settings to eeprom - eeprom_write_block((void*)&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); - // we could restart directly here, but eeprom may still be busy, thus reboot (we check for idle eeprom before rebooting) and save some bytes :) + eeprom_update_block(&fc, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS, sizeof(NodeFirmwareConfig)); } // final step reboot(); diff --git a/MYSBootloader/MYSBootloader.h b/MYSBootloader/MYSBootloader.h index 10c48d8..1f66faf 100644 --- a/MYSBootloader/MYSBootloader.h +++ b/MYSBootloader/MYSBootloader.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "MyMessage.h" #include "MySensor.h" @@ -13,11 +14,17 @@ #define FIRMWARE_BLOCK_SIZE 16 +#define EEPROM_SIZE 1024 // 1024 bytes for ATMEGA328 -// FW config structure, stored in eeprom typedef struct { - uint16_t type; - uint16_t version; + union { + uint16_t type; + uint16_t bl_command; + }; + union { + uint16_t version; + uint16_t bl_data + }; uint16_t blocks; uint16_t crc; } __attribute__((packed)) NodeFirmwareConfig; @@ -48,9 +55,10 @@ static NodeFirmwareConfig fc; static MyMessage outMsg; static MyMessage inMsg; -#ifdef PRESCALE -static clock_div_t orgClockDiv = 0; -#endif +static boolean configuredParentFound = false; +static uint8_t configuredParentID = 0xFF; + +//static clock_div_t orgClockDiv = 0; static uint8_t progBuf[SPM_PAGESIZE]; diff --git a/MYSBootloader/MYSBootloader.hex b/MYSBootloader/MYSBootloader.hex index 7039c3b..8095224 100644 --- a/MYSBootloader/MYSBootloader.hex +++ b/MYSBootloader/MYSBootloader.hex @@ -1,117 +1,128 @@ -:1078000021E0A0E0B1E001C01D92A53DB207E1F783 -:10781000CDB7DEB76897DEBFCDBF112414BE88E1B7 -:107820008093600089E2809360008FEE84B963E00A -:1078300083E201D26FE584E2FED16BE381E2FBD10A -:107840006CE485E2F8D167E286E2F5D10DD263E718 -:1078500080E5F1D166E08DE3EED16FE38CE3EBD10F -:107860006EEF80E2E8D185E053D143E050E060E084 -:1078700070E08AEC91E032D348E050E06BE171E0D7 -:1078800082EC91E02BD38FEF8093CC018093CB01DE -:107890002091CA012093A2012093A1018093A70106 -:1078A0008093A30182E08093A4018091A501887058 -:1078B00083608093A5012F3FD1F130E040E050E09C -:1078C00060E070E080E090E034504E4157456745FD -:1078D0007F4F8F4F9F4F29013A014B015C01298B4C -:1078E0005A8A4B8B7C8A6D8B9E8A8F8BB88E85E0F3 -:1078F000FE017196ADECB1E001900D928A95E1F731 -:1079000045E0BE016F5E7F4F8AE27FD149865A868D -:107910006B867C868D869E86AF86B88A45E0BE01E2 -:10792000675F7F4F8BE271D163E082E284D168E0D0 -:1079300087E09FD1811101C049D11092A3018091AC -:10794000CA018F3FF1F489838CEF8A8381EE8B83A8 -:1079500088EA8C838D831E821F82188645E0BE01D3 -:107960006F5F7F4F8BE251D164E083E082D1882347 -:1079700039F087E891E080D2682F80E090E0C7D2AC -:107980001CD1A8958091A401877080658093A40183 -:107990008091A5018871846C8093A50188E0E2EC58 -:1079A000F1E0A8EAB1E001900D928A95E1F781E05B -:1079B00090E09093B1018093B00161E080E059D1F3 -:1079C000811101C003D148E050E067E871E082EC2A -:1079D00091E06FD2892B09F4F9D08FEF9FEF90934C -:1079E000C9018093C80148E050E06BE171E082EC8E -:1079F00091E084D288E0E7E8F1E0A2ECB1E0019008 -:107A00000D928A95E1F78091A4018770806380933D -:107A1000A4018091C2019091C3019093A901809328 -:107A2000A8018091C4019091C5019093AB0180930E -:107A3000AA01A090C601B090C70185010150104F66 -:107A400064E0000F111F6A95E1F770E1972E88241A -:107A50008394E5E07E2EF1E16F2EA114B10409F4C8 -:107A60004AC081E0A81AB108B092AD01A092AC0161 -:107A700063E082E0FED0882309F482CF802F8077F4 -:107A8000A82FB0E0A050BF4FEDE8F1E0992D019094 -:107A90000D929A95E1F781112BC083E0F80187BF21 -:107AA000E89507B600FCFDCF4091000180E090E032 -:107AB000DC01A050BF4FFC01E00FF11F11962C918B -:107AC000119730E0322F2227240F311D090187BE84 -:107AD000E895112412964C9102968038910541F751 -:107AE000F80177BEE89507B600FCFDCF67BEE895C4 -:107AF00000511109B2CFA8952CD0882309F440CFAA -:107B000048E050E06BE171E082EC91E0F7D138CFD2 -:107B100090E0981751F02DE730E000002150310936 -:107B200021153105D1F79F5FF4CF089598E087FFC5 -:107B300002C02B9A01C02B9800002D9A000023B19F -:107B4000880F22952170822B2D980000915079F793 -:107B500008958091C6019091C70124E0880F991F74 -:107B60002A95E1F7E0E0F0E02FEF3FEFE817F907A3 -:107B7000D1F044912427422F42954227042E469566 -:107B800046954025042E469540254770022E232F0A -:107B9000469507944795302D242706944795302520 -:107BA00024273196E3CF81E04091C8015091C9016B -:107BB0002417350709F080E00895F999FECF88E190 -:107BC0008093600088E080936000FFCFC2DF88234D -:107BD00041F088E18093600010926000E0E0F0E006 -:107BE0000994EBDF1F93CF93DF93EB01142F2A98B7 -:107BF0009DDF1C0F1C1721F08FEF98DF8993FACFC0 -:107C00002A9ADF91CF911F9108951F93CF93DF930D -:107C1000EB01142F2A988ADF1C0F1C1719F0899189 -:107C200085DFFBCF2A9ADF91CF911F91089541E024 -:107C300060E070E0D7CFCF93DF931F92CDB7DEB770 -:107C4000698341E0BE016F5F7F4FDFDF0F90DF91FF -:107C5000CF91089540E060E070E082EED6CF40E042 -:107C600060E070E081EED1CFF5DFF9DF60E787E219 -:107C7000E2CF6F927F928F929F92AF92BF92CF92FC -:107C8000DF92EF92FF920F931F93CF93DF93CDB7C5 -:107C9000DEB7AA97DEBFCDBF762E8093A60105E0A2 -:107CA00041E2642EE1EAF1E0DE011196862D0190B9 -:107CB0000D928A95E1F7FB801C8116951695169515 -:107CC000195F2091CB0129982AA7CEDF6EEF80E2C1 -:107CD000B2DF2AA530E040E050E060E070E080E0F4 -:107CE00090E034504E41574567457F4F8F4F9F4F2F -:107CF0002AA33BA34CA35DA36EA37FA388A799A748 -:107D000045E0BE016E5D7F4F8AE27FDF45E0BE0148 -:107D10006E5D7F4F80E379DF8FEFF81202C080EB5A -:107D200001C080EA412FBE016F5F7F4F6EDF299A4D -:107D300081E0EEDE299840E060E070E08FEF52DFF6 -:107D40008073C9F360E787E276DF84FD88DF6FE048 -:107D500080E271DF89DF8090CD019090CE01A0900C -:107D6000CF01B090D001C090D101D090D201E0906D -:107D7000D301F090D4019401A501B601C701A0E0A0 -:107D80006FD029F045E06DEC71E08AE23EDF299A80 -:107D900014E134E6F32EA89587E149DF80FD4BC05E -:107DA00080E645DF813210F055DF80E0482F60E843 -:107DB00071E081E617DF60E787E23DDF80918301B4 -:107DC0008770823059F5909182018091CA01981391 -:107DD00025C040918401842F87708330B1F4809155 -:107DE0008501883091F450918701252F30E08091F2 -:107DF000CC0190E00197281739073CF45F5F50935E -:107E0000CC01809181018093CB018091A5018427D1 -:107E1000877021F480918501871559F0FA9409F053 -:107E2000BACF115009F0B5CF015009F03BCF80E037 -:107E300005C081E003C08AE06BDEF0CFAA96DEBF0A -:107E4000CDBFDF91CF911F910F91FF90EF90DF9009 -:107E5000CF90BF90AF909F908F907F906F9008953C -:107E60000024A7FD00942A17300540055005600541 -:107E70007005800590050895FC0188279927E894EE -:107E800021912032E9F3293010F02E30C8F32B3243 -:107E900039F02D3231F4689403C018D0820F911D4F -:107EA000219120532A30C8F31EF4909581959F4F5D -:107EB0000895FB01DC0104C08D910190801921F42B -:107EC00041505040C8F7881B990B08957AE0979F5E -:107ED000902D879F802D910D11240895DC01CB01F9 -:107EE000FC01F999FECF06C0F2BDE1BDF89A3196CA -:107EF00000B40D9241505040B8F70895DC01CB0119 -:107F000002C02D9105D041505040D8F70895262F3A -:107F1000F999FECF1FBA92BD81BD20BD0FB6F8946E -:0A7F2000FA9AF99A0FBE019608952F +:1078000011E0A0E0B1E0E0EDFFE702C005900D92CD +:10781000A230B107D9F721E0A2E0B1E001C01D928A +:10782000A83DB207E1F7CDB7DEB76897DEBFCDBFA1 +:10783000112414BE88E18093600089E28093600087 +:107840008FEE84B963E083E2D9D16FE584E2D6D1CB +:107850006BE381E2D3D16CE485E2D0D167E286E2CA +:10786000CDD12ED263E780E5C9D166E08DE3C6D1E4 +:107870006FE38CE3C3D16EEF80E2C0D18FE19EE471 +:107880000197F1F700C0000043E050E060E070E0D5 +:107890008DEC91E06CD348E050E06BE171E085EC59 +:1078A00091E065D38091CE01809300018FEF8093AA +:1078B000CF012091CD012093A5012093A4018093B5 +:1078C000AA018093A60182E08093A7018091A8017C +:1078D000887083608093A8012F3FD1F130E040E0B1 +:1078E00050E060E070E080E090E034504E41574559 +:1078F00067457F4F8F4F9F4F29013A014B015C0134 +:10790000298B5A8A4B8B7C8A6D8B9E8A8F8BB88E83 +:1079100085E0FE017196A0EDB1E001900D928A958F +:10792000E1F745E0BE016F5E7F4F8AE255D149869F +:107930005A866B867C868D869E86AF86B88A45E0A1 +:10794000BE01675F7F4F8BE247D163E082E256D191 +:1079500068E087E0BAD1811101C09CD11092A601E4 +:107960008091CD018F3FF1F489838CEF8A8381EE82 +:107970008B8388EA8C838D831E821F82188645E064 +:10798000BE016F5F7F4F8BE227D164E083E09DD122 +:10799000882339F08AE891E0B8D2682F80E090E03F +:1079A00005D36FD1A8958091A701877080658093DA +:1079B000A7018091A8018871846C8093A80188E058 +:1079C000E5ECF1E0ABEAB1E001900D928A95E1F7C8 +:1079D00081E091E09093B4018093B30161E080E095 +:1079E00074D1811101C056D180918E0190918F0187 +:1079F000892B09F580919001909191018A379A4DD8 +:107A000081F680918A0190918B018130910569F412 +:107A1000A12CB12C6FEFC501C9D2FFEFAF1ABF0A7D +:107A2000A11424E0B206B1F7BCCF029709F0B9CF98 +:107A300060918C01B3CF48E050E06AE871E085ECDA +:107A400091E080D2892B09F425D18FEF9FEF90939D +:107A5000CC018093CB0148E050E06BE171E085EC14 +:107A600091E095D288E0EAE8F1E0A5ECB1E0019080 +:107A70000D928A95E1F78091A701877080638093CA +:107A8000A7018091C5019091C6019093AC018093AC +:107A9000AB018091C7019091C8019093AE01809392 +:107AA000AD01A090C901B090CA0110E101E0E5E08C +:107AB0007E2EF1E16F2E450181E0881A91089092A7 +:107AC000B0018092AF0163E082E0FFD0882309F427 +:107AD00068CF46E050E06AE871E08BEA91E032D28C +:107AE000892B09F045C091E0A91A90EFB90A8A2DB7 +:107AF00082958077A82FB0E0AE5FBE4FE0E9F1E05D +:107B0000912F01900D929A95E1F7811130C074E0A8 +:107B1000AA0CBB1C7A95E1F783E0F50187BFE895D5 +:107B200007B600FCFDCF4091020180E090E0DC014F +:107B3000AE5FBE4FFC01EA0DFB1D11962C91119713 +:107B400030E0322F2227240F311D090107BFE895AD +:107B5000112412964C9102968038910541F7F50157 +:107B600077BEE89507B600FCFDCF67BEE8955401E7 +:107B7000A114B10409F09FCFA8954FD0882309F430 +:107B800010CF48E050E06BE171E085EC91E0FFD16F +:107B900008CF98E087FF02C02B9A01C02B982D9A3E +:107BA00023B1880F22952170822B2D98915091F747 +:107BB00008951F93CF93DF93EB01142F2A98E9DFE9 +:107BC0001C0F1C1721F08FEFE4DF8993FACF2A9A5C +:107BD000DF91CF911F9108951F93CF93DF93EB0116 +:107BE000142F2A98D6DF1C0F1C1719F08991D1DFAA +:107BF000FBCF2A9ADF91CF911F910895CF93DF9306 +:107C00001F92CDB7DEB7698341E0BE016F5F7F4F42 +:107C1000E3DF0F90DF91CF9108958091C90190919A +:107C2000CA0124E0880F991F2A95E1F7E0E0F0E00F +:107C30002FEF3FEFE817F907D1F044912427422FA7 +:107C400042954227042E469546954025042E46959A +:107C500040254770022E232F469507944795302DD7 +:107C6000242706944795302524273196E3CF81E0D9 +:107C70004091CB015091CC012417350709F080E0E9 +:107C80000895F999FECF88E18093600088E08093A1 +:107C90006000FFCFC2DF882341F088E1809360005D +:107CA00010926000E0E0F0E00994EBDF40E060E07B +:107CB00070E082EE91CF40E060E070E081EE8CCF2A +:107CC000F5DFF9DF60E787E299CF6F927F928F92BD +:107CD0009F92AF92BF92CF92DF92EF92FF920F935B +:107CE0001F93CF93DF93CDB7DEB7AA97DEBFCDBF8B +:107CF000762E8093A90105E051E2652EE4EAF1E0D9 +:107D0000DE011196862D01900D928A95E1F7FB8098 +:107D10001C81169516951695195F2091CE0129980C +:107D20002AA7CEDF6EEF80E269DF2AA530E040E0CF +:107D300050E060E070E080E090E034504E41574504 +:107D400067457F4F8F4F9F4F2AA33BA34CA35DA353 +:107D50006EA37FA388A799A745E0BE016E5D7F4F04 +:107D60008AE23ADF45E0BE016E5D7F4F80E334DF9B +:107D70008FEFF81202C080EB01C080EA412FBE01F4 +:107D80006F5F7F4F29DF299A9AE69A95F1F700C035 +:107D9000299840E060E070E08FEF0BDF8073C9F35B +:107DA00060E787E22BDF84FD86DF6FE080E226DF7D +:107DB00087DF8090D0019090D101A090D201B09047 +:107DC000D301C090D401D090D501E090D601F090BD +:107DD000D7019401A501B601C701A0E08AD029F01E +:107DE00045E060ED71E08AE2F7DE299A44E1E42E95 +:107DF00034E6F32EA89541E060E070E087E1D9DE3B +:107E000080FD5EC041E060E070E080E6D2DE182FC9 +:107E1000813210F04BDF10E0412F63E871E081E622 +:107E2000C8DE60E787E2EADE1123E9F1809186018E +:107E300087708230C1F5909185018091CD019813B2 +:107E400032C050918701852F8770833019F580915A +:107E500088018830F9F47091000140918401741315 +:107E600003C081E08093820160918A01262F30E077 +:107E70008091CF0190E001972817390724F4809171 +:107E80008201882311F0741305C06F5F6093CF01E6 +:107E90004093CE018091A8018527877021F48091BD +:107EA0008801871559F0FA9409F0A4CFEA9409F0F3 +:107EB0009FCF015009F022CF80E009C081E007C0C8 +:107EC0008FE99FE00197F1F700C00000ECCFAA9680 +:107ED000DEBFCDBFDF91CF911F910F91FF90EF904B +:107EE000DF90CF90BF90AF909F908F907F906F90DA +:107EF00008950024A7FD00942A1730054005500579 +:107F000060057005800590050895FC018827992774 +:107F1000E89421912032E9F3293010F02E30C8F393 +:107F20002B3239F02D3231F4689403C018D0820F0F +:107F3000911D219120532A30C8F31EF4909581950C +:107F40009F4F0895FB01DC0104C08D9101908019C1 +:107F500021F441505040C8F7881B990B08957AE0EE +:107F6000979F902D879F802D910D11240895DC01FE +:107F7000CB01FC01F999FECF06C0F2BDE1BDF89A34 +:107F8000319600B40D9241505040B8F70895DC018D +:107F9000A40FB51F4150504040F0CB01840F951FF6 +:107FA0002E9105D041505040D8F70895262FF999C9 +:107FB000FECF92BD81BDF89A019700B4021639F048 +:107FC0001FBA20BD0FB6F894FA9AF99A0FBE089519 +:027FD000FF00B0 :040000030000780081 :00000001FF diff --git a/MYSBootloader/MYSBootloaderHW.h b/MYSBootloader/MYSBootloaderHW.h index 8769ce1..d62b543 100644 --- a/MYSBootloader/MYSBootloaderHW.h +++ b/MYSBootloader/MYSBootloaderHW.h @@ -5,18 +5,10 @@ // hardware - - -#ifdef USE_PRESCALER #define F_CPU_DIV clock_div_4 -#else -#define F_CPU_DIV clock_div_1 -#endif - -#define F_CPU_REAL F_CPU / (1 << F_CPU_DIV) -#define DELAY_M 125 * (1 << F_CPU_DIV) -#define BAUD_SETTING (( (F_CPU + BAUD_RATE * 4L) / ((BAUD_RATE * 8L))) - 1 ) -#define BAUD_ACTUAL (F_CPU/(8 * ((BAUD_SETTING)+1))) +#define F_CPU_REAL F_CPU / (F_CPU_DIV) +#define BAUD_SETTING (( (F_CPU_REAL + BAUD_RATE * 4L) / ((BAUD_RATE * 8L))) - 1 ) +#define BAUD_ACTUAL (F_CPU_REAL/(8 * ((BAUD_SETTING)+1))) #define BAUD_ERROR (( 100*(BAUD_RATE - BAUD_ACTUAL) ) / BAUD_RATE) #define UART_SRA UCSR0A #define UART_SRB UCSR0B @@ -56,20 +48,6 @@ void watchdogConfig(uint8_t x) { WDTCSR = x; } -// delay procedures - -inline static void delayu() { - asm volatile ("nop"); -} - -static void delaym(uint8_t value) { - for (uint8_t outer = 0; outer < value; outer++) { - for (uint16_t inner = 0; inner < DELAY_M; inner++) { - delayu(); - } - } -} - // SPI communication #define SPI_DDR DDRB @@ -80,10 +58,12 @@ static void delaym(uint8_t value) { #define SPI_MOSI 3 // Arduino Pin 11 <-> Bit 3 of port B #define SPI_CSN 2 // Arduino Pin 10 <-> Bit 2 of port B #define SPI_CE 1 // Arduino Pin 9 <-> Bit 1 of port B -#define csnlow() SPI_PORT &= ~_BV(SPI_CSN)//;delaym(1) // not necessary -#define csnhigh() SPI_PORT |= _BV(SPI_CSN)//;delaym(1) // not necessary -#define celow() SPI_PORT &= ~_BV(SPI_CE)//;delaym(1) // not necessary -#define cehigh() SPI_PORT |= _BV(SPI_CE)//;delaym(1) // minimum puls width 10us +#define CE_PULSE_LENGTH 20 // IMPORTANT: minimum CE pulse width 10us, see nRF24L01 specs. Set 20us to be on the safe side + +#define csnlow() SPI_PORT &= ~_BV(SPI_CSN) +#define csnhigh() SPI_PORT |= _BV(SPI_CSN) +#define celow() SPI_PORT &= ~_BV(SPI_CE) +#define cehigh() SPI_PORT |= _BV(SPI_CE) static void SPIinit() { // set pin mode: MOSI,SCLK,CE = OUTPUT, MISO = INPUT @@ -91,15 +71,16 @@ static void SPIinit() { } static uint8_t SPItransfer(uint8_t value) { - for(uint8_t i = 0 ;i < 8;i++) { + // bit bang SPI + for(uint8_t i = 0; i<8; i++) { if (value & 0x80) SPI_PORT |= _BV(SPI_MOSI); else SPI_PORT &= ~_BV(SPI_MOSI); - delayu(); + //_delay_us(1); value <<= 1; SPI_PORT |= _BV(SPI_SCLK); - delayu(); + //_delay_us(1); value |= ((SPI_PIN >> SPI_MISO) & 0x01); SPI_PORT &= ~_BV(SPI_SCLK); - delayu(); + //_delay_us(1); } return value; } diff --git a/MYSBootloader/MYSBootloaderRF24.h b/MYSBootloader/MYSBootloaderRF24.h index c91f902..c290527 100644 --- a/MYSBootloader/MYSBootloaderRF24.h +++ b/MYSBootloader/MYSBootloaderRF24.h @@ -9,12 +9,11 @@ typedef enum { RF24_1MBPS = 0, RF24_2MBPS, RF24_250KBPS } rf24_datarate_e; #define _write_register(reg) ( (reg) | W_REGISTER) #define _read_register(reg) ( (reg) | R_REGISTER) - #define addr_width 5 + uint64_t pipe0_reading_address = 0; - -uint8_t BurstReadAddress(uint8_t addr, uint8_t* buf, uint8_t len) { +static uint8_t BurstReadAddress(uint8_t addr, uint8_t* buf, uint8_t len) { csnlow(); uint8_t status = SPItransfer( addr ); while ( len-- ) { @@ -25,7 +24,7 @@ uint8_t BurstReadAddress(uint8_t addr, uint8_t* buf, uint8_t len) { return status; } -uint8_t BurstWriteAddress(uint8_t addr, uint8_t* buf, uint8_t len) { +static uint8_t BurstWriteAddress(uint8_t addr, uint8_t* buf, uint8_t len) { csnlow(); uint8_t status = SPItransfer( addr ); while ( len-- ) { @@ -35,30 +34,30 @@ uint8_t BurstWriteAddress(uint8_t addr, uint8_t* buf, uint8_t len) { return status; } -uint8_t ReadAddress(uint8_t addr) { +static uint8_t ReadAddress(uint8_t addr) { return BurstReadAddress(addr,NULL,1); } -uint8_t WriteAddress(uint8_t addr, uint8_t val) { +static uint8_t WriteAddress(uint8_t addr, uint8_t val) { return BurstWriteAddress(addr,&val,1); } -#define BurstWriteRegister(reg,buf,len) BurstWriteAddress(_write_register(reg),buf,len) -#define WriteRegister(reg,val) WriteAddress(_write_register(reg),val) -#define BurstReadRegister(reg,buf,len) BurstReadAddress(_read_register(reg),buf,len) +#define BurstWriteRegister(reg,buf,len) BurstWriteAddress(_write_register(reg), buf, len) +#define WriteRegister(reg,val) WriteAddress(_write_register(reg), val) +#define BurstReadRegister(reg,buf,len) BurstReadAddress(_read_register(reg), buf, len) #define ReadRegister(reg) ReadAddress(_read_register(reg)) -#define get_status() BurstReadAddress(NOP,NULL,0) +#define get_status() BurstReadAddress(NOP, NULL, 0) void Flush_RX(void) { - BurstWriteAddress(FLUSH_RX,NULL,0); + BurstWriteAddress(FLUSH_RX, NULL, 0); } void Flush_TX(void) { - BurstWriteAddress(FLUSH_TX,NULL,0); + BurstWriteAddress(FLUSH_TX, NULL, 0); } -void Flush_RXTX_CLI(void) { +static void Flush_RXTX_CLI(void) { // flush RX and TX buffer Flush_RX(); Flush_TX(); @@ -86,18 +85,18 @@ static void stopListening(void) { -static bool write_buf(uint8_t* buf, uint8_t len, const bool multicast ) { +static boolean write_buf(uint8_t* buf, uint8_t len, const bool multicast ) { // write payload to FIFO BurstWriteRegister( multicast ? W_TX_PAYLOAD_NO_ACK : W_TX_PAYLOAD, buf, len) ; // CE pulse to start transmission cehigh(); // IMPORTANT: minimum CE pulse width 10us, see nRF24L01 specs - delaym(1); + _delay_us(CE_PULSE_LENGTH); // start transmitting celow(); - // wait until sent, here we potentially have a deadlock when transmitter not connected/not working + // wait until sent or ACKed, here we potentially have a deadlock when transmitter not connected/not working => wdt recovers while( ! ( get_status() & ( _BV(TX_DS) | _BV(MAX_RT) ))) { } // read interrupts and clear uint8_t status = WriteRegister(STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) ); @@ -119,7 +118,7 @@ static uint8_t getDynamicPayloadSize(void) { } -static bool available(uint8_t* pipe_num) { +static boolean available(uint8_t* pipe_num) { if (!(ReadAddress(FIFO_STATUS) & _BV(RX_EMPTY) )){ if (pipe_num) { uint8_t status = get_status(); @@ -131,11 +130,13 @@ static bool available(uint8_t* pipe_num) { } -static void readMessage(uint8_t* buf) { +static uint8_t readMessage(uint8_t* buf) { // read payload - BurstReadRegister(R_RX_PAYLOAD,buf,getDynamicPayloadSize()); + uint8_t PL_LEN = getDynamicPayloadSize(); + BurstReadRegister(R_RX_PAYLOAD,buf,PL_LEN); // reset interrupts - WriteRegister(STATUS,_BV(RX_DR) | _BV(MAX_RT) | _BV(TX_DS)); + WriteRegister(STATUS,_BV(RX_DR) | _BV(TX_DS) | _BV(MAX_RT) ); + return PL_LEN; } static void openWritingPipe(uint64_t value) { @@ -162,7 +163,7 @@ static void openReadingPipe(uint8_t pipe, uint64_t address) { static boolean write(uint8_t destination, uint8_t* buf, uint8_t len, boolean multicast) { stopListening(); openWritingPipe(TO_ADDR(destination)); - bool result = write_buf(buf, len, multicast); + boolean result = write_buf(buf, len, multicast); startListening(); return result; } @@ -177,6 +178,8 @@ static void setAddress(uint8_t addr) } } + + static void RFinit(void){ // set address width WriteRegister(SETUP_AW, (addr_width-2) % 4); @@ -190,7 +193,7 @@ static void RFinit(void){ WriteRegister(RF_SETUP, ((RF24_DATARATE & 0b00000010 ) << 4) | ((RF24_DATARATE & 0b00000001 ) << 3) | ((RF24_PA_LEVEL << 1) + 1)); // flush RX and TX FIFO, clear interrupts Flush_RXTX_CLI(); - // activate dynamic payload feature + // activate to unlock features WriteAddress(ACTIVATE,0x73); // enable payload with ACK and dynamic payload length WriteRegister(FEATURE, _BV(EN_ACK_PAY) | _BV(EN_DPL) ); @@ -198,13 +201,8 @@ static void RFinit(void){ WriteRegister(DYNPD, _BV(DPL_P5) | _BV(DPL_P4) | _BV(DPL_P3) | _BV(DPL_P2) | _BV(DPL_P1) | _BV(DPL_P0)); //powerUp, enable 16bit CRC, no RX mode WriteRegister(CONFIG, _BV(PWR_UP) | _BV(CRCO) | _BV(EN_CRC) | ~_BV(PRIM_RX)); - // stabilize - delaym(5); - - // We are not listening to broadcast pipe since we do not reply to broadcasting messages (e.g. FIND_PARENT_RESPONSE messages) - // openReadingPipe(BROADCAST_PIPE, TO_ADDR(BROADCAST_ADDRESS)); - - + // stabilize 5ms + _delay_ms(5); } #endif // MYSBootloaderRF24_H diff --git a/MYSBootloader/boot.h b/MYSBootloader/boot.h new file mode 100644 index 0000000..2639cd8 --- /dev/null +++ b/MYSBootloader/boot.h @@ -0,0 +1,848 @@ +/* Modified to use out for SPM access +** Peter Knight, Optiboot project http://optiboot.googlecode.com +** +** Todo: Tidy up +** +** "_short" routines execute 1 cycle faster and use 1 less word of flash +** by using "out" instruction instead of "sts". +** +** Additional elpm variants that trust the value of RAMPZ +*/ + +/* Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Eric B. Weddington + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name of the copyright holders nor the names of + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. */ + +/* $Id: boot.h,v 1.27.2.3 2008/09/30 13:58:48 arcanum Exp $ */ + +#ifndef _AVR_BOOT_H_ +#define _AVR_BOOT_H_ 1 + +/** \file */ +/** \defgroup avr_boot : Bootloader Support Utilities + \code + #include + #include + \endcode + + The macros in this module provide a C language interface to the + bootloader support functionality of certain AVR processors. These + macros are designed to work with all sizes of flash memory. + + Global interrupts are not automatically disabled for these macros. It + is left up to the programmer to do this. See the code example below. + Also see the processor datasheet for caveats on having global interrupts + enabled during writing of the Flash. + + \note Not all AVR processors provide bootloader support. See your + processor datasheet to see if it provides bootloader support. + + \todo From email with Marek: On smaller devices (all except ATmega64/128), + __SPM_REG is in the I/O space, accessible with the shorter "in" and "out" + instructions - since the boot loader has a limited size, this could be an + important optimization. + + \par API Usage Example + The following code shows typical usage of the boot API. + + \code + #include + #include + #include + + void boot_program_page (uint32_t page, uint8_t *buf) + { + uint16_t i; + uint8_t sreg; + + // Disable interrupts. + + sreg = SREG; + cli(); + + eeprom_busy_wait (); + + boot_page_erase (page); + boot_spm_busy_wait (); // Wait until the memory is erased. + + for (i=0; i +#include +#include +#include + +/* Check for SPM Control Register in processor. */ +#if defined (SPMCSR) +# define __SPM_REG SPMCSR +#elif defined (SPMCR) +# define __SPM_REG SPMCR +#else +# error AVR processor does not provide bootloader support! +#endif + + +/* Check for SPM Enable bit. */ +#if defined(SPMEN) +# define __SPM_ENABLE SPMEN +#elif defined(SELFPRGEN) +# define __SPM_ENABLE SELFPRGEN +#else +# error Cannot find SPM Enable bit definition! +#endif + +/** \ingroup avr_boot + \def BOOTLOADER_SECTION + + Used to declare a function or variable to be placed into a + new section called .bootloader. This section and its contents + can then be relocated to any address (such as the bootloader + NRWW area) at link-time. */ + +#define BOOTLOADER_SECTION __attribute__ ((section (".bootloader"))) + +/* Create common bit definitions. */ +#ifdef ASB +#define __COMMON_ASB ASB +#else +#define __COMMON_ASB RWWSB +#endif + +#ifdef ASRE +#define __COMMON_ASRE ASRE +#else +#define __COMMON_ASRE RWWSRE +#endif + +/* Define the bit positions of the Boot Lock Bits. */ + +#define BLB12 5 +#define BLB11 4 +#define BLB02 3 +#define BLB01 2 + +/** \ingroup avr_boot + \def boot_spm_interrupt_enable() + Enable the SPM interrupt. */ + +#define boot_spm_interrupt_enable() (__SPM_REG |= (uint8_t)_BV(SPMIE)) + +/** \ingroup avr_boot + \def boot_spm_interrupt_disable() + Disable the SPM interrupt. */ + +#define boot_spm_interrupt_disable() (__SPM_REG &= (uint8_t)~_BV(SPMIE)) + +/** \ingroup avr_boot + \def boot_is_spm_interrupt() + Check if the SPM interrupt is enabled. */ + +#define boot_is_spm_interrupt() (__SPM_REG & (uint8_t)_BV(SPMIE)) + +/** \ingroup avr_boot + \def boot_rww_busy() + Check if the RWW section is busy. */ + +#define boot_rww_busy() (__SPM_REG & (uint8_t)_BV(__COMMON_ASB)) + +/** \ingroup avr_boot + \def boot_spm_busy() + Check if the SPM instruction is busy. */ + +#define boot_spm_busy() (__SPM_REG & (uint8_t)_BV(__SPM_ENABLE)) + +/** \ingroup avr_boot + \def boot_spm_busy_wait() + Wait while the SPM instruction is busy. */ + +#define boot_spm_busy_wait() do{}while(boot_spm_busy()) + +#define __BOOT_PAGE_ERASE (_BV(__SPM_ENABLE) | _BV(PGERS)) +#define __BOOT_PAGE_WRITE (_BV(__SPM_ENABLE) | _BV(PGWRT)) +#define __BOOT_PAGE_FILL _BV(__SPM_ENABLE) +#define __BOOT_RWW_ENABLE (_BV(__SPM_ENABLE) | _BV(__COMMON_ASRE)) +#define __BOOT_LOCK_BITS_SET (_BV(__SPM_ENABLE) | _BV(BLBSET)) + +#define __boot_page_fill_short(address, data) \ +(__extension__({ \ + __asm__ __volatile__ \ + ( \ + "movw r0, %3\n\t" \ + "out %0, %1\n\t" \ + "spm\n\t" \ + "clr r1\n\t" \ + : \ + : "i" (_SFR_IO_ADDR(__SPM_REG)), \ + "r" ((uint8_t)__BOOT_PAGE_FILL), \ + "z" ((uint16_t)address), \ + "r" ((uint16_t)data) \ + : "r0" \ + ); \ +})) + +#define __boot_page_fill_normal(address, data) \ +(__extension__({ \ + __asm__ __volatile__ \ + ( \ + "movw r0, %3\n\t" \ + "sts %0, %1\n\t" \ + "spm\n\t" \ + "clr r1\n\t" \ + : \ + : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ + "r" ((uint8_t)__BOOT_PAGE_FILL), \ + "z" ((uint16_t)address), \ + "r" ((uint16_t)data) \ + : "r0" \ + ); \ +})) + +#define __boot_page_fill_alternate(address, data)\ +(__extension__({ \ + __asm__ __volatile__ \ + ( \ + "movw r0, %3\n\t" \ + "sts %0, %1\n\t" \ + "spm\n\t" \ + ".word 0xffff\n\t" \ + "nop\n\t" \ + "clr r1\n\t" \ + : \ + : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ + "r" ((uint8_t)__BOOT_PAGE_FILL), \ + "z" ((uint16_t)address), \ + "r" ((uint16_t)data) \ + : "r0" \ + ); \ +})) + +#define __boot_page_fill_extended(address, data) \ +(__extension__({ \ + __asm__ __volatile__ \ + ( \ + "movw r0, %4\n\t" \ + "movw r30, %A3\n\t" \ + "sts %1, %C3\n\t" \ + "sts %0, %2\n\t" \ + "spm\n\t" \ + "clr r1\n\t" \ + : \ + : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ + "i" (_SFR_MEM_ADDR(RAMPZ)), \ + "r" ((uint8_t)__BOOT_PAGE_FILL), \ + "r" ((uint32_t)address), \ + "r" ((uint16_t)data) \ + : "r0", "r30", "r31" \ + ); \ +})) + +#define __boot_page_fill_extended_short(address, data) \ +(__extension__({ \ + __asm__ __volatile__ \ + ( \ + "movw r0, %4\n\t" \ + "movw r30, %A3\n\t" \ + "out %1, %C3\n\t" \ + "out %0, %2\n\t" \ + "spm\n\t" \ + "clr r1\n\t" \ + : \ + : "i" (_SFR_IO_ADDR(__SPM_REG)), \ + "i" (_SFR_IO_ADDR(RAMPZ)), \ + "r" ((uint8_t)__BOOT_PAGE_FILL), \ + "r" ((uint32_t)address), \ + "r" ((uint16_t)data) \ + : "r0", "r30", "r31" \ + ); \ +})) + +#define __boot_page_erase_short(address) \ +(__extension__({ \ + __asm__ __volatile__ \ + ( \ + "out %0, %1\n\t" \ + "spm\n\t" \ + : \ + : "i" (_SFR_IO_ADDR(__SPM_REG)), \ + "r" ((uint8_t)__BOOT_PAGE_ERASE), \ + "z" ((uint16_t)address) \ + ); \ +})) + + +#define __boot_page_erase_normal(address) \ +(__extension__({ \ + __asm__ __volatile__ \ + ( \ + "sts %0, %1\n\t" \ + "spm\n\t" \ + : \ + : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ + "r" ((uint8_t)__BOOT_PAGE_ERASE), \ + "z" ((uint16_t)address) \ + ); \ +})) + +#define __boot_page_erase_alternate(address) \ +(__extension__({ \ + __asm__ __volatile__ \ + ( \ + "sts %0, %1\n\t" \ + "spm\n\t" \ + ".word 0xffff\n\t" \ + "nop\n\t" \ + : \ + : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ + "r" ((uint8_t)__BOOT_PAGE_ERASE), \ + "z" ((uint16_t)address) \ + ); \ +})) + +#define __boot_page_erase_extended(address) \ +(__extension__({ \ + __asm__ __volatile__ \ + ( \ + "movw r30, %A3\n\t" \ + "sts %1, %C3\n\t" \ + "sts %0, %2\n\t" \ + "spm\n\t" \ + : \ + : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ + "i" (_SFR_MEM_ADDR(RAMPZ)), \ + "r" ((uint8_t)__BOOT_PAGE_ERASE), \ + "r" ((uint32_t)address) \ + : "r30", "r31" \ + ); \ +})) +#define __boot_page_erase_extended_short(address) \ +(__extension__({ \ + __asm__ __volatile__ \ + ( \ + "movw r30, %A3\n\t" \ + "out %1, %C3\n\t" \ + "out %0, %2\n\t" \ + "spm\n\t" \ + : \ + : "i" (_SFR_IO_ADDR(__SPM_REG)), \ + "i" (_SFR_IO_ADDR(RAMPZ)), \ + "r" ((uint8_t)__BOOT_PAGE_ERASE), \ + "r" ((uint32_t)address) \ + : "r30", "r31" \ + ); \ +})) + +#define __boot_page_write_short(address) \ +(__extension__({ \ + __asm__ __volatile__ \ + ( \ + "out %0, %1\n\t" \ + "spm\n\t" \ + : \ + : "i" (_SFR_IO_ADDR(__SPM_REG)), \ + "r" ((uint8_t)__BOOT_PAGE_WRITE), \ + "z" ((uint16_t)address) \ + ); \ +})) + +#define __boot_page_write_normal(address) \ +(__extension__({ \ + __asm__ __volatile__ \ + ( \ + "sts %0, %1\n\t" \ + "spm\n\t" \ + : \ + : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ + "r" ((uint8_t)__BOOT_PAGE_WRITE), \ + "z" ((uint16_t)address) \ + ); \ +})) + +#define __boot_page_write_alternate(address) \ +(__extension__({ \ + __asm__ __volatile__ \ + ( \ + "sts %0, %1\n\t" \ + "spm\n\t" \ + ".word 0xffff\n\t" \ + "nop\n\t" \ + : \ + : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ + "r" ((uint8_t)__BOOT_PAGE_WRITE), \ + "z" ((uint16_t)address) \ + ); \ +})) + +#define __boot_page_write_extended(address) \ +(__extension__({ \ + __asm__ __volatile__ \ + ( \ + "movw r30, %A3\n\t" \ + "sts %1, %C3\n\t" \ + "sts %0, %2\n\t" \ + "spm\n\t" \ + : \ + : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ + "i" (_SFR_MEM_ADDR(RAMPZ)), \ + "r" ((uint8_t)__BOOT_PAGE_WRITE), \ + "r" ((uint32_t)address) \ + : "r30", "r31" \ + ); \ +})) +#define __boot_page_write_extended_short(address) \ +(__extension__({ \ + __asm__ __volatile__ \ + ( \ + "movw r30, %A3\n\t" \ + "out %1, %C3\n\t" \ + "out %0, %2\n\t" \ + "spm\n\t" \ + : \ + : "i" (_SFR_IO_ADDR(__SPM_REG)), \ + "i" (_SFR_IO_ADDR(RAMPZ)), \ + "r" ((uint8_t)__BOOT_PAGE_WRITE), \ + "r" ((uint32_t)address) \ + : "r30", "r31" \ + ); \ +})) + +#define __boot_rww_enable_short() \ +(__extension__({ \ + __asm__ __volatile__ \ + ( \ + "out %0, %1\n\t" \ + "spm\n\t" \ + : \ + : "i" (_SFR_IO_ADDR(__SPM_REG)), \ + "r" ((uint8_t)__BOOT_RWW_ENABLE) \ + ); \ +})) + +#define __boot_rww_enable() \ +(__extension__({ \ + __asm__ __volatile__ \ + ( \ + "sts %0, %1\n\t" \ + "spm\n\t" \ + : \ + : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ + "r" ((uint8_t)__BOOT_RWW_ENABLE) \ + ); \ +})) + +#define __boot_rww_enable_alternate() \ +(__extension__({ \ + __asm__ __volatile__ \ + ( \ + "sts %0, %1\n\t" \ + "spm\n\t" \ + ".word 0xffff\n\t" \ + "nop\n\t" \ + : \ + : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ + "r" ((uint8_t)__BOOT_RWW_ENABLE) \ + ); \ +})) + +/* From the mega16/mega128 data sheets (maybe others): + + Bits by SPM To set the Boot Loader Lock bits, write the desired data to + R0, write "X0001001" to SPMCR and execute SPM within four clock cycles + after writing SPMCR. The only accessible Lock bits are the Boot Lock bits + that may prevent the Application and Boot Loader section from any + software update by the MCU. + + If bits 5..2 in R0 are cleared (zero), the corresponding Boot Lock bit + will be programmed if an SPM instruction is executed within four cycles + after BLBSET and SPMEN (or SELFPRGEN) are set in SPMCR. The Z-pointer is + don't care during this operation, but for future compatibility it is + recommended to load the Z-pointer with $0001 (same as used for reading the + Lock bits). For future compatibility It is also recommended to set bits 7, + 6, 1, and 0 in R0 to 1 when writing the Lock bits. When programming the + Lock bits the entire Flash can be read during the operation. */ + +#define __boot_lock_bits_set_short(lock_bits) \ +(__extension__({ \ + uint8_t value = (uint8_t)(~(lock_bits)); \ + __asm__ __volatile__ \ + ( \ + "ldi r30, 1\n\t" \ + "ldi r31, 0\n\t" \ + "mov r0, %2\n\t" \ + "out %0, %1\n\t" \ + "spm\n\t" \ + : \ + : "i" (_SFR_IO_ADDR(__SPM_REG)), \ + "r" ((uint8_t)__BOOT_LOCK_BITS_SET), \ + "r" (value) \ + : "r0", "r30", "r31" \ + ); \ +})) + +#define __boot_lock_bits_set(lock_bits) \ +(__extension__({ \ + uint8_t value = (uint8_t)(~(lock_bits)); \ + __asm__ __volatile__ \ + ( \ + "ldi r30, 1\n\t" \ + "ldi r31, 0\n\t" \ + "mov r0, %2\n\t" \ + "sts %0, %1\n\t" \ + "spm\n\t" \ + : \ + : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ + "r" ((uint8_t)__BOOT_LOCK_BITS_SET), \ + "r" (value) \ + : "r0", "r30", "r31" \ + ); \ +})) + +#define __boot_lock_bits_set_alternate(lock_bits) \ +(__extension__({ \ + uint8_t value = (uint8_t)(~(lock_bits)); \ + __asm__ __volatile__ \ + ( \ + "ldi r30, 1\n\t" \ + "ldi r31, 0\n\t" \ + "mov r0, %2\n\t" \ + "sts %0, %1\n\t" \ + "spm\n\t" \ + ".word 0xffff\n\t" \ + "nop\n\t" \ + : \ + : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ + "r" ((uint8_t)__BOOT_LOCK_BITS_SET), \ + "r" (value) \ + : "r0", "r30", "r31" \ + ); \ +})) + +/* + Reading lock and fuse bits: + + Similarly to writing the lock bits above, set BLBSET and SPMEN (or + SELFPRGEN) bits in __SPMREG, and then (within four clock cycles) issue an + LPM instruction. + + Z address: contents: + 0x0000 low fuse bits + 0x0001 lock bits + 0x0002 extended fuse bits + 0x0003 high fuse bits + + Sounds confusing, doesn't it? + + Unlike the macros in pgmspace.h, no need to care for non-enhanced + cores here as these old cores do not provide SPM support anyway. + */ + +/** \ingroup avr_boot + \def GET_LOW_FUSE_BITS + address to read the low fuse bits, using boot_lock_fuse_bits_get + */ +#define GET_LOW_FUSE_BITS (0x0000) +/** \ingroup avr_boot + \def GET_LOCK_BITS + address to read the lock bits, using boot_lock_fuse_bits_get + */ +#define GET_LOCK_BITS (0x0001) +/** \ingroup avr_boot + \def GET_EXTENDED_FUSE_BITS + address to read the extended fuse bits, using boot_lock_fuse_bits_get + */ +#define GET_EXTENDED_FUSE_BITS (0x0002) +/** \ingroup avr_boot + \def GET_HIGH_FUSE_BITS + address to read the high fuse bits, using boot_lock_fuse_bits_get + */ +#define GET_HIGH_FUSE_BITS (0x0003) + +/** \ingroup avr_boot + \def boot_lock_fuse_bits_get(address) + + Read the lock or fuse bits at \c address. + + Parameter \c address can be any of GET_LOW_FUSE_BITS, + GET_LOCK_BITS, GET_EXTENDED_FUSE_BITS, or GET_HIGH_FUSE_BITS. + + \note The lock and fuse bits returned are the physical values, + i.e. a bit returned as 0 means the corresponding fuse or lock bit + is programmed. + */ +#define boot_lock_fuse_bits_get_short(address) \ +(__extension__({ \ + uint8_t __result; \ + __asm__ __volatile__ \ + ( \ + "ldi r30, %3\n\t" \ + "ldi r31, 0\n\t" \ + "out %1, %2\n\t" \ + "lpm %0, Z\n\t" \ + : "=r" (__result) \ + : "i" (_SFR_IO_ADDR(__SPM_REG)), \ + "r" ((uint8_t)__BOOT_LOCK_BITS_SET), \ + "M" (address) \ + : "r0", "r30", "r31" \ + ); \ + __result; \ +})) + +#define boot_lock_fuse_bits_get(address) \ +(__extension__({ \ + uint8_t __result; \ + __asm__ __volatile__ \ + ( \ + "ldi r30, %3\n\t" \ + "ldi r31, 0\n\t" \ + "sts %1, %2\n\t" \ + "lpm %0, Z\n\t" \ + : "=r" (__result) \ + : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ + "r" ((uint8_t)__BOOT_LOCK_BITS_SET), \ + "M" (address) \ + : "r0", "r30", "r31" \ + ); \ + __result; \ +})) + +/** \ingroup avr_boot + \def boot_signature_byte_get(address) + + Read the Signature Row byte at \c address. For some MCU types, + this function can also retrieve the factory-stored oscillator + calibration bytes. + + Parameter \c address can be 0-0x1f as documented by the datasheet. + \note The values are MCU type dependent. +*/ + +#define __BOOT_SIGROW_READ (_BV(__SPM_ENABLE) | _BV(SIGRD)) + +#define boot_signature_byte_get_short(addr) \ +(__extension__({ \ + uint16_t __addr16 = (uint16_t)(addr); \ + uint8_t __result; \ + __asm__ __volatile__ \ + ( \ + "out %1, %2\n\t" \ + "lpm %0, Z" "\n\t" \ + : "=r" (__result) \ + : "i" (_SFR_IO_ADDR(__SPM_REG)), \ + "r" ((uint8_t) __BOOT_SIGROW_READ), \ + "z" (__addr16) \ + ); \ + __result; \ +})) + +#define boot_signature_byte_get(addr) \ +(__extension__({ \ + uint16_t __addr16 = (uint16_t)(addr); \ + uint8_t __result; \ + __asm__ __volatile__ \ + ( \ + "sts %1, %2\n\t" \ + "lpm %0, Z" "\n\t" \ + : "=r" (__result) \ + : "i" (_SFR_MEM_ADDR(__SPM_REG)), \ + "r" ((uint8_t) __BOOT_SIGROW_READ), \ + "z" (__addr16) \ + ); \ + __result; \ +})) + +/** \ingroup avr_boot + \def boot_page_fill(address, data) + + Fill the bootloader temporary page buffer for flash + address with data word. + + \note The address is a byte address. The data is a word. The AVR + writes data to the buffer a word at a time, but addresses the buffer + per byte! So, increment your address by 2 between calls, and send 2 + data bytes in a word format! The LSB of the data is written to the lower + address; the MSB of the data is written to the higher address.*/ + +/** \ingroup avr_boot + \def boot_page_erase(address) + + Erase the flash page that contains address. + + \note address is a byte address in flash, not a word address. */ + +/** \ingroup avr_boot + \def boot_page_write(address) + + Write the bootloader temporary page buffer + to flash page that contains address. + + \note address is a byte address in flash, not a word address. */ + +/** \ingroup avr_boot + \def boot_rww_enable() + + Enable the Read-While-Write memory section. */ + +/** \ingroup avr_boot + \def boot_lock_bits_set(lock_bits) + + Set the bootloader lock bits. + + \param lock_bits A mask of which Boot Loader Lock Bits to set. + + \note In this context, a 'set bit' will be written to a zero value. + Note also that only BLBxx bits can be programmed by this command. + + For example, to disallow the SPM instruction from writing to the Boot + Loader memory section of flash, you would use this macro as such: + + \code + boot_lock_bits_set (_BV (BLB11)); + \endcode + + \note Like any lock bits, the Boot Loader Lock Bits, once set, + cannot be cleared again except by a chip erase which will in turn + also erase the boot loader itself. */ + +/* Normal versions of the macros use 16-bit addresses. + Extended versions of the macros use 32-bit addresses. + Alternate versions of the macros use 16-bit addresses and require special + instruction sequences after LPM. + + FLASHEND is defined in the ioXXXX.h file. + USHRT_MAX is defined in . */ + +#if defined(__AVR_ATmega161__) || defined(__AVR_ATmega163__) \ + || defined(__AVR_ATmega323__) + +/* Alternate: ATmega161/163/323 and 16 bit address */ +#define boot_page_fill(address, data) __boot_page_fill_alternate(address, data) +#define boot_page_erase(address) __boot_page_erase_alternate(address) +#define boot_page_write(address) __boot_page_write_alternate(address) +#define boot_rww_enable() __boot_rww_enable_alternate() +#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_alternate(lock_bits) + +#elif (FLASHEND > USHRT_MAX) + +/* Extended: >16 bit address */ +#define boot_page_fill(address, data) __boot_page_fill_extended_short(address, data) +#define boot_page_erase(address) __boot_page_erase_extended_short(address) +#define boot_page_write(address) __boot_page_write_extended_short(address) +#define boot_rww_enable() __boot_rww_enable_short() +#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_short(lock_bits) + +#else + +/* Normal: 16 bit address */ +#define boot_page_fill(address, data) __boot_page_fill_short(address, data) +#define boot_page_erase(address) __boot_page_erase_short(address) +#define boot_page_write(address) __boot_page_write_short(address) +#define boot_rww_enable() __boot_rww_enable_short() +#define boot_lock_bits_set(lock_bits) __boot_lock_bits_set_short(lock_bits) + +#endif + +/** \ingroup avr_boot + + Same as boot_page_fill() except it waits for eeprom and spm operations to + complete before filling the page. */ + +#define boot_page_fill_safe(address, data) \ +do { \ + boot_spm_busy_wait(); \ + eeprom_busy_wait(); \ + boot_page_fill(address, data); \ +} while (0) + +/** \ingroup avr_boot + + Same as boot_page_erase() except it waits for eeprom and spm operations to + complete before erasing the page. */ + +#define boot_page_erase_safe(address) \ +do { \ + boot_spm_busy_wait(); \ + eeprom_busy_wait(); \ + boot_page_erase (address); \ +} while (0) + +/** \ingroup avr_boot + + Same as boot_page_write() except it waits for eeprom and spm operations to + complete before writing the page. */ + +#define boot_page_write_safe(address) \ +do { \ + boot_spm_busy_wait(); \ + eeprom_busy_wait(); \ + boot_page_write (address); \ +} while (0) + +/** \ingroup avr_boot + + Same as boot_rww_enable() except waits for eeprom and spm operations to + complete before enabling the RWW mameory. */ + +#define boot_rww_enable_safe() \ +do { \ + boot_spm_busy_wait(); \ + eeprom_busy_wait(); \ + boot_rww_enable(); \ +} while (0) + +/** \ingroup avr_boot + + Same as boot_lock_bits_set() except waits for eeprom and spm operations to + complete before setting the lock bits. */ + +#define boot_lock_bits_set_safe(lock_bits) \ +do { \ + boot_spm_busy_wait(); \ + eeprom_busy_wait(); \ + boot_lock_bits_set (lock_bits); \ +} while (0) + +#endif /* _AVR_BOOT_H_ */ From 985f9c344600d3c4205a17dab23240fe42131411 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Sat, 14 Mar 2015 19:13:09 +0100 Subject: [PATCH 11/24] Moved static strings for Serial.println() to flash storage --- .../examples/MysensorMicro/MysensorMicro.ino | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino index 8c10883..6c7ae6e 100644 --- a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino +++ b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino @@ -1,7 +1,7 @@ // Default sensor sketch for MySensor Micro module // Act as a temperature / humidity sensor by default. // -// If A1 is held low while powering on, it will clear eeprom (and thereby the stored nodeid) +// If A0 is held low while powering on, it will enter testmode, which verifies all on-board peripherals // // Battery voltage is repported as child sensorId 199, as well as battery percentage @@ -193,16 +193,16 @@ void testMode() { byte tests = 0; - Serial.println("Testing peripherals!"); + Serial.println(F("Testing peripherals!")); if (humiditySensor.begin()) { - Serial.println("Si7021 ok!"); + Serial.println(F("Si7021 ok!")); tests ++; } else { - Serial.println("---> Si7021 FAILED!"); + Serial.println(F("---> Si7021 FAILED!")); } if (flash.initialize()) @@ -212,14 +212,14 @@ void testMode() } else { - Serial.println("---> flash failed!"); + Serial.println(F("---> flash failed!")); } - Serial.println("Test finished"); + Serial.println(F("Test finished")); if (tests == 2) { - Serial.println("Selftest ok!"); + Serial.println(F("Selftest ok!")); while (1) // Blink OK pattern! { digitalWrite(LED_PIN, HIGH); @@ -230,7 +230,7 @@ void testMode() } else { - Serial.println("----> Selftest failed!"); + Serial.println(F("----> Selftest failed!")); while (1) // Blink FAILED pattern! Rappidly blinking.. { digitalWrite(LED_PIN, HIGH); From 405c8fd0f2121f094a487bb51dbfb8f35913e825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Thu, 19 Mar 2015 20:55:41 +0100 Subject: [PATCH 12/24] Update testmode, after initial tests on the bench --- .../examples/MysensorMicro/MysensorMicro.ino | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino index 6c7ae6e..8a00948 100644 --- a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino +++ b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino @@ -34,7 +34,7 @@ #define FORCE_TRANSMIT_INTERVAL 30 SI7021 humiditySensor; -SPIFlash flash(8, 0xEF30); +SPIFlash flash(8, 0x1F65); MySensor gw; @@ -57,10 +57,13 @@ void setup() { pinMode(LED_PIN, OUTPUT); digitalWrite(LED_PIN, LOW); - // First check if we should boot into clear eeprom mode + Serial.begin(115200); + // First check if we should boot into test mode + testMode(); pinMode(TEST_PIN,INPUT); digitalWrite(TEST_PIN, HIGH); if (!digitalRead(TEST_PIN)) testMode(); + digitalWrite(TEST_PIN,LOW); digitalWrite(LED_PIN, HIGH); @@ -194,27 +197,32 @@ void testMode() byte tests = 0; Serial.println(F("Testing peripherals!")); + Serial.print(F("-> SI7021 : ")); + delay(500); if (humiditySensor.begin()) { - Serial.println(F("Si7021 ok!")); + Serial.println(F("ok!")); tests ++; } else { - Serial.println(F("---> Si7021 FAILED!")); + Serial.println(F("failed!")); } - + delay(500); + + Serial.print(F("-> Flash : ")); +delay(500); if (flash.initialize()) { - Serial.println("flash OK!"); + Serial.println(F("ok!")); tests ++; } else { - Serial.println(F("---> flash failed!")); + Serial.println(F("failed!")); } - +delay(500); Serial.println(F("Test finished")); if (tests == 2) @@ -234,9 +242,9 @@ void testMode() while (1) // Blink FAILED pattern! Rappidly blinking.. { digitalWrite(LED_PIN, HIGH); - delay(200); + delay(100); digitalWrite(LED_PIN, LOW); - delay(200); + delay(100); } } } From 199b130492d8a51e46c5cfa382ac8724670a8355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Thu, 19 Mar 2015 20:56:02 +0100 Subject: [PATCH 13/24] Updated SPIflash to work with Arduino 1.6.x --- libraries/SPIFlash/SPIFlash.cpp | 60 ++++++++++++++++++++++++--------- libraries/SPIFlash/SPIFlash.h | 38 ++++++++++++--------- 2 files changed, 67 insertions(+), 31 deletions(-) diff --git a/libraries/SPIFlash/SPIFlash.cpp b/libraries/SPIFlash/SPIFlash.cpp index 03d6a1a..bad4cdf 100644 --- a/libraries/SPIFlash/SPIFlash.cpp +++ b/libraries/SPIFlash/SPIFlash.cpp @@ -6,6 +6,9 @@ * Minimal modifications should allow chips that have different page size but modifications * DEPENDS ON: Arduino SPI library * + * Updated Jan. 5, 2015, TomWS1, modified writeBytes to allow blocks > 256 bytes and handle page misalignment. + * Updated Feb. 26, 2015 TomWS1, added support for SPI Transactions (Arduino 1.5.8 and above) + * * This file is free software; you can redistribute it and/or modify * it under the terms of either the GNU General Public License version 2 * or the GNU Lesser General Public License version 2.1, both as @@ -32,15 +35,22 @@ SPIFlash::SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID) { /// Select the flash chip void SPIFlash::select() { - noInterrupts(); //save current SPI settings +#ifndef SPI_HAS_TRANSACTION + _SREG = SREG; + noInterrupts(); +#endif _SPCR = SPCR; _SPSR = SPSR; - //set FLASH chip SPI settings + +#ifdef SPI_HAS_TRANSACTION + SPI.beginTransaction(_settings); +#else + // set FLASH SPI settings SPI.setDataMode(SPI_MODE0); SPI.setBitOrder(MSBFIRST); - SPI.setClockDivider(SPI_CLOCK_DIV4); //decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present - SPI.begin(); + SPI.setClockDivider(SPI_CLOCK_DIV4); // decided to slow down from DIV2 after SPI stalling in some instances, especially visible on mega1284p when RFM69 and FLASH chip both present +#endif digitalWrite(_slaveSelectPin, LOW); } @@ -48,9 +58,13 @@ void SPIFlash::select() { void SPIFlash::unselect() { digitalWrite(_slaveSelectPin, HIGH); //restore SPI settings to what they were before talking to the FLASH chip +#ifdef SPI_HAS_TRANSACTION + SPI.endTransaction(); +#else + SREG = _SREG; // restore interrupts IFF they were enabled +#endif SPCR = _SPCR; SPSR = _SPSR; - interrupts(); } /// setup SPI, read device ID etc... @@ -58,7 +72,10 @@ boolean SPIFlash::initialize() { _SPCR = SPCR; _SPSR = SPSR; + digitalWrite(_slaveSelectPin, HIGH); pinMode(_slaveSelectPin, OUTPUT); + SPI.begin(); + _settings = SPISettings(4000000, MSBFIRST, SPI_MODE0); unselect(); wakeup(); @@ -185,22 +202,33 @@ void SPIFlash::writeByte(long addr, uint8_t byt) { unselect(); } -/// write 1-256 bytes to flash memory +/// write multiple bytes to flash memory (up to 64K) /// WARNING: you can only write to previously erased memory locations (see datasheet) /// use the block erase commands to first clear memory (write 0xFFs) -/// WARNING: if you write beyond a page boundary (or more than 256bytes), -/// the bytes will wrap around and start overwriting at the beginning of that same page -/// see datasheet for more details +/// This version handles both page alignment and data blocks larger than 256 bytes. +/// void SPIFlash::writeBytes(long addr, const void* buf, uint16_t len) { - command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program - SPI.transfer(addr >> 16); - SPI.transfer(addr >> 8); - SPI.transfer(addr); - for (uint16_t i = 0; i < len; i++) - SPI.transfer(((byte*) buf)[i]); - unselect(); + uint16_t n; + uint16_t maxBytes = 256-(addr%256); // force the first set of bytes to stay within the first page + uint16_t offset = 0; + while (len>0) + { + n = (len<=maxBytes) ? len : maxBytes; + command(SPIFLASH_BYTEPAGEPROGRAM, true); // Byte/Page Program + SPI.transfer(addr >> 16); + SPI.transfer(addr >> 8); + SPI.transfer(addr); + for (uint16_t i = 0; i < n; i++) + SPI.transfer(((byte*) buf)[offset + i]); + unselect(); + addr+=n; // adjust the addresses and remaining bytes by what we've just transferred. + offset +=n; + len -= n; + maxBytes = 256; // now we can do up to 256 bytes per loop + } } + /// erase entire flash memory array /// may take several seconds depending on size, but is non blocking /// so you may wait for this to complete using busy() or continue doing diff --git a/libraries/SPIFlash/SPIFlash.h b/libraries/SPIFlash/SPIFlash.h index f0c071a..8f530b7 100644 --- a/libraries/SPIFlash/SPIFlash.h +++ b/libraries/SPIFlash/SPIFlash.h @@ -1,11 +1,13 @@ /* * Copyright (c) 2013 by Felix Rusu * SPI Flash memory library for arduino/moteino. - * This works with 256byte/page SPI flash memory - * For instance a 4MBit (512Kbyte) flash chip will have 2048 pages: 256*2048 = 524288 bytes (512Kbytes) + * This works with 256uint8_t/page SPI flash memory + * For instance a 4MBit (512Kuint8_t) flash chip will have 2048 pages: 256*2048 = 524288 uint8_ts (512Kuint8_ts) * Minimal modifications should allow chips that have different page size but modifications * DEPENDS ON: Arduino SPI library * + * Updated Feb. 26, 2015 TomWS1, added support for SPI Transactions (Arduino 1.5.8 and above) + * * This file is free software; you can redistribute it and/or modify * it under the terms of either the GNU General Public License version 2 * or the GNU Lesser General Public License version 2.1, both as @@ -56,34 +58,34 @@ // but no actual need to wait for completion (instead need to check the status register BUSY bit) #define SPIFLASH_STATUSREAD 0x05 // read status register #define SPIFLASH_STATUSWRITE 0x01 // write status register -#define SPIFLASH_ARRAYREAD 0x0B // read array (fast, need to add 1 dummy byte after 3 address bytes) +#define SPIFLASH_ARRAYREAD 0x0B // read array (fast, need to add 1 dummy uint8_t after 3 address uint8_ts) #define SPIFLASH_ARRAYREADLOWFREQ 0x03 // read array (low frequency) #define SPIFLASH_SLEEP 0xB9 // deep power down #define SPIFLASH_WAKE 0xAB // deep power wake up -#define SPIFLASH_BYTEPAGEPROGRAM 0x02 // write (1 to 256bytes) -#define SPIFLASH_IDREAD 0x9F // read JEDEC manufacturer and device ID (2 bytes, specific bytes for each manufacturer and device) +#define SPIFLASH_BYTEPAGEPROGRAM 0x02 // write (1 to 256uint8_ts) +#define SPIFLASH_IDREAD 0x9F // read JEDEC manufacturer and device ID (2 uint8_ts, specific uint8_ts for each manufacturer and device) // Example for Atmel-Adesto 4Mbit AT25DF041A: 0x1F44 (page 27: http://www.adestotech.com/sites/default/files/datasheets/doc3668.pdf) // Example for Winbond 4Mbit W25X40CL: 0xEF30 (page 14: http://www.winbond.com/NR/rdonlyres/6E25084C-0BFE-4B25-903D-AE10221A0929/0/W25X40CL.pdf) #define SPIFLASH_MACREAD 0x4B // read unique ID number (MAC) class SPIFlash { public: - static byte UNIQUEID[8]; - SPIFlash(byte slaveSelectPin, uint16_t jedecID=0); + static uint8_t UNIQUEID[8]; + SPIFlash(uint8_t slaveSelectPin, uint16_t jedecID=0); boolean initialize(); - void command(byte cmd, boolean isWrite=false); - byte readStatus(); - byte readByte(long addr); + void command(uint8_t cmd, boolean isWrite=false); + uint8_t readStatus(); + uint8_t readByte(long addr); void readBytes(long addr, void* buf, word len); - void writeByte(long addr, byte byt); + void writeByte(long addr, uint8_t byt); void writeBytes(long addr, const void* buf, uint16_t len); boolean busy(); void chipErase(); void blockErase4K(long address); void blockErase32K(long address); word readDeviceId(); - byte* readUniqueId(); + uint8_t* readUniqueId(); void sleep(); void wakeup(); @@ -91,10 +93,16 @@ public: protected: void select(); void unselect(); - byte _slaveSelectPin; + uint8_t _slaveSelectPin; uint16_t _jedecID; - byte _SPCR; - byte _SPSR; + uint8_t _SPCR; + uint8_t _SPSR; + uint8_t _SREG; + +#ifdef SPI_HAS_TRANSACTION + SPISettings _settings; +#endif + }; #endif \ No newline at end of file From 5b9c9736c9f052062c8b445a63289b5aee4e0f88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Thu, 19 Mar 2015 21:27:20 +0100 Subject: [PATCH 14/24] Merged sha204 from dev, in order to detect sha204 in MySensors Micro board (Testmode) --- libraries/sha204/sha204_lib_return_codes.h | 48 ++ libraries/sha204/sha204_library.cpp | 819 +++++++++++++++++++++ libraries/sha204/sha204_library.h | 321 ++++++++ 3 files changed, 1188 insertions(+) create mode 100644 libraries/sha204/sha204_lib_return_codes.h create mode 100644 libraries/sha204/sha204_library.cpp create mode 100644 libraries/sha204/sha204_library.h diff --git a/libraries/sha204/sha204_lib_return_codes.h b/libraries/sha204/sha204_lib_return_codes.h new file mode 100644 index 0000000..db61120 --- /dev/null +++ b/libraries/sha204/sha204_lib_return_codes.h @@ -0,0 +1,48 @@ +// ---------------------------------------------------------------------------- +// ATMEL Microcontroller Software Support - Colorado Springs, CO - +// ---------------------------------------------------------------------------- +// DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR +// IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE +// DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// ---------------------------------------------------------------------------- + +/** \file + * \brief SHA204 Library Return Code Definitions + * \author Atmel Crypto Products + * \date September 27, 2010 + */ + +#ifndef SHA204_LIB_RETURN_CODES_H +# define SHA204_LIB_RETURN_CODES_H + +#include // data type definitions + +/** \todo Use same values for same meanings for SHA204 and AES132. + * */ + +#define SHA204_SUCCESS ((uint8_t) 0x00) //!< Function succeeded. +#define SHA204_PARSE_ERROR ((uint8_t) 0xD2) //!< response status byte indicates parsing error +#define SHA204_CMD_FAIL ((uint8_t) 0xD3) //!< response status byte indicates command execution error +#define SHA204_STATUS_CRC ((uint8_t) 0xD4) //!< response status byte indicates CRC error +#define SHA204_STATUS_UNKNOWN ((uint8_t) 0xD5) //!< response status byte is unknown +#define SHA204_FUNC_FAIL ((uint8_t) 0xE0) //!< Function could not execute due to incorrect condition / state. +#define SHA204_GEN_FAIL ((uint8_t) 0xE1) //!< unspecified error +#define SHA204_BAD_PARAM ((uint8_t) 0xE2) //!< bad argument (out of range, null pointer, etc.) +#define SHA204_INVALID_ID ((uint8_t) 0xE3) //!< invalid device id, id not set +#define SHA204_INVALID_SIZE ((uint8_t) 0xE4) //!< Count value is out of range or greater than buffer size. +#define SHA204_BAD_CRC ((uint8_t) 0xE5) //!< incorrect CRC received +#define SHA204_RX_FAIL ((uint8_t) 0xE6) //!< Timed out while waiting for response. Number of bytes received is > 0. +#define SHA204_RX_NO_RESPONSE ((uint8_t) 0xE7) //!< Not an error while the Command layer is polling for a command response. +#define SHA204_RESYNC_WITH_WAKEUP ((uint8_t) 0xE8) //!< re-synchronization succeeded, but only after generating a Wake-up + +#define SHA204_COMM_FAIL ((uint8_t) 0xF0) //!< Communication with device failed. Same as in hardware dependent modules. +#define SHA204_TIMEOUT ((uint8_t) 0xF1) //!< Timed out while waiting for response. Number of bytes received is 0. + +#endif diff --git a/libraries/sha204/sha204_library.cpp b/libraries/sha204/sha204_library.cpp new file mode 100644 index 0000000..8e43890 --- /dev/null +++ b/libraries/sha204/sha204_library.cpp @@ -0,0 +1,819 @@ +#include "Arduino.h" +#include "sha204_library.h" +#include "sha204_lib_return_codes.h" + + +// atsha204Class Constructor +// Feed this function the Arduino-ized pin number you want to assign to the ATSHA204's SDA pin +// This will find the DDRX, PORTX, and PINX registrs it'll need to point to to control that pin +// As well as the bit value for each of those registers +atsha204Class::atsha204Class(uint8_t pin) +{ + device_pin = digitalPinToBitMask(pin); // Find the bit value of the pin + uint8_t port = digitalPinToPort(pin); // temoporarily used to get the next three registers + + // Point to data direction register port of pin + device_port_DDR = portModeRegister(port); + // Point to output register of pin + device_port_OUT = portOutputRegister(port); + // Point to input register of pin + device_port_IN = portInputRegister(port); +} + +/* Puts a the ATSHA204's unique, 4-byte serial number in the response array + returns an SHA204 Return code */ +uint8_t atsha204Class::getSerialNumber(uint8_t * response) +{ + uint8_t readCommand[READ_COUNT]; + uint8_t readResponse[READ_4_RSP_SIZE]; + + /* read from bytes 0->3 of config zone */ + uint8_t returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN03); + if (!returnCode) // should return 0 if successful + { + for (int i=0; i<4; i++) // store bytes 0-3 into respones array + response[i] = readResponse[SHA204_BUFFER_POS_DATA+i]; + + /* read from bytes 8->11 of config zone */ + returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN47); + + for (int i=4; i<8; i++) // store bytes 4-7 of SN into response array + response[i] = readResponse[SHA204_BUFFER_POS_DATA+(i-4)]; + + if (!returnCode) + { /* Finally if last two reads were successful, read byte 8 of the SN */ + returnCode = sha204m_read(readCommand, readResponse, SHA204_ZONE_CONFIG, ADDRESS_SN8); + response[8] = readResponse[SHA204_BUFFER_POS_DATA]; // Byte 8 of SN should always be 0xEE + } + } + + return returnCode; +} + +/* Calculates CRC16 value of provided data (and optionally including provided existing CRC16 data) + returns the calculated CRC16 value */ +uint16_t atsha204Class::calculateAndUpdateCrc(uint8_t length, uint8_t *data, uint16_t current_crc) +{ + uint8_t counter; + uint16_t crc_register = current_crc; + uint16_t polynom = 0x8005; + uint8_t shift_register; + uint8_t data_bit, crc_bit; + + for (counter = 0; counter < length; counter++) + { + for (shift_register = 0x01; shift_register > 0x00; shift_register <<= 1) + { + data_bit = (data[counter] & shift_register) ? 1 : 0; + crc_bit = crc_register >> 15; + + // Shift CRC to the left by 1. + crc_register <<= 1; + + if ((data_bit ^ crc_bit) != 0) + crc_register ^= polynom; + } + } + return crc_register; +} + +/* SWI bit bang functions */ + +void atsha204Class::swi_set_signal_pin(uint8_t is_high) +{ + *device_port_DDR |= device_pin; + + if (is_high) + *device_port_OUT |= device_pin; + else + *device_port_OUT &= ~device_pin; +} + +uint8_t atsha204Class::swi_send_bytes(uint8_t count, uint8_t *buffer) +{ + uint8_t i, bit_mask; + + // Disable interrupts while sending. + noInterrupts(); //swi_disable_interrupts(); + + // Set signal pin as output. + *device_port_OUT |= device_pin; + *device_port_DDR |= device_pin; + + // Wait turn around time. + delayMicroseconds(RX_TX_DELAY); //RX_TX_DELAY; + + for (i = 0; i < count; i++) + { + for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1) + { + if (bit_mask & buffer[i]) + { + *device_port_OUT &= ~device_pin; + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + *device_port_OUT |= device_pin; + delayMicroseconds(7*BIT_DELAY); //BIT_DELAY_7; + } + else + { + // Send a zero bit. + *device_port_OUT &= ~device_pin; + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + *device_port_OUT |= device_pin; + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + *device_port_OUT &= ~device_pin; + delayMicroseconds(BIT_DELAY); //BIT_DELAY_1; + *device_port_OUT |= device_pin; + delayMicroseconds(5*BIT_DELAY); //BIT_DELAY_5; + } + } + } + interrupts(); //swi_enable_interrupts(); + return SWI_FUNCTION_RETCODE_SUCCESS; +} + +uint8_t atsha204Class::swi_send_byte(uint8_t value) +{ + return swi_send_bytes(1, &value); +} + +uint8_t atsha204Class::swi_receive_bytes(uint8_t count, uint8_t *buffer) +{ + uint8_t status = SWI_FUNCTION_RETCODE_SUCCESS; + uint8_t i; + uint8_t bit_mask; + uint8_t pulse_count; + uint8_t timeout_count; + + // Disable interrupts while receiving. + noInterrupts(); //swi_disable_interrupts(); + + // Configure signal pin as input. + *device_port_DDR &= ~device_pin; + + // Receive bits and store in buffer. + for (i = 0; i < count; i++) + { + for (bit_mask = 1; bit_mask > 0; bit_mask <<= 1) + { + pulse_count = 0; + + // Make sure that the variable below is big enough. + // Change it to uint16_t if 255 is too small, but be aware that + // the loop resolution decreases on an 8-bit controller in that case. + timeout_count = START_PULSE_TIME_OUT; + + // Detect start bit. + while (--timeout_count > 0) + { + // Wait for falling edge. + if ((*device_port_IN & device_pin) == 0) + break; + } + + if (timeout_count == 0) + { + status = SWI_FUNCTION_RETCODE_TIMEOUT; + break; + } + + do + { + // Wait for rising edge. + if ((*device_port_IN & device_pin) != 0) + { + // For an Atmel microcontroller this might be faster than "pulse_count++". + pulse_count = 1; + break; + } + } while (--timeout_count > 0); + + if (pulse_count == 0) + { + status = SWI_FUNCTION_RETCODE_TIMEOUT; + break; + } + + // Trying to measure the time of start bit and calculating the timeout + // for zero bit detection is not accurate enough for an 8 MHz 8-bit CPU. + // So let's just wait the maximum time for the falling edge of a zero bit + // to arrive after we have detected the rising edge of the start bit. + timeout_count = ZERO_PULSE_TIME_OUT; + + // Detect possible edge indicating zero bit. + do + { + if ((*device_port_IN & device_pin) == 0) + { + // For an Atmel microcontroller this might be faster than "pulse_count++". + pulse_count = 2; + break; + } + } while (--timeout_count > 0); + + // Wait for rising edge of zero pulse before returning. Otherwise we might interpret + // its rising edge as the next start pulse. + if (pulse_count == 2) + { + do + { + if ((*device_port_IN & device_pin) != 0) + break; + } while (timeout_count-- > 0); + } + + // Update byte at current buffer index. + else + buffer[i] |= bit_mask; // received "one" bit + } + + if (status != SWI_FUNCTION_RETCODE_SUCCESS) + break; + } + interrupts(); //swi_enable_interrupts(); + + if (status == SWI_FUNCTION_RETCODE_TIMEOUT) + { + if (i > 0) + // Indicate that we timed out after having received at least one byte. + status = SWI_FUNCTION_RETCODE_RX_FAIL; + } + return status; +} + +/* Physical functions */ + +uint8_t atsha204Class::sha204p_wakeup() +{ + swi_set_signal_pin(0); + delayMicroseconds(10*SHA204_WAKEUP_PULSE_WIDTH); + swi_set_signal_pin(1); + delay(SHA204_WAKEUP_DELAY); + + return SHA204_SUCCESS; +} + +uint8_t atsha204Class::sha204p_sleep() +{ + return swi_send_byte(SHA204_SWI_FLAG_SLEEP); +} + +uint8_t atsha204Class::sha204p_resync(uint8_t size, uint8_t *response) +{ + delay(SHA204_SYNC_TIMEOUT); + return sha204p_receive_response(size, response); +} + +uint8_t atsha204Class::sha204p_receive_response(uint8_t size, uint8_t *response) +{ + uint8_t count_byte; + uint8_t i; + uint8_t ret_code; + + for (i = 0; i < size; i++) + response[i] = 0; + + (void) swi_send_byte(SHA204_SWI_FLAG_TX); + + ret_code = swi_receive_bytes(size, response); + if (ret_code == SWI_FUNCTION_RETCODE_SUCCESS || ret_code == SWI_FUNCTION_RETCODE_RX_FAIL) + { + count_byte = response[SHA204_BUFFER_POS_COUNT]; + if ((count_byte < SHA204_RSP_SIZE_MIN) || (count_byte > size)) + return SHA204_INVALID_SIZE; + + return SHA204_SUCCESS; + } + + // Translate error so that the Communication layer + // can distinguish between a real error or the + // device being busy executing a command. + if (ret_code == SWI_FUNCTION_RETCODE_TIMEOUT) + return SHA204_RX_NO_RESPONSE; + else + return SHA204_RX_FAIL; +} + +uint8_t atsha204Class::sha204p_send_command(uint8_t count, uint8_t * command) +{ + uint8_t ret_code = swi_send_byte(SHA204_SWI_FLAG_CMD); + if (ret_code != SWI_FUNCTION_RETCODE_SUCCESS) + return SHA204_COMM_FAIL; + + return swi_send_bytes(count, command); +} + +/* Communication functions */ + +uint8_t atsha204Class::sha204c_wakeup(uint8_t *response) +{ + uint8_t ret_code = sha204p_wakeup(); + if (ret_code != SHA204_SUCCESS) + return ret_code; + + ret_code = sha204p_receive_response(SHA204_RSP_SIZE_MIN, response); + if (ret_code != SHA204_SUCCESS) + return ret_code; + + // Verify status response. + if (response[SHA204_BUFFER_POS_COUNT] != SHA204_RSP_SIZE_MIN) + ret_code = SHA204_INVALID_SIZE; + else if (response[SHA204_BUFFER_POS_STATUS] != SHA204_STATUS_BYTE_WAKEUP) + ret_code = SHA204_COMM_FAIL; + else + { + if ((response[SHA204_RSP_SIZE_MIN - SHA204_CRC_SIZE] != 0x33) + || (response[SHA204_RSP_SIZE_MIN + 1 - SHA204_CRC_SIZE] != 0x43)) + ret_code = SHA204_BAD_CRC; + } + if (ret_code != SHA204_SUCCESS) + delay(SHA204_COMMAND_EXEC_MAX); + + return ret_code; +} + +uint8_t atsha204Class::sha204c_resync(uint8_t size, uint8_t *response) +{ + // Try to re-synchronize without sending a Wake token + // (step 1 of the re-synchronization process). + uint8_t ret_code = sha204p_resync(size, response); + if (ret_code == SHA204_SUCCESS) + return ret_code; + + // We lost communication. Send a Wake pulse and try + // to receive a response (steps 2 and 3 of the + // re-synchronization process). + (void) sha204p_sleep(); + ret_code = sha204c_wakeup(response); + + // Translate a return value of success into one + // that indicates that the device had to be woken up + // and might have lost its TempKey. + return (ret_code == SHA204_SUCCESS ? SHA204_RESYNC_WITH_WAKEUP : ret_code); +} + +uint8_t atsha204Class::sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout) +{ + uint8_t ret_code = SHA204_FUNC_FAIL; + uint8_t ret_code_resync; + uint8_t n_retries_send; + uint8_t n_retries_receive; + uint8_t i; + uint8_t status_byte; + uint8_t count = tx_buffer[SHA204_BUFFER_POS_COUNT]; + uint8_t count_minus_crc = count - SHA204_CRC_SIZE; + uint16_t execution_timeout_us = (uint16_t) (execution_timeout * 1000) + SHA204_RESPONSE_TIMEOUT; + volatile uint16_t timeout_countdown; + + // Append CRC. + sha204c_calculate_crc(count_minus_crc, tx_buffer, tx_buffer + count_minus_crc); + + // Retry loop for sending a command and receiving a response. + n_retries_send = SHA204_RETRY_COUNT + 1; + + while ((n_retries_send-- > 0) && (ret_code != SHA204_SUCCESS)) + { + // Send command. + ret_code = sha204p_send_command(count, tx_buffer); + if (ret_code != SHA204_SUCCESS) + { + if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE) + return ret_code; // The device seems to be dead in the water. + else + continue; + } + + // Wait minimum command execution time and then start polling for a response. + delay(execution_delay); + + // Retry loop for receiving a response. + n_retries_receive = SHA204_RETRY_COUNT + 1; + while (n_retries_receive-- > 0) + { + // Reset response buffer. + for (i = 0; i < rx_size; i++) + rx_buffer[i] = 0; + + // Poll for response. + timeout_countdown = execution_timeout_us; + do + { + ret_code = sha204p_receive_response(rx_size, rx_buffer); + timeout_countdown -= SHA204_RESPONSE_TIMEOUT; + } + while ((timeout_countdown > SHA204_RESPONSE_TIMEOUT) && (ret_code == SHA204_RX_NO_RESPONSE)); + + if (ret_code == SHA204_RX_NO_RESPONSE) + { + // We did not receive a response. Re-synchronize and send command again. + if (sha204c_resync(rx_size, rx_buffer) == SHA204_RX_NO_RESPONSE) + // The device seems to be dead in the water. + return ret_code; + else + break; + } + + // Check whether we received a valid response. + if (ret_code == SHA204_INVALID_SIZE) + { + // We see 0xFF for the count when communication got out of sync. + ret_code_resync = sha204c_resync(rx_size, rx_buffer); + if (ret_code_resync == SHA204_SUCCESS) + // We did not have to wake up the device. Try receiving response again. + continue; + if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP) + // We could re-synchronize, but only after waking up the device. + // Re-send command. + break; + else + // We failed to re-synchronize. + return ret_code; + } + + // We received a response of valid size. + // Check the consistency of the response. + ret_code = sha204c_check_crc(rx_buffer); + if (ret_code == SHA204_SUCCESS) + { + // Received valid response. + if (rx_buffer[SHA204_BUFFER_POS_COUNT] > SHA204_RSP_SIZE_MIN) + // Received non-status response. We are done. + return ret_code; + + // Received status response. + status_byte = rx_buffer[SHA204_BUFFER_POS_STATUS]; + + // Translate the three possible device status error codes + // into library return codes. + if (status_byte == SHA204_STATUS_BYTE_PARSE) + return SHA204_PARSE_ERROR; + if (status_byte == SHA204_STATUS_BYTE_EXEC) + return SHA204_CMD_FAIL; + if (status_byte == SHA204_STATUS_BYTE_COMM) + { + // In case of the device status byte indicating a communication + // error this function exits the retry loop for receiving a response + // and enters the overall retry loop + // (send command / receive response). + ret_code = SHA204_STATUS_CRC; + break; + } + + // Received status response from CheckMAC, DeriveKey, GenDig, + // Lock, Nonce, Pause, UpdateExtra, or Write command. + return ret_code; + } + + else + { + // Received response with incorrect CRC. + ret_code_resync = sha204c_resync(rx_size, rx_buffer); + if (ret_code_resync == SHA204_SUCCESS) + // We did not have to wake up the device. Try receiving response again. + continue; + if (ret_code_resync == SHA204_RESYNC_WITH_WAKEUP) + // We could re-synchronize, but only after waking up the device. + // Re-send command. + break; + else + // We failed to re-synchronize. + return ret_code; + } // block end of check response consistency + + } // block end of receive retry loop + + } // block end of send and receive retry loop + + return ret_code; +} + + +/* Marshaling functions */ + +uint8_t atsha204Class::sha204m_random(uint8_t * tx_buffer, uint8_t * rx_buffer, uint8_t mode) +{ + if (!tx_buffer || !rx_buffer || (mode > RANDOM_NO_SEED_UPDATE)) + return SHA204_BAD_PARAM; + + tx_buffer[SHA204_COUNT_IDX] = RANDOM_COUNT; + tx_buffer[SHA204_OPCODE_IDX] = SHA204_RANDOM; + tx_buffer[RANDOM_MODE_IDX] = mode & RANDOM_SEED_UPDATE; + + tx_buffer[RANDOM_PARAM2_IDX] = + tx_buffer[RANDOM_PARAM2_IDX + 1] = 0; + + return sha204c_send_and_receive(&tx_buffer[0], RANDOM_RSP_SIZE, &rx_buffer[0], RANDOM_DELAY, RANDOM_EXEC_MAX - RANDOM_DELAY); +} + +uint8_t atsha204Class::sha204m_dev_rev(uint8_t *tx_buffer, uint8_t *rx_buffer) +{ + if (!tx_buffer || !rx_buffer) + return SHA204_BAD_PARAM; + + tx_buffer[SHA204_COUNT_IDX] = DEVREV_COUNT; + tx_buffer[SHA204_OPCODE_IDX] = SHA204_DEVREV; + + // Parameters are 0. + tx_buffer[DEVREV_PARAM1_IDX] = + tx_buffer[DEVREV_PARAM2_IDX] = + tx_buffer[DEVREV_PARAM2_IDX + 1] = 0; + + return sha204c_send_and_receive(&tx_buffer[0], DEVREV_RSP_SIZE, &rx_buffer[0], + DEVREV_DELAY, DEVREV_EXEC_MAX - DEVREV_DELAY); +} + +uint8_t atsha204Class::sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address) +{ + uint8_t rx_size; + + if (!tx_buffer || !rx_buffer || ((zone & ~READ_ZONE_MASK) != 0) + || ((zone & READ_ZONE_MODE_32_BYTES) && (zone == SHA204_ZONE_OTP))) + return SHA204_BAD_PARAM; + + address >>= 2; + if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_CONFIG) + { + if (address > SHA204_ADDRESS_MASK_CONFIG) + return SHA204_BAD_PARAM; + } + else if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_OTP) + { + if (address > SHA204_ADDRESS_MASK_OTP) + return SHA204_BAD_PARAM; + } + else if ((zone & SHA204_ZONE_MASK) == SHA204_ZONE_DATA) + { + if (address > SHA204_ADDRESS_MASK) + return SHA204_BAD_PARAM; + } + + tx_buffer[SHA204_COUNT_IDX] = READ_COUNT; + tx_buffer[SHA204_OPCODE_IDX] = SHA204_READ; + tx_buffer[READ_ZONE_IDX] = zone; + tx_buffer[READ_ADDR_IDX] = (uint8_t) (address & SHA204_ADDRESS_MASK); + tx_buffer[READ_ADDR_IDX + 1] = 0; + + rx_size = (zone & SHA204_ZONE_COUNT_FLAG) ? READ_32_RSP_SIZE : READ_4_RSP_SIZE; + + return sha204c_send_and_receive(&tx_buffer[0], rx_size, &rx_buffer[0], READ_DELAY, READ_EXEC_MAX - READ_DELAY); +} + +uint8_t atsha204Class::sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t param2, + uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3, + uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer) +{ + uint8_t poll_delay, poll_timeout, response_size; + uint8_t *p_buffer; + uint8_t len; + + uint8_t ret_code = sha204m_check_parameters(op_code, param1, param2, + datalen1, data1, datalen2, data2, datalen3, data3, + tx_size, tx_buffer, rx_size, rx_buffer); + if (ret_code != SHA204_SUCCESS) + return ret_code; + + // Supply delays and response size. + switch (op_code) + { + case SHA204_CHECKMAC: + poll_delay = CHECKMAC_DELAY; + poll_timeout = CHECKMAC_EXEC_MAX - CHECKMAC_DELAY; + response_size = CHECKMAC_RSP_SIZE; + break; + + case SHA204_DERIVE_KEY: + poll_delay = DERIVE_KEY_DELAY; + poll_timeout = DERIVE_KEY_EXEC_MAX - DERIVE_KEY_DELAY; + response_size = DERIVE_KEY_RSP_SIZE; + break; + + case SHA204_DEVREV: + poll_delay = DEVREV_DELAY; + poll_timeout = DEVREV_EXEC_MAX - DEVREV_DELAY; + response_size = DEVREV_RSP_SIZE; + break; + + case SHA204_GENDIG: + poll_delay = GENDIG_DELAY; + poll_timeout = GENDIG_EXEC_MAX - GENDIG_DELAY; + response_size = GENDIG_RSP_SIZE; + break; + + case SHA204_HMAC: + poll_delay = HMAC_DELAY; + poll_timeout = HMAC_EXEC_MAX - HMAC_DELAY; + response_size = HMAC_RSP_SIZE; + break; + + case SHA204_LOCK: + poll_delay = LOCK_DELAY; + poll_timeout = LOCK_EXEC_MAX - LOCK_DELAY; + response_size = LOCK_RSP_SIZE; + break; + + case SHA204_MAC: + poll_delay = MAC_DELAY; + poll_timeout = MAC_EXEC_MAX - MAC_DELAY; + response_size = MAC_RSP_SIZE; + break; + + case SHA204_NONCE: + poll_delay = NONCE_DELAY; + poll_timeout = NONCE_EXEC_MAX - NONCE_DELAY; + response_size = param1 == NONCE_MODE_PASSTHROUGH + ? NONCE_RSP_SIZE_SHORT : NONCE_RSP_SIZE_LONG; + break; + + case SHA204_PAUSE: + poll_delay = PAUSE_DELAY; + poll_timeout = PAUSE_EXEC_MAX - PAUSE_DELAY; + response_size = PAUSE_RSP_SIZE; + break; + + case SHA204_RANDOM: + poll_delay = RANDOM_DELAY; + poll_timeout = RANDOM_EXEC_MAX - RANDOM_DELAY; + response_size = RANDOM_RSP_SIZE; + break; + + case SHA204_READ: + poll_delay = READ_DELAY; + poll_timeout = READ_EXEC_MAX - READ_DELAY; + response_size = (param1 & SHA204_ZONE_COUNT_FLAG) + ? READ_32_RSP_SIZE : READ_4_RSP_SIZE; + break; + + case SHA204_UPDATE_EXTRA: + poll_delay = UPDATE_DELAY; + poll_timeout = UPDATE_EXEC_MAX - UPDATE_DELAY; + response_size = UPDATE_RSP_SIZE; + break; + + case SHA204_WRITE: + poll_delay = WRITE_DELAY; + poll_timeout = WRITE_EXEC_MAX - WRITE_DELAY; + response_size = WRITE_RSP_SIZE; + break; + + default: + poll_delay = 0; + poll_timeout = SHA204_COMMAND_EXEC_MAX; + response_size = rx_size; + } + + // Assemble command. + len = datalen1 + datalen2 + datalen3 + SHA204_CMD_SIZE_MIN; + p_buffer = tx_buffer; + *p_buffer++ = len; + *p_buffer++ = op_code; + *p_buffer++ = param1; + *p_buffer++ = param2 & 0xFF; + *p_buffer++ = param2 >> 8; + + if (datalen1 > 0) { + memcpy(p_buffer, data1, datalen1); + p_buffer += datalen1; + } + if (datalen2 > 0) { + memcpy(p_buffer, data2, datalen2); + p_buffer += datalen2; + } + if (datalen3 > 0) { + memcpy(p_buffer, data3, datalen3); + p_buffer += datalen3; + } + + sha204c_calculate_crc(len - SHA204_CRC_SIZE, tx_buffer, p_buffer); + + // Send command and receive response. + return sha204c_send_and_receive(&tx_buffer[0], response_size, + &rx_buffer[0], poll_delay, poll_timeout); +} + +uint8_t atsha204Class::sha204m_check_parameters(uint8_t op_code, uint8_t param1, uint16_t param2, + uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3, + uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer) +{ +#ifdef SHA204_CHECK_PARAMETERS + + uint8_t len = datalen1 + datalen2 + datalen3 + SHA204_CMD_SIZE_MIN; + if (!tx_buffer || tx_size < len || rx_size < SHA204_RSP_SIZE_MIN || !rx_buffer) + return SHA204_BAD_PARAM; + + if ((datalen1 > 0 && !data1) || (datalen2 > 0 && !data2) || (datalen3 > 0 && !data3)) + return SHA204_BAD_PARAM; + + // Check parameters depending on op-code. + switch (op_code) + { + case SHA204_CHECKMAC: + if ( + // no null pointers allowed + !data1 || !data2 + // No reserved bits should be set. + || (param1 | CHECKMAC_MODE_MASK) != CHECKMAC_MODE_MASK + // key_id > 15 not allowed + || param2 > SHA204_KEY_ID_MAX + ) + return SHA204_BAD_PARAM; + break; + + case SHA204_DERIVE_KEY: + if (param2 > SHA204_KEY_ID_MAX) + return SHA204_BAD_PARAM; + break; + + case SHA204_DEVREV: + break; + + case SHA204_GENDIG: + if ((param1 != GENDIG_ZONE_OTP) && (param1 != GENDIG_ZONE_DATA)) + return SHA204_BAD_PARAM; + break; + + case SHA204_HMAC: + if ((param1 & ~HMAC_MODE_MASK) != 0) + return SHA204_BAD_PARAM; + break; + + case SHA204_LOCK: + if (((param1 & ~LOCK_ZONE_MASK) != 0) + || ((param1 & LOCK_ZONE_NO_CRC) && (param2 != 0))) + return SHA204_BAD_PARAM; + break; + + case SHA204_MAC: + if (((param1 & ~MAC_MODE_MASK) != 0) + || (((param1 & MAC_MODE_BLOCK2_TEMPKEY) == 0) && !data1)) + return SHA204_BAD_PARAM; + break; + + case SHA204_NONCE: + if ( !data1 + || (param1 > NONCE_MODE_PASSTHROUGH) + || (param1 == NONCE_MODE_INVALID) + ) + return SHA204_BAD_PARAM; + break; + + case SHA204_PAUSE: + break; + + case SHA204_RANDOM: + if (param1 > RANDOM_NO_SEED_UPDATE) + return SHA204_BAD_PARAM; + break; + + case SHA204_READ: + if (((param1 & ~READ_ZONE_MASK) != 0) + || ((param1 & READ_ZONE_MODE_32_BYTES) && (param1 == SHA204_ZONE_OTP))) + return SHA204_BAD_PARAM; + break; + + case SHA204_TEMPSENSE: + break; + + case SHA204_UPDATE_EXTRA: + if (param1 > UPDATE_CONFIG_BYTE_86) + return SHA204_BAD_PARAM; + break; + + case SHA204_WRITE: + if (!data1 || ((param1 & ~WRITE_ZONE_MASK) != 0)) + return SHA204_BAD_PARAM; + break; + + default: + // unknown op-code + return SHA204_BAD_PARAM; + } + + return SHA204_SUCCESS; + +#else + return SHA204_SUCCESS; +#endif +} + +/* CRC Calculator and Checker */ + +void atsha204Class::sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc) +{ + uint16_t crc_register = 0; + + crc_register = calculateAndUpdateCrc(length, data, crc_register); + crc[0] = (uint8_t) (crc_register & 0x00FF); + crc[1] = (uint8_t) (crc_register >> 8); +} + +uint8_t atsha204Class::sha204c_check_crc(uint8_t *response) +{ + uint8_t crc[SHA204_CRC_SIZE]; + uint8_t count = response[SHA204_BUFFER_POS_COUNT]; + + count -= SHA204_CRC_SIZE; + sha204c_calculate_crc(count, response, crc); + + return (crc[0] == response[count] && crc[1] == response[count + 1]) + ? SHA204_SUCCESS : SHA204_BAD_CRC; +} diff --git a/libraries/sha204/sha204_library.h b/libraries/sha204/sha204_library.h new file mode 100644 index 0000000..3e2c9f0 --- /dev/null +++ b/libraries/sha204/sha204_library.h @@ -0,0 +1,321 @@ +#include "Arduino.h" + +#ifndef sha204_library_H +#define sha204_library_H + +/* bitbang_config.h */ + +#define PORT_ACCESS_TIME (630) //! time it takes to toggle the pin at CPU clock of 16 MHz (ns) +#define START_PULSE_WIDTH (4340) //! width of start pulse (ns) +#define BIT_DELAY (4) //! delay macro for width of one pulse (start pulse or zero pulse, in ns) +#define RX_TX_DELAY (15) //! turn around time when switching from receive to transmit +#define START_PULSE_TIME_OUT (255) //! This value is decremented while waiting for the falling edge of a start pulse. +#define ZERO_PULSE_TIME_OUT (26) //! This value is decremented while waiting for the falling edge of a zero pulse. + +/* swi_phys.h */ + +#define SWI_FUNCTION_RETCODE_SUCCESS ((uint8_t) 0x00) //!< Communication with device succeeded. +#define SWI_FUNCTION_RETCODE_TIMEOUT ((uint8_t) 0xF1) //!< Communication timed out. +#define SWI_FUNCTION_RETCODE_RX_FAIL ((uint8_t) 0xF9) //!< Communication failed after at least one byte was received. + +/* sha204_physical.h */ + +#define SHA204_RSP_SIZE_MIN ((uint8_t) 4) //!< minimum number of bytes in response +#define SHA204_RSP_SIZE_MAX ((uint8_t) 35) //!< maximum size of response packet +#define SHA204_BUFFER_POS_COUNT (0) //!< buffer index of count byte in command or response +#define SHA204_BUFFER_POS_DATA (1) //!< buffer index of data in response +#define SHA204_WAKEUP_PULSE_WIDTH (uint8_t) (6.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5) //! width of Wakeup pulse in 10 us units +#define SHA204_WAKEUP_DELAY (uint8_t) (3.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5) //! delay between Wakeup pulse and communication in ms + +/* sha204_swi.c */ +#define SHA204_SWI_FLAG_CMD ((uint8_t) 0x77) //!< flag preceding a command +#define SHA204_SWI_FLAG_TX ((uint8_t) 0x88) //!< flag requesting a response +#define SHA204_SWI_FLAG_IDLE ((uint8_t) 0xBB) //!< flag requesting to go into Idle mode +#define SHA204_SWI_FLAG_SLEEP ((uint8_t) 0xCC) //!< flag requesting to go into Sleep mode + +/* sha204_comm_marshaling.h */ +// command op-code definitions +#define SHA204_CHECKMAC ((uint8_t) 0x28) //!< CheckMac command op-code +#define SHA204_DERIVE_KEY ((uint8_t) 0x1C) //!< DeriveKey command op-code +#define SHA204_DEVREV ((uint8_t) 0x30) //!< DevRev command op-code +#define SHA204_GENDIG ((uint8_t) 0x15) //!< GenDig command op-code +#define SHA204_HMAC ((uint8_t) 0x11) //!< HMAC command op-code +#define SHA204_LOCK ((uint8_t) 0x17) //!< Lock command op-code +#define SHA204_MAC ((uint8_t) 0x08) //!< MAC command op-code +#define SHA204_NONCE ((uint8_t) 0x16) //!< Nonce command op-code +#define SHA204_PAUSE ((uint8_t) 0x01) //!< Pause command op-code +#define SHA204_RANDOM ((uint8_t) 0x1B) //!< Random command op-code +#define SHA204_READ ((uint8_t) 0x02) //!< Read command op-code +#define SHA204_UPDATE_EXTRA ((uint8_t) 0x20) //!< UpdateExtra command op-code +#define SHA204_WRITE ((uint8_t) 0x12) //!< Write command op-code + +// packet size definitions +#define SHA204_RSP_SIZE_VAL ((uint8_t) 7) //!< size of response packet containing four bytes of data + +// parameter range definitions +#define SHA204_KEY_ID_MAX ((uint8_t) 15) //!< maximum value for key id +#define SHA204_OTP_BLOCK_MAX ((uint8_t) 1) //!< maximum value for OTP block + +// definitions for command packet indexes common to all commands +#define SHA204_COUNT_IDX ( 0) //!< command packet index for count +#define SHA204_OPCODE_IDX ( 1) //!< command packet index for op-code +#define SHA204_PARAM1_IDX ( 2) //!< command packet index for first parameter +#define SHA204_PARAM2_IDX ( 3) //!< command packet index for second parameter +#define SHA204_DATA_IDX ( 5) //!< command packet index for second parameter + +// zone definitions +#define SHA204_ZONE_CONFIG ((uint8_t) 0x00) //!< Configuration zone +#define SHA204_ZONE_OTP ((uint8_t) 0x01) //!< OTP (One Time Programming) zone +#define SHA204_ZONE_DATA ((uint8_t) 0x02) //!< Data zone +#define SHA204_ZONE_MASK ((uint8_t) 0x03) //!< Zone mask +#define SHA204_ZONE_COUNT_FLAG ((uint8_t) 0x80) //!< Zone bit 7 set: Access 32 bytes, otherwise 4 bytes. +#define SHA204_ZONE_ACCESS_4 ((uint8_t) 4) //!< Read or write 4 bytes. +#define SHA204_ZONE_ACCESS_32 ((uint8_t) 32) //!< Read or write 32 bytes. +#define SHA204_ADDRESS_MASK_CONFIG ( 0x001F) //!< Address bits 5 to 7 are 0 for Configuration zone. +#define SHA204_ADDRESS_MASK_OTP ( 0x000F) //!< Address bits 4 to 7 are 0 for OTP zone. +#define SHA204_ADDRESS_MASK ( 0x007F) //!< Address bit 7 to 15 are always 0. + +// CheckMAC command definitions +#define CHECKMAC_MODE_IDX SHA204_PARAM1_IDX //!< CheckMAC command index for mode +#define CHECKMAC_KEYID_IDX SHA204_PARAM2_IDX //!< CheckMAC command index for key identifier +#define CHECKMAC_CLIENT_CHALLENGE_IDX SHA204_DATA_IDX //!< CheckMAC command index for client challenge +#define CHECKMAC_CLIENT_RESPONSE_IDX (37) //!< CheckMAC command index for client response +#define CHECKMAC_DATA_IDX (69) //!< CheckMAC command index for other data +#define CHECKMAC_COUNT (84) //!< CheckMAC command packet size +#define CHECKMAC_MODE_MASK ((uint8_t) 0x27) //!< CheckMAC mode bits 3, 4, 6, and 7 are 0. +#define CHECKMAC_CLIENT_CHALLENGE_SIZE (32) //!< CheckMAC size of client challenge +#define CHECKMAC_CLIENT_RESPONSE_SIZE (32) //!< CheckMAC size of client response +#define CHECKMAC_OTHER_DATA_SIZE (13) //!< CheckMAC size of "other data" + +// DeriveKey command definitions +#define DERIVE_KEY_RANDOM_IDX SHA204_PARAM1_IDX //!< DeriveKey command index for random bit +#define DERIVE_KEY_TARGETKEY_IDX SHA204_PARAM2_IDX //!< DeriveKey command index for target slot +#define DERIVE_KEY_MAC_IDX SHA204_DATA_IDX //!< DeriveKey command index for optional MAC +#define DERIVE_KEY_COUNT_SMALL SHA204_CMD_SIZE_MIN //!< DeriveKey command packet size without MAC +#define DERIVE_KEY_COUNT_LARGE (39) //!< DeriveKey command packet size with MAC +#define DERIVE_KEY_RANDOM_FLAG ((uint8_t) 4) //!< DeriveKey 1. parameter +#define DERIVE_KEY_MAC_SIZE (32) //!< DeriveKey MAC size + +// DevRev command definitions +#define DEVREV_PARAM1_IDX SHA204_PARAM1_IDX //!< DevRev command index for 1. parameter (ignored) +#define DEVREV_PARAM2_IDX SHA204_PARAM2_IDX //!< DevRev command index for 2. parameter (ignored) +#define DEVREV_COUNT SHA204_CMD_SIZE_MIN //!< DevRev command packet size + +// GenDig command definitions +#define GENDIG_ZONE_IDX SHA204_PARAM1_IDX //!< GenDig command index for zone +#define GENDIG_KEYID_IDX SHA204_PARAM2_IDX //!< GenDig command index for key id +#define GENDIG_DATA_IDX SHA204_DATA_IDX //!< GenDig command index for optional data +#define GENDIG_COUNT SHA204_CMD_SIZE_MIN //!< GenDig command packet size without "other data" +#define GENDIG_COUNT_DATA (11) //!< GenDig command packet size with "other data" +#define GENDIG_OTHER_DATA_SIZE (4) //!< GenDig size of "other data" +#define GENDIG_ZONE_CONFIG ((uint8_t) 0) //!< GenDig zone id config +#define GENDIG_ZONE_OTP ((uint8_t) 1) //!< GenDig zone id OTP +#define GENDIG_ZONE_DATA ((uint8_t) 2) //!< GenDig zone id data + +// HMAC command definitions +#define HMAC_MODE_IDX SHA204_PARAM1_IDX //!< HMAC command index for mode +#define HMAC_KEYID_IDX SHA204_PARAM2_IDX //!< HMAC command index for key id +#define HMAC_COUNT SHA204_CMD_SIZE_MIN //!< HMAC command packet size +#define HMAC_MODE_MASK ((uint8_t) 0x74) //!< HMAC mode bits 0, 1, 3, and 7 are 0. + +// Lock command definitions +#define LOCK_ZONE_IDX SHA204_PARAM1_IDX //!< Lock command index for zone +#define LOCK_SUMMARY_IDX SHA204_PARAM2_IDX //!< Lock command index for summary +#define LOCK_COUNT SHA204_CMD_SIZE_MIN //!< Lock command packet size +#define LOCK_ZONE_NO_CONFIG ((uint8_t) 0x01) //!< Lock zone is OTP or Data +#define LOCK_ZONE_NO_CRC ((uint8_t) 0x80) //!< Lock command: Ignore summary. +#define LOCK_ZONE_MASK (0x81) //!< Lock parameter 1 bits 2 to 6 are 0. + +// Mac command definitions +#define MAC_MODE_IDX SHA204_PARAM1_IDX //!< MAC command index for mode +#define MAC_KEYID_IDX SHA204_PARAM2_IDX //!< MAC command index for key id +#define MAC_CHALLENGE_IDX SHA204_DATA_IDX //!< MAC command index for optional challenge +#define MAC_COUNT_SHORT SHA204_CMD_SIZE_MIN //!< MAC command packet size without challenge +#define MAC_COUNT_LONG (39) //!< MAC command packet size with challenge +#define MAC_MODE_BLOCK2_TEMPKEY ((uint8_t) 0x01) //!< MAC mode bit 0: second SHA block from TempKey +#define MAC_MODE_BLOCK1_TEMPKEY ((uint8_t) 0x02) //!< MAC mode bit 1: first SHA block from TempKey +#define MAC_MODE_SOURCE_FLAG_MATCH ((uint8_t) 0x04) //!< MAC mode bit 2: match TempKey.SourceFlag +#define MAC_MODE_PASSTHROUGH ((uint8_t) 0x07) //!< MAC mode bit 0-2: pass-through mode +#define MAC_MODE_INCLUDE_OTP_88 ((uint8_t) 0x10) //!< MAC mode bit 4: include first 88 OTP bits +#define MAC_MODE_INCLUDE_OTP_64 ((uint8_t) 0x20) //!< MAC mode bit 5: include first 64 OTP bits +#define MAC_MODE_INCLUDE_SN ((uint8_t) 0x40) //!< MAC mode bit 6: include serial number +#define MAC_CHALLENGE_SIZE (32) //!< MAC size of challenge +#define MAC_MODE_MASK ((uint8_t) 0x77) //!< MAC mode bits 3 and 7 are 0. + +// Nonce command definitions +#define NONCE_MODE_IDX SHA204_PARAM1_IDX //!< Nonce command index for mode +#define NONCE_PARAM2_IDX SHA204_PARAM2_IDX //!< Nonce command index for 2. parameter +#define NONCE_INPUT_IDX SHA204_DATA_IDX //!< Nonce command index for input data +#define NONCE_COUNT_SHORT (27) //!< Nonce command packet size for 20 bytes of data +#define NONCE_COUNT_LONG (39) //!< Nonce command packet size for 32 bytes of data +#define NONCE_MODE_MASK ((uint8_t) 3) //!< Nonce mode bits 2 to 7 are 0. +#define NONCE_MODE_SEED_UPDATE ((uint8_t) 0x00) //!< Nonce mode: update seed +#define NONCE_MODE_NO_SEED_UPDATE ((uint8_t) 0x01) //!< Nonce mode: do not update seed +#define NONCE_MODE_INVALID ((uint8_t) 0x02) //!< Nonce mode 2 is invalid. +#define NONCE_MODE_PASSTHROUGH ((uint8_t) 0x03) //!< Nonce mode: pass-through +#define NONCE_NUMIN_SIZE (20) //!< Nonce data length +#define NONCE_NUMIN_SIZE_PASSTHROUGH (32) //!< Nonce data length in pass-through mode (mode = 3) + +// Pause command definitions +#define PAUSE_SELECT_IDX SHA204_PARAM1_IDX //!< Pause command index for Selector +#define PAUSE_PARAM2_IDX SHA204_PARAM2_IDX //!< Pause command index for 2. parameter +#define PAUSE_COUNT SHA204_CMD_SIZE_MIN //!< Pause command packet size + +// Random command definitions +#define RANDOM_MODE_IDX SHA204_PARAM1_IDX //!< Random command index for mode +#define RANDOM_PARAM2_IDX SHA204_PARAM2_IDX //!< Random command index for 2. parameter +#define RANDOM_COUNT SHA204_CMD_SIZE_MIN //!< Random command packet size +#define RANDOM_SEED_UPDATE ((uint8_t) 0x00) //!< Random mode for automatic seed update +#define RANDOM_NO_SEED_UPDATE ((uint8_t) 0x01) //!< Random mode for no seed update + +// Read command definitions +#define READ_ZONE_IDX SHA204_PARAM1_IDX //!< Read command index for zone +#define READ_ADDR_IDX SHA204_PARAM2_IDX //!< Read command index for address +#define READ_COUNT SHA204_CMD_SIZE_MIN //!< Read command packet size +#define READ_ZONE_MASK ((uint8_t) 0x83) //!< Read zone bits 2 to 6 are 0. +#define READ_ZONE_MODE_32_BYTES ((uint8_t) 0x80) //!< Read mode: 32 bytes + +// UpdateExtra command definitions +#define UPDATE_MODE_IDX SHA204_PARAM1_IDX //!< UpdateExtra command index for mode +#define UPDATE_VALUE_IDX SHA204_PARAM2_IDX //!< UpdateExtra command index for new value +#define UPDATE_COUNT SHA204_CMD_SIZE_MIN //!< UpdateExtra command packet size +#define UPDATE_CONFIG_BYTE_86 ((uint8_t) 0x01) //!< UpdateExtra mode: update Config byte 86 + +// Write command definitions +#define WRITE_ZONE_IDX SHA204_PARAM1_IDX //!< Write command index for zone +#define WRITE_ADDR_IDX SHA204_PARAM2_IDX //!< Write command index for address +#define WRITE_VALUE_IDX SHA204_DATA_IDX //!< Write command index for data +#define WRITE_MAC_VS_IDX ( 9) //!< Write command index for MAC following short data +#define WRITE_MAC_VL_IDX (37) //!< Write command index for MAC following long data +#define WRITE_COUNT_SHORT (11) //!< Write command packet size with short data and no MAC +#define WRITE_COUNT_LONG (39) //!< Write command packet size with long data and no MAC +#define WRITE_COUNT_SHORT_MAC (43) //!< Write command packet size with short data and MAC +#define WRITE_COUNT_LONG_MAC (71) //!< Write command packet size with long data and MAC +#define WRITE_MAC_SIZE (32) //!< Write MAC size +#define WRITE_ZONE_MASK ((uint8_t) 0xC3) //!< Write zone bits 2 to 5 are 0. +#define WRITE_ZONE_WITH_MAC ((uint8_t) 0x40) //!< Write zone bit 6: write encrypted with MAC + +// Response size definitions +#define CHECKMAC_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of DeriveKey command +#define DERIVE_KEY_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of DeriveKey command +#define DEVREV_RSP_SIZE SHA204_RSP_SIZE_VAL //!< response size of DevRev command returns 4 bytes +#define GENDIG_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of GenDig command +#define HMAC_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of HMAC command +#define LOCK_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of Lock command +#define MAC_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of MAC command +#define NONCE_RSP_SIZE_SHORT SHA204_RSP_SIZE_MIN //!< response size of Nonce command with mode[0:1] = 3 +#define NONCE_RSP_SIZE_LONG SHA204_RSP_SIZE_MAX //!< response size of Nonce command +#define PAUSE_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of Pause command +#define RANDOM_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of Random command +#define READ_4_RSP_SIZE SHA204_RSP_SIZE_VAL //!< response size of Read command when reading 4 bytes +#define READ_32_RSP_SIZE SHA204_RSP_SIZE_MAX //!< response size of Read command when reading 32 bytes +#define TEMP_SENSE_RSP_SIZE SHA204_RSP_SIZE_VAL //!< response size of TempSense command returns 4 bytes +#define UPDATE_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of UpdateExtra command +#define WRITE_RSP_SIZE SHA204_RSP_SIZE_MIN //!< response size of Write command + +// command timing definitions for minimum execution times (ms) +#define CHECKMAC_DELAY ((uint8_t) (12.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define DERIVE_KEY_DELAY ((uint8_t) (14.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define DEVREV_DELAY ((uint8_t) ( 0.4 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define GENDIG_DELAY ((uint8_t) (11.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define HMAC_DELAY ((uint8_t) (27.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define LOCK_DELAY ((uint8_t) ( 5.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define MAC_DELAY ((uint8_t) (12.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define NONCE_DELAY ((uint8_t) (22.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define PAUSE_DELAY ((uint8_t) ( 0.4 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define RANDOM_DELAY ((uint8_t) (11.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define READ_DELAY ((uint8_t) ( 0.4 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define TEMP_SENSE_DELAY ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define UPDATE_DELAY ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) +#define WRITE_DELAY ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_NEGATIVE - 0.5)) + +// command timing definitions for maximum execution times (ms) +#define CHECKMAC_EXEC_MAX ((uint8_t) (38.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define DERIVE_KEY_EXEC_MAX ((uint8_t) (62.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define DEVREV_EXEC_MAX ((uint8_t) ( 2.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define GENDIG_EXEC_MAX ((uint8_t) (43.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define HMAC_EXEC_MAX ((uint8_t) (69.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define LOCK_EXEC_MAX ((uint8_t) (24.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define MAC_EXEC_MAX ((uint8_t) (35.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define NONCE_EXEC_MAX ((uint8_t) (60.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define PAUSE_EXEC_MAX ((uint8_t) ( 2.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define RANDOM_EXEC_MAX ((uint8_t) (50.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define READ_EXEC_MAX ((uint8_t) ( 4.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define TEMP_SENSE_EXEC_MAX ((uint8_t) (11.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define UPDATE_EXEC_MAX ((uint8_t) ( 6.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) +#define WRITE_EXEC_MAX ((uint8_t) (42.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) + +/* from sha204_config.h */ + +#define CPU_CLOCK_DEVIATION_POSITIVE (1.01) +#define CPU_CLOCK_DEVIATION_NEGATIVE (0.99) +#define SHA204_RETRY_COUNT (1) +#define SWI_RECEIVE_TIME_OUT ((uint16_t) 163) //! #START_PULSE_TIME_OUT in us instead of loop counts +#define SWI_US_PER_BYTE ((uint16_t) 313) //! It takes 312.5 us to send a byte (9 single-wire bits / 230400 Baud * 8 flag bits). +#define SHA204_SYNC_TIMEOUT ((uint8_t) 85)//! delay before sending a transmit flag in the synchronization routine +#define SHA204_RESPONSE_TIMEOUT ((uint16_t) SWI_RECEIVE_TIME_OUT + SWI_US_PER_BYTE) //! SWI response timeout is the sum of receive timeout and the time it takes to send the TX flag. + +/* from sha204_comm.h */ + +#define SHA204_COMMAND_EXEC_MAX ((uint8_t) (69.0 * CPU_CLOCK_DEVIATION_POSITIVE + 0.5)) //! maximum command delay +#define SHA204_CMD_SIZE_MIN ((uint8_t) 7) //! minimum number of bytes in command (from count byte to second CRC byte) +#define SHA204_CMD_SIZE_MAX ((uint8_t) 84) //! maximum size of command packet (CheckMac) +#define SHA204_CRC_SIZE ((uint8_t) 2) //! number of CRC bytes +#define SHA204_BUFFER_POS_STATUS (1) //! buffer index of status byte in status response +#define SHA204_BUFFER_POS_DATA (1) //! buffer index of first data byte in data response +#define SHA204_STATUS_BYTE_WAKEUP ((uint8_t) 0x11) //! command parse error +#define SHA204_STATUS_BYTE_PARSE ((uint8_t) 0x03) //! command parse error +#define SHA204_STATUS_BYTE_EXEC ((uint8_t) 0x0F) //! command execution error +#define SHA204_STATUS_BYTE_COMM ((uint8_t) 0xFF) //! communication error + +/* EEPROM Addresses */ +/* Configuration Zone */ +#define ADDRESS_SN03 0 // SN[0:3] are bytes 0->3 of configuration zone +#define ADDRESS_RevNum 4 // bytes 4->7 of config zone are RevNum +#define ADDRESS_SN47 8 // SN[4:7] are bytes 8->11 of config zone +#define ADDRESS_SN8 12 // SN[8] is byte 12 of config zone, should be 0xEE +#define ADDRESS_I2CEN 14 // I2C Enable, bit 0 represents I2C enable status +#define ADDRESS_I2CADD 16 // Defines I2C address of SHA204 +#define ADDRESS_OTPMODE 18 // Sets the One-time-programmable mode +#define ADDRESS_SELECTOR 19 // Controls writability of Selector + + +class atsha204Class +{ +private: + uint8_t device_pin; + volatile uint8_t *device_port_DDR, *device_port_OUT, *device_port_IN; + void sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc); + uint8_t sha204c_check_crc(uint8_t *response); + void swi_set_signal_pin(uint8_t is_high); + uint8_t swi_receive_bytes(uint8_t count, uint8_t *buffer); + uint8_t swi_send_bytes(uint8_t count, uint8_t *buffer); + uint8_t swi_send_byte(uint8_t value); + uint8_t sha204p_receive_response(uint8_t size, uint8_t *response); + uint8_t sha204p_wakeup(); + uint8_t sha204p_send_command(uint8_t count, uint8_t * command); + uint8_t sha204p_sleep(); + uint8_t sha204p_resync(uint8_t size, uint8_t *response); + + +public: + atsha204Class(uint8_t pin); // Constructor + uint8_t sha204c_wakeup(uint8_t *response); + uint8_t sha204c_send_and_receive(uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer, uint8_t execution_delay, uint8_t execution_timeout); + uint8_t sha204c_resync(uint8_t size, uint8_t *response); + uint8_t sha204m_random(uint8_t * tx_buffer, uint8_t * rx_buffer, uint8_t mode); + uint8_t sha204m_dev_rev(uint8_t *tx_buffer, uint8_t *rx_buffer); + uint8_t sha204m_read(uint8_t *tx_buffer, uint8_t *rx_buffer, uint8_t zone, uint16_t address); + uint8_t sha204m_execute(uint8_t op_code, uint8_t param1, uint16_t param2, + uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3, + uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer); + uint8_t sha204m_check_parameters(uint8_t op_code, uint8_t param1, uint16_t param2, + uint8_t datalen1, uint8_t *data1, uint8_t datalen2, uint8_t *data2, uint8_t datalen3, uint8_t *data3, + uint8_t tx_size, uint8_t *tx_buffer, uint8_t rx_size, uint8_t *rx_buffer); + + uint8_t getSerialNumber(uint8_t *response); + uint16_t calculateAndUpdateCrc(uint8_t length, uint8_t *data, uint16_t current_crc); + +}; + +#endif From 4a0c3bb6f770a6a223e397b0272842f5a4744e7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Thu, 19 Mar 2015 21:47:51 +0100 Subject: [PATCH 15/24] Added SHA204 check routine to testmode --- .../examples/MysensorMicro/MysensorMicro.ino | 53 ++++++++++++++++--- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino index 8a00948..fa8b5e1 100644 --- a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino +++ b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino @@ -12,8 +12,8 @@ #include #include #include -//#include - +#include +#include // Define a static node address, remove if you want auto address assignment //#define NODE_ADDRESS 3 @@ -28,6 +28,10 @@ #define LED_PIN A2 #define ATSHA204_PIN 17 // A3 +const int sha204Pin = ATSHA204_PIN; +atsha204Class sha204(sha204Pin); + + #define MEASURE_INTERVAL 60000 // FORCE_TRANSMIT_INTERVAL, this number of times of wakeup, the sensor is forced to report all values to the controller @@ -194,11 +198,13 @@ void switchClock(unsigned char clk) // Verify all peripherals, and signal via the LED if any problems. void testMode() { + uint8_t rx_buffer[SHA204_RSP_SIZE_MAX]; + uint8_t ret_code; byte tests = 0; Serial.println(F("Testing peripherals!")); Serial.print(F("-> SI7021 : ")); - delay(500); + delay(100); if (humiditySensor.begin()) { @@ -209,10 +215,10 @@ void testMode() { Serial.println(F("failed!")); } - delay(500); + delay(100); Serial.print(F("-> Flash : ")); -delay(500); +delay(100); if (flash.initialize()) { Serial.println(F("ok!")); @@ -222,10 +228,43 @@ delay(500); { Serial.println(F("failed!")); } -delay(500); +delay(100); + + Serial.println(F("-> SHA204 : ")); + ret_code = sha204.sha204c_wakeup(rx_buffer); + if (ret_code != SHA204_SUCCESS) + { + Serial.print(F("Failed to wake device. Response: ")); Serial.println(ret_code, HEX); + } + + if (ret_code == SHA204_SUCCESS) + { + ret_code = sha204.getSerialNumber(rx_buffer); + if (ret_code != SHA204_SUCCESS) + { + Serial.print(F("Failed to obtain device serial number. Response: ")); Serial.println(ret_code, HEX); + } + else + { + Serial.print(F("Device serial: ")); + for (int i=0; i<9; i++) + { + if (rx_buffer[i] < 0x10) + { + Serial.print('0'); // Because Serial.print does not 0-pad HEX + } + Serial.print(rx_buffer[i], HEX); + } + Serial.println(); + tests ++; + } + + } + + Serial.println(F("Test finished")); - if (tests == 2) + if (tests == 3) { Serial.println(F("Selftest ok!")); while (1) // Blink OK pattern! From 3ab43d5ff5bd6352338a05f9753cd371c6b04e33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Sun, 22 Mar 2015 22:19:19 +0100 Subject: [PATCH 16/24] Updated sketch, removed the forced testmode (used for testing) --- .../MySensors/examples/MysensorMicro/MysensorMicro.ino | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino index fa8b5e1..a6420d1 100644 --- a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino +++ b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino @@ -63,9 +63,9 @@ void setup() { Serial.begin(115200); // First check if we should boot into test mode - testMode(); + pinMode(TEST_PIN,INPUT); - digitalWrite(TEST_PIN, HIGH); + digitalWrite(TEST_PIN, HIGH); // Enable pullup if (!digitalRead(TEST_PIN)) testMode(); digitalWrite(TEST_PIN,LOW); @@ -202,6 +202,8 @@ void testMode() uint8_t ret_code; byte tests = 0; + digitalWrite(LED_PIN, HIGH); // Turn on LED. + Serial.println(F("Testing peripherals!")); Serial.print(F("-> SI7021 : ")); delay(100); From fe8fdc00de99b78c95c029ffbbb245a9f68c990d Mon Sep 17 00:00:00 2001 From: gizmocuz Date: Mon, 23 Mar 2015 08:47:57 +0100 Subject: [PATCH 17/24] Modified example code, solved some issues in previous version --- .../WaterMeterPulseSensor.ino | 117 ++++++++++-------- 1 file changed, 68 insertions(+), 49 deletions(-) diff --git a/libraries/MySensors/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino b/libraries/MySensors/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino index 1add41d..39e70dc 100644 --- a/libraries/MySensors/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino +++ b/libraries/MySensors/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino @@ -1,7 +1,7 @@ // // Use this sensor to measure volume and flow of your house watermeter. // You need to set the correct pulsefactor of your meter (pulses per m3). -// The sensor starts by fetching current volume reading from gateway (VAR 1). +// The sensor starts by reading the pulse count reading from the eprom. // Reports both volume and flow back to gateway. // // Unfortunately millis() won't increment when the Arduino is in @@ -13,15 +13,23 @@ #include #define DIGITAL_INPUT_SENSOR 3 // The digital input you attached your sensor. (Only 2 and 3 generates interrupt!) +#define SENSOR_INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway) + #define PULSE_FACTOR 1000 // Nummber of blinks per m3 of your meter (One rotation/liter) + #define SLEEP_MODE false // flowvalue can only be reported when sleep mode is false. -#define MAX_FLOW 40 // Max flow (l/min) value to report. This filetrs outliers. -#define INTERRUPT DIGITAL_INPUT_SENSOR-2 // Usually the interrupt = pin -2 (on uno/nano anyway) -#define CHILD_ID 5 // Id of the sensor child + +#define MAX_FLOW 40 // Max flow (l/min) value to report. This filters outliers. + +#define CHILD_ID 1 // Id of the sensor child + unsigned long SEND_FREQUENCY = 20000; // Minimum time between send (in milliseconds). We don't want to spam the gateway. MySensor gw; - +MyMessage flowMsg(CHILD_ID,V_FLOW); +MyMessage volumeMsg(CHILD_ID,V_VOLUME); +MyMessage lastCounterMsg(CHILD_ID,V_VAR1); + double ppl = ((double)PULSE_FACTOR)/1000; // Pulses per liter volatile unsigned long pulseCount = 0; @@ -31,108 +39,119 @@ boolean pcReceived = false; unsigned long oldPulseCount = 0; unsigned long newBlink = 0; double oldflow = 0; -double volume; -double oldvolume; -unsigned long lastSend; -unsigned long lastPulse; -unsigned long currentTime; -boolean metric; -MyMessage flowMsg(CHILD_ID,V_FLOW); -MyMessage volumeMsg(CHILD_ID,V_VOLUME); -MyMessage pcMsg(CHILD_ID,V_VAR1); - +double volume =0; +double oldvolume =0; +unsigned long lastSend =0; +unsigned long lastPulse =0; void setup() { gw.begin(incomingMessage); // Send the sketch version information to the gateway and Controller - gw.sendSketchInfo("Water Meter", "1.0"); + gw.sendSketchInfo("Water Meter", "1.2"); // Register this device as Waterflow sensor gw.present(CHILD_ID, S_WATER); + pulseCount = oldPulseCount = 0; + // Fetch last known pulse count value from gw gw.request(CHILD_ID, V_VAR1); - attachInterrupt(INTERRUPT, onPulse, RISING); - lastSend = millis(); + lastSend = lastPulse = millis(); + + attachInterrupt(SENSOR_INTERRUPT, onPulse, RISING); } void loop() { gw.process(); - currentTime = millis(); + unsigned long currentTime = millis(); // Only send values at a maximum frequency or woken up from sleep - bool sendTime = currentTime - lastSend > SEND_FREQUENCY; - if (pcReceived && (SLEEP_MODE || sendTime)) { - // New flow value has been calculated + if (SLEEP_MODE || (currentTime - lastSend > SEND_FREQUENCY)) + { + lastSend=currentTime; + + if (!pcReceived) { + //Last Pulsecount not yet received from controller, request it again + gw.request(CHILD_ID, V_VAR1); + return; + } + if (!SLEEP_MODE && flow != oldflow) { + oldflow = flow; + + Serial.print("l/min:"); + Serial.println(flow); + // Check that we dont get unresonable large flow value. // could hapen when long wraps or false interrupt triggered if (flow<((unsigned long)MAX_FLOW)) { gw.send(flowMsg.set(flow, 2)); // Send flow value to gw } - //Serial.print("l/min:"); - //Serial.println(flow); - oldflow = flow; } - // No Pulse count in 2min + // No Pulse count received in 2min if(currentTime - lastPulse > 120000){ flow = 0; } - - + // Pulse count has changed if (pulseCount != oldPulseCount) { - gw.send(pcMsg.set(pulseCount)); // Send volumevalue to gw VAR1 - double volume = ((double)pulseCount/((double)PULSE_FACTOR)); oldPulseCount = pulseCount; + + Serial.print("pulsecount:"); + Serial.println(pulseCount); + + gw.send(lastCounterMsg.set(pulseCount)); // Send pulsecount value to gw in VAR1 + + double volume = ((double)pulseCount/((double)PULSE_FACTOR)); if (volume != oldvolume) { - gw.send(volumeMsg.set(volume, 3)); // Send volume value to gw oldvolume = volume; + + Serial.print("volume:"); + Serial.println(volume, 3); + + gw.send(volumeMsg.set(volume, 3)); // Send volume value to gw } } - lastSend = currentTime; - } else if (sendTime && !pcReceived) { - // No count received. Try requesting it again - gw.request(CHILD_ID, V_VAR1); - lastSend=currentTime; } - if (SLEEP_MODE) { gw.sleep(SEND_FREQUENCY); } } void incomingMessage(const MyMessage &message) { - if (message.type==V_VAR1) { - pulseCount = oldPulseCount = message.getLong(); + if (message.type==V_VAR1) { + unsigned long gwPulseCount=message.getULong(); + pulseCount += gwPulseCount; Serial.print("Received last pulse count from gw:"); Serial.println(pulseCount); pcReceived = true; } } - void onPulse() -{ - if (!SLEEP_MODE) { +{ + if (!SLEEP_MODE) + { unsigned long newBlink = micros(); unsigned long interval = newBlink-lastBlink; - lastPulse = millis(); - if (interval<500000L) { - // Sometimes we get interrupt on RISING, 500000 = 0.5sek debounce ( max 120 l/min) - return; + + if (interval!=0) + { + lastPulse = millis(); + if (interval<500000L) { + // Sometimes we get interrupt on RISING, 500000 = 0.5sek debounce ( max 120 l/min) + return; + } + flow = (60000000.0 /interval) / ppl; } - flow = (60000000.0 /interval) / ppl; lastBlink = newBlink; } pulseCount++; } - - From 93e8f2e1072ef035124cdf1001161d4ab5e28def Mon Sep 17 00:00:00 2001 From: gizmocuz Date: Mon, 23 Mar 2015 08:53:04 +0100 Subject: [PATCH 18/24] Corrected Sketch header --- .../examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/MySensors/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino b/libraries/MySensors/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino index 39e70dc..6e9c4ee 100644 --- a/libraries/MySensors/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino +++ b/libraries/MySensors/examples/WaterMeterPulseSensor/WaterMeterPulseSensor.ino @@ -1,7 +1,7 @@ // // Use this sensor to measure volume and flow of your house watermeter. // You need to set the correct pulsefactor of your meter (pulses per m3). -// The sensor starts by reading the pulse count reading from the eprom. +// The sensor starts by fetching current volume reading from gateway (VAR 1). // Reports both volume and flow back to gateway. // // Unfortunately millis() won't increment when the Arduino is in From e908e854c1cabd5cb19afcd70daa8c066f24e0d5 Mon Sep 17 00:00:00 2001 From: gizmocuz Date: Tue, 24 Mar 2015 09:26:50 +0100 Subject: [PATCH 19/24] Enhanced the UVSensor example with 1 decimal to the UVI index. Because the UVI graph is almost lineair This gives a more accurate overview Also the UVI is send at least every 5 minutes, this is good for the controller to know the sensor is still 'alive' --- .../MySensors/examples/UVSensor/UVSensor.ino | 61 +++++++++++++------ 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/libraries/MySensors/examples/UVSensor/UVSensor.ino b/libraries/MySensors/examples/UVSensor/UVSensor.ino index 838cdbd..417ae43 100644 --- a/libraries/MySensors/examples/UVSensor/UVSensor.ino +++ b/libraries/MySensors/examples/UVSensor/UVSensor.ino @@ -1,5 +1,7 @@ +#include +#include /* - Vera Arduino UVM-30A + Arduino UVM-30A connect the sensor as follows : @@ -7,44 +9,55 @@ - >>> GND out >>> A0 - Contribution: epierre, bulldoglowell - Converted to 1.4 by Henrik Ekblad + Contribution: epierre, bulldoglowell, gizmocuz + + Index table taken from: http://www.elecrow.com/sensors-c-111/environment-c-111_112/uv-sensor-moduleuvm30a-p-716.html + Because this table is pretty lineair, we can calculate a UVI with one decimal License: Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0) - */ #include #include -#define CHILD_ID_UV 0 #define UV_SENSOR_ANALOG_PIN 0 + +#define CHILD_ID_UV 0 + unsigned long SLEEP_TIME = 30*1000; // Sleep time between reads (in milliseconds) MySensor gw; MyMessage uvMsg(CHILD_ID_UV, V_UV); -int lastUV = -1; -int uvIndexValue [13] = { 50, 227, 318, 408, 503, 606, 696, 795, 881, 976, 1079, 1170, 3000}; -int uvIndex; + +unsigned long lastSend =0; +float uvIndex; +float lastUV = -1; +int uvIndexValue [12] = { 50, 227, 318, 408, 503, 606, 696, 795, 881, 976, 1079, 1170}; void setup() { gw.begin(); // Send the sketch version information to the gateway and Controller - gw.sendSketchInfo("UV Sensor", "1.1"); + gw.sendSketchInfo("UV Sensor", "1.2"); // Register all sensors to gateway (they will be created as child devices) gw.present(CHILD_ID_UV, S_UV); - } void loop() -{ - uint16_t uv = analogRead(0);// Get UV value - Serial.print("Uv reading: "); - Serial.println(uv); - for (int i = 0; i < 13; i++) +{ + unsigned long currentTime = millis(); + + uint16_t uv = analogRead(UV_SENSOR_ANALOG_PIN);// Get UV value + if (uv>1170) + uv=1170; + + //Serial.print("UV Analog reading: "); + //Serial.println(uv); + + int i; + for (i = 0; i < 12; i++) { if (uv <= uvIndexValue[i]) { @@ -52,11 +65,21 @@ void loop() break; } } - Serial.print("Uv index: "); - Serial.println(uvIndex); + + //calculate 1 decimal if possible + if (i>0) { + float vRange=uvIndexValue[i]-uvIndexValue[i-1]; + float vCalc=uv-uvIndexValue[i-1]; + uvIndex+=(1.0/vRange)*vCalc-1.0; + } - if (uvIndex != lastUV) { - gw.send(uvMsg.set(uvIndex)); + //Serial.print("UVI: "); + //Serial.println(uvIndex,2); + + //Send value to gateway if changed, or at least every 5 minutes + if ((uvIndex != lastUV)||(currentTime-lastSend >= 5*60*1000)) { + lastSend=currentTime; + gw.send(uvMsg.set(uvIndex,2)); lastUV = uvIndex; } From b66408e3d471427e166a74c1385de1eb78cc77ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Sat, 28 Mar 2015 11:17:52 +0100 Subject: [PATCH 20/24] Updated sketch, using Serial.flush() in test routine, instead of delay() Changed name that is reported back to controler, to "MysensorMicro" instead of "EnvironmentSensor" --- .../examples/MysensorMicro/MysensorMicro.ino | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino index a6420d1..2d70c41 100644 --- a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino +++ b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino @@ -81,7 +81,7 @@ void setup() { humiditySensor.begin(); - gw.sendSketchInfo("EnvironmentSensor", "1.0"); + gw.sendSketchInfo("MysensorMicro", "1.0"); gw.present(CHILD_ID_TEMP,S_TEMP); gw.present(CHILD_ID_HUM,S_HUM); @@ -205,8 +205,9 @@ void testMode() digitalWrite(LED_PIN, HIGH); // Turn on LED. Serial.println(F("Testing peripherals!")); + Serial.flush(); Serial.print(F("-> SI7021 : ")); - delay(100); + Serial.flush(); if (humiditySensor.begin()) { @@ -217,10 +218,10 @@ void testMode() { Serial.println(F("failed!")); } - delay(100); + Serial.flush(); Serial.print(F("-> Flash : ")); -delay(100); + Serial.flush(); if (flash.initialize()) { Serial.println(F("ok!")); @@ -230,15 +231,17 @@ delay(100); { Serial.println(F("failed!")); } -delay(100); + Serial.flush(); + - Serial.println(F("-> SHA204 : ")); + Serial.print(F("-> SHA204 : ")); ret_code = sha204.sha204c_wakeup(rx_buffer); + Serial.flush(); if (ret_code != SHA204_SUCCESS) { Serial.print(F("Failed to wake device. Response: ")); Serial.println(ret_code, HEX); } - + Serial.flush(); if (ret_code == SHA204_SUCCESS) { ret_code = sha204.getSerialNumber(rx_buffer); @@ -248,7 +251,7 @@ delay(100); } else { - Serial.print(F("Device serial: ")); + Serial.print(F("Ok (serial : ")); for (int i=0; i<9; i++) { if (rx_buffer[i] < 0x10) @@ -257,12 +260,12 @@ delay(100); } Serial.print(rx_buffer[i], HEX); } - Serial.println(); + Serial.println(")"); tests ++; } } - + Serial.flush(); Serial.println(F("Test finished")); From 9a7dadf5c40fb3668461ff6396a06011766726d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Sun, 29 Mar 2015 00:48:08 +0100 Subject: [PATCH 21/24] Added HW definitions for mysensor micro --- hardware/MySensors/avr/boards.txt | 22 ++ hardware/MySensors/avr/platform.txt | 104 ++++++++ .../avr/variants/micro/pins_arduino.h | 238 ++++++++++++++++++ 3 files changed, 364 insertions(+) create mode 100644 hardware/MySensors/avr/boards.txt create mode 100644 hardware/MySensors/avr/platform.txt create mode 100644 hardware/MySensors/avr/variants/micro/pins_arduino.h diff --git a/hardware/MySensors/avr/boards.txt b/hardware/MySensors/avr/boards.txt new file mode 100644 index 0000000..67d8121 --- /dev/null +++ b/hardware/MySensors/avr/boards.txt @@ -0,0 +1,22 @@ + +SenseBenderMicro.name=SenseBender Micro + +SenseBenderMicro.upload.tool=arduino:avrdude +SenseBenderMicro.upload.protocol=arduino +SenseBenderMicro.upload.maximum_size=30720 +SenseBenderMicro.upload.maximum_data_size=2048 +SenseBenderMicro.upload.speed=57600 + +SenseBenderMicro.bootloader.tool=arduino:avrdude +SenseBenderMicro.bootloader.unlock_bits=0x3F +SenseBenderMicro.bootloader.lock_bits=0x0F +SenseBenderMicro.bootloader.low_fuses=0xFF +SenseBenderMicro.bootloader.high_fuses=0xDA +SenseBenderMicro.bootloader.extended_fuses=0x05 +SenseBenderMicro.bootloader.file=DualOptiboot/optiboot_atmega328p-pro8.hex + +SenseBenderMicro.build.board=AVR_MICRO8 +SenseBenderMicro.build.core=arduino:arduino +SenseBenderMicro.build.variant=micro +SenseBenderMicro.build.mcu=atmega328p +SenseBenderMicro.build.f_cpu=8000000L diff --git a/hardware/MySensors/avr/platform.txt b/hardware/MySensors/avr/platform.txt new file mode 100644 index 0000000..f88a155 --- /dev/null +++ b/hardware/MySensors/avr/platform.txt @@ -0,0 +1,104 @@ + +# Arduino AVR Core and platform. +# ------------------------------ + +# For more info: +# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification + +name=SenseBender Boards +version=1.6.0 + +# AVR compile variables +# --------------------- + +# Default "compiler.path" is correct, change only if you want to overidde the initial value +compiler.path={runtime.tools.avr-gcc.path}/bin/ +compiler.c.cmd=avr-gcc +compiler.c.flags=-c -g -Os -w -ffunction-sections -fdata-sections -MMD +# -w flag added to avoid printing a wrong warning http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59396 +# This is fixed in gcc 4.8.3 and will be removed as soon as we update the toolchain +compiler.c.elf.flags=-w -Os -Wl,--gc-sections +compiler.c.elf.cmd=avr-gcc +compiler.S.flags=-c -g -x assembler-with-cpp +compiler.cpp.cmd=avr-g++ +compiler.cpp.flags=-c -g -Os -w -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD +compiler.ar.cmd=avr-ar +compiler.ar.flags=rcs +compiler.objcopy.cmd=avr-objcopy +compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0 +compiler.elf2hex.flags=-O ihex -R .eeprom +compiler.elf2hex.cmd=avr-objcopy +compiler.ldflags= +compiler.size.cmd=avr-size + +# This can be overriden in boards.txt +build.extra_flags= + +# These can be overridden in platform.local.txt +compiler.c.extra_flags= +compiler.c.elf.extra_flags= +compiler.S.extra_flags= +compiler.cpp.extra_flags= +compiler.ar.extra_flags= +compiler.objcopy.eep.extra_flags= +compiler.elf2hex.extra_flags= + +# AVR compile patterns +# -------------------- + +## Compile c files +recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" + +## Compile c++ files +recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" + +## Compile S files +recipe.S.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.S.flags} -mmcu={build.mcu} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {includes} "{source_file}" -o "{object_file}" + +## Create archives +recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{build.path}/{archive_file}" "{object_file}" + +## Combine gc-sections, archives, and objects +recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" {compiler.c.elf.flags} -mmcu={build.mcu} {compiler.c.elf.extra_flags} -o "{build.path}/{build.project_name}.elf" {object_files} "{build.path}/{archive_file}" "-L{build.path}" -lm + +## Create eeprom +recipe.objcopy.eep.pattern="{compiler.path}{compiler.objcopy.cmd}" {compiler.objcopy.eep.flags} {compiler.objcopy.eep.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.eep" + +## Create hex +recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.hex" + +## Compute size +recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf" +recipe.size.regex=^(?:\.text|\.data|\.bootloader)\s+([0-9]+).* +recipe.size.regex.data=^(?:\.data|\.bss|\.noinit)\s+([0-9]+).* +recipe.size.regex.eeprom=^(?:\.eeprom)\s+([0-9]+).* + + +# AVR Uploader/Programmers tools +# ------------------------------ + +tools.avrdude.cmd.path={runtime.ide.path}/hardware/tools/avr/bin/avrdude +tools.avrdude.config.path={runtime.ide.path}/hardware/tools/avr/etc/avrdude.conf + +tools.avrdude.upload.params.verbose=-v +tools.avrdude.upload.params.quiet=-q -q +tools.avrdude.upload.pattern="{cmd.path}" "-C{config.path}" {upload.verbose} -p{build.mcu} -c{upload.protocol} -P{serial.port} -b{upload.speed} -D "-Uflash:w:{build.path}/{build.project_name}.hex:i" + +tools.avrdude.program.params.verbose=-v +tools.avrdude.program.params.quiet=-q -q +tools.avrdude.program.pattern="{cmd.path}" "-C{config.path}" {program.verbose} -p{build.mcu} -c{protocol} {program.extra_params} "-Uflash:w:{build.path}/{build.project_name}.hex:i" + +tools.avrdude.erase.params.verbose=-v +tools.avrdude.erase.params.quiet=-q -q +tools.avrdude.erase.pattern="{cmd.path}" "-C{config.path}" {erase.verbose} -p{build.mcu} -c{protocol} {program.extra_params} -e -Ulock:w:{bootloader.unlock_bits}:m -Uefuse:w:{bootloader.extended_fuses}:m -Uhfuse:w:{bootloader.high_fuses}:m -Ulfuse:w:{bootloader.low_fuses}:m + +tools.avrdude.bootloader.params.verbose=-v +tools.avrdude.bootloader.params.quiet=-q -q +tools.avrdude.bootloader.pattern="{cmd.path}" "-C{config.path}" {bootloader.verbose} -p{build.mcu} -c{protocol} {program.extra_params} "-Uflash:w:{runtime.platform.path}/bootloaders/{bootloader.file}:i" -Ulock:w:{bootloader.lock_bits}:m + + +# USB Default Flags +# Default blank usb manufacturer will be filled it at compile time +# - from numeric vendor ID, set to Unknown otherwise +build.usb_manufacturer= +build.usb_flags=-DUSB_VID={build.vid} -DUSB_PID={build.pid} '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' diff --git a/hardware/MySensors/avr/variants/micro/pins_arduino.h b/hardware/MySensors/avr/variants/micro/pins_arduino.h new file mode 100644 index 0000000..3d4a9f6 --- /dev/null +++ b/hardware/MySensors/avr/variants/micro/pins_arduino.h @@ -0,0 +1,238 @@ +/* + pins_arduino.h - Pin definition functions for Arduino + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2007 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id: wiring.h 249 2007-02-03 16:52:51Z mellis $ +*/ + +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +#define NUM_DIGITAL_PINS 20 +#define NUM_ANALOG_INPUTS 6 +#define analogInputToDigitalPin(p) ((p < 6) ? (p) + 14 : -1) + +#if defined(__AVR_ATmega8__) +#define digitalPinHasPWM(p) ((p) == 9 || (p) == 10 || (p) == 11) +#else +#define digitalPinHasPWM(p) ((p) == 3 || (p) == 5 || (p) == 6 || (p) == 9 || (p) == 10 || (p) == 11) +#endif + +static const uint8_t SS = 10; +static const uint8_t MOSI = 11; +static const uint8_t MISO = 12; +static const uint8_t SCK = 13; + +static const uint8_t SDA = 18; +static const uint8_t SCL = 19; +#define LED_BUILTIN 13 + +static const uint8_t A0 = 14; +static const uint8_t A1 = 15; +static const uint8_t A2 = 16; +static const uint8_t A3 = 17; +static const uint8_t A4 = 18; +static const uint8_t A5 = 19; +static const uint8_t A6 = 20; +static const uint8_t A7 = 21; + +#define digitalPinToPCICR(p) (((p) >= 0 && (p) <= 21) ? (&PCICR) : ((uint8_t *)0)) +#define digitalPinToPCICRbit(p) (((p) <= 7) ? 2 : (((p) <= 13) ? 0 : 1)) +#define digitalPinToPCMSK(p) (((p) <= 7) ? (&PCMSK2) : (((p) <= 13) ? (&PCMSK0) : (((p) <= 21) ? (&PCMSK1) : ((uint8_t *)0)))) +#define digitalPinToPCMSKbit(p) (((p) <= 7) ? (p) : (((p) <= 13) ? ((p) - 8) : ((p) - 14))) + +#define digitalPinToInterrupt(p) ((p) == 2 ? 0 : ((p) == 3 ? 1 : NOT_AN_INTERRUPT)) + +#ifdef ARDUINO_MAIN + +// On the Arduino board, digital pins are also used +// for the analog output (software PWM). Analog input +// pins are a separate set. + +// ATMEL ATMEGA8 & 168 / ARDUINO +// +// +-\/-+ +// PC6 1| |28 PC5 (AI 5) +// (D 0) PD0 2| |27 PC4 (AI 4) +// (D 1) PD1 3| |26 PC3 (AI 3) +// (D 2) PD2 4| |25 PC2 (AI 2) +// PWM+ (D 3) PD3 5| |24 PC1 (AI 1) +// (D 4) PD4 6| |23 PC0 (AI 0) +// VCC 7| |22 GND +// GND 8| |21 AREF +// PB6 9| |20 AVCC +// PB7 10| |19 PB5 (D 13) +// PWM+ (D 5) PD5 11| |18 PB4 (D 12) +// PWM+ (D 6) PD6 12| |17 PB3 (D 11) PWM +// (D 7) PD7 13| |16 PB2 (D 10) PWM +// (D 8) PB0 14| |15 PB1 (D 9) PWM +// +----+ +// +// (PWM+ indicates the additional PWM pins on the ATmega168.) + +// ATMEL ATMEGA1280 / ARDUINO +// +// 0-7 PE0-PE7 works +// 8-13 PB0-PB5 works +// 14-21 PA0-PA7 works +// 22-29 PH0-PH7 works +// 30-35 PG5-PG0 works +// 36-43 PC7-PC0 works +// 44-51 PJ7-PJ0 works +// 52-59 PL7-PL0 works +// 60-67 PD7-PD0 works +// A0-A7 PF0-PF7 +// A8-A15 PK0-PK7 + + +// these arrays map port names (e.g. port B) to the +// appropriate addresses for various functions (e.g. reading +// and writing) +const uint16_t PROGMEM port_to_mode_PGM[] = { + NOT_A_PORT, + NOT_A_PORT, + (uint16_t) &DDRB, + (uint16_t) &DDRC, + (uint16_t) &DDRD, +}; + +const uint16_t PROGMEM port_to_output_PGM[] = { + NOT_A_PORT, + NOT_A_PORT, + (uint16_t) &PORTB, + (uint16_t) &PORTC, + (uint16_t) &PORTD, +}; + +const uint16_t PROGMEM port_to_input_PGM[] = { + NOT_A_PORT, + NOT_A_PORT, + (uint16_t) &PINB, + (uint16_t) &PINC, + (uint16_t) &PIND, +}; + +const uint8_t PROGMEM digital_pin_to_port_PGM[] = { + PD, /* 0 */ + PD, + PD, + PD, + PD, + PD, + PD, + PD, + PB, /* 8 */ + PB, + PB, + PB, + PB, + PB, + PC, /* 14 */ + PC, + PC, + PC, + PC, + PC, +}; + +const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { + _BV(0), /* 0, port D */ + _BV(1), + _BV(2), + _BV(3), + _BV(4), + _BV(5), + _BV(6), + _BV(7), + _BV(0), /* 8, port B */ + _BV(1), + _BV(2), + _BV(3), + _BV(4), + _BV(5), + _BV(0), /* 14, port C */ + _BV(1), + _BV(2), + _BV(3), + _BV(4), + _BV(5), +}; + +const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { + NOT_ON_TIMER, /* 0 - port D */ + NOT_ON_TIMER, + NOT_ON_TIMER, + // on the ATmega168, digital pin 3 has hardware pwm +#if defined(__AVR_ATmega8__) + NOT_ON_TIMER, +#else + TIMER2B, +#endif + NOT_ON_TIMER, + // on the ATmega168, digital pins 5 and 6 have hardware pwm +#if defined(__AVR_ATmega8__) + NOT_ON_TIMER, + NOT_ON_TIMER, +#else + TIMER0B, + TIMER0A, +#endif + NOT_ON_TIMER, + NOT_ON_TIMER, /* 8 - port B */ + TIMER1A, + TIMER1B, +#if defined(__AVR_ATmega8__) + TIMER2, +#else + TIMER2A, +#endif + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, /* 14 - port C */ + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, + NOT_ON_TIMER, +}; + +#endif + +// These serial port names are intended to allow libraries and architecture-neutral +// sketches to automatically default to the correct port name for a particular type +// of use. For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN, +// the first hardware serial port whose RX/TX pins are not dedicated to another use. +// +// SERIAL_PORT_MONITOR Port which normally prints to the Arduino Serial Monitor +// +// SERIAL_PORT_USBVIRTUAL Port which is USB virtual serial +// +// SERIAL_PORT_LINUXBRIDGE Port which connects to a Linux system via Bridge library +// +// SERIAL_PORT_HARDWARE Hardware serial port, physical RX & TX pins. +// +// SERIAL_PORT_HARDWARE_OPEN Hardware serial ports which are open for use. Their RX & TX +// pins are NOT connected to anything by default. +#define SERIAL_PORT_MONITOR Serial +#define SERIAL_PORT_HARDWARE Serial + +#endif From ff0644af58387f643734329c33313e591330599f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Sun, 29 Mar 2015 00:51:07 +0100 Subject: [PATCH 22/24] Updated naming in the files --- hardware/MySensors/avr/boards.txt | 36 ++++++++++++++--------------- hardware/MySensors/avr/platform.txt | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/hardware/MySensors/avr/boards.txt b/hardware/MySensors/avr/boards.txt index 67d8121..75e1e53 100644 --- a/hardware/MySensors/avr/boards.txt +++ b/hardware/MySensors/avr/boards.txt @@ -1,22 +1,22 @@ -SenseBenderMicro.name=SenseBender Micro +MysensorsMicro.name=Mysensors Micro -SenseBenderMicro.upload.tool=arduino:avrdude -SenseBenderMicro.upload.protocol=arduino -SenseBenderMicro.upload.maximum_size=30720 -SenseBenderMicro.upload.maximum_data_size=2048 -SenseBenderMicro.upload.speed=57600 +MysensorsMicro.upload.tool=arduino:avrdude +MysensorsMicro.upload.protocol=arduino +MysensorsMicro.upload.maximum_size=30720 +MysensorsMicro.upload.maximum_data_size=2048 +MysensorsMicro.upload.speed=57600 -SenseBenderMicro.bootloader.tool=arduino:avrdude -SenseBenderMicro.bootloader.unlock_bits=0x3F -SenseBenderMicro.bootloader.lock_bits=0x0F -SenseBenderMicro.bootloader.low_fuses=0xFF -SenseBenderMicro.bootloader.high_fuses=0xDA -SenseBenderMicro.bootloader.extended_fuses=0x05 -SenseBenderMicro.bootloader.file=DualOptiboot/optiboot_atmega328p-pro8.hex +MysensorsMicro.bootloader.tool=arduino:avrdude +MysensorsMicro.bootloader.unlock_bits=0x3F +MysensorsMicro.bootloader.lock_bits=0x0F +MysensorsMicro.bootloader.low_fuses=0xFF +MysensorsMicro.bootloader.high_fuses=0xDA +MysensorsMicro.bootloader.extended_fuses=0x05 +MysensorsMicro.bootloader.file=DualOptiboot/optiboot_atmega328p-pro8.hex -SenseBenderMicro.build.board=AVR_MICRO8 -SenseBenderMicro.build.core=arduino:arduino -SenseBenderMicro.build.variant=micro -SenseBenderMicro.build.mcu=atmega328p -SenseBenderMicro.build.f_cpu=8000000L +MysensorsMicro.build.board=AVR_MICRO8 +MysensorsMicro.build.core=arduino:arduino +MysensorsMicro.build.variant=micro +MysensorsMicro.build.mcu=atmega328p +MysensorsMicro.build.f_cpu=8000000L diff --git a/hardware/MySensors/avr/platform.txt b/hardware/MySensors/avr/platform.txt index f88a155..332dfce 100644 --- a/hardware/MySensors/avr/platform.txt +++ b/hardware/MySensors/avr/platform.txt @@ -5,7 +5,7 @@ # For more info: # https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification -name=SenseBender Boards +name=MySensors Boards version=1.6.0 # AVR compile variables From 6ae64373f9ee2dd65ee7fa6b22b89716cf4f6d52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Sun, 29 Mar 2015 11:29:47 +0200 Subject: [PATCH 23/24] Added .gitignore file to ignore backup files Updated MySensorsMicro sketch with comments, and rearranged code a little --- .gitignore | 2 ++ .../examples/MysensorMicro/MysensorMicro.ino | 17 ++++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bfc784e --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*~ +*bak \ No newline at end of file diff --git a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino index 2d70c41..c25fac2 100644 --- a/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino +++ b/libraries/MySensors/examples/MysensorMicro/MysensorMicro.ino @@ -23,6 +23,15 @@ #define CHILD_ID_HUM 2 #define CHILD_ID_BATT 199 +// How many milli seconds between each measurement +#define MEASURE_INTERVAL 60000 + +// FORCE_TRANSMIT_INTERVAL, this number of times of wakeup, the sensor is forced to report all values to the controller +#define FORCE_TRANSMIT_INTERVAL 30 + +// When MEASURE_INTERVAL is 60000 and FORCE_TRANSMIT_INTERVAL is 30, we force a transmission every 30 minutes. +// Between the forced transmissions a tranmission will only occur if the measured value differs from the previous measurement + //Pin definitions #define TEST_PIN A0 #define LED_PIN A2 @@ -31,12 +40,6 @@ const int sha204Pin = ATSHA204_PIN; atsha204Class sha204(sha204Pin); - -#define MEASURE_INTERVAL 60000 - -// FORCE_TRANSMIT_INTERVAL, this number of times of wakeup, the sensor is forced to report all values to the controller -#define FORCE_TRANSMIT_INTERVAL 30 - SI7021 humiditySensor; SPIFlash flash(8, 0x1F65); @@ -97,7 +100,7 @@ void loop() { bool forceTransmit = false; if (measureCount > FORCE_TRANSMIT_INTERVAL - ) {// Every 60th time we wake up, force a transmission on all sensors. + ) { // force a transmission forceTransmit = true; measureCount = 0; } From 0c057e82e24cad75c15e43cc69fb8ada0e07dd9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=B8rch?= Date: Tue, 31 Mar 2015 10:53:17 +0200 Subject: [PATCH 24/24] Corrected fuse settings for the micro board --- hardware/MySensors/avr/boards.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hardware/MySensors/avr/boards.txt b/hardware/MySensors/avr/boards.txt index 75e1e53..a603989 100644 --- a/hardware/MySensors/avr/boards.txt +++ b/hardware/MySensors/avr/boards.txt @@ -10,9 +10,9 @@ MysensorsMicro.upload.speed=57600 MysensorsMicro.bootloader.tool=arduino:avrdude MysensorsMicro.bootloader.unlock_bits=0x3F MysensorsMicro.bootloader.lock_bits=0x0F -MysensorsMicro.bootloader.low_fuses=0xFF -MysensorsMicro.bootloader.high_fuses=0xDA -MysensorsMicro.bootloader.extended_fuses=0x05 +MysensorsMicro.bootloader.low_fuses=0xE2 +MysensorsMicro.bootloader.high_fuses=0xD2 +MysensorsMicro.bootloader.extended_fuses=0xFE MysensorsMicro.bootloader.file=DualOptiboot/optiboot_atmega328p-pro8.hex MysensorsMicro.build.board=AVR_MICRO8