Consolidate Lora memory usage

This commit is contained in:
Theo Arends 2024-03-30 15:02:20 +01:00
parent 6ccb3ae290
commit caed27645e
7 changed files with 201 additions and 215 deletions

View File

@ -183,13 +183,13 @@ typedef struct LoraSettings_t {
LoraEndNode_t end_node[TAS_LORAWAN_ENDNODES]; // End node parameters LoraEndNode_t end_node[TAS_LORAWAN_ENDNODES]; // End node parameters
#endif // USE_LORAWAN_BRIDGE #endif // USE_LORAWAN_BRIDGE
} LoraSettings_t; } LoraSettings_t;
LoraSettings_t* LoraSettings = nullptr;
typedef struct Lora_t { typedef struct Lora_t {
bool (* Config)(void); bool (* Config)(void);
bool (* Available)(void); bool (* Available)(void);
int (* Receive)(char*); int (* Receive)(char*);
bool (* Send)(uint8_t*, uint32_t, bool); bool (* Send)(uint8_t*, uint32_t, bool);
LoraSettings_t settings; // Persistent settings
uint32_t receive_time; uint32_t receive_time;
float rssi; float rssi;
float snr; float snr;
@ -197,19 +197,15 @@ typedef struct Lora_t {
volatile bool received_flag; // flag to indicate that a packet was received volatile bool received_flag; // flag to indicate that a packet was received
bool send_flag; bool send_flag;
bool raw; bool raw;
#ifdef USE_LORAWAN_BRIDGE
uint32_t device_address;
uint8_t* send_buffer;
uint8_t send_buffer_step;
uint8_t send_buffer_len;
bool rx;
#endif // USE_LORAWAN_BRIDGE
} Lora_t; } Lora_t;
Lora_t* Lora = nullptr; Lora_t* Lora = nullptr;
#ifdef USE_LORAWAN_BRIDGE
typedef struct Lorawan_t {
uint32_t device_address;
uint32_t send_buffer_step;
size_t send_buffer_len;
uint8_t send_buffer[64];
bool rx;
} Lorawan_t;
Lorawan_t* Lorawan = nullptr;
#endif // USE_LORAWAN_BRIDGE
#endif // USE_SPI_LORA #endif // USE_SPI_LORA
#endif // USE_SPI #endif // USE_SPI

View File

@ -120,17 +120,17 @@ bool LoraSx126xSend(uint8_t* data, uint32_t len, bool invert) {
} }
bool LoraSx126xConfig(void) { bool LoraSx126xConfig(void) {
LoRaRadio.setCodingRate(LoraSettings->coding_rate); LoRaRadio.setCodingRate(Lora->settings.coding_rate);
LoRaRadio.setSyncWord(LoraSettings->sync_word); LoRaRadio.setSyncWord(Lora->settings.sync_word);
LoRaRadio.setPreambleLength(LoraSettings->preamble_length); LoRaRadio.setPreambleLength(Lora->settings.preamble_length);
LoRaRadio.setCurrentLimit(LoraSettings->current_limit); LoRaRadio.setCurrentLimit(Lora->settings.current_limit);
LoRaRadio.setCRC(LoraSettings->crc_bytes); LoRaRadio.setCRC(Lora->settings.crc_bytes);
LoRaRadio.setSpreadingFactor(LoraSettings->spreading_factor); LoRaRadio.setSpreadingFactor(Lora->settings.spreading_factor);
LoRaRadio.setBandwidth(LoraSettings->bandwidth); LoRaRadio.setBandwidth(Lora->settings.bandwidth);
LoRaRadio.setFrequency(LoraSettings->frequency); LoRaRadio.setFrequency(Lora->settings.frequency);
LoRaRadio.setOutputPower(LoraSettings->output_power); LoRaRadio.setOutputPower(Lora->settings.output_power);
if (LoraSettings->implicit_header) { if (Lora->settings.implicit_header) {
LoRaRadio.implicitHeader(LoraSettings->implicit_header); LoRaRadio.implicitHeader(Lora->settings.implicit_header);
} else { } else {
LoRaRadio.explicitHeader(); LoRaRadio.explicitHeader();
} }
@ -140,7 +140,7 @@ bool LoraSx126xConfig(void) {
bool LoraSx126xInit(void) { bool LoraSx126xInit(void) {
LoRaRadio = new Module(Pin(GPIO_LORA_CS), Pin(GPIO_LORA_DI1), Pin(GPIO_LORA_RST), Pin(GPIO_LORA_BUSY)); LoRaRadio = new Module(Pin(GPIO_LORA_CS), Pin(GPIO_LORA_DI1), Pin(GPIO_LORA_RST), Pin(GPIO_LORA_BUSY));
if (RADIOLIB_ERR_NONE == LoRaRadio.begin(LoraSettings->frequency)) { if (RADIOLIB_ERR_NONE == LoRaRadio.begin(Lora->settings.frequency)) {
LoraSx126xConfig(); LoraSx126xConfig();
LoRaRadio.setDio1Action(LoraSx126xOnInterrupt); LoRaRadio.setDio1Action(LoraSx126xOnInterrupt);
if (RADIOLIB_ERR_NONE == LoRaRadio.startReceive()) { if (RADIOLIB_ERR_NONE == LoRaRadio.startReceive()) {

View File

@ -63,7 +63,7 @@ bool LoraSx127xSend(uint8_t* data, uint32_t len, bool invert) {
if (invert) { if (invert) {
LoRa.enableInvertIQ(); // active invert I and Q signals LoRa.enableInvertIQ(); // active invert I and Q signals
} }
LoRa.beginPacket(LoraSettings->implicit_header); // start packet LoRa.beginPacket(Lora->settings.implicit_header); // start packet
LoRa.write(data, len); // send message LoRa.write(data, len); // send message
LoRa.endPacket(); // finish packet and send it LoRa.endPacket(); // finish packet and send it
if (invert) { if (invert) {
@ -74,21 +74,21 @@ bool LoraSx127xSend(uint8_t* data, uint32_t len, bool invert) {
} }
bool LoraSx127xConfig(void) { bool LoraSx127xConfig(void) {
LoRa.setFrequency(LoraSettings->frequency * 1000 * 1000); LoRa.setFrequency(Lora->settings.frequency * 1000 * 1000);
LoRa.setSignalBandwidth(LoraSettings->bandwidth * 1000); LoRa.setSignalBandwidth(Lora->settings.bandwidth * 1000);
LoRa.setSpreadingFactor(LoraSettings->spreading_factor); LoRa.setSpreadingFactor(Lora->settings.spreading_factor);
LoRa.setCodingRate4(LoraSettings->coding_rate); LoRa.setCodingRate4(Lora->settings.coding_rate);
LoRa.setSyncWord(LoraSettings->sync_word); LoRa.setSyncWord(Lora->settings.sync_word);
LoRa.setTxPower(LoraSettings->output_power); LoRa.setTxPower(Lora->settings.output_power);
LoRa.setPreambleLength(LoraSettings->preamble_length); LoRa.setPreambleLength(Lora->settings.preamble_length);
LoRa.setOCP(LoraSettings->current_limit); LoRa.setOCP(Lora->settings.current_limit);
if (LoraSettings->crc_bytes) { if (Lora->settings.crc_bytes) {
LoRa.enableCrc(); LoRa.enableCrc();
} else { } else {
LoRa.disableCrc(); LoRa.disableCrc();
} }
/* /*
if (LoraSettings->implicit_header) { if (Lora->settings.implicit_header) {
LoRa.implicitHeaderMode(); LoRa.implicitHeaderMode();
} else { } else {
LoRa.explicitHeaderMode(); LoRa.explicitHeaderMode();
@ -100,7 +100,7 @@ bool LoraSx127xConfig(void) {
bool LoraSx127xInit(void) { bool LoraSx127xInit(void) {
LoRa.setPins(Pin(GPIO_LORA_CS), Pin(GPIO_LORA_RST), Pin(GPIO_LORA_DI0)); LoRa.setPins(Pin(GPIO_LORA_CS), Pin(GPIO_LORA_RST), Pin(GPIO_LORA_DI0));
if (LoRa.begin(LoraSettings->frequency * 1000 * 1000)) { if (LoRa.begin(Lora->settings.frequency * 1000 * 1000)) {
LoraSx127xConfig(); LoraSx127xConfig();
LoRa.onReceive(LoraSx127xOnReceive); LoRa.onReceive(LoraSx127xOnReceive);
LoRa.receive(); LoRa.receive();

View File

@ -69,7 +69,7 @@ void _LoraWanDeriveLegacyAppSKey(uint8_t* key, uint32_t jn, uint32_t nid, uint16
} }
void LoraWanDeriveLegacyAppSKey(uint32_t node, uint8_t* AppSKey) { void LoraWanDeriveLegacyAppSKey(uint32_t node, uint8_t* AppSKey) {
_LoraWanDeriveLegacyAppSKey(LoraSettings->end_node[node].AppKey, TAS_LORAWAN_JOINNONCE +node, TAS_LORAWAN_NETID, LoraSettings->end_node[node].DevNonce, AppSKey); _LoraWanDeriveLegacyAppSKey(Lora->settings.end_node[node].AppKey, TAS_LORAWAN_JOINNONCE +node, TAS_LORAWAN_NETID, Lora->settings.end_node[node].DevNonce, AppSKey);
} }
// DeriveLegacyNwkSKey derives the LoRaWAN 1.0 Network Session Key. AppNonce is entered as JoinNonce. // DeriveLegacyNwkSKey derives the LoRaWAN 1.0 Network Session Key. AppNonce is entered as JoinNonce.
@ -82,7 +82,7 @@ void _LoraWanDeriveLegacyNwkSKey(uint8_t* appKey, uint32_t jn, uint32_t nid, uin
} }
void LoraWanDeriveLegacyNwkSKey(uint32_t node, uint8_t* NwkSKey) { void LoraWanDeriveLegacyNwkSKey(uint32_t node, uint8_t* NwkSKey) {
_LoraWanDeriveLegacyNwkSKey(LoraSettings->end_node[node].AppKey, TAS_LORAWAN_JOINNONCE +node, TAS_LORAWAN_NETID, LoraSettings->end_node[node].DevNonce, NwkSKey); _LoraWanDeriveLegacyNwkSKey(Lora->settings.end_node[node].AppKey, TAS_LORAWAN_JOINNONCE +node, TAS_LORAWAN_NETID, Lora->settings.end_node[node].DevNonce, NwkSKey);
} }
#ifdef USE_LORAWAN_TEST #ifdef USE_LORAWAN_TEST

View File

@ -29,11 +29,11 @@ void LoraWanPublishHeader(uint32_t node) {
} }
if (!Settings->flag5.zb_omit_json_addr) { // SetOption119 - (Zigbee) Remove the device addr from json payload, can be used with zb_topic_fname where the addr is already known from the topic if (!Settings->flag5.zb_omit_json_addr) { // SetOption119 - (Zigbee) Remove the device addr from json payload, can be used with zb_topic_fname where the addr is already known from the topic
ResponseAppend_P(PSTR("{\"%s\":"), EscapeJSONString(LoraSettings->end_node[node].name.c_str()).c_str()); ResponseAppend_P(PSTR("{\"%s\":"), EscapeJSONString(Lora->settings.end_node[node].name.c_str()).c_str());
} }
ResponseAppend_P(PSTR("{\"Node\":%d,\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\""), node +1, LoraSettings->end_node[node].DevEUIl & 0x0000FFFF); ResponseAppend_P(PSTR("{\"Node\":%d,\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\""), node +1, Lora->settings.end_node[node].DevEUIl & 0x0000FFFF);
if (!LoraSettings->end_node[node].name.startsWith(F("0x"))) { if (!Lora->settings.end_node[node].name.startsWith(F("0x"))) {
ResponseAppend_P(PSTR(",\"" D_JSON_ZIGBEE_NAME "\":\"%s\""), EscapeJSONString(LoraSettings->end_node[node].name.c_str()).c_str()); ResponseAppend_P(PSTR(",\"" D_JSON_ZIGBEE_NAME "\":\"%s\""), EscapeJSONString(Lora->settings.end_node[node].name.c_str()).c_str());
} }
ResponseAppend_P(PSTR(",\"RSSI\":%1_f,\"SNR\":%1_f"), &Lora->rssi, &Lora->snr); ResponseAppend_P(PSTR(",\"RSSI\":%1_f,\"SNR\":%1_f"), &Lora->rssi, &Lora->snr);
} }
@ -57,7 +57,7 @@ void LoraWanPublishFooter(uint32_t node) {
char subtopic[TOPSZ]; char subtopic[TOPSZ];
// Clean special characters // Clean special characters
char stemp[TOPSZ]; char stemp[TOPSZ];
strlcpy(stemp, LoraSettings->end_node[node].name.c_str(), sizeof(stemp)); strlcpy(stemp, Lora->settings.end_node[node].name.c_str(), sizeof(stemp));
MakeValidMqtt(0, stemp); MakeValidMqtt(0, stemp);
if (Settings->flag5.zigbee_hide_bridge_topic) { // SetOption125 - (Zigbee) Hide bridge topic from zigbee topic (use with SetOption89) (1) if (Settings->flag5.zigbee_hide_bridge_topic) { // SetOption125 - (Zigbee) Hide bridge topic from zigbee topic (use with SetOption89) (1)
snprintf_P(subtopic, sizeof(subtopic), PSTR("%s"), stemp); snprintf_P(subtopic, sizeof(subtopic), PSTR("%s"), stemp);
@ -87,8 +87,8 @@ void LoraWanDecode(struct LoraNodeData_t* node_data) {
uint8_t node; uint8_t node;
uint8_t FPort; uint8_t FPort;
*/ */
if (bitRead(LoraSettings->flags, TAS_LORA_FLAG_DECODE_ENABLED)) { // LoraOption3 1 if (bitRead(Lora->settings.flags, TAS_LORA_FLAG_DECODE_ENABLED)) { // LoraOption3 1
if (0x00161600 == LoraSettings->end_node[node_data->node].DevEUIh) { // MerryIoT if (0x00161600 == Lora->settings.end_node[node_data->node].DevEUIh) { // MerryIoT
if (120 == node_data->FPort) { // MerryIoT door/window Sensor (DW10) if (120 == node_data->FPort) { // MerryIoT door/window Sensor (DW10)
if (9 == node_data->payload_len) { // MerryIoT Sensor state if (9 == node_data->payload_len) { // MerryIoT Sensor state
// 1 2 3 4 5 6 7 8 9 // 1 2 3 4 5 6 7 8 9
@ -102,7 +102,7 @@ void LoraWanDecode(struct LoraNodeData_t* node_data) {
uint32_t events = node_data->payload[6] | (node_data->payload[7] << 8) | (node_data->payload[8] << 16); uint32_t events = node_data->payload[6] | (node_data->payload[7] << 8) | (node_data->payload[8] << 16);
#ifdef USE_LORA_DEBUG #ifdef USE_LORA_DEBUG
AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Node %d, DevEUI %08X%08X, Events %d, LastEvent %d min, DoorOpen %d, Button %d, Tamper %d, Tilt %d, Battery %1_fV, Temp %d, Hum %d"), AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Node %d, DevEUI %08X%08X, Events %d, LastEvent %d min, DoorOpen %d, Button %d, Tamper %d, Tilt %d, Battery %1_fV, Temp %d, Hum %d"),
node_data->node +1, LoraSettings->end_node[node_data->node].DevEUIh, LoraSettings->end_node[node_data->node].DevEUIl, node_data->node +1, Lora->settings.end_node[node_data->node].DevEUIh, Lora->settings.end_node[node_data->node].DevEUIl,
events, elapsed_time, events, elapsed_time,
bitRead(status, 0), bitRead(status, 1), bitRead(status, 2), bitRead(status, 3), bitRead(status, 0), bitRead(status, 1), bitRead(status, 2), bitRead(status, 3),
&battery_volt, &battery_volt,
@ -122,7 +122,7 @@ void LoraWanDecode(struct LoraNodeData_t* node_data) {
} }
} }
else if (0xA840410E == LoraSettings->end_node[node_data->node].DevEUIh) { // Dragino else if (0xA840410E == Lora->settings.end_node[node_data->node].DevEUIh) { // Dragino
if (10 == node_data->FPort) { // Dragino LDS02 if (10 == node_data->FPort) { // Dragino LDS02
// 8CD2 01 000010 000000 00 - Door Open, 3.282V // 8CD2 01 000010 000000 00 - Door Open, 3.282V
// 0CD2 01 000011 000000 00 - Door Closed // 0CD2 01 000011 000000 00 - Door Closed
@ -134,7 +134,7 @@ void LoraWanDecode(struct LoraNodeData_t* node_data) {
uint8_t alarm = node_data->payload[9]; uint8_t alarm = node_data->payload[9];
#ifdef USE_LORA_DEBUG #ifdef USE_LORA_DEBUG
AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Node %d, DevEUI %08X%08X, Events %d, LastEvent %d min, DoorOpen %d, Battery %3_fV, Alarm %d"), AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Node %d, DevEUI %08X%08X, Events %d, LastEvent %d min, DoorOpen %d, Battery %3_fV, Alarm %d"),
node_data->node +1, LoraSettings->end_node[node_data->node].DevEUIh, LoraSettings->end_node[node_data->node].DevEUIl, node_data->node +1, Lora->settings.end_node[node_data->node].DevEUIh, Lora->settings.end_node[node_data->node].DevEUIl,
events, open_duration, events, open_duration,
bitRead(status, 7), bitRead(status, 7),
&battery_volt, &battery_volt,
@ -152,7 +152,7 @@ void LoraWanDecode(struct LoraNodeData_t* node_data) {
// Joined device without decoding // Joined device without decoding
LoraWanPublishHeader(node_data->node); LoraWanPublishHeader(node_data->node);
ResponseAppend_P(PSTR(",\"DevEUIh\":\"%08X\",\"DevEUIl\":\"%08X\",\"FPort\":%d,\"Payload\":["), ResponseAppend_P(PSTR(",\"DevEUIh\":\"%08X\",\"DevEUIl\":\"%08X\",\"FPort\":%d,\"Payload\":["),
LoraSettings->end_node[node_data->node].DevEUIh, LoraSettings->end_node[node_data->node].DevEUIl, node_data->FPort); Lora->settings.end_node[node_data->node].DevEUIh, Lora->settings.end_node[node_data->node].DevEUIl, node_data->FPort);
for (uint32_t i = 0; i < node_data->payload_len; i++) { for (uint32_t i = 0; i < node_data->payload_len; i++) {
ResponseAppend_P(PSTR("%s%d"), (0==i)?"":",", node_data->payload[i]); ResponseAppend_P(PSTR("%s%d"), (0==i)?"":",", node_data->payload[i]);
} }

View File

@ -93,18 +93,18 @@ bool LoraWanLoadData(void) {
app_key = root.getStr(PSTR(D_JSON_APPKEY), nullptr); app_key = root.getStr(PSTR(D_JSON_APPKEY), nullptr);
if (strlen(app_key)) { if (strlen(app_key)) {
size_t out_len = TAS_LORAWAN_AES128_KEY_SIZE; size_t out_len = TAS_LORAWAN_AES128_KEY_SIZE;
HexToBytes(app_key, LoraSettings->end_node[n].AppKey, &out_len); HexToBytes(app_key, Lora->settings.end_node[n].AppKey, &out_len);
} }
LoraSettings->end_node[n].DevEUIh = root.getUInt(PSTR(D_JSON_DEVEUI "h"), LoraSettings->end_node[n].DevEUIh); Lora->settings.end_node[n].DevEUIh = root.getUInt(PSTR(D_JSON_DEVEUI "h"), Lora->settings.end_node[n].DevEUIh);
LoraSettings->end_node[n].DevEUIl = root.getUInt(PSTR(D_JSON_DEVEUI "l"), LoraSettings->end_node[n].DevEUIl); Lora->settings.end_node[n].DevEUIl = root.getUInt(PSTR(D_JSON_DEVEUI "l"), Lora->settings.end_node[n].DevEUIl);
LoraSettings->end_node[n].DevNonce = root.getUInt(PSTR(D_JSON_DEVNONCE), LoraSettings->end_node[n].DevNonce); Lora->settings.end_node[n].DevNonce = root.getUInt(PSTR(D_JSON_DEVNONCE), Lora->settings.end_node[n].DevNonce);
LoraSettings->end_node[n].FCntUp = root.getUInt(PSTR(D_JSON_FCNTUP), LoraSettings->end_node[n].FCntUp); Lora->settings.end_node[n].FCntUp = root.getUInt(PSTR(D_JSON_FCNTUP), Lora->settings.end_node[n].FCntUp);
LoraSettings->end_node[n].FCntDown = root.getUInt(PSTR(D_JSON_FCNTDOWN), LoraSettings->end_node[n].FCntDown); Lora->settings.end_node[n].FCntDown = root.getUInt(PSTR(D_JSON_FCNTDOWN), Lora->settings.end_node[n].FCntDown);
LoraSettings->end_node[n].flags = root.getUInt(PSTR(D_JSON_FLAGS), LoraSettings->end_node[n].flags); Lora->settings.end_node[n].flags = root.getUInt(PSTR(D_JSON_FLAGS), Lora->settings.end_node[n].flags);
const char* name = nullptr; const char* name = nullptr;
name = root.getStr(PSTR(D_JSON_NAME), nullptr); name = root.getStr(PSTR(D_JSON_NAME), nullptr);
if (strlen(app_key)) { if (strlen(app_key)) {
LoraSettings->end_node[n].name = name; Lora->settings.end_node[n].name = name;
} }
} }
return true; return true;
@ -113,7 +113,7 @@ bool LoraWanLoadData(void) {
bool LoraWanSaveData(void) { bool LoraWanSaveData(void) {
bool result = false; bool result = false;
for (uint32_t n = 0; n < TAS_LORAWAN_ENDNODES; n++) { for (uint32_t n = 0; n < TAS_LORAWAN_ENDNODES; n++) {
if (LoraSettings->end_node[n].AppKey[0] > 0) { // Only save used slots if (Lora->settings.end_node[n].AppKey[0] > 0) { // Only save used slots
Response_P(PSTR("{\"" XDRV_73_KEY "_%d\":{\"" D_JSON_APPKEY "\":\"%16_H\"" Response_P(PSTR("{\"" XDRV_73_KEY "_%d\":{\"" D_JSON_APPKEY "\":\"%16_H\""
",\"" D_JSON_DEVEUI "h\":%lu,\"" D_JSON_DEVEUI "l\":%lu" ",\"" D_JSON_DEVEUI "h\":%lu,\"" D_JSON_DEVEUI "l\":%lu"
",\"" D_JSON_DEVNONCE "\":%u" ",\"" D_JSON_DEVNONCE "\":%u"
@ -121,12 +121,12 @@ bool LoraWanSaveData(void) {
",\"" D_JSON_FLAGS "\":%u" ",\"" D_JSON_FLAGS "\":%u"
",\"" D_JSON_NAME "\":\"%s\"}}"), ",\"" D_JSON_NAME "\":\"%s\"}}"),
n +1, n +1,
LoraSettings->end_node[n].AppKey, Lora->settings.end_node[n].AppKey,
LoraSettings->end_node[n].DevEUIh,LoraSettings->end_node[n].DevEUIl, Lora->settings.end_node[n].DevEUIh, Lora->settings.end_node[n].DevEUIl,
LoraSettings->end_node[n].DevNonce, Lora->settings.end_node[n].DevNonce,
LoraSettings->end_node[n].FCntUp, LoraSettings->end_node[n].FCntDown, Lora->settings.end_node[n].FCntUp, Lora->settings.end_node[n].FCntDown,
LoraSettings->end_node[n].flags, Lora->settings.end_node[n].flags,
LoraSettings->end_node[n].name.c_str()); Lora->settings.end_node[n].name.c_str());
result = UfsJsonSettingsWrite(ResponseData()); result = UfsJsonSettingsWrite(ResponseData());
} }
} }
@ -148,21 +148,24 @@ void LoraWanDeleteData(void) {
Ticker LoraWan_Send; Ticker LoraWan_Send;
void LoraWanTickerSend(void) { void LoraWanTickerSend(void) {
Lorawan->send_buffer_step--; Lora->send_buffer_step--;
if (1 == Lorawan->send_buffer_step) { if (1 == Lora->send_buffer_step) {
Lorawan->rx = true; // Always send during RX1 Lora->rx = true; // Always send during RX1
Lora->receive_time = 0; // Reset receive timer Lora->receive_time = 0; // Reset receive timer
LoraWan_Send.once_ms(TAS_LORAWAN_RECEIVE_DELAY2, LoraWanTickerSend); // Retry after 1000 ms LoraWan_Send.once_ms(TAS_LORAWAN_RECEIVE_DELAY2, LoraWanTickerSend); // Retry after 1000 ms
} }
if (Lorawan->rx) { // If received in RX1 do not resend in RX2 if (Lora->rx) { // If received in RX1 do not resend in RX2
LoraSend(Lorawan->send_buffer, Lorawan->send_buffer_len, true); LoraSend(Lora->send_buffer, Lora->send_buffer_len, true);
} }
} }
void LoraWanSendResponse(uint8_t* buffer, size_t len, uint32_t lorawan_delay) { void LoraWanSendResponse(uint8_t* buffer, size_t len, uint32_t lorawan_delay) {
memcpy(Lorawan->send_buffer, buffer, sizeof(Lorawan->send_buffer)); free(Lora->send_buffer); // Free previous buffer (if any)
Lorawan->send_buffer_len = len; Lora->send_buffer = (uint8_t*)malloc(len +1);
Lorawan->send_buffer_step = 2; if (nullptr == Lora->send_buffer) { return; }
memcpy(Lora->send_buffer, buffer, len);
Lora->send_buffer_len = len;
Lora->send_buffer_step = 2; // Send at RX1 and RX2
LoraWan_Send.once_ms(lorawan_delay - TimePassedSince(Lora->receive_time), LoraWanTickerSend); LoraWan_Send.once_ms(lorawan_delay - TimePassedSince(Lora->receive_time), LoraWanTickerSend);
} }
@ -170,19 +173,19 @@ void LoraWanSendResponse(uint8_t* buffer, size_t len, uint32_t lorawan_delay) {
uint32_t LoraWanSpreadingFactorToDataRate(void) { uint32_t LoraWanSpreadingFactorToDataRate(void) {
// Allow only JoinReq message datarates (125kHz bandwidth) // Allow only JoinReq message datarates (125kHz bandwidth)
if (LoraSettings->spreading_factor > 12) { if (Lora->settings.spreading_factor > 12) {
LoraSettings->spreading_factor = 12; Lora->settings.spreading_factor = 12;
} }
if (LoraSettings->spreading_factor < 7) { if (Lora->settings.spreading_factor < 7) {
LoraSettings->spreading_factor = 7; Lora->settings.spreading_factor = 7;
} }
LoraSettings->bandwidth = 125; Lora->settings.bandwidth = 125;
return 12 - LoraSettings->spreading_factor; return 12 - Lora->settings.spreading_factor;
} }
uint32_t LoraWanFrequencyToChannel(void) { uint32_t LoraWanFrequencyToChannel(void) {
// EU863-870 (EU868) JoinReq message frequencies are 868.1, 868.3 and 868.5 // EU863-870 (EU868) JoinReq message frequencies are 868.1, 868.3 and 868.5
uint32_t frequency = (LoraSettings->frequency * 10); uint32_t frequency = (Lora->settings.frequency * 10);
uint32_t channel = 250; uint32_t channel = 250;
if (8681 == frequency) { if (8681 == frequency) {
channel = 0; channel = 0;
@ -194,7 +197,7 @@ uint32_t LoraWanFrequencyToChannel(void) {
channel = 2; channel = 2;
} }
if (250 == channel) { if (250 == channel) {
LoraSettings->frequency = 868.1; Lora->settings.frequency = 868.1;
Lora->Config(); Lora->Config();
channel = 0; channel = 0;
} }
@ -204,8 +207,8 @@ uint32_t LoraWanFrequencyToChannel(void) {
/*********************************************************************************************/ /*********************************************************************************************/
void LoraWanSendLinkADRReq(uint32_t node) { void LoraWanSendLinkADRReq(uint32_t node) {
uint32_t DevAddr = Lorawan->device_address +node; uint32_t DevAddr = Lora->device_address +node;
uint16_t FCnt = LoraSettings->end_node[node].FCntDown++; uint16_t FCnt = Lora->settings.end_node[node].FCntDown++;
uint8_t NwkSKey[TAS_LORAWAN_AES128_KEY_SIZE]; uint8_t NwkSKey[TAS_LORAWAN_AES128_KEY_SIZE];
LoraWanDeriveLegacyNwkSKey(node, NwkSKey); LoraWanDeriveLegacyNwkSKey(node, NwkSKey);
@ -254,26 +257,26 @@ bool LoraWanInput(uint8_t* data, uint32_t packet_size) {
((uint32_t)data[21] << 16) | ((uint32_t)data[22] << 24); ((uint32_t)data[21] << 16) | ((uint32_t)data[22] << 24);
for (uint32_t node = 0; node < TAS_LORAWAN_ENDNODES; node++) { for (uint32_t node = 0; node < TAS_LORAWAN_ENDNODES; node++) {
uint32_t CalcMIC = LoraWanGenerateMIC(data, 19, LoraSettings->end_node[node].AppKey); uint32_t CalcMIC = LoraWanGenerateMIC(data, 19, Lora->settings.end_node[node].AppKey);
if (MIC == CalcMIC) { // Valid MIC based on LoraWanAppKey if (MIC == CalcMIC) { // Valid MIC based on LoraWanAppKey
AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: JoinEUI %8_H, DevEUIh %08X, DevEUIl %08X, DevNonce %04X, MIC %08X"), AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: JoinEUI %8_H, DevEUIh %08X, DevEUIl %08X, DevNonce %04X, MIC %08X"),
(uint8_t*)&JoinEUI, DevEUIh, DevEUIl, DevNonce, MIC); (uint8_t*)&JoinEUI, DevEUIh, DevEUIl, DevNonce, MIC);
LoraSettings->end_node[node].DevEUIl = DevEUIl; Lora->settings.end_node[node].DevEUIl = DevEUIl;
LoraSettings->end_node[node].DevEUIh = DevEUIh; Lora->settings.end_node[node].DevEUIh = DevEUIh;
LoraSettings->end_node[node].DevNonce = DevNonce; Lora->settings.end_node[node].DevNonce = DevNonce;
LoraSettings->end_node[node].FCntUp = 0; Lora->settings.end_node[node].FCntUp = 0;
LoraSettings->end_node[node].FCntDown = 0; Lora->settings.end_node[node].FCntDown = 0;
bitClear(LoraSettings->end_node[node].flags, TAS_LORAWAN_FLAG_LINK_ADR_REQ); bitClear(Lora->settings.end_node[node].flags, TAS_LORAWAN_FLAG_LINK_ADR_REQ);
if (LoraSettings->end_node[node].name.equals(F("0x0000"))) { if (Lora->settings.end_node[node].name.equals(F("0x0000"))) {
char name[10]; char name[10];
ext_snprintf_P(name, sizeof(name), PSTR("0x%04X"), LoraSettings->end_node[node].DevEUIl & 0x0000FFFF); ext_snprintf_P(name, sizeof(name), PSTR("0x%04X"), Lora->settings.end_node[node].DevEUIl & 0x0000FFFF);
LoraSettings->end_node[node].name = name; Lora->settings.end_node[node].name = name;
} }
uint32_t JoinNonce = TAS_LORAWAN_JOINNONCE +node; uint32_t JoinNonce = TAS_LORAWAN_JOINNONCE +node;
uint32_t DevAddr = Lorawan->device_address +node; uint32_t DevAddr = Lora->device_address +node;
uint32_t NetID = TAS_LORAWAN_NETID; uint32_t NetID = TAS_LORAWAN_NETID;
uint8_t join_data[33] = { 0 }; uint8_t join_data[33] = { 0 };
join_data[0] = TAS_LORAWAN_MTYPE_JOIN_ACCEPT << 5; join_data[0] = TAS_LORAWAN_MTYPE_JOIN_ACCEPT << 5;
@ -290,14 +293,14 @@ bool LoraWanInput(uint8_t* data, uint32_t packet_size) {
join_data[11] = LoraWanSpreadingFactorToDataRate(); // DLSettings join_data[11] = LoraWanSpreadingFactorToDataRate(); // DLSettings
join_data[12] = 1; // RXDelay; join_data[12] = 1; // RXDelay;
uint32_t NewMIC = LoraWanGenerateMIC(join_data, 13, LoraSettings->end_node[node].AppKey); uint32_t NewMIC = LoraWanGenerateMIC(join_data, 13, Lora->settings.end_node[node].AppKey);
join_data[13] = NewMIC; join_data[13] = NewMIC;
join_data[14] = NewMIC >> 8; join_data[14] = NewMIC >> 8;
join_data[15] = NewMIC >> 16; join_data[15] = NewMIC >> 16;
join_data[16] = NewMIC >> 24; join_data[16] = NewMIC >> 24;
uint8_t EncData[33]; uint8_t EncData[33];
EncData[0] = join_data[0]; EncData[0] = join_data[0];
LoraWanEncryptJoinAccept(LoraSettings->end_node[node].AppKey, &join_data[1], 16, &EncData[1]); LoraWanEncryptJoinAccept(Lora->settings.end_node[node].AppKey, &join_data[1], 16, &EncData[1]);
// AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Join %17_H"), join_data); // AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Join %17_H"), join_data);
@ -335,12 +338,12 @@ bool LoraWanInput(uint8_t* data, uint32_t packet_size) {
uint32_t DevAddr = (uint32_t)data[1] | ((uint32_t)data[2] << 8) | ((uint32_t)data[3] << 16) | ((uint32_t)data[4] << 24); uint32_t DevAddr = (uint32_t)data[1] | ((uint32_t)data[2] << 8) | ((uint32_t)data[3] << 16) | ((uint32_t)data[4] << 24);
for (uint32_t node = 0; node < TAS_LORAWAN_ENDNODES; node++) { for (uint32_t node = 0; node < TAS_LORAWAN_ENDNODES; node++) {
if (0 == LoraSettings->end_node[node].DevEUIh) { continue; } // No DevEUI so never joined if (0 == Lora->settings.end_node[node].DevEUIh) { continue; } // No DevEUI so never joined
if ((Lorawan->device_address +node) != DevAddr) { continue; } // Not my device if ((Lora->device_address +node) != DevAddr) { continue; } // Not my device
uint32_t FCtrl = data[5]; uint32_t FCtrl = data[5];
uint32_t FOptsLen = FCtrl & 0x0F; uint32_t FOptsLen = FCtrl & 0x0F;
uint32_t FCnt = (LoraSettings->end_node[node].FCntUp & 0xFFFF0000) | data[6] | (data[7] << 8); uint32_t FCnt = (Lora->settings.end_node[node].FCntUp & 0xFFFF0000) | data[6] | (data[7] << 8);
uint8_t* FOpts = &data[8]; uint8_t* FOpts = &data[8];
uint32_t FPort = data[8 +FOptsLen]; uint32_t FPort = data[8 +FOptsLen];
uint8_t* FRMPayload = &data[9 +FOptsLen]; uint8_t* FRMPayload = &data[9 +FOptsLen];
@ -384,17 +387,17 @@ bool LoraWanInput(uint8_t* data, uint32_t packet_size) {
DevAddr, FCtrl, FOptsLen, FCnt, FOptsLen, FOpts, FPort, org_payload_len, FRMPayload, org_payload_len, payload_decrypted, MIC); DevAddr, FCtrl, FOptsLen, FCnt, FOptsLen, FOpts, FPort, org_payload_len, FRMPayload, org_payload_len, payload_decrypted, MIC);
#endif // USE_LORA_DEBUG #endif // USE_LORA_DEBUG
if (LoraSettings->end_node[node].FCntUp <= FCnt) { // Skip re-transmissions if (Lora->settings.end_node[node].FCntUp <= FCnt) { // Skip re-transmissions
Lorawan->rx = false; // Skip RX2 as this is a response from RX1 Lora->rx = false; // Skip RX2 as this is a response from RX1
LoraSettings->end_node[node].FCntUp++; Lora->settings.end_node[node].FCntUp++;
if (LoraSettings->end_node[node].FCntUp < FCnt) { // Report missed frames if (Lora->settings.end_node[node].FCntUp < FCnt) { // Report missed frames
uint32_t FCnt_missed = FCnt - LoraSettings->end_node[node].FCntUp; uint32_t FCnt_missed = FCnt - Lora->settings.end_node[node].FCntUp;
AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Missed frames %d"), FCnt_missed); AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Missed frames %d"), FCnt_missed);
if (FCnt_missed > 1) { // Missed two or more frames if (FCnt_missed > 1) { // Missed two or more frames
bitClear(LoraSettings->end_node[node].flags, TAS_LORAWAN_FLAG_LINK_ADR_REQ); // Resend LinkADRReq bitClear(Lora->settings.end_node[node].flags, TAS_LORAWAN_FLAG_LINK_ADR_REQ); // Resend LinkADRReq
} }
} }
LoraSettings->end_node[node].FCntUp = FCnt; Lora->settings.end_node[node].FCntUp = FCnt;
if (FOptsLen) { if (FOptsLen) {
uint32_t i = 0; uint32_t i = 0;
@ -408,7 +411,7 @@ bool LoraWanInput(uint8_t* data, uint32_t packet_size) {
uint8_t status = FOpts[i]; uint8_t status = FOpts[i];
AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: MAC LinkADRAns PowerACK %d, DataRateACK %d, ChannelMaskACK %d"), AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: MAC LinkADRAns PowerACK %d, DataRateACK %d, ChannelMaskACK %d"),
bitRead(status, 2), bitRead(status, 1), bitRead(status, 0)); bitRead(status, 2), bitRead(status, 1), bitRead(status, 0));
bitSet(LoraSettings->end_node[node].flags, TAS_LORAWAN_FLAG_LINK_ADR_REQ); bitSet(Lora->settings.end_node[node].flags, TAS_LORAWAN_FLAG_LINK_ADR_REQ);
} }
else if (TAS_LORAWAN_CID_DUTY_CYCLE_ANS == FOpts[i]) { else if (TAS_LORAWAN_CID_DUTY_CYCLE_ANS == FOpts[i]) {
i++; i++;
@ -450,20 +453,20 @@ bool LoraWanInput(uint8_t* data, uint32_t packet_size) {
node_data.FPort = FPort; node_data.FPort = FPort;
LoraWanDecode(&node_data); LoraWanDecode(&node_data);
if (0xA840410E == LoraSettings->end_node[node].DevEUIh) { // Dragino if (0xA840410E == Lora->settings.end_node[node].DevEUIh) { // Dragino
// Dragino v1.7 fails to set DR with ADR so set it using serial interface: // Dragino v1.7 fails to set DR with ADR so set it using serial interface:
// Password 123456 // Password 123456
// AT+CHS=868100000 // AT+CHS=868100000
// Start join using reset button // Start join using reset button
// AT+CADR=0 // AT+CADR=0
// AT+CDATARATE=3 // AT+CDATARATE=3
bitSet(LoraSettings->end_node[node].flags, TAS_LORAWAN_FLAG_LINK_ADR_REQ); bitSet(Lora->settings.end_node[node].flags, TAS_LORAWAN_FLAG_LINK_ADR_REQ);
} }
if (TAS_LORAWAN_MTYPE_CONFIRMED_DATA_UPLINK == MType) { if (TAS_LORAWAN_MTYPE_CONFIRMED_DATA_UPLINK == MType) {
data[0] = TAS_LORAWAN_MTYPE_UNCONFIRMED_DATA_DOWNLINK << 5; data[0] = TAS_LORAWAN_MTYPE_UNCONFIRMED_DATA_DOWNLINK << 5;
data[5] |= 0x20; // FCtrl Set ACK bit data[5] |= 0x20; // FCtrl Set ACK bit
uint16_t FCnt = LoraSettings->end_node[node].FCntDown++; uint16_t FCnt = Lora->settings.end_node[node].FCntDown++;
data[6] = FCnt; data[6] = FCnt;
data[7] = FCnt >> 8; data[7] = FCnt >> 8;
uint32_t MIC = LoraWanComputeLegacyDownlinkMIC(NwkSKey, DevAddr, FCnt, data, packet_size -4); uint32_t MIC = LoraWanComputeLegacyDownlinkMIC(NwkSKey, DevAddr, FCnt, data, packet_size -4);
@ -475,7 +478,7 @@ bool LoraWanInput(uint8_t* data, uint32_t packet_size) {
} }
} }
if (TAS_LORAWAN_MTYPE_UNCONFIRMED_DATA_UPLINK == MType) { if (TAS_LORAWAN_MTYPE_UNCONFIRMED_DATA_UPLINK == MType) {
if (!bitRead(LoraSettings->end_node[node].flags, TAS_LORAWAN_FLAG_LINK_ADR_REQ) && if (!bitRead(Lora->settings.end_node[node].flags, TAS_LORAWAN_FLAG_LINK_ADR_REQ) &&
FCtrl_ADR && !FCtrl_ACK) { FCtrl_ADR && !FCtrl_ACK) {
// Try to fix single channel and datarate // Try to fix single channel and datarate
LoraWanSendLinkADRReq(node); // Resend LinkADRReq LoraWanSendLinkADRReq(node); // Resend LinkADRReq
@ -509,14 +512,14 @@ void CmndLoraWanBridge(void) {
// LoraWanBridge 1 - Set LoraOption1 1 = Enable LoraWanBridge // LoraWanBridge 1 - Set LoraOption1 1 = Enable LoraWanBridge
uint32_t pindex = 0; uint32_t pindex = 0;
if (XdrvMailbox.payload >= 0) { if (XdrvMailbox.payload >= 0) {
bitWrite(LoraSettings->flags, pindex, XdrvMailbox.payload); bitWrite(Lora->settings.flags, pindex, XdrvMailbox.payload);
} }
#ifdef USE_LORAWAN_TEST #ifdef USE_LORAWAN_TEST
LoraWanTestKeyDerivation(); LoraWanTestKeyDerivation();
LorWanTestUplinkDownlinkEncryption(); LorWanTestUplinkDownlinkEncryption();
LorWanTestUplinkDownlinkMIC(); LorWanTestUplinkDownlinkMIC();
#endif // USE_LORAWAN_TEST #endif // USE_LORAWAN_TEST
ResponseCmndChar(GetStateText(bitRead(LoraSettings->flags, pindex))); ResponseCmndChar(GetStateText(bitRead(Lora->settings.flags, pindex)));
} }
void CmndLoraWanAppKey(void) { void CmndLoraWanAppKey(void) {
@ -526,16 +529,16 @@ void CmndLoraWanAppKey(void) {
uint32_t node = XdrvMailbox.index -1; uint32_t node = XdrvMailbox.index -1;
if (32 == XdrvMailbox.data_len) { if (32 == XdrvMailbox.data_len) {
size_t out_len = 16; size_t out_len = 16;
HexToBytes(XdrvMailbox.data, LoraSettings->end_node[node].AppKey, &out_len); HexToBytes(XdrvMailbox.data, Lora->settings.end_node[node].AppKey, &out_len);
if (0 == LoraSettings->end_node[node].name.length()) { if (0 == Lora->settings.end_node[node].name.length()) {
LoraSettings->end_node[node].name = F("0x0000"); Lora->settings.end_node[node].name = F("0x0000");
} }
} }
else if (0 == XdrvMailbox.payload) { else if (0 == XdrvMailbox.payload) {
memset(&LoraSettings->end_node[node], 0, sizeof(LoraEndNode_t)); memset(&Lora->settings.end_node[node], 0, sizeof(LoraEndNode_t));
} }
char appkey[33]; char appkey[33];
ext_snprintf_P(appkey, sizeof(appkey), PSTR("%16_H"), LoraSettings->end_node[node].AppKey); ext_snprintf_P(appkey, sizeof(appkey), PSTR("%16_H"), Lora->settings.end_node[node].AppKey);
ResponseCmndIdxChar(appkey); ResponseCmndIdxChar(appkey);
} }
} }
@ -549,13 +552,13 @@ void CmndLoraWanName(void) {
if (XdrvMailbox.data_len) { if (XdrvMailbox.data_len) {
if (1 == XdrvMailbox.payload) { if (1 == XdrvMailbox.payload) {
char name[10]; char name[10];
ext_snprintf_P(name, sizeof(name), PSTR("0x%04X"), LoraSettings->end_node[node].DevEUIl & 0x0000FFFF); ext_snprintf_P(name, sizeof(name), PSTR("0x%04X"), Lora->settings.end_node[node].DevEUIl & 0x0000FFFF);
LoraSettings->end_node[node].name = name; Lora->settings.end_node[node].name = name;
} else { } else {
LoraSettings->end_node[node].name = XdrvMailbox.data; Lora->settings.end_node[node].name = XdrvMailbox.data;
} }
} }
ResponseCmndIdxChar(LoraSettings->end_node[node].name.c_str()); ResponseCmndIdxChar(Lora->settings.end_node[node].name.c_str());
} }
} }
@ -563,16 +566,12 @@ void CmndLoraWanName(void) {
* Interface * Interface
\*********************************************************************************************/ \*********************************************************************************************/
bool LoraWanInit(void) { void LoraWanInit(void) {
Lorawan = (Lorawan_t*)calloc(sizeof(Lorawan_t), 1); // Need calloc to reset registers to 0/false
if (nullptr == Lorawan) { return false; }
// The Things Network has been assigned a 7-bits "device address prefix" a.k.a. NwkID // The Things Network has been assigned a 7-bits "device address prefix" a.k.a. NwkID
// %0010011. Using that, TTN currently sends NetID 0x000013, and a TTN DevAddr always // %0010011. Using that, TTN currently sends NetID 0x000013, and a TTN DevAddr always
// starts with 0x26 or 0x27 // starts with 0x26 or 0x27
// Private networks are supposed to used NetID 0x000000. // Private networks are supposed to used NetID 0x000000.
Lorawan->device_address = (TAS_LORAWAN_NETID << 25) | (ESP_getChipId() & 0x01FFFFFF); Lora->device_address = (TAS_LORAWAN_NETID << 25) | (ESP_getChipId() & 0x01FFFFFF);
return true;
} }
#endif // USE_LORAWAN_BRIDGE #endif // USE_LORAWAN_BRIDGE

View File

@ -17,55 +17,55 @@
/*********************************************************************************************/ /*********************************************************************************************/
void LoraDefaults(void) { void LoraDefaults(void) {
LoraSettings->frequency = TAS_LORA_FREQUENCY; Lora->settings.frequency = TAS_LORA_FREQUENCY;
LoraSettings->bandwidth = TAS_LORA_BANDWIDTH; Lora->settings.bandwidth = TAS_LORA_BANDWIDTH;
LoraSettings->spreading_factor = TAS_LORA_SPREADING_FACTOR; Lora->settings.spreading_factor = TAS_LORA_SPREADING_FACTOR;
LoraSettings->coding_rate = TAS_LORA_CODING_RATE; Lora->settings.coding_rate = TAS_LORA_CODING_RATE;
LoraSettings->sync_word = TAS_LORA_SYNC_WORD; Lora->settings.sync_word = TAS_LORA_SYNC_WORD;
LoraSettings->output_power = TAS_LORA_OUTPUT_POWER; Lora->settings.output_power = TAS_LORA_OUTPUT_POWER;
LoraSettings->preamble_length = TAS_LORA_PREAMBLE_LENGTH; Lora->settings.preamble_length = TAS_LORA_PREAMBLE_LENGTH;
LoraSettings->current_limit = TAS_LORA_CURRENT_LIMIT; Lora->settings.current_limit = TAS_LORA_CURRENT_LIMIT;
LoraSettings->implicit_header = TAS_LORA_HEADER; Lora->settings.implicit_header = TAS_LORA_HEADER;
LoraSettings->crc_bytes = TAS_LORA_CRC_BYTES; Lora->settings.crc_bytes = TAS_LORA_CRC_BYTES;
} }
void LoraWanDefaults(void) { void LoraWanDefaults(void) {
LoraSettings->frequency = TAS_LORAWAN_FREQUENCY; Lora->settings.frequency = TAS_LORAWAN_FREQUENCY;
LoraSettings->bandwidth = TAS_LORAWAN_BANDWIDTH; Lora->settings.bandwidth = TAS_LORAWAN_BANDWIDTH;
LoraSettings->spreading_factor = TAS_LORAWAN_SPREADING_FACTOR; Lora->settings.spreading_factor = TAS_LORAWAN_SPREADING_FACTOR;
LoraSettings->coding_rate = TAS_LORAWAN_CODING_RATE; Lora->settings.coding_rate = TAS_LORAWAN_CODING_RATE;
LoraSettings->sync_word = TAS_LORAWAN_SYNC_WORD; Lora->settings.sync_word = TAS_LORAWAN_SYNC_WORD;
LoraSettings->output_power = TAS_LORAWAN_OUTPUT_POWER; Lora->settings.output_power = TAS_LORAWAN_OUTPUT_POWER;
LoraSettings->preamble_length = TAS_LORAWAN_PREAMBLE_LENGTH; Lora->settings.preamble_length = TAS_LORAWAN_PREAMBLE_LENGTH;
LoraSettings->current_limit = TAS_LORAWAN_CURRENT_LIMIT; Lora->settings.current_limit = TAS_LORAWAN_CURRENT_LIMIT;
LoraSettings->implicit_header = TAS_LORAWAN_HEADER; Lora->settings.implicit_header = TAS_LORAWAN_HEADER;
LoraSettings->crc_bytes = TAS_LORAWAN_CRC_BYTES; Lora->settings.crc_bytes = TAS_LORAWAN_CRC_BYTES;
} }
void LoraSettings2Json(void) { void LoraSettings2Json(void) {
ResponseAppend_P(PSTR("\"" D_JSON_FREQUENCY "\":%1_f"), &LoraSettings->frequency); // xxx.x MHz ResponseAppend_P(PSTR("\"" D_JSON_FREQUENCY "\":%1_f"), &Lora->settings.frequency); // xxx.x MHz
ResponseAppend_P(PSTR(",\"" D_JSON_BANDWIDTH "\":%1_f"), &LoraSettings->bandwidth); // xxx.x kHz ResponseAppend_P(PSTR(",\"" D_JSON_BANDWIDTH "\":%1_f"), &Lora->settings.bandwidth); // xxx.x kHz
ResponseAppend_P(PSTR(",\"" D_JSON_SPREADING_FACTOR "\":%d"), LoraSettings->spreading_factor); ResponseAppend_P(PSTR(",\"" D_JSON_SPREADING_FACTOR "\":%d"), Lora->settings.spreading_factor);
ResponseAppend_P(PSTR(",\"" D_JSON_CODINGRATE4 "\":%d"), LoraSettings->coding_rate); ResponseAppend_P(PSTR(",\"" D_JSON_CODINGRATE4 "\":%d"), Lora->settings.coding_rate);
ResponseAppend_P(PSTR(",\"" D_JSON_SYNCWORD "\":%d"), LoraSettings->sync_word); ResponseAppend_P(PSTR(",\"" D_JSON_SYNCWORD "\":%d"), Lora->settings.sync_word);
ResponseAppend_P(PSTR(",\"" D_JSON_OUTPUT_POWER "\":%d"), LoraSettings->output_power); // dBm ResponseAppend_P(PSTR(",\"" D_JSON_OUTPUT_POWER "\":%d"), Lora->settings.output_power); // dBm
ResponseAppend_P(PSTR(",\"" D_JSON_PREAMBLE_LENGTH "\":%d"), LoraSettings->preamble_length); // symbols ResponseAppend_P(PSTR(",\"" D_JSON_PREAMBLE_LENGTH "\":%d"), Lora->settings.preamble_length); // symbols
ResponseAppend_P(PSTR(",\"" D_JSON_CURRENT_LIMIT "\":%1_f"), &LoraSettings->current_limit); // xx.x mA (Overcurrent Protection - OCP) ResponseAppend_P(PSTR(",\"" D_JSON_CURRENT_LIMIT "\":%1_f"), &Lora->settings.current_limit); // xx.x mA (Overcurrent Protection - OCP)
ResponseAppend_P(PSTR(",\"" D_JSON_IMPLICIT_HEADER "\":%d"), LoraSettings->implicit_header); // 0 = explicit ResponseAppend_P(PSTR(",\"" D_JSON_IMPLICIT_HEADER "\":%d"), Lora->settings.implicit_header); // 0 = explicit
ResponseAppend_P(PSTR(",\"" D_JSON_CRC_BYTES "\":%d"), LoraSettings->crc_bytes); // bytes ResponseAppend_P(PSTR(",\"" D_JSON_CRC_BYTES "\":%d"), Lora->settings.crc_bytes); // bytes
} }
void LoraJson2Settings(JsonParserObject root) { void LoraJson2Settings(JsonParserObject root) {
LoraSettings->frequency = root.getFloat(PSTR(D_JSON_FREQUENCY), LoraSettings->frequency); Lora->settings.frequency = root.getFloat(PSTR(D_JSON_FREQUENCY), Lora->settings.frequency);
LoraSettings->bandwidth = root.getFloat(PSTR(D_JSON_BANDWIDTH), LoraSettings->bandwidth); Lora->settings.bandwidth = root.getFloat(PSTR(D_JSON_BANDWIDTH), Lora->settings.bandwidth);
LoraSettings->spreading_factor = root.getUInt(PSTR(D_JSON_SPREADING_FACTOR), LoraSettings->spreading_factor); Lora->settings.spreading_factor = root.getUInt(PSTR(D_JSON_SPREADING_FACTOR), Lora->settings.spreading_factor);
LoraSettings->coding_rate = root.getUInt(PSTR(D_JSON_CODINGRATE4), LoraSettings->coding_rate); Lora->settings.coding_rate = root.getUInt(PSTR(D_JSON_CODINGRATE4), Lora->settings.coding_rate);
LoraSettings->sync_word = root.getUInt(PSTR(D_JSON_SYNCWORD), LoraSettings->sync_word); Lora->settings.sync_word = root.getUInt(PSTR(D_JSON_SYNCWORD), Lora->settings.sync_word);
LoraSettings->output_power = root.getUInt(PSTR(D_JSON_OUTPUT_POWER), LoraSettings->output_power); Lora->settings.output_power = root.getUInt(PSTR(D_JSON_OUTPUT_POWER), Lora->settings.output_power);
LoraSettings->preamble_length = root.getUInt(PSTR(D_JSON_PREAMBLE_LENGTH), LoraSettings->preamble_length); Lora->settings.preamble_length = root.getUInt(PSTR(D_JSON_PREAMBLE_LENGTH), Lora->settings.preamble_length);
LoraSettings->current_limit = root.getFloat(PSTR(D_JSON_CURRENT_LIMIT), LoraSettings->current_limit); Lora->settings.current_limit = root.getFloat(PSTR(D_JSON_CURRENT_LIMIT), Lora->settings.current_limit);
LoraSettings->implicit_header = root.getUInt(PSTR(D_JSON_IMPLICIT_HEADER), LoraSettings->implicit_header); Lora->settings.implicit_header = root.getUInt(PSTR(D_JSON_IMPLICIT_HEADER), Lora->settings.implicit_header);
LoraSettings->crc_bytes = root.getUInt(PSTR(D_JSON_CRC_BYTES), LoraSettings->crc_bytes); Lora->settings.crc_bytes = root.getUInt(PSTR(D_JSON_CRC_BYTES), Lora->settings.crc_bytes);
} }
/*********************************************************************************************\ /*********************************************************************************************\
@ -85,8 +85,8 @@ bool LoraLoadData(void) {
JsonParserObject root = parser.getRootObject(); JsonParserObject root = parser.getRootObject();
if (!root) { return false; } if (!root) { return false; }
LoraSettings->crc32 = root.getUInt(PSTR("Crc"), LoraSettings->crc32); Lora->settings.crc32 = root.getUInt(PSTR("Crc"), Lora->settings.crc32);
LoraSettings->flags = root.getUInt(PSTR("Flags"), LoraSettings->flags); Lora->settings.flags = root.getUInt(PSTR("Flags"), Lora->settings.flags);
LoraJson2Settings(root); LoraJson2Settings(root);
#ifdef USE_LORAWAN_BRIDGE #ifdef USE_LORAWAN_BRIDGE
@ -102,8 +102,8 @@ bool LoraSaveData(void) {
Response_P(PSTR("{\"" XDRV_73_KEY "\":{" Response_P(PSTR("{\"" XDRV_73_KEY "\":{"
"\"Crc\":%u," "\"Crc\":%u,"
"\"Flags\":%u,"), "\"Flags\":%u,"),
LoraSettings->crc32, Lora->settings.crc32,
LoraSettings->flags); Lora->settings.flags);
LoraSettings2Json(); LoraSettings2Json();
ResponseAppend_P(PSTR("}}")); ResponseAppend_P(PSTR("}}"));
@ -134,7 +134,7 @@ void LoraSettingsLoad(bool erase) {
// Called from FUNC_RESET_SETTINGS (erase = 1) after command reset 4, 5, or 6 // Called from FUNC_RESET_SETTINGS (erase = 1) after command reset 4, 5, or 6
// *** Start init default values in case key is not found *** // *** Start init default values in case key is not found ***
memset(LoraSettings, 0x00, sizeof(LoraSettings_t)); memset(&Lora->settings, 0x00, sizeof(LoraSettings_t));
// Init any other parameter in struct LoraSettings // Init any other parameter in struct LoraSettings
LoraDefaults(); LoraDefaults();
// *** End Init default values *** // *** End Init default values ***
@ -159,11 +159,9 @@ void LoraSettingsLoad(bool erase) {
void LoraSettingsSave(void) { void LoraSettingsSave(void) {
// Called from FUNC_SAVE_SETTINGS every SaveData second and at restart // Called from FUNC_SAVE_SETTINGS every SaveData second and at restart
#ifdef USE_UFILESYS #ifdef USE_UFILESYS
uint32_t crc32 = GetCfgCrc32((uint8_t*)LoraSettings +4, sizeof(LoraSettings_t) -4); // Skip crc32 uint32_t crc32 = GetCfgCrc32((uint8_t*)&Lora->settings +4, sizeof(LoraSettings_t) -4); // Skip crc32
if (crc32 != LoraSettings->crc32) { if (crc32 != Lora->settings.crc32) {
// Try to save file /.drvset122 Lora->settings.crc32 = crc32;
LoraSettings->crc32 = crc32;
if (LoraSaveData()) { if (LoraSaveData()) {
AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: Lora saved to file")); AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: Lora saved to file"));
} else { } else {
@ -194,7 +192,7 @@ void LoraInput(void) {
Lora->receive_time, packet_size, data, &Lora->rssi, &Lora->snr); Lora->receive_time, packet_size, data, &Lora->rssi, &Lora->snr);
#ifdef USE_LORAWAN_BRIDGE #ifdef USE_LORAWAN_BRIDGE
if (bitRead(LoraSettings->flags, TAS_LORA_FLAG_BRIDGE_ENABLED)) { if (bitRead(Lora->settings.flags, TAS_LORA_FLAG_BRIDGE_ENABLED)) {
if (LoraWanInput((uint8_t*)data, packet_size)) { if (LoraWanInput((uint8_t*)data, packet_size)) {
return; return;
} }
@ -255,16 +253,15 @@ void LoraInit(void) {
Lora = (Lora_t*)calloc(sizeof(Lora_t), 1); // Need calloc to reset registers to 0/false Lora = (Lora_t*)calloc(sizeof(Lora_t), 1); // Need calloc to reset registers to 0/false
if (nullptr == Lora) { return; } if (nullptr == Lora) { return; }
LoraSettings = (LoraSettings_t*)calloc(sizeof(LoraSettings_t), 1); // Need calloc to reset registers to 0/false
if (nullptr == LoraSettings) {
free(Lora);
return;
}
LoraSettingsLoad(0); LoraSettingsLoad(0);
#ifdef USE_LORAWAN_BRIDGE
LoraWanInit();
#endif // USE_LORAWAN_BRIDGE
bool present = false; bool present = false;
char hardware[20]; char hardware[20];
if (false) { if (false) {
// Need this as following `else if`s may not be present
} }
#ifdef USE_LORA_SX127X #ifdef USE_LORA_SX127X
else if (PinUsed(GPIO_LORA_DI0)) { else if (PinUsed(GPIO_LORA_DI0)) {
@ -293,15 +290,9 @@ void LoraInit(void) {
} }
#endif // USE_LORA_SX126X #endif // USE_LORA_SX126X
#ifdef USE_LORAWAN_BRIDGE
if (present && !LoraWanInit()) {
present = false;
}
#endif // USE_LORAWAN_BRIDGE
if (present) { if (present) {
AddLog(LOG_LEVEL_INFO, PSTR("LOR: %s initialized"), hardware); AddLog(LOG_LEVEL_INFO, PSTR("LOR: %s initialized"), hardware);
} else { } else {
free(LoraSettings);
free(Lora); free(Lora);
Lora = nullptr; Lora = nullptr;
} }
@ -330,9 +321,9 @@ void CmndLoraOption(void) {
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 8)) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 8)) {
uint32_t pindex = XdrvMailbox.index -1; uint32_t pindex = XdrvMailbox.index -1;
if (XdrvMailbox.payload >= 0) { if (XdrvMailbox.payload >= 0) {
bitWrite(LoraSettings->flags, pindex, XdrvMailbox.payload); bitWrite(Lora->settings.flags, pindex, XdrvMailbox.payload);
} }
ResponseCmndIdxChar(GetStateText(bitRead(LoraSettings->flags, pindex))); ResponseCmndIdxChar(GetStateText(bitRead(Lora->settings.flags, pindex)));
} }
} }