Move Lora variables from fixed to heap

This commit is contained in:
Theo Arends 2024-03-29 17:56:06 +01:00
parent 7774ce5ad8
commit 6ccb3ae290
7 changed files with 251 additions and 229 deletions

View File

@ -91,7 +91,7 @@
#define TAS_LORAWAN_RECEIVE_DELAY2 1000 // LoRaWan Receive delay 2
#define TAS_LORAWAN_JOIN_ACCEPT_DELAY1 5000 // LoRaWan Join accept delay 1
#define TAS_LORAWAN_JOIN_ACCEPT_DELAY2 1000 // LoRaWan Join accept delay 2
#define TAS_LORAWAN_ENDNODES 4 // Max number od supported endnodes
#define TAS_LORAWAN_ENDNODES 4 // Max number of supported endnodes
#define TAS_LORAWAN_AES128_KEY_SIZE 16 // Size in bytes
enum TasLoraFlags {
@ -166,7 +166,7 @@ typedef struct LoraEndNode_t {
} LoraEndNode_t;
// Global structure containing driver saved variables
struct {
typedef struct LoraSettings_t {
uint32_t crc32; // To detect file changes
float frequency; // 868.0 MHz
float bandwidth; // 125.0 kHz
@ -182,9 +182,10 @@ struct {
#ifdef USE_LORAWAN_BRIDGE
LoraEndNode_t end_node[TAS_LORAWAN_ENDNODES]; // End node parameters
#endif // USE_LORAWAN_BRIDGE
} LoraSettings;
} LoraSettings_t;
LoraSettings_t* LoraSettings = nullptr;
struct {
typedef struct Lora_t {
bool (* Config)(void);
bool (* Available)(void);
int (* Receive)(char*);
@ -193,20 +194,21 @@ struct {
float rssi;
float snr;
uint8_t packet_size; // Max is 255 (LORA_MAX_PACKET_LENGTH)
volatile bool receivedFlag; // flag to indicate that a packet was received
bool sendFlag;
volatile bool received_flag; // flag to indicate that a packet was received
bool send_flag;
bool raw;
bool present;
} Lora;
} Lora_t;
Lora_t* Lora = nullptr;
#ifdef USE_LORAWAN_BRIDGE
struct {
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;
} Lorawan_t;
Lorawan_t* Lorawan = nullptr;
#endif // USE_LORAWAN_BRIDGE
#endif // USE_SPI_LORA

View File

@ -46,24 +46,24 @@ bool LoraSx126xBusy(void) {
void IRAM_ATTR LoraSx126xOnInterrupt(void);
void LoraSx126xOnInterrupt(void) {
// This is called after EVERY type of enabled interrupt so chk for valid receivedFlag in LoraAvailableSx126x()
if (!Lora.sendFlag && !Lora.receivedFlag && !Lora.receive_time) {
Lora.receive_time = millis();
if (!Lora->send_flag && !Lora->received_flag && !Lora->receive_time) {
Lora->receive_time = millis();
}
Lora.receivedFlag = true; // we got a packet, set the flag
Lora->received_flag = true; // we got a packet, set the flag
}
bool LoraSx126xAvailable(void) {
if (Lora.sendFlag) {
Lora.receivedFlag = false; // Reset receive flag as it was caused by send interrupt
if (Lora->send_flag) {
Lora->received_flag = false; // Reset receive flag as it was caused by send interrupt
uint32_t time = millis();
int state = LoRaRadio.startReceive(); // Put module back to listen mode
Lora.sendFlag = false;
Lora->send_flag = false;
if (state != RADIOLIB_ERR_NONE) {
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("S6X: Rcvd (%d) restarted (%d)"), time, state);
}
}
else if (Lora.receivedFlag) {
else if (Lora->received_flag) {
uint32_t irq_stat = LoRaRadio.getIrqStatus();
#ifdef USE_LORA_SX126X_DEBUG
@ -73,14 +73,14 @@ bool LoraSx126xAvailable(void) {
#endif // USE_LORA_SX126X_DEBUG
if (0 == (irq_stat & RADIOLIB_SX126X_IRQ_RX_DONE)) {
Lora.receivedFlag = false; // Reset receive flag
Lora->received_flag = false; // Reset receive flag
}
}
return (Lora.receivedFlag); // Check if the receive flag is set
return (Lora->received_flag); // Check if the receive flag is set
}
int LoraSx126xReceive(char* data) {
Lora.receivedFlag = false; // Reset flag
Lora->received_flag = false; // Reset flag
int packet_size = LoRaRadio.getPacketLength();
int state = LoRaRadio.readData((uint8_t*)data, TAS_LORA_MAX_PACKET_LENGTH -1);
// LoRaWan downlink frames are sent without CRC, which will raise error on SX126x. We can ignore that error
@ -89,8 +89,8 @@ int LoraSx126xReceive(char* data) {
AddLog(LOG_LEVEL_DEBUG, PSTR("S6X: Ignoring CRC error"));
}
if (RADIOLIB_ERR_NONE == state) {
Lora.rssi = LoRaRadio.getRSSI();
Lora.snr = LoRaRadio.getSNR();
Lora->rssi = LoRaRadio.getRSSI();
Lora->snr = LoRaRadio.getSNR();
} else {
packet_size = 0; // Some other error occurred
AddLog(LOG_LEVEL_DEBUG, PSTR("S6X: Receive error %d"), state);
@ -107,7 +107,7 @@ bool LoraSx126xSend(uint8_t* data, uint32_t len, bool invert) {
LoraSx126xBusy();
}
int state = LoRaRadio.transmit(data, len);
Lora.sendFlag = true; // Use this flag as LoRaRadio.transmit enable send interrupt
Lora->send_flag = true; // Use this flag as LoRaRadio.transmit enable send interrupt
if (invert) {
LoraSx126xBusy();
state2 = LoRaRadio.invertIQ(false);
@ -120,17 +120,17 @@ bool LoraSx126xSend(uint8_t* data, uint32_t len, bool invert) {
}
bool LoraSx126xConfig(void) {
LoRaRadio.setCodingRate(LoraSettings.coding_rate);
LoRaRadio.setSyncWord(LoraSettings.sync_word);
LoRaRadio.setPreambleLength(LoraSettings.preamble_length);
LoRaRadio.setCurrentLimit(LoraSettings.current_limit);
LoRaRadio.setCRC(LoraSettings.crc_bytes);
LoRaRadio.setSpreadingFactor(LoraSettings.spreading_factor);
LoRaRadio.setBandwidth(LoraSettings.bandwidth);
LoRaRadio.setFrequency(LoraSettings.frequency);
LoRaRadio.setOutputPower(LoraSettings.output_power);
if (LoraSettings.implicit_header) {
LoRaRadio.implicitHeader(LoraSettings.implicit_header);
LoRaRadio.setCodingRate(LoraSettings->coding_rate);
LoRaRadio.setSyncWord(LoraSettings->sync_word);
LoRaRadio.setPreambleLength(LoraSettings->preamble_length);
LoRaRadio.setCurrentLimit(LoraSettings->current_limit);
LoRaRadio.setCRC(LoraSettings->crc_bytes);
LoRaRadio.setSpreadingFactor(LoraSettings->spreading_factor);
LoRaRadio.setBandwidth(LoraSettings->bandwidth);
LoRaRadio.setFrequency(LoraSettings->frequency);
LoRaRadio.setOutputPower(LoraSettings->output_power);
if (LoraSettings->implicit_header) {
LoRaRadio.implicitHeader(LoraSettings->implicit_header);
} else {
LoRaRadio.explicitHeader();
}
@ -140,7 +140,7 @@ bool LoraSx126xConfig(void) {
bool LoraSx126xInit(void) {
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(LoraSettings->frequency)) {
LoraSx126xConfig();
LoRaRadio.setDio1Action(LoraSx126xOnInterrupt);
if (RADIOLIB_ERR_NONE == LoRaRadio.startReceive()) {

View File

@ -35,27 +35,27 @@ void LoraSx127xOnReceive(int packet_size) {
// AddLog(LOG_LEVEL_DEBUG, PSTR("S7X: Packet size %d"), packet_size);
#endif
if (0 == packet_size) { return; } // if there's no packet, return
if (!Lora.receive_time) {
Lora.receive_time = millis();
if (!Lora->receive_time) {
Lora->receive_time = millis();
}
Lora.packet_size = packet_size; // we got a packet, set the flag
Lora->packet_size = packet_size; // we got a packet, set the flag
}
bool LoraSx127xAvailable(void) {
return (Lora.packet_size > 0); // check if the flag is set
return (Lora->packet_size > 0); // check if the flag is set
}
int LoraSx127xReceive(char* data) {
int packet_size = 0;
while (LoRa.available()) { // read packet up to LORA_MAX_PACKET_LENGTH
while (Lora->Available()) { // read packet up to LORA_MAX_PACKET_LENGTH
char sdata = LoRa.read();
if (packet_size < TAS_LORA_MAX_PACKET_LENGTH -1) {
data[packet_size++] = sdata;
}
}
Lora.rssi = LoRa.packetRssi();
Lora.snr = LoRa.packetSnr();
Lora.packet_size = 0; // reset flag
Lora->rssi = LoRa.packetRssi();
Lora->snr = LoRa.packetSnr();
Lora->packet_size = 0; // reset flag
return packet_size;
}
@ -63,7 +63,7 @@ bool LoraSx127xSend(uint8_t* data, uint32_t len, bool invert) {
if (invert) {
LoRa.enableInvertIQ(); // active invert I and Q signals
}
LoRa.beginPacket(LoraSettings.implicit_header); // start packet
LoRa.beginPacket(LoraSettings->implicit_header); // start packet
LoRa.write(data, len); // send message
LoRa.endPacket(); // finish packet and send it
if (invert) {
@ -74,21 +74,21 @@ bool LoraSx127xSend(uint8_t* data, uint32_t len, bool invert) {
}
bool LoraSx127xConfig(void) {
LoRa.setFrequency(LoraSettings.frequency * 1000 * 1000);
LoRa.setSignalBandwidth(LoraSettings.bandwidth * 1000);
LoRa.setSpreadingFactor(LoraSettings.spreading_factor);
LoRa.setCodingRate4(LoraSettings.coding_rate);
LoRa.setSyncWord(LoraSettings.sync_word);
LoRa.setTxPower(LoraSettings.output_power);
LoRa.setPreambleLength(LoraSettings.preamble_length);
LoRa.setOCP(LoraSettings.current_limit);
if (LoraSettings.crc_bytes) {
LoRa.setFrequency(LoraSettings->frequency * 1000 * 1000);
LoRa.setSignalBandwidth(LoraSettings->bandwidth * 1000);
LoRa.setSpreadingFactor(LoraSettings->spreading_factor);
LoRa.setCodingRate4(LoraSettings->coding_rate);
LoRa.setSyncWord(LoraSettings->sync_word);
LoRa.setTxPower(LoraSettings->output_power);
LoRa.setPreambleLength(LoraSettings->preamble_length);
LoRa.setOCP(LoraSettings->current_limit);
if (LoraSettings->crc_bytes) {
LoRa.enableCrc();
} else {
LoRa.disableCrc();
}
/*
if (LoraSettings.implicit_header) {
if (LoraSettings->implicit_header) {
LoRa.implicitHeaderMode();
} else {
LoRa.explicitHeaderMode();
@ -100,7 +100,7 @@ bool LoraSx127xConfig(void) {
bool LoraSx127xInit(void) {
LoRa.setPins(Pin(GPIO_LORA_CS), Pin(GPIO_LORA_RST), Pin(GPIO_LORA_DI0));
if (LoRa.begin(LoraSettings.frequency * 1000 * 1000)) {
if (LoRa.begin(LoraSettings->frequency * 1000 * 1000)) {
LoraSx127xConfig();
LoRa.onReceive(LoraSx127xOnReceive);
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) {
_LoraWanDeriveLegacyAppSKey(LoraSettings.end_node[node].AppKey, TAS_LORAWAN_JOINNONCE +node, TAS_LORAWAN_NETID, LoraSettings.end_node[node].DevNonce, AppSKey);
_LoraWanDeriveLegacyAppSKey(LoraSettings->end_node[node].AppKey, TAS_LORAWAN_JOINNONCE +node, TAS_LORAWAN_NETID, LoraSettings->end_node[node].DevNonce, AppSKey);
}
// 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) {
_LoraWanDeriveLegacyNwkSKey(LoraSettings.end_node[node].AppKey, TAS_LORAWAN_JOINNONCE +node, TAS_LORAWAN_NETID, LoraSettings.end_node[node].DevNonce, NwkSKey);
_LoraWanDeriveLegacyNwkSKey(LoraSettings->end_node[node].AppKey, TAS_LORAWAN_JOINNONCE +node, TAS_LORAWAN_NETID, LoraSettings->end_node[node].DevNonce, NwkSKey);
}
#ifdef USE_LORAWAN_TEST

View File

@ -29,13 +29,13 @@ 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
ResponseAppend_P(PSTR("{\"%s\":"), EscapeJSONString(LoraSettings.end_node[node].name.c_str()).c_str());
ResponseAppend_P(PSTR("{\"%s\":"), EscapeJSONString(LoraSettings->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);
if (!LoraSettings.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("{\"Node\":%d,\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\""), node +1, LoraSettings->end_node[node].DevEUIl & 0x0000FFFF);
if (!LoraSettings->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(",\"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];
// Clean special characters
char stemp[TOPSZ];
strlcpy(stemp, LoraSettings.end_node[node].name.c_str(), sizeof(stemp));
strlcpy(stemp, LoraSettings->end_node[node].name.c_str(), sizeof(stemp));
MakeValidMqtt(0, stemp);
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);
@ -87,8 +87,8 @@ void LoraWanDecode(struct LoraNodeData_t* node_data) {
uint8_t node;
uint8_t FPort;
*/
if (bitRead(LoraSettings.flags, TAS_LORA_FLAG_DECODE_ENABLED)) { // LoraOption3 1
if (0x00161600 == LoraSettings.end_node[node_data->node].DevEUIh) { // MerryIoT
if (bitRead(LoraSettings->flags, TAS_LORA_FLAG_DECODE_ENABLED)) { // LoraOption3 1
if (0x00161600 == LoraSettings->end_node[node_data->node].DevEUIh) { // MerryIoT
if (120 == node_data->FPort) { // MerryIoT door/window Sensor (DW10)
if (9 == node_data->payload_len) { // MerryIoT Sensor state
// 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);
#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"),
node_data->node +1, LoraSettings.end_node[node_data->node].DevEUIh, LoraSettings.end_node[node_data->node].DevEUIl,
node_data->node +1, LoraSettings->end_node[node_data->node].DevEUIh, LoraSettings->end_node[node_data->node].DevEUIl,
events, elapsed_time,
bitRead(status, 0), bitRead(status, 1), bitRead(status, 2), bitRead(status, 3),
&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 == LoraSettings->end_node[node_data->node].DevEUIh) { // Dragino
if (10 == node_data->FPort) { // Dragino LDS02
// 8CD2 01 000010 000000 00 - Door Open, 3.282V
// 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];
#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"),
node_data->node +1, LoraSettings.end_node[node_data->node].DevEUIh, LoraSettings.end_node[node_data->node].DevEUIl,
node_data->node +1, LoraSettings->end_node[node_data->node].DevEUIh, LoraSettings->end_node[node_data->node].DevEUIl,
events, open_duration,
bitRead(status, 7),
&battery_volt,
@ -152,7 +152,7 @@ void LoraWanDecode(struct LoraNodeData_t* node_data) {
// Joined device without decoding
LoraWanPublishHeader(node_data->node);
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);
LoraSettings->end_node[node_data->node].DevEUIh, LoraSettings->end_node[node_data->node].DevEUIl, node_data->FPort);
for (uint32_t i = 0; i < node_data->payload_len; 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);
if (strlen(app_key)) {
size_t out_len = TAS_LORAWAN_AES128_KEY_SIZE;
HexToBytes(app_key, LoraSettings.end_node[n].AppKey, &out_len);
HexToBytes(app_key, LoraSettings->end_node[n].AppKey, &out_len);
}
LoraSettings.end_node[n].DevEUIh = root.getUInt(PSTR(D_JSON_DEVEUI "h"), LoraSettings.end_node[n].DevEUIh);
LoraSettings.end_node[n].DevEUIl = root.getUInt(PSTR(D_JSON_DEVEUI "l"), LoraSettings.end_node[n].DevEUIl);
LoraSettings.end_node[n].DevNonce = root.getUInt(PSTR(D_JSON_DEVNONCE), LoraSettings.end_node[n].DevNonce);
LoraSettings.end_node[n].FCntUp = root.getUInt(PSTR(D_JSON_FCNTUP), LoraSettings.end_node[n].FCntUp);
LoraSettings.end_node[n].FCntDown = root.getUInt(PSTR(D_JSON_FCNTDOWN), LoraSettings.end_node[n].FCntDown);
LoraSettings.end_node[n].flags = root.getUInt(PSTR(D_JSON_FLAGS), LoraSettings.end_node[n].flags);
LoraSettings->end_node[n].DevEUIh = root.getUInt(PSTR(D_JSON_DEVEUI "h"), LoraSettings->end_node[n].DevEUIh);
LoraSettings->end_node[n].DevEUIl = root.getUInt(PSTR(D_JSON_DEVEUI "l"), LoraSettings->end_node[n].DevEUIl);
LoraSettings->end_node[n].DevNonce = root.getUInt(PSTR(D_JSON_DEVNONCE), LoraSettings->end_node[n].DevNonce);
LoraSettings->end_node[n].FCntUp = root.getUInt(PSTR(D_JSON_FCNTUP), LoraSettings->end_node[n].FCntUp);
LoraSettings->end_node[n].FCntDown = root.getUInt(PSTR(D_JSON_FCNTDOWN), LoraSettings->end_node[n].FCntDown);
LoraSettings->end_node[n].flags = root.getUInt(PSTR(D_JSON_FLAGS), LoraSettings->end_node[n].flags);
const char* name = nullptr;
name = root.getStr(PSTR(D_JSON_NAME), nullptr);
if (strlen(app_key)) {
LoraSettings.end_node[n].name = name;
LoraSettings->end_node[n].name = name;
}
}
return true;
@ -113,7 +113,7 @@ bool LoraWanLoadData(void) {
bool LoraWanSaveData(void) {
bool result = false;
for (uint32_t n = 0; n < TAS_LORAWAN_ENDNODES; n++) {
if (LoraSettings.end_node[n].AppKey[0] > 0) { // Only save used slots
if (LoraSettings->end_node[n].AppKey[0] > 0) { // Only save used slots
Response_P(PSTR("{\"" XDRV_73_KEY "_%d\":{\"" D_JSON_APPKEY "\":\"%16_H\""
",\"" D_JSON_DEVEUI "h\":%lu,\"" D_JSON_DEVEUI "l\":%lu"
",\"" D_JSON_DEVNONCE "\":%u"
@ -121,12 +121,12 @@ bool LoraWanSaveData(void) {
",\"" D_JSON_FLAGS "\":%u"
",\"" D_JSON_NAME "\":\"%s\"}}"),
n +1,
LoraSettings.end_node[n].AppKey,
LoraSettings.end_node[n].DevEUIh,LoraSettings.end_node[n].DevEUIl,
LoraSettings.end_node[n].DevNonce,
LoraSettings.end_node[n].FCntUp, LoraSettings.end_node[n].FCntDown,
LoraSettings.end_node[n].flags,
LoraSettings.end_node[n].name.c_str());
LoraSettings->end_node[n].AppKey,
LoraSettings->end_node[n].DevEUIh,LoraSettings->end_node[n].DevEUIl,
LoraSettings->end_node[n].DevNonce,
LoraSettings->end_node[n].FCntUp, LoraSettings->end_node[n].FCntDown,
LoraSettings->end_node[n].flags,
LoraSettings->end_node[n].name.c_str());
result = UfsJsonSettingsWrite(ResponseData());
}
}
@ -148,41 +148,41 @@ void LoraWanDeleteData(void) {
Ticker LoraWan_Send;
void LoraWanTickerSend(void) {
Lorawan.send_buffer_step--;
if (1 == Lorawan.send_buffer_step) {
Lorawan.rx = true; // Always send during RX1
Lora.receive_time = 0; // Reset receive timer
Lorawan->send_buffer_step--;
if (1 == Lorawan->send_buffer_step) {
Lorawan->rx = true; // Always send during RX1
Lora->receive_time = 0; // Reset receive timer
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
LoraSend(Lorawan.send_buffer, Lorawan.send_buffer_len, true);
if (Lorawan->rx) { // If received in RX1 do not resend in RX2
LoraSend(Lorawan->send_buffer, Lorawan->send_buffer_len, true);
}
}
void LoraWanSendResponse(uint8_t* buffer, size_t len, uint32_t lorawan_delay) {
memcpy(Lorawan.send_buffer, buffer, sizeof(Lorawan.send_buffer));
Lorawan.send_buffer_len = len;
Lorawan.send_buffer_step = 2;
LoraWan_Send.once_ms(lorawan_delay - TimePassedSince(Lora.receive_time), LoraWanTickerSend);
memcpy(Lorawan->send_buffer, buffer, sizeof(Lorawan->send_buffer));
Lorawan->send_buffer_len = len;
Lorawan->send_buffer_step = 2;
LoraWan_Send.once_ms(lorawan_delay - TimePassedSince(Lora->receive_time), LoraWanTickerSend);
}
/*-------------------------------------------------------------------------------------------*/
uint32_t LoraWanSpreadingFactorToDataRate(void) {
// Allow only JoinReq message datarates (125kHz bandwidth)
if (LoraSettings.spreading_factor > 12) {
LoraSettings.spreading_factor = 12;
if (LoraSettings->spreading_factor > 12) {
LoraSettings->spreading_factor = 12;
}
if (LoraSettings.spreading_factor < 7) {
LoraSettings.spreading_factor = 7;
if (LoraSettings->spreading_factor < 7) {
LoraSettings->spreading_factor = 7;
}
LoraSettings.bandwidth = 125;
return 12 - LoraSettings.spreading_factor;
LoraSettings->bandwidth = 125;
return 12 - LoraSettings->spreading_factor;
}
uint32_t LoraWanFrequencyToChannel(void) {
// EU863-870 (EU868) JoinReq message frequencies are 868.1, 868.3 and 868.5
uint32_t frequency = (LoraSettings.frequency * 10);
uint32_t frequency = (LoraSettings->frequency * 10);
uint32_t channel = 250;
if (8681 == frequency) {
channel = 0;
@ -194,8 +194,8 @@ uint32_t LoraWanFrequencyToChannel(void) {
channel = 2;
}
if (250 == channel) {
LoraSettings.frequency = 868.1;
Lora.Config();
LoraSettings->frequency = 868.1;
Lora->Config();
channel = 0;
}
return channel;
@ -204,8 +204,8 @@ uint32_t LoraWanFrequencyToChannel(void) {
/*********************************************************************************************/
void LoraWanSendLinkADRReq(uint32_t node) {
uint32_t DevAddr = Lorawan.device_address +node;
uint16_t FCnt = LoraSettings.end_node[node].FCntDown++;
uint32_t DevAddr = Lorawan->device_address +node;
uint16_t FCnt = LoraSettings->end_node[node].FCntDown++;
uint8_t NwkSKey[TAS_LORAWAN_AES128_KEY_SIZE];
LoraWanDeriveLegacyNwkSKey(node, NwkSKey);
@ -254,26 +254,26 @@ bool LoraWanInput(uint8_t* data, uint32_t packet_size) {
((uint32_t)data[21] << 16) | ((uint32_t)data[22] << 24);
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, LoraSettings->end_node[node].AppKey);
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"),
(uint8_t*)&JoinEUI, DevEUIh, DevEUIl, DevNonce, MIC);
LoraSettings.end_node[node].DevEUIl = DevEUIl;
LoraSettings.end_node[node].DevEUIh = DevEUIh;
LoraSettings.end_node[node].DevNonce = DevNonce;
LoraSettings.end_node[node].FCntUp = 0;
LoraSettings.end_node[node].FCntDown = 0;
bitClear(LoraSettings.end_node[node].flags, TAS_LORAWAN_FLAG_LINK_ADR_REQ);
if (LoraSettings.end_node[node].name.equals(F("0x0000"))) {
LoraSettings->end_node[node].DevEUIl = DevEUIl;
LoraSettings->end_node[node].DevEUIh = DevEUIh;
LoraSettings->end_node[node].DevNonce = DevNonce;
LoraSettings->end_node[node].FCntUp = 0;
LoraSettings->end_node[node].FCntDown = 0;
bitClear(LoraSettings->end_node[node].flags, TAS_LORAWAN_FLAG_LINK_ADR_REQ);
if (LoraSettings->end_node[node].name.equals(F("0x0000"))) {
char name[10];
ext_snprintf_P(name, sizeof(name), PSTR("0x%04X"), LoraSettings.end_node[node].DevEUIl & 0x0000FFFF);
LoraSettings.end_node[node].name = name;
ext_snprintf_P(name, sizeof(name), PSTR("0x%04X"), LoraSettings->end_node[node].DevEUIl & 0x0000FFFF);
LoraSettings->end_node[node].name = name;
}
uint32_t JoinNonce = TAS_LORAWAN_JOINNONCE +node;
uint32_t DevAddr = Lorawan.device_address +node;
uint32_t DevAddr = Lorawan->device_address +node;
uint32_t NetID = TAS_LORAWAN_NETID;
uint8_t join_data[33] = { 0 };
join_data[0] = TAS_LORAWAN_MTYPE_JOIN_ACCEPT << 5;
@ -290,14 +290,14 @@ bool LoraWanInput(uint8_t* data, uint32_t packet_size) {
join_data[11] = LoraWanSpreadingFactorToDataRate(); // DLSettings
join_data[12] = 1; // RXDelay;
uint32_t NewMIC = LoraWanGenerateMIC(join_data, 13, LoraSettings.end_node[node].AppKey);
uint32_t NewMIC = LoraWanGenerateMIC(join_data, 13, LoraSettings->end_node[node].AppKey);
join_data[13] = NewMIC;
join_data[14] = NewMIC >> 8;
join_data[15] = NewMIC >> 16;
join_data[16] = NewMIC >> 24;
uint8_t EncData[33];
EncData[0] = join_data[0];
LoraWanEncryptJoinAccept(LoraSettings.end_node[node].AppKey, &join_data[1], 16, &EncData[1]);
LoraWanEncryptJoinAccept(LoraSettings->end_node[node].AppKey, &join_data[1], 16, &EncData[1]);
// AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Join %17_H"), join_data);
@ -335,12 +335,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);
for (uint32_t node = 0; node < TAS_LORAWAN_ENDNODES; node++) {
if (0 == LoraSettings.end_node[node].DevEUIh) { continue; } // No DevEUI so never joined
if ((Lorawan.device_address +node) != DevAddr) { continue; } // Not my device
if (0 == LoraSettings->end_node[node].DevEUIh) { continue; } // No DevEUI so never joined
if ((Lorawan->device_address +node) != DevAddr) { continue; } // Not my device
uint32_t FCtrl = data[5];
uint32_t FOptsLen = FCtrl & 0x0F;
uint32_t FCnt = (LoraSettings.end_node[node].FCntUp & 0xFFFF0000) | data[6] | (data[7] << 8);
uint32_t FCnt = (LoraSettings->end_node[node].FCntUp & 0xFFFF0000) | data[6] | (data[7] << 8);
uint8_t* FOpts = &data[8];
uint32_t FPort = data[8 +FOptsLen];
uint8_t* FRMPayload = &data[9 +FOptsLen];
@ -384,17 +384,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);
#endif // USE_LORA_DEBUG
if (LoraSettings.end_node[node].FCntUp <= FCnt) { // Skip re-transmissions
Lorawan.rx = false; // Skip RX2 as this is a response from RX1
LoraSettings.end_node[node].FCntUp++;
if (LoraSettings.end_node[node].FCntUp < FCnt) { // Report missed frames
uint32_t FCnt_missed = FCnt - LoraSettings.end_node[node].FCntUp;
if (LoraSettings->end_node[node].FCntUp <= FCnt) { // Skip re-transmissions
Lorawan->rx = false; // Skip RX2 as this is a response from RX1
LoraSettings->end_node[node].FCntUp++;
if (LoraSettings->end_node[node].FCntUp < FCnt) { // Report missed frames
uint32_t FCnt_missed = FCnt - LoraSettings->end_node[node].FCntUp;
AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: Missed frames %d"), FCnt_missed);
if (FCnt_missed > 1) { // Missed two or more frames
bitClear(LoraSettings.end_node[node].flags, TAS_LORAWAN_FLAG_LINK_ADR_REQ); // Resend LinkADRReq
bitClear(LoraSettings->end_node[node].flags, TAS_LORAWAN_FLAG_LINK_ADR_REQ); // Resend LinkADRReq
}
}
LoraSettings.end_node[node].FCntUp = FCnt;
LoraSettings->end_node[node].FCntUp = FCnt;
if (FOptsLen) {
uint32_t i = 0;
@ -408,7 +408,7 @@ bool LoraWanInput(uint8_t* data, uint32_t packet_size) {
uint8_t status = FOpts[i];
AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: MAC LinkADRAns PowerACK %d, DataRateACK %d, ChannelMaskACK %d"),
bitRead(status, 2), bitRead(status, 1), bitRead(status, 0));
bitSet(LoraSettings.end_node[node].flags, TAS_LORAWAN_FLAG_LINK_ADR_REQ);
bitSet(LoraSettings->end_node[node].flags, TAS_LORAWAN_FLAG_LINK_ADR_REQ);
}
else if (TAS_LORAWAN_CID_DUTY_CYCLE_ANS == FOpts[i]) {
i++;
@ -442,28 +442,28 @@ bool LoraWanInput(uint8_t* data, uint32_t packet_size) {
if (payload_len) {
LoraNodeData_t node_data;
node_data.rssi = Lora.rssi;
node_data.snr = Lora.snr;
node_data.rssi = Lora->rssi;
node_data.snr = Lora->snr;
node_data.payload = payload_decrypted;
node_data.payload_len = payload_len;
node_data.node = node;
node_data.FPort = FPort;
LoraWanDecode(&node_data);
if (0xA840410E == LoraSettings.end_node[node].DevEUIh) { // Dragino
if (0xA840410E == LoraSettings->end_node[node].DevEUIh) { // Dragino
// Dragino v1.7 fails to set DR with ADR so set it using serial interface:
// Password 123456
// AT+CHS=868100000
// Start join using reset button
// AT+CADR=0
// AT+CDATARATE=3
bitSet(LoraSettings.end_node[node].flags, TAS_LORAWAN_FLAG_LINK_ADR_REQ);
bitSet(LoraSettings->end_node[node].flags, TAS_LORAWAN_FLAG_LINK_ADR_REQ);
}
if (TAS_LORAWAN_MTYPE_CONFIRMED_DATA_UPLINK == MType) {
data[0] = TAS_LORAWAN_MTYPE_UNCONFIRMED_DATA_DOWNLINK << 5;
data[5] |= 0x20; // FCtrl Set ACK bit
uint16_t FCnt = LoraSettings.end_node[node].FCntDown++;
uint16_t FCnt = LoraSettings->end_node[node].FCntDown++;
data[6] = FCnt;
data[7] = FCnt >> 8;
uint32_t MIC = LoraWanComputeLegacyDownlinkMIC(NwkSKey, DevAddr, FCnt, data, packet_size -4);
@ -475,7 +475,7 @@ bool LoraWanInput(uint8_t* data, uint32_t packet_size) {
}
}
if (TAS_LORAWAN_MTYPE_UNCONFIRMED_DATA_UPLINK == MType) {
if (!bitRead(LoraSettings.end_node[node].flags, TAS_LORAWAN_FLAG_LINK_ADR_REQ) &&
if (!bitRead(LoraSettings->end_node[node].flags, TAS_LORAWAN_FLAG_LINK_ADR_REQ) &&
FCtrl_ADR && !FCtrl_ACK) {
// Try to fix single channel and datarate
LoraWanSendLinkADRReq(node); // Resend LinkADRReq
@ -486,7 +486,7 @@ bool LoraWanInput(uint8_t* data, uint32_t packet_size) {
break;
}
}
Lora.receive_time = 0;
Lora->receive_time = 0;
return result;
}
@ -509,14 +509,14 @@ void CmndLoraWanBridge(void) {
// LoraWanBridge 1 - Set LoraOption1 1 = Enable LoraWanBridge
uint32_t pindex = 0;
if (XdrvMailbox.payload >= 0) {
bitWrite(LoraSettings.flags, pindex, XdrvMailbox.payload);
bitWrite(LoraSettings->flags, pindex, XdrvMailbox.payload);
}
#ifdef USE_LORAWAN_TEST
LoraWanTestKeyDerivation();
LorWanTestUplinkDownlinkEncryption();
LorWanTestUplinkDownlinkMIC();
#endif // USE_LORAWAN_TEST
ResponseCmndChar(GetStateText(bitRead(LoraSettings.flags, pindex)));
ResponseCmndChar(GetStateText(bitRead(LoraSettings->flags, pindex)));
}
void CmndLoraWanAppKey(void) {
@ -526,16 +526,16 @@ void CmndLoraWanAppKey(void) {
uint32_t node = XdrvMailbox.index -1;
if (32 == XdrvMailbox.data_len) {
size_t out_len = 16;
HexToBytes(XdrvMailbox.data, LoraSettings.end_node[node].AppKey, &out_len);
if (0 == LoraSettings.end_node[node].name.length()) {
LoraSettings.end_node[node].name = F("0x0000");
HexToBytes(XdrvMailbox.data, LoraSettings->end_node[node].AppKey, &out_len);
if (0 == LoraSettings->end_node[node].name.length()) {
LoraSettings->end_node[node].name = F("0x0000");
}
}
else if (0 == XdrvMailbox.payload) {
memset(&LoraSettings.end_node[node], 0, sizeof(LoraEndNode_t));
memset(&LoraSettings->end_node[node], 0, sizeof(LoraEndNode_t));
}
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"), LoraSettings->end_node[node].AppKey);
ResponseCmndIdxChar(appkey);
}
}
@ -549,13 +549,13 @@ void CmndLoraWanName(void) {
if (XdrvMailbox.data_len) {
if (1 == XdrvMailbox.payload) {
char name[10];
ext_snprintf_P(name, sizeof(name), PSTR("0x%04X"), LoraSettings.end_node[node].DevEUIl & 0x0000FFFF);
LoraSettings.end_node[node].name = name;
ext_snprintf_P(name, sizeof(name), PSTR("0x%04X"), LoraSettings->end_node[node].DevEUIl & 0x0000FFFF);
LoraSettings->end_node[node].name = name;
} else {
LoraSettings.end_node[node].name = XdrvMailbox.data;
LoraSettings->end_node[node].name = XdrvMailbox.data;
}
}
ResponseCmndIdxChar(LoraSettings.end_node[node].name.c_str());
ResponseCmndIdxChar(LoraSettings->end_node[node].name.c_str());
}
}
@ -563,12 +563,16 @@ void CmndLoraWanName(void) {
* Interface
\*********************************************************************************************/
void LoraWanInit(void) {
bool 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
// %0010011. Using that, TTN currently sends NetID 0x000013, and a TTN DevAddr always
// starts with 0x26 or 0x27
// Private networks are supposed to used NetID 0x000000.
Lorawan.device_address = (TAS_LORAWAN_NETID << 25) | (ESP_getChipId() & 0x01FFFFFF);
Lorawan->device_address = (TAS_LORAWAN_NETID << 25) | (ESP_getChipId() & 0x01FFFFFF);
return true;
}
#endif // USE_LORAWAN_BRIDGE

View File

@ -17,55 +17,55 @@
/*********************************************************************************************/
void LoraDefaults(void) {
LoraSettings.frequency = TAS_LORA_FREQUENCY;
LoraSettings.bandwidth = TAS_LORA_BANDWIDTH;
LoraSettings.spreading_factor = TAS_LORA_SPREADING_FACTOR;
LoraSettings.coding_rate = TAS_LORA_CODING_RATE;
LoraSettings.sync_word = TAS_LORA_SYNC_WORD;
LoraSettings.output_power = TAS_LORA_OUTPUT_POWER;
LoraSettings.preamble_length = TAS_LORA_PREAMBLE_LENGTH;
LoraSettings.current_limit = TAS_LORA_CURRENT_LIMIT;
LoraSettings.implicit_header = TAS_LORA_HEADER;
LoraSettings.crc_bytes = TAS_LORA_CRC_BYTES;
LoraSettings->frequency = TAS_LORA_FREQUENCY;
LoraSettings->bandwidth = TAS_LORA_BANDWIDTH;
LoraSettings->spreading_factor = TAS_LORA_SPREADING_FACTOR;
LoraSettings->coding_rate = TAS_LORA_CODING_RATE;
LoraSettings->sync_word = TAS_LORA_SYNC_WORD;
LoraSettings->output_power = TAS_LORA_OUTPUT_POWER;
LoraSettings->preamble_length = TAS_LORA_PREAMBLE_LENGTH;
LoraSettings->current_limit = TAS_LORA_CURRENT_LIMIT;
LoraSettings->implicit_header = TAS_LORA_HEADER;
LoraSettings->crc_bytes = TAS_LORA_CRC_BYTES;
}
void LoraWanDefaults(void) {
LoraSettings.frequency = TAS_LORAWAN_FREQUENCY;
LoraSettings.bandwidth = TAS_LORAWAN_BANDWIDTH;
LoraSettings.spreading_factor = TAS_LORAWAN_SPREADING_FACTOR;
LoraSettings.coding_rate = TAS_LORAWAN_CODING_RATE;
LoraSettings.sync_word = TAS_LORAWAN_SYNC_WORD;
LoraSettings.output_power = TAS_LORAWAN_OUTPUT_POWER;
LoraSettings.preamble_length = TAS_LORAWAN_PREAMBLE_LENGTH;
LoraSettings.current_limit = TAS_LORAWAN_CURRENT_LIMIT;
LoraSettings.implicit_header = TAS_LORAWAN_HEADER;
LoraSettings.crc_bytes = TAS_LORAWAN_CRC_BYTES;
LoraSettings->frequency = TAS_LORAWAN_FREQUENCY;
LoraSettings->bandwidth = TAS_LORAWAN_BANDWIDTH;
LoraSettings->spreading_factor = TAS_LORAWAN_SPREADING_FACTOR;
LoraSettings->coding_rate = TAS_LORAWAN_CODING_RATE;
LoraSettings->sync_word = TAS_LORAWAN_SYNC_WORD;
LoraSettings->output_power = TAS_LORAWAN_OUTPUT_POWER;
LoraSettings->preamble_length = TAS_LORAWAN_PREAMBLE_LENGTH;
LoraSettings->current_limit = TAS_LORAWAN_CURRENT_LIMIT;
LoraSettings->implicit_header = TAS_LORAWAN_HEADER;
LoraSettings->crc_bytes = TAS_LORAWAN_CRC_BYTES;
}
void LoraSettings2Json(void) {
ResponseAppend_P(PSTR("\"" D_JSON_FREQUENCY "\":%1_f"), &LoraSettings.frequency); // xxx.x MHz
ResponseAppend_P(PSTR(",\"" D_JSON_BANDWIDTH "\":%1_f"), &LoraSettings.bandwidth); // xxx.x kHz
ResponseAppend_P(PSTR(",\"" D_JSON_SPREADING_FACTOR "\":%d"), LoraSettings.spreading_factor);
ResponseAppend_P(PSTR(",\"" D_JSON_CODINGRATE4 "\":%d"), LoraSettings.coding_rate);
ResponseAppend_P(PSTR(",\"" D_JSON_SYNCWORD "\":%d"), LoraSettings.sync_word);
ResponseAppend_P(PSTR(",\"" D_JSON_OUTPUT_POWER "\":%d"), LoraSettings.output_power); // dBm
ResponseAppend_P(PSTR(",\"" D_JSON_PREAMBLE_LENGTH "\":%d"), LoraSettings.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_IMPLICIT_HEADER "\":%d"), LoraSettings.implicit_header); // 0 = explicit
ResponseAppend_P(PSTR(",\"" D_JSON_CRC_BYTES "\":%d"), LoraSettings.crc_bytes); // bytes
ResponseAppend_P(PSTR("\"" D_JSON_FREQUENCY "\":%1_f"), &LoraSettings->frequency); // xxx.x MHz
ResponseAppend_P(PSTR(",\"" D_JSON_BANDWIDTH "\":%1_f"), &LoraSettings->bandwidth); // xxx.x kHz
ResponseAppend_P(PSTR(",\"" D_JSON_SPREADING_FACTOR "\":%d"), LoraSettings->spreading_factor);
ResponseAppend_P(PSTR(",\"" D_JSON_CODINGRATE4 "\":%d"), LoraSettings->coding_rate);
ResponseAppend_P(PSTR(",\"" D_JSON_SYNCWORD "\":%d"), LoraSettings->sync_word);
ResponseAppend_P(PSTR(",\"" D_JSON_OUTPUT_POWER "\":%d"), LoraSettings->output_power); // dBm
ResponseAppend_P(PSTR(",\"" D_JSON_PREAMBLE_LENGTH "\":%d"), LoraSettings->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_IMPLICIT_HEADER "\":%d"), LoraSettings->implicit_header); // 0 = explicit
ResponseAppend_P(PSTR(",\"" D_JSON_CRC_BYTES "\":%d"), LoraSettings->crc_bytes); // bytes
}
void LoraJson2Settings(JsonParserObject root) {
LoraSettings.frequency = root.getFloat(PSTR(D_JSON_FREQUENCY), LoraSettings.frequency);
LoraSettings.bandwidth = root.getFloat(PSTR(D_JSON_BANDWIDTH), LoraSettings.bandwidth);
LoraSettings.spreading_factor = root.getUInt(PSTR(D_JSON_SPREADING_FACTOR), LoraSettings.spreading_factor);
LoraSettings.coding_rate = root.getUInt(PSTR(D_JSON_CODINGRATE4), LoraSettings.coding_rate);
LoraSettings.sync_word = root.getUInt(PSTR(D_JSON_SYNCWORD), LoraSettings.sync_word);
LoraSettings.output_power = root.getUInt(PSTR(D_JSON_OUTPUT_POWER), LoraSettings.output_power);
LoraSettings.preamble_length = root.getUInt(PSTR(D_JSON_PREAMBLE_LENGTH), LoraSettings.preamble_length);
LoraSettings.current_limit = root.getFloat(PSTR(D_JSON_CURRENT_LIMIT), LoraSettings.current_limit);
LoraSettings.implicit_header = root.getUInt(PSTR(D_JSON_IMPLICIT_HEADER), LoraSettings.implicit_header);
LoraSettings.crc_bytes = root.getUInt(PSTR(D_JSON_CRC_BYTES), LoraSettings.crc_bytes);
LoraSettings->frequency = root.getFloat(PSTR(D_JSON_FREQUENCY), LoraSettings->frequency);
LoraSettings->bandwidth = root.getFloat(PSTR(D_JSON_BANDWIDTH), LoraSettings->bandwidth);
LoraSettings->spreading_factor = root.getUInt(PSTR(D_JSON_SPREADING_FACTOR), LoraSettings->spreading_factor);
LoraSettings->coding_rate = root.getUInt(PSTR(D_JSON_CODINGRATE4), LoraSettings->coding_rate);
LoraSettings->sync_word = root.getUInt(PSTR(D_JSON_SYNCWORD), LoraSettings->sync_word);
LoraSettings->output_power = root.getUInt(PSTR(D_JSON_OUTPUT_POWER), LoraSettings->output_power);
LoraSettings->preamble_length = root.getUInt(PSTR(D_JSON_PREAMBLE_LENGTH), LoraSettings->preamble_length);
LoraSettings->current_limit = root.getFloat(PSTR(D_JSON_CURRENT_LIMIT), LoraSettings->current_limit);
LoraSettings->implicit_header = root.getUInt(PSTR(D_JSON_IMPLICIT_HEADER), LoraSettings->implicit_header);
LoraSettings->crc_bytes = root.getUInt(PSTR(D_JSON_CRC_BYTES), LoraSettings->crc_bytes);
}
/*********************************************************************************************\
@ -85,8 +85,8 @@ bool LoraLoadData(void) {
JsonParserObject root = parser.getRootObject();
if (!root) { return false; }
LoraSettings.crc32 = root.getUInt(PSTR("Crc"), LoraSettings.crc32);
LoraSettings.flags = root.getUInt(PSTR("Flags"), LoraSettings.flags);
LoraSettings->crc32 = root.getUInt(PSTR("Crc"), LoraSettings->crc32);
LoraSettings->flags = root.getUInt(PSTR("Flags"), LoraSettings->flags);
LoraJson2Settings(root);
#ifdef USE_LORAWAN_BRIDGE
@ -102,8 +102,8 @@ bool LoraSaveData(void) {
Response_P(PSTR("{\"" XDRV_73_KEY "\":{"
"\"Crc\":%u,"
"\"Flags\":%u,"),
LoraSettings.crc32,
LoraSettings.flags);
LoraSettings->crc32,
LoraSettings->flags);
LoraSettings2Json();
ResponseAppend_P(PSTR("}}"));
@ -134,20 +134,20 @@ void LoraSettingsLoad(bool erase) {
// Called from FUNC_RESET_SETTINGS (erase = 1) after command reset 4, 5, or 6
// *** Start init default values in case key is not found ***
memset(&LoraSettings, 0x00, sizeof(LoraSettings));
memset(LoraSettings, 0x00, sizeof(LoraSettings_t));
// Init any other parameter in struct LoraSettings
LoraDefaults();
// *** End Init default values ***
#ifndef USE_UFILESYS
AddLog(LOG_LEVEL_INFO, PSTR("CFG: Lora use defaults as file system not enabled"));
AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: Lora use defaults as file system not enabled"));
#else
// Try to load key
if (erase) {
LoraDeleteData();
}
else if (LoraLoadData()) {
AddLog(LOG_LEVEL_INFO, PSTR("CFG: Lora loaded from file"));
AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: Lora loaded from file"));
}
else {
// File system not ready: No flash space reserved for file system
@ -159,10 +159,10 @@ void LoraSettingsLoad(bool erase) {
void LoraSettingsSave(void) {
// Called from FUNC_SAVE_SETTINGS every SaveData second and at restart
#ifdef USE_UFILESYS
uint32_t crc32 = GetCfgCrc32((uint8_t*)&LoraSettings +4, sizeof(LoraSettings) -4); // Skip crc32
if (crc32 != LoraSettings.crc32) {
uint32_t crc32 = GetCfgCrc32((uint8_t*)LoraSettings +4, sizeof(LoraSettings_t) -4); // Skip crc32
if (crc32 != LoraSettings->crc32) {
// Try to save file /.drvset122
LoraSettings.crc32 = crc32;
LoraSettings->crc32 = crc32;
if (LoraSaveData()) {
AddLog(LOG_LEVEL_DEBUG, PSTR("CFG: Lora saved to file"));
@ -178,29 +178,29 @@ void LoraSettingsSave(void) {
bool LoraSend(uint8_t* data, uint32_t len, bool invert) {
uint32_t lora_time = millis(); // Time is important for LoRaWan RX windows
bool result = Lora.Send(data, len, invert);
bool result = Lora->Send(data, len, invert);
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("LOR: Send (%u) '%*_H', Invert %d, Time %d"),
lora_time, len, data, invert, TimePassedSince(lora_time));
return result;
}
void LoraInput(void) {
if (!Lora.Available()) { return; }
if (!Lora->Available()) { return; }
char data[TAS_LORA_MAX_PACKET_LENGTH] = { 0 };
int packet_size = Lora.Receive(data);
int packet_size = Lora->Receive(data);
if (!packet_size) { return; }
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("LOR: Rcvd (%u) '%*_H', RSSI %1_f, SNR %1_f"),
Lora.receive_time, packet_size, data, &Lora.rssi, &Lora.snr);
Lora->receive_time, packet_size, data, &Lora->rssi, &Lora->snr);
#ifdef USE_LORAWAN_BRIDGE
if (bitRead(LoraSettings.flags, TAS_LORA_FLAG_BRIDGE_ENABLED)) {
if (bitRead(LoraSettings->flags, TAS_LORA_FLAG_BRIDGE_ENABLED)) {
if (LoraWanInput((uint8_t*)data, packet_size)) {
return;
}
}
#endif // USE_LORAWAN_BRIDGE
Lora.receive_time = 0;
Lora->receive_time = 0;
if (TAS_LORA_REMOTE_COMMAND == data[0]) {
char *payload = data +1; // Skip TAS_LORA_REMOTE_COMMAND
@ -216,7 +216,7 @@ void LoraInput(void) {
}
}
bool raw = Lora.raw;
bool raw = Lora->raw;
// Set raw mode if zeroes within data
for (uint32_t i = 0; i < packet_size; i++) {
if (0 == data[i]) {
@ -237,7 +237,7 @@ void LoraInput(void) {
}
ResponseAppend_P(PSTR("\""));
}
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);
MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR("LoRaReceived"));
}
@ -253,25 +253,29 @@ void LoraInit(void) {
// SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0));
#endif // ESP32
#ifdef USE_LORAWAN_BRIDGE
LoraWanInit();
#endif // USE_LORAWAN_BRIDGE
Lora = (Lora_t*)calloc(sizeof(Lora_t), 1); // Need calloc to reset registers to 0/false
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);
bool present = false;
char hardware[20];
strcpy_P(hardware, PSTR("Not"));
if (false) {
}
#ifdef USE_LORA_SX127X
else if (PinUsed(GPIO_LORA_DI0)) {
// SX1276, RFM95W
if (LoraSx127xInit()) {
Lora.Config = &LoraSx127xConfig;
Lora.Available = &LoraSx127xAvailable;
Lora.Receive = &LoraSx127xReceive;
Lora.Send = &LoraSx127xSend;
Lora->Config = &LoraSx127xConfig;
Lora->Available = &LoraSx127xAvailable;
Lora->Receive = &LoraSx127xReceive;
Lora->Send = &LoraSx127xSend;
strcpy_P(hardware, PSTR("SX127x"));
Lora.present = true;
present = true;
}
}
#endif // USE_LORA_SX127X
@ -279,16 +283,28 @@ void LoraInit(void) {
else if (PinUsed(GPIO_LORA_DI1) && PinUsed(GPIO_LORA_BUSY)) {
// SX1262, LilyGoT3S3
if (LoraSx126xInit()) {
Lora.Config = &LoraSx126xConfig;
Lora.Available = &LoraSx126xAvailable;
Lora.Receive = &LoraSx126xReceive;
Lora.Send = &LoraSx126xSend;
Lora->Config = &LoraSx126xConfig;
Lora->Available = &LoraSx126xAvailable;
Lora->Receive = &LoraSx126xReceive;
Lora->Send = &LoraSx126xSend;
strcpy_P(hardware, PSTR("SX126x"));
Lora.present = true;
present = true;
}
}
#endif // USE_LORA_SX126X
AddLog(LOG_LEVEL_DEBUG, PSTR("LOR: %s initialized"), hardware);
#ifdef USE_LORAWAN_BRIDGE
if (present && !LoraWanInit()) {
present = false;
}
#endif // USE_LORAWAN_BRIDGE
if (present) {
AddLog(LOG_LEVEL_INFO, PSTR("LOR: %s initialized"), hardware);
} else {
free(LoraSettings);
free(Lora);
Lora = nullptr;
}
}
}
@ -314,9 +330,9 @@ void CmndLoraOption(void) {
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 8)) {
uint32_t pindex = XdrvMailbox.index -1;
if (XdrvMailbox.payload >= 0) {
bitWrite(LoraSettings.flags, pindex, XdrvMailbox.payload);
bitWrite(LoraSettings->flags, pindex, XdrvMailbox.payload);
}
ResponseCmndIdxChar(GetStateText(bitRead(LoraSettings.flags, pindex)));
ResponseCmndIdxChar(GetStateText(bitRead(LoraSettings->flags, pindex)));
}
}
@ -353,7 +369,7 @@ void CmndLoraSend(void) {
invert = true;
}
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 6)) {
Lora.raw = (XdrvMailbox.index > 3); // Global flag set even without data
Lora->raw = (XdrvMailbox.index > 3); // Global flag set even without data
if (XdrvMailbox.data_len > 0) {
char data[TAS_LORA_MAX_PACKET_LENGTH] = { 0 };
uint32_t len = (XdrvMailbox.data_len < TAS_LORA_MAX_PACKET_LENGTH -1) ? XdrvMailbox.data_len : TAS_LORA_MAX_PACKET_LENGTH -2;
@ -417,18 +433,18 @@ void CmndLoraConfig(void) {
if (XdrvMailbox.data_len > 0) {
if (XdrvMailbox.payload == 1) {
LoraDefaults();
Lora.Config();
Lora->Config();
}
else if (XdrvMailbox.payload == 2) {
LoraWanDefaults();
Lora.Config();
Lora->Config();
}
else {
JsonParser parser(XdrvMailbox.data);
JsonParserObject root = parser.getRootObject();
if (root) {
LoraJson2Settings(root);
Lora.Config();
Lora->Config();
}
}
}
@ -448,7 +464,7 @@ bool Xdrv73(uint32_t function) {
if (FUNC_INIT == function) {
LoraInit();
}
else if (Lora.present) {
else if (Lora) {
switch (function) {
case FUNC_LOOP:
case FUNC_SLEEP_LOOP: