#include "LoRaWan_APP.h" #include "defines.h" #include "configuration.h" #include #include #include #include "HT_SSD1306Wire.h" extern SSD1306Wire display; // from config.cpp extern config_t myConfig; /*LoraWan channelsmask, default channels 0-7*/ uint16_t userChannelsMask[6]={ 0x00FF,0x0000,0x0000,0x0000,0x0000,0x0000 }; /*LoraWan Class, Class A and Class C are supported*/ DeviceClass_t loraWanClass = CLASS_C; /*the application data transmission duty cycle. value in [ms].*/ uint32_t appTxDutyCycle = 15000; /*ADR enable*/ bool loraWanAdr = true; /* Indicates if the node is sending confirmed or unconfirmed messages */ bool isTxConfirmed = true; /* Application port */ uint8_t appPort = 2; /*! * Number of trials to transmit the frame, if the LoRaMAC layer did not * receive an acknowledgment. The MAC performs a datarate adaptation, * according to the LoRaWAN Specification V1.0.2, chapter 18.4, according * to the following table: * * Transmission nb | Data Rate * ----------------|----------- * 1 (first) | DR * 2 | DR * 3 | max(DR-1,0) * 4 | max(DR-1,0) * 5 | max(DR-2,0) * 6 | max(DR-2,0) * 7 | max(DR-3,0) * 8 | max(DR-3,0) * * Note, that if NbTrials is set to 1 or 2, the MAC will not decrease * the datarate, in case the LoRaMAC layer did not receive an acknowledgment */ uint8_t confirmedNbTrials = 4; OneWire oneWire(ONE_WIRE); DallasTemperature DS18B20(&oneWire); bool firstrun = true; typedef struct { uint64_t addr; uint8_t index; char label[LABEL_LENGTH+1]; } __attribute__((packed)) sensor_t; sensor_t sensors[NUM_OF_SENSORS]; typedef enum { ERR_OK = 0x0000, ERR_SENSOR_LOST = 0x0001, ERR_ILLEGAL_DOWNLINK_MESSAGE_RECEIVED = 0x0002, ERR_START_UP = 0x0004, ERR_INVALID_NUM_OF_SENSORS = 0x8008, } errorCode_t; #define FATAL_MASK 0x8000 uint16_t errorCode = ERR_OK; /* Prepares the payload of the frame */ static void prepareTxFrame( uint8_t port ) { if ((errorCode & FATAL_MASK) == 0) { display.clear(); if (firstrun) { struct { uint16_t status; uint64_t addrs[NUM_OF_SENSORS]; } __attribute__((packed)) msg; msg.status = ERR_START_UP; for (uint8_t i = 0; i < NUM_OF_SENSORS; i++) { msg.addrs[i] = sensors[i].addr; } appDataSize = sizeof(msg); Serial.printf("appDataSize: %ld\n\r", appDataSize); memcpy(&appData, (void*)&msg, appDataSize); display.drawString(1, 0, "Start up"); Serial.println("Start up message send"); firstrun = false; } else { DS18B20.begin(); struct { uint16_t status; struct { uint64_t addr; int32_t value; } __attribute__((packed)) sensors[NUM_OF_SENSORS]; } __attribute__((packed)) msg; msg.status = (DS18B20.getDS18Count() == NUM_OF_SENSORS) ? errorCode : errorCode | ERR_SENSOR_LOST; DS18B20.requestTemperatures(); for (uint8_t i = 0; i < NUM_OF_SENSORS; i++) { msg.sensors[i].addr = sensors[i].addr; Serial.printf("%d: %s: %016llx\n\r", i, sensors[i].label, sensors[i].addr); msg.sensors[i].value = DS18B20.getTemp(((const uint8_t*)(&(sensors[i].addr)))); Serial.printf("v: %08x\n\r", msg.sensors[i].value); float tempC = ((float)msg.sensors[i].value) / 128; Serial.printf("f: %.2f\n\r", tempC); char dispbuf[128]; sprintf(dispbuf, "%s: %.2f °C", sensors[i].label, tempC); display.drawString(1, i * 16, dispbuf); Serial.printf("%d, %016llx, %s, %.2f\n\r", sensors[i].index, sensors[i].addr, sensors[i].label, tempC); } appDataSize = sizeof(msg); memcpy(&appData, (void*)&msg, appDataSize); Serial.println("Send"); } display.display(); errorCode = ERR_OK; } else { appDataSize = 2; appData[0] = errorCode; } } void downLinkDataHandle(McpsIndication_t *mcpsIndication) { Serial.printf("+REV DATA:%s,RXSIZE %d,PORT %d\r\n",mcpsIndication->RxSlot?"RXWIN2":"RXWIN1",mcpsIndication->BufferSize,mcpsIndication->Port); Serial.print("+REV DATA:"); sensor_t downlinkSensors[NUM_OF_SENSORS]; if (mcpsIndication->BufferSize != sizeof(downlinkSensors)) { Serial.println("illegal number of octets in downlink message"); } else { for(uint8_t i=0;iBufferSize;i++) { Serial.printf("%02X",mcpsIndication->Buffer[i]); } memcpy(&downlinkSensors, mcpsIndication->Buffer, sizeof(downlinkSensors)); for (uint8_t i = 0; i < NUM_OF_SENSORS; i++) { bool found = false; for (uint8_t j = 0; j < NUM_OF_SENSORS; j++) { if (sensors[i].addr == downlinkSensors[i].addr) { found = true; sensors[i].index = downlinkSensors[i].index; memcpy(sensors[i].label, downlinkSensors[i].label, LABEL_LENGTH); sensors[i].label[LABEL_LENGTH] = 0; } } if (! found) { Serial.printf("Illegal label received for not existing %08x\n\r", downlinkSensors[i].addr); errorCode |= ERR_ILLEGAL_DOWNLINK_MESSAGE_RECEIVED; } } } Serial.println(); uint32_t color=mcpsIndication->Buffer[0]<<16|mcpsIndication->Buffer[1]<<8|mcpsIndication->Buffer[2]; } void productionSetup() { Serial.println("Starting"); Mcu.begin(); digitalWrite(Vext,LOW); display.init(); display.setFont(ArialMT_Plain_16); display.clear(); display.display(); deviceState = DEVICE_STATE_INIT; DS18B20.begin(); uint8_t cnt = DS18B20.getDS18Count(); if (cnt != 4) { display.drawString(1, 0, "invalid number of sensors"); Serial.println("invalid number of sensors"); errorCode = ERR_INVALID_NUM_OF_SENSORS; } else { for (uint8_t i = 0; i < NUM_OF_SENSORS; i++) { sprintf(sensors[i].label, "Sens%d", i); DS18B20.getAddress(((uint8_t*)(&(sensors[i].addr))), i); char buf[128]; sprintf(buf, "%d: %s: %016llx", i, sensors[i].label, sensors[i].addr); Serial.println(buf); //display.drawString(1, i*16, buf); sensors[i].index = 0; } } } void productionLoop() { static uint32_t goingToSleepTime = 0; static uint8_t subStateSleep = 0; static uint32_t myCycleTime = 0; digitalWrite(LED_GREEN, HIGH); if (deviceState != DEVICE_STATE_SLEEP) { Serial.printf("State: %d\n\r", deviceState); } switch( deviceState ) { case DEVICE_STATE_INIT: digitalWrite(LED_GREEN, LOW); LoRaWAN.generateDeveuiByChipID(); LoRaWAN.init(loraWanClass,loraWanRegion); break; case DEVICE_STATE_JOIN: Serial.println("Joining"); LoRaWAN.join(); break; case DEVICE_STATE_SEND: digitalWrite(LED_BLUE, HIGH); Serial.println("sending"); prepareTxFrame( appPort ); LoRaWAN.send(); deviceState = DEVICE_STATE_CYCLE; break; case DEVICE_STATE_CYCLE: digitalWrite(LED_BLUE, LOW); // Schedule next packet transmission txDutyCycleTime = appTxDutyCycle + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); LoRaWAN.cycle(txDutyCycleTime); deviceState = DEVICE_STATE_SLEEP; break; case DEVICE_STATE_SLEEP: LoRaWAN.sleep(loraWanClass); break; default: deviceState = DEVICE_STATE_INIT; break; } }