diff --git a/tasmota/tasmota_xdrv_driver/xdrv_73_0_lora_struct.ino b/tasmota/tasmota_xdrv_driver/xdrv_73_0_lora_struct.ino index 622e36dd1..f4849c439 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_73_0_lora_struct.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_73_0_lora_struct.ino @@ -13,86 +13,146 @@ #define USE_LORAWAN #endif /*********************************************************************************************\ - * LoRa defines and global struct + * LoRa and LoRaWan defines and global struct \*********************************************************************************************/ //#define USE_LORA_DEBUG -#define XDRV_73_KEY "drvset73" +#define XDRV_73_KEY "drvset73" -#ifndef TAS_LORA_FREQUENCY -#define TAS_LORA_FREQUENCY 868.0 // Allowed values range from 150.0 to 960.0 MHz +/*********************************************************************************************/ + +// AU915 value +#ifndef TAS_LORA_AU915_FREQUENCY +#define TAS_LORA_AU915_FREQUENCY 915.0 // Allowed values range from 150.0 to 960.0 MHz #endif + +// EU868 value +#ifndef TAS_LORA_FREQUENCY +#define TAS_LORA_FREQUENCY 868.0 // Allowed values range from 150.0 to 960.0 MHz +#endif + +// Common LoRa values #ifndef TAS_LORA_BANDWIDTH -#define TAS_LORA_BANDWIDTH 125.0 // Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125.0, 250.0 and 500.0 kHz +#define TAS_LORA_BANDWIDTH 125.0 // Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125.0, 250.0 and 500.0 kHz #endif #ifndef TAS_LORA_SPREADING_FACTOR -#define TAS_LORA_SPREADING_FACTOR 9 // Allowed values range from 5 to 12 +#define TAS_LORA_SPREADING_FACTOR 9 // Allowed values range from 5 to 12 #endif #ifndef TAS_LORA_CODING_RATE -#define TAS_LORA_CODING_RATE 7 // Allowed values range from 5 to 8 +#define TAS_LORA_CODING_RATE 7 // Allowed values range from 5 to 8 #endif #ifndef TAS_LORA_SYNC_WORD -#define TAS_LORA_SYNC_WORD 0x12 // Allowed values range from 1 to 255 +#define TAS_LORA_SYNC_WORD 0x12 // Allowed values range from 1 to 255 #endif #ifndef TAS_LORA_OUTPUT_POWER -#define TAS_LORA_OUTPUT_POWER 10 // Allowed values range from 1 to 20 +#define TAS_LORA_OUTPUT_POWER 10 // Allowed values range from 1 to 20 #endif #ifndef TAS_LORA_PREAMBLE_LENGTH -#define TAS_LORA_PREAMBLE_LENGTH 8 // Allowed values range from 1 to 65535 +#define TAS_LORA_PREAMBLE_LENGTH 8 // Allowed values range from 1 to 65535 #endif #ifndef TAS_LORA_CURRENT_LIMIT -#define TAS_LORA_CURRENT_LIMIT 60.0 // Overcurrent Protection - OCP in mA +#define TAS_LORA_CURRENT_LIMIT 60.0 // Overcurrent Protection - OCP in mA #endif #ifndef TAS_LORA_HEADER -#define TAS_LORA_HEADER 0 // Explicit (0) or Implicit (1 to 4) Header +#define TAS_LORA_HEADER 0 // Explicit (0) or Implicit (1 to 4) Header #endif #ifndef TAS_LORA_CRC_BYTES -#define TAS_LORA_CRC_BYTES 2 // No (0) or Number (1 to 4) of CRC bytes +#define TAS_LORA_CRC_BYTES 2 // No (0) or Number (1 to 4) of CRC bytes #endif +/*********************************************************************************************/ + +// AU915 values +// These are default AU915 values when waiting for JOIN REQUEST +// AU915 has 2 sets up UPLINK channels +#ifndef TAS_LORAWAN_AU915_FREQUENCY_UP1 +#define TAS_LORAWAN_AU915_FREQUENCY_UP1 915.2 // Channel 0. There are 64 125 MHz channels (0-63), spaced 0.2 MHz apart. +#endif +#ifndef TAS_LORAWAN_AU915_BANDWIDTH_UP1 +#define TAS_LORAWAN_AU915_BANDWIDTH_UP1 125.0 // Allowed values are 125.0 and 500.0 kHz +#endif +#ifndef TAS_LORAWAN_AU915_SPREADING_FACTOR_UP1 +#define TAS_LORAWAN_AU915_SPREADING_FACTOR_UP1 10 // Allowed values range from 7 to 12 +#endif + +#ifndef TAS_LORAWAN_AU915_FREQUENCY_UP2 +#define TAS_LORAWAN_AU915_FREQUENCY_UP2 915.9 // Channel 64. There are 8 500 MHz channels (64-71), spaced 1.6 MHz apart +#endif +#ifndef TAS_LORAWAN_AU915_BANDWIDTH_UP2 +#define TAS_LORAWAN_AU915_BANDWIDTH_UP2 500.0 // Allowed values are 125.0 and 500.0 kHz +#endif +#ifndef TAS_LORAWAN_AU915_SPREADING_FACTOR_UP2 +#define TAS_LORAWAN_AU915_SPREADING_FACTOR_UP2 8 // Allowed values range from 7 to 12 +#endif + +#ifndef TAS_LORAWAN_AU915_FREQUENCY_DN +#define TAS_LORAWAN_AU915_FREQUENCY_DN 923.3 // Channel 0 down +#endif + +#ifndef TAS_LORAWAN_AU915_BANDWIDTH_RX1 +#define TAS_LORAWAN_AU915_BANDWIDTH_RX1 500 // DR8 +#endif +#ifndef TAS_LORAWAN_AU915_SPREADING_FACTOR_RX1 +#define TAS_LORAWAN_AU915_SPREADING_FACTOR_RX1 12 // DR8 +#endif + +#ifndef TAS_LORAWAN_AU915_BANDWIDTH_RX2 +#define TAS_LORAWAN_AU915_BANDWIDTH_RX2 500 // DR8 +#endif +#ifndef TAS_LORAWAN_AU915_SPREADING_FACTOR_RX2 +#define TAS_LORAWAN_AU915_SPREADING_FACTOR_RX2 12 // DR8 +#endif + +// EU868 values #ifndef TAS_LORAWAN_FREQUENCY -#define TAS_LORAWAN_FREQUENCY 868.1 // Allowed values range from 150.0 to 960.0 MHz +#define TAS_LORAWAN_FREQUENCY 868.1 // Allowed values range from 150.0 to 960.0 MHz #endif #ifndef TAS_LORAWAN_BANDWIDTH -#define TAS_LORAWAN_BANDWIDTH 125.0 // Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125.0, 250.0 and 500.0 kHz +#define TAS_LORAWAN_BANDWIDTH 125.0 // Allowed values are 7.8, 10.4, 15.6, 20.8, 31.25, 41.7, 62.5, 125.0, 250.0 and 500.0 kHz #endif #ifndef TAS_LORAWAN_SPREADING_FACTOR -#define TAS_LORAWAN_SPREADING_FACTOR 9 // Allowed values range from 5 to 12 +#define TAS_LORAWAN_SPREADING_FACTOR 9 // Allowed values range from 5 to 12 #endif + +// Common LoRaWan values #ifndef TAS_LORAWAN_CODING_RATE -#define TAS_LORAWAN_CODING_RATE 5 // Allowed values range from 5 to 8 +#define TAS_LORAWAN_CODING_RATE 5 // Allowed values range from 5 to 8 #endif #ifndef TAS_LORAWAN_SYNC_WORD -#define TAS_LORAWAN_SYNC_WORD 0x34 // Allowed values range from 1 to 255 +#define TAS_LORAWAN_SYNC_WORD 0x34 // Allowed values range from 1 to 255 #endif #ifndef TAS_LORAWAN_OUTPUT_POWER -#define TAS_LORAWAN_OUTPUT_POWER 10 // Allowed values range from 1 to 20 +#define TAS_LORAWAN_OUTPUT_POWER 10 // Allowed values range from 1 to 20 #endif #ifndef TAS_LORAWAN_PREAMBLE_LENGTH -#define TAS_LORAWAN_PREAMBLE_LENGTH 8 // Allowed values range from 1 to 65535 +#define TAS_LORAWAN_PREAMBLE_LENGTH 8 // Allowed values range from 1 to 65535 #endif #ifndef TAS_LORAWAN_CURRENT_LIMIT -#define TAS_LORAWAN_CURRENT_LIMIT 60.0 // Overcurrent Protection - OCP in mA +#define TAS_LORAWAN_CURRENT_LIMIT 60.0 // Overcurrent Protection - OCP in mA #endif #ifndef TAS_LORAWAN_HEADER -#define TAS_LORAWAN_HEADER 0 // Explicit (0) or Implicit (1 to 4) Header +#define TAS_LORAWAN_HEADER 0 // Explicit (0) or Implicit (1 to 4) Header #endif #ifndef TAS_LORAWAN_CRC_BYTES -#define TAS_LORAWAN_CRC_BYTES 2 // No (0) or Number (1 to 4) of CRC bytes +#define TAS_LORAWAN_CRC_BYTES 2 // No (0) or Number (1 to 4) of CRC bytes #endif -#define TAS_LORA_MAX_PACKET_LENGTH 252 // Max packet length allowed (keeping room for control bytes) -#define TAS_LORA_REMOTE_COMMAND 0x17 // Header defining remote LoRaCommand +/*********************************************************************************************/ -#define TAS_LORAWAN_JOINNONCE 0x00E50631 // Tasmota node 1 JoinNonce -#define TAS_LORAWAN_NETID 0x00000000 // Tasmota private network -#define TAS_LORAWAN_RECEIVE_DELAY1 1000 // LoRaWan Receive delay 1 -#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 of supported endnodes -#define TAS_LORAWAN_AES128_KEY_SIZE 16 // Size in bytes +#define TAS_LORA_MAX_PACKET_LENGTH 252 // Max packet length allowed (keeping room for control bytes) +#define TAS_LORA_REMOTE_COMMAND 0x17 // Header defining remote LoRaCommand + +#define TAS_LORAWAN_JOINNONCE 0x00E50631 // Tasmota node 1 JoinNonce +#define TAS_LORAWAN_NETID 0x00000000 // Tasmota private network +#define TAS_LORAWAN_RECEIVE_DELAY1 1000 // LoRaWan Receive delay 1 +#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 of supported endnodes +#define TAS_LORAWAN_AES128_KEY_SIZE 16 // Size in bytes + +/*********************************************************************************************/ enum TasLoraFlags { TAS_LORA_FLAG_BRIDGE_ENABLED, @@ -146,6 +206,24 @@ enum TasLoraWanCIDNode { TAS_LORAWAN_CID_DEVICE_TIME_REQ }; +enum TasLoraRegion { + TAS_LORA_REGION_EU868, // 0 + TAS_LORA_REGION_US915, // 1 + TAS_LORA_REGION_CN779, // 2 + TAS_LORA_REGION_EU433, // 3 + TAS_LORA_REGION_AU915, // 4 + TAS_LORA_REGION_CN470, // 5 + TAS_LORA_REGION_AS923, // 6 + TAS_LORA_REGION_KR920, // 7 + TAS_LORA_REGION_IN865, // 8 + TAS_LORA_REGION_RU864 // 9 +}; + +// LoRaWan bands: One for each enum above +const char kLoraRegions[] PROGMEM = "EU868|US915|CN779|EU433|AU915|CN470|AS923|KR920|IN865|RU864"; + +/*********************************************************************************************/ + typedef struct LoraNodeData_t { float rssi; float snr; @@ -180,6 +258,7 @@ typedef struct LoraSettings_t { uint8_t implicit_header; // 0 uint8_t crc_bytes; // 2 bytes uint8_t flags; + uint8_t region; // 0 = Default, 1 = AU915, ... #ifdef USE_LORAWAN_BRIDGE LoraEndNode_t end_node[TAS_LORAWAN_ENDNODES]; // End node parameters #endif // USE_LORAWAN_BRIDGE @@ -190,6 +269,7 @@ typedef struct Lora_t { bool (* Available)(void); int (* Receive)(char*); bool (* Send)(uint8_t*, uint32_t, bool); + bool (* Init)(void); LoraSettings_t settings; // Persistent settings volatile uint32_t receive_time; float rssi; diff --git a/tasmota/tasmota_xdrv_driver/xdrv_73_8_lorawan_bridge.ino b/tasmota/tasmota_xdrv_driver/xdrv_73_8_lorawan_bridge.ino index 37712062a..917da4cf2 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_73_8_lorawan_bridge.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_73_8_lorawan_bridge.ino @@ -9,7 +9,7 @@ #ifdef USE_SPI_LORA #ifdef USE_LORAWAN_BRIDGE /*********************************************************************************************\ - * EU868 LoRaWan bridge support + * EU868 and AU915 LoRaWan bridge support * * The goal of the LoRaWan Bridge is to receive from joined LoRaWan End-Devices or Nodes and * provide decrypted MQTT data. @@ -27,11 +27,11 @@ * spreadingfactor using command * LoRaConfig 2 * or individual commands - * LoRaFrequency 868.1 (or 868.3 and 868.5) - * LoRaSpreadingFactor 9 (or 7..12 equals LoRaWan DataRate 5..0) - * LoRaBandwidth 125 - * LoRaCodingRate4 5 - * LoRaSyncWord 52 + * LoRaConfig {"Frequency":868.1} (or 868.3 and 868.5) + * LoRaConfig {"SpreadingFactor":9} (or 7..12 equals LoRaWan DataRate 5..0) + * LoRaConfig {"Bandwidth":125} + * LoRaConfig {"CodingRate4":5} + * LoRaConfig {"SyncWord":52} * - LoRaWan has to be enabled (#define USE_LORAWAN_BRIDGE) and configured for the End-Device * 32 character AppKey using command LoRaWanAppKey * - The End-Device needs to start it's LoRaWan join process as documented by vendor. @@ -110,7 +110,7 @@ bool LoraWanLoadData(void) { } bool LoraWanSaveData(void) { - bool result = false; + bool result = true; // Return true if no Endnodes for (uint32_t n = 0; n < TAS_LORAWAN_ENDNODES; n++) { 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\"" @@ -126,17 +126,17 @@ bool LoraWanSaveData(void) { Lora->settings.end_node[n].FCntUp, Lora->settings.end_node[n].FCntDown, Lora->settings.end_node[n].flags, Lora->settings.end_node[n].name.c_str()); - result = UfsJsonSettingsWrite(ResponseData()); + result &= UfsJsonSettingsWrite(ResponseData()); } } return result; } void LoraWanDeleteData(void) { - char key[12]; // Max 99 nodes (drvset73_1 to drvset73_99) + char key[12]; // Max 99 nodes (drvset73_1 to drvset73_99) for (uint32_t n = 0; n < TAS_LORAWAN_ENDNODES; n++) { snprintf_P(key, sizeof(key), PSTR(XDRV_73_KEY "_%d"), n +1); - UfsJsonSettingsDelete(key); // Use defaults + UfsJsonSettingsDelete(key); // Use defaults } } #endif // USE_UFILESYS @@ -149,37 +149,89 @@ Ticker LoraWan_Send; void LoraWanTickerSend(void) { Lora->send_buffer_step--; if (1 == Lora->send_buffer_step) { - Lora->rx = true; // Always send during RX1 - Lora->receive_time = 0; // Reset receive timer + Lora->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 (Lora->rx) { // If received in RX1 do not resend in RX2 - LoraSend(Lora->send_buffer, Lora->send_buffer_len, true); + + bool uplink_profile = (Lora->settings.region == TAS_LORA_REGION_AU915); + if (Lora->rx) { // If received in RX1 do not resend in RX2 + LoraSend(Lora->send_buffer, Lora->send_buffer_len, true, uplink_profile); + } + if (uplink_profile && (0 == Lora->send_buffer_step)) { + Lora->Init(); // Necessary to re-init the SXxxxx chip in cases where TX/RX frequencies differ } } void LoraWanSendResponse(uint8_t* buffer, size_t len, uint32_t lorawan_delay) { - free(Lora->send_buffer); // Free previous buffer (if any) + free(Lora->send_buffer); // Free previous buffer (if any) Lora->send_buffer = (uint8_t*)malloc(len +1); 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 + Lora->send_buffer_step = 2; // Send at RX1 and RX2 LoraWan_Send.once_ms(lorawan_delay - TimePassedSince(Lora->receive_time), LoraWanTickerSend); } /*-------------------------------------------------------------------------------------------*/ -uint32_t LoraWanSpreadingFactorToDataRate(void) { - // Allow only JoinReq message datarates (125kHz bandwidth) - if (Lora->settings.spreading_factor > 12) { - Lora->settings.spreading_factor = 12; +size_t LoraWanCFList(uint8_t * CFList, size_t uLen) { + // Populates CFList for use in JOIN-ACCEPT message to lock device to specific frequencies + // Returns: Number of bytes added + uint8_t idx = 0; + + switch (Lora->settings.region) { + case TAS_LORA_REGION_AU915: { + if (uLen < 16) return 0; + + uint8_t uChannel = LoraChannel(); // 0..71 + uint8_t uMaskByte = uChannel /8; // 0..8 + + // Add first 10 bytes + for (uint32_t i = 0; i < 10; i++) { + CFList[idx++] = (i == uMaskByte) ? (0x01 << uChannel %8) : 0x00; + } + + // Add next 6 bytes + CFList[idx++] = 0x00; //RFU + CFList[idx++] = 0x00; + + CFList[idx++] = 0x00; //RFU + CFList[idx++] = 0x00; + CFList[idx++] = 0x00; + + CFList[idx++] = 0x01; //CFListType + break; + } + default: { // TAS_LORA_REGION_EU868 + } } - if (Lora->settings.spreading_factor < 7) { - Lora->settings.spreading_factor = 7; + return idx; +} + +uint32_t LoraWanSpreadingFactorToDataRate(bool downlink) { + /* + Returns DLSettings defined as + Bits 7= RFA + 6:4= RX1DROffset + 3:0= RX2DataRate DateRate for RX2 window + */ + switch (Lora->settings.region) { + case TAS_LORA_REGION_AU915: { + return downlink ? 8 : 2; // AU915 must use DR8 for RX2, and we want to use DR2 for Uplinks + } + default: { // TAS_LORA_REGION_EU868 + // Allow only JoinReq message datarates (125kHz bandwidth) + if (Lora->settings.spreading_factor > 12) { + Lora->settings.spreading_factor = 12; + } + if (Lora->settings.spreading_factor < 7) { + Lora->settings.spreading_factor = 7; + } + Lora->settings.bandwidth = 125; + return 12 - Lora->settings.spreading_factor; + } } - Lora->settings.bandwidth = 125; - return 12 - Lora->settings.spreading_factor; } uint32_t LoraWanFrequencyToChannel(void) { @@ -217,15 +269,42 @@ void LoraWanSendLinkADRReq(uint32_t node) { data[2] = DevAddr >> 8; data[3] = DevAddr >> 16; data[4] = DevAddr >> 24; - data[5] = 0x05; // FCtrl with 5 FOpts + data[5] = 0x05; // FCtrl with 5 FOpts data[6] = FCnt; data[7] = FCnt >> 8; data[8] = TAS_LORAWAN_CID_LINK_ADR_REQ; - data[9] = LoraWanSpreadingFactorToDataRate() << 4 | 0x0F; // DataRate 3 and unchanged TXPower - data[10] = 0x01 << LoraWanFrequencyToChannel(); // Single channel - data[11] = 0x00; - data[12] = 0x00; // ChMaskCntl applies to Channels0..15, NbTrans is default (1) + // Next 4 bytes are Region Specific + switch (Lora->settings.region) { + case TAS_LORA_REGION_AU915: { + //Ref: https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf + // page 39 + uint8_t uChannel = LoraChannel(); // 0..71 + uint8_t ChMaskCntl = uChannel/16.0; // 0..4 + uChannel = uChannel%16; // 0..15 + uint16_t uMask = 0x01 << uChannel; + + data[9] = LoraWanSpreadingFactorToDataRate(false) << 4 | 0x0F; // Uplink DataRate_TXPower Should be 'DR2' for & 'unchanged' = 0x2F + + data[10] = uMask; // ChMask LSB + data[11] = uMask >> 8; // ChMask MSB + + data[12] = ChMaskCntl << 4; // Redundancy: + // bits 7=RFU ------- 6:4=ChMaskCntl ----------- --- 3:0=NbTrans --- + // 0 000=Mask applies to Channels 0-15 0000 = Use Default + // 001=Mask applies to Channels 16-31 + // .... + // 100=Mask applies to Channels 64-71 + break; + } + default: { // TAS_LORA_REGION_EU868 + data[9] = LoraWanSpreadingFactorToDataRate(false) << 4 | 0x0F; // Uplink DataRate 3 and unchanged TXPower + data[10] = 0x01 << LoraWanFrequencyToChannel(); // Single channel + data[11] = 0x00; + data[12] = 0x00; // ChMaskCntl applies to Channels0..15, NbTrans is default (1) + } + } + uint32_t MIC = LoraWanComputeLegacyDownlinkMIC(NwkSKey, DevAddr, FCnt, data, 13); data[13] = MIC; data[14] = MIC >> 8; @@ -308,34 +387,43 @@ bool LoraWanInput(uint8_t* data, uint32_t packet_size) { uint32_t DevAddr = Lora->device_address +node; uint32_t NetID = TAS_LORAWAN_NETID; uint8_t join_data[33] = { 0 }; - join_data[0] = TAS_LORAWAN_MTYPE_JOIN_ACCEPT << 5; - join_data[1] = JoinNonce; - join_data[2] = JoinNonce >> 8; - join_data[3] = JoinNonce >> 16; - join_data[4] = NetID; - join_data[5] = NetID >> 8; - join_data[6] = NetID >> 16; - join_data[7] = DevAddr; - join_data[8] = DevAddr >> 8; - join_data[9] = DevAddr >> 16; - join_data[10] = DevAddr >> 24; - join_data[11] = LoraWanSpreadingFactorToDataRate(); // DLSettings - join_data[12] = 1; // RXDelay; + uint8_t join_data_index = 0; - uint32_t NewMIC = LoraWanGenerateMIC(join_data, 13, Lora->settings.end_node[node].AppKey); - join_data[13] = NewMIC; - join_data[14] = NewMIC >> 8; - join_data[15] = NewMIC >> 16; - join_data[16] = NewMIC >> 24; + join_data[join_data_index++] = TAS_LORAWAN_MTYPE_JOIN_ACCEPT << 5; // [0] + join_data[join_data_index++] = JoinNonce; + join_data[join_data_index++] = JoinNonce >> 8; + join_data[join_data_index++] = JoinNonce >> 16; + join_data[join_data_index++] = NetID; + join_data[join_data_index++] = NetID >> 8; + join_data[join_data_index++] = NetID >> 16; + join_data[join_data_index++] = DevAddr; + join_data[join_data_index++] = DevAddr >> 8; + join_data[join_data_index++] = DevAddr >> 16; + join_data[join_data_index++] = DevAddr >> 24; + join_data[join_data_index++] = LoraWanSpreadingFactorToDataRate(true); // DLSettings - Downlink + join_data[join_data_index++] = 1; // RXDelay; [12] + + // Add CFList to instruct device to use one channel + uint8_t CFList[16]; + size_t CFListSize = LoraWanCFList(CFList, sizeof(CFList)); + uint8_t CFListIdx = 0; + while (CFListSize > 0 ) { + join_data[join_data_index++] = CFList[CFListIdx++]; + CFListSize--; + } + + uint32_t NewMIC = LoraWanGenerateMIC(join_data, join_data_index, Lora->settings.end_node[node].AppKey); + join_data[join_data_index++] = NewMIC; + join_data[join_data_index++] = NewMIC >> 8; + join_data[join_data_index++] = NewMIC >> 16; + join_data[join_data_index++] = NewMIC >> 24; //[16] or [32] uint8_t EncData[33]; EncData[0] = join_data[0]; - LoraWanEncryptJoinAccept(Lora->settings.end_node[node].AppKey, &join_data[1], 16, &EncData[1]); - -// AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Join %17_H"), join_data); + LoraWanEncryptJoinAccept(Lora->settings.end_node[node].AppKey, &join_data[1], join_data_index-1, &EncData[1]); // 203106E5000000412E010003017CB31DD4 - Dragino // 203206E5000000422E010003016A210EEA - MerryIoT - LoraWanSendResponse(EncData, 17, TAS_LORAWAN_JOIN_ACCEPT_DELAY1); + LoraWanSendResponse(EncData, join_data_index, TAS_LORAWAN_JOIN_ACCEPT_DELAY1); result = true; break; @@ -356,14 +444,16 @@ bool LoraWanInput(uint8_t* data, uint32_t packet_size) { // 80 412E0100 80 2A00 0A A58EF5E0D1DDE03424F0 6F2D56FA - decrypt using AppSKey // 80 412E0100 80 2B00 0A 8F2F0D33E5C5027D57A6 F67C9DFE - decrypt using AppSKey // 80 909AE100 00 0800 0A EEC4A52568A346A8684E F2D4BF05 - // 40 412E0100 A0 1800 00 0395 2C94B1D8 - FCtrl ADR support, Ack, FPort = 0 -> MAC commands, decrypt using NwkSKey - // 40 412E0100 A0 7800 00 78C9 A60D8977 - FCtrl ADR support, Ack, FPort = 0 -> MAC commands, decrypt using NwkSKey - // 40 F3F51700 20 0100 00 2A7C 407036A2 - FCtrl No ADR support, Ack, FPort = 0 -> MAC commands, decrypt using NwkSKey, response after LinkADRReq + // 40 412E0100 A0 1800 00 0395 2C94B1D8 - FCtrl ADR support , ADRACKReq=0, FPort = 0 -> MAC commands, decrypt using NwkSKey + // 40 412E0100 A0 7800 00 78C9 A60D8977 - FCtrl ADR support , ADRACKReq=0, FPort = 0 -> MAC commands, decrypt using NwkSKey + // 40 F3F51700 20 0100 00 2A7C 407036A2 - FCtrl No ADR support, ADRACKReq=0, FPort = 0 -> MAC commands, decrypt using NwkSKey, response after LinkADRReq // - MerryIoT // 40 422E0100 80 0400 78 B9C75DF9E8934C6651 A57DA6B1 - decrypt using AppSKey // 40 422E0100 80 0100 CC 7C462537AC00C07F99 5500BF2B - decrypt using AppSKey - // 40 422E0100 A2 1800 0307 78 29FBF8FD9227729984 8C71E95B - FCtrl ADR support, Ack, FOptsLen = 2 -> FOpts = MAC, response after LinkADRReq - // 40 F4F51700 A2 0200 0307 CC 6517D4AB06D32C9A9F 14CBA305 - FCtrl ADR support, Ack, FOptsLen = 2 -> FOpts = MAC, response after LinkADRReq + // 40 422E0100 A2 1800 0307 78 29FBF8FD9227729984 8C71E95B - FCtrl ADR support, ADRACKReq=0, FOptsLen = 2 -> FOpts = MAC, response after LinkADRReq + // 40 F4F51700 A2 0200 0307 CC 6517D4AB06D32C9A9F 14CBA305 - FCtrl ADR support, ADRACKReq=0, FOptsLen = 2 -> FOpts = MAC, response after LinkADRReq + + bool bResponseSent = false; // Make sure do not send multiple responses 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++) { @@ -384,8 +474,15 @@ bool LoraWanInput(uint8_t* data, uint32_t packet_size) { uint32_t CalcMIC = LoraWanComputeLegacyUplinkMIC(NwkSKey, DevAddr, FCnt, data, packet_size -4); if (MIC != CalcMIC) { continue; } // Same device address but never joined - bool FCtrl_ADR = bitRead(FCtrl, 7); - bool FCtrl_ACK = bitRead(FCtrl, 5); + bool FCtrl_ADR = bitRead(FCtrl, 7); + bool FCtrl_ADRACKReq = bitRead(FCtrl, 6); //Device is requesting a response, so that it knows comms is still up. + // else device will eventually enter backoff mode and we loose comms + // ref: https://lora-alliance.org/wp-content/uploads/2021/11/LoRaWAN-Link-Layer-Specification-v1.0.4.pdf + // page 19 + // In testing with a Dragino LHT52 device, FCtrl_ADRACKReq was set after 64 (0x40) uplinks (= 21.3 hrs) + bool FCtrl_ACK = bitRead(FCtrl, 5); + bool Fctrl_ClassB = bitRead(FCtrl, 4); + /* if ((0 == FOptsLen) && (0 == FOpts[0])) { // MAC response FOptsLen = payload_len; @@ -491,6 +588,7 @@ bool LoraWanInput(uint8_t* data, uint32_t packet_size) { i++; } if (mac_data_idx > 0) { + bResponseSent = true; LoraWanSendMacResponse(node, mac_data, mac_data_idx); } } @@ -526,6 +624,7 @@ bool LoraWanInput(uint8_t* data, uint32_t packet_size) { data[packet_size -3] = MIC >> 8; data[packet_size -2] = MIC >> 16; data[packet_size -1] = MIC >> 24; + bResponseSent = true; LoraWanSendResponse(data, packet_size, TAS_LORAWAN_RECEIVE_DELAY1); } } @@ -533,10 +632,17 @@ bool LoraWanInput(uint8_t* data, uint32_t packet_size) { if (!bitRead(Lora->settings.end_node[node].flags, TAS_LORAWAN_FLAG_LINK_ADR_REQ) && FCtrl_ADR && !FCtrl_ACK) { // Try to fix single channel and datarate + bResponseSent = true; LoraWanSendLinkADRReq(node); // Resend LinkADRReq } } - } + + if (!bResponseSent && FCtrl_ADRACKReq ) { + // FCtrl_ADRACKReq requires we send ANY Class A message. Here's one prepared earlier. + LoraWanSendLinkADRReq(node); + } + + } // Not retransmission result = true; break; } @@ -626,4 +732,4 @@ void LoraWanInit(void) { } #endif // USE_LORAWAN_BRIDGE -#endif // USE_SPI_LORA +#endif // USE_SPI_LORA \ No newline at end of file diff --git a/tasmota/tasmota_xdrv_driver/xdrv_73_9_lora.ino b/tasmota/tasmota_xdrv_driver/xdrv_73_9_lora.ino index 33eb00269..54786306d 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_73_9_lora.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_73_9_lora.ino @@ -16,36 +16,242 @@ /*********************************************************************************************/ -void LoraDefaults(void) { - Lora->settings.frequency = TAS_LORA_FREQUENCY; - Lora->settings.bandwidth = TAS_LORA_BANDWIDTH; +void LoraDefaults(uint32_t region = TAS_LORA_REGION_EU868) { + Lora->settings.region = region; + switch (region) { + case TAS_LORA_REGION_AU915: + Lora->settings.frequency = TAS_LORA_AU915_FREQUENCY; + break; + default: // TAS_LORA_REGION_EU868 + Lora->settings.frequency = TAS_LORA_FREQUENCY; + } + Lora->settings.bandwidth = TAS_LORA_BANDWIDTH; Lora->settings.spreading_factor = TAS_LORA_SPREADING_FACTOR; - Lora->settings.coding_rate = TAS_LORA_CODING_RATE; - Lora->settings.sync_word = TAS_LORA_SYNC_WORD; - Lora->settings.output_power = TAS_LORA_OUTPUT_POWER; - Lora->settings.preamble_length = TAS_LORA_PREAMBLE_LENGTH; - Lora->settings.current_limit = TAS_LORA_CURRENT_LIMIT; - Lora->settings.implicit_header = TAS_LORA_HEADER; - Lora->settings.crc_bytes = TAS_LORA_CRC_BYTES; + Lora->settings.coding_rate = TAS_LORA_CODING_RATE; + Lora->settings.sync_word = TAS_LORA_SYNC_WORD; + Lora->settings.output_power = TAS_LORA_OUTPUT_POWER; + Lora->settings.preamble_length = TAS_LORA_PREAMBLE_LENGTH; + Lora->settings.current_limit = TAS_LORA_CURRENT_LIMIT; + Lora->settings.implicit_header = TAS_LORA_HEADER; + Lora->settings.crc_bytes = TAS_LORA_CRC_BYTES; } -void LoraWanDefaults(void) { - Lora->settings.frequency = TAS_LORAWAN_FREQUENCY; - Lora->settings.bandwidth = TAS_LORAWAN_BANDWIDTH; - Lora->settings.spreading_factor = TAS_LORAWAN_SPREADING_FACTOR; - Lora->settings.coding_rate = TAS_LORAWAN_CODING_RATE; - Lora->settings.sync_word = TAS_LORAWAN_SYNC_WORD; - Lora->settings.output_power = TAS_LORAWAN_OUTPUT_POWER; - Lora->settings.preamble_length = TAS_LORAWAN_PREAMBLE_LENGTH; - Lora->settings.current_limit = TAS_LORAWAN_CURRENT_LIMIT; - Lora->settings.implicit_header = TAS_LORAWAN_HEADER; - Lora->settings.crc_bytes = TAS_LORAWAN_CRC_BYTES; +/*********************************************************************************************/ + +/* +For LoraWan EU bands, the Uplink/Downlink (TX/RX) frequencies can be the same. +For Others, same Uplink/Downlink (TX/RX) frequencies may not be allowed. +See: https://lora-alliance.org/wp-content/uploads/2020/11/RP_2-1.0.2.pdf +*/ + +// Determines the channel from the current Uplink LoraSettings +// return 0..71 +uint32_t LoraChannel(void) { + float fFrequencyDiff; + uint8_t uChannel = 0; + + switch (Lora->settings.region) { + case TAS_LORA_REGION_AU915: + if (125.0 == Lora->settings.bandwidth) { + fFrequencyDiff = Lora->settings.frequency - TAS_LORAWAN_AU915_FREQUENCY_UP1; + uChannel = (0.01 + (fFrequencyDiff / 0.2)); //0.01 to fix rounding errors + } else { + fFrequencyDiff = Lora->settings.frequency - TAS_LORAWAN_AU915_FREQUENCY_UP2; + uChannel = 64 + ((0.01 + (fFrequencyDiff / 1.6))); + } + break; + + //default: + //not implemented + } + return uChannel; } -void LoraSettings2Json(void) { - ResponseAppend_P(PSTR("\"" D_JSON_FREQUENCY "\":%1_f"), &Lora->settings.frequency); // xxx.x MHz - ResponseAppend_P(PSTR(",\"" D_JSON_BANDWIDTH "\":%1_f"), &Lora->settings.bandwidth); // xxx.x kHz - ResponseAppend_P(PSTR(",\"" D_JSON_SPREADING_FACTOR "\":%d"), Lora->settings.spreading_factor); +enum LoRaRadioMode_t { + TAS_LORAWAN_RADIO_UPLINK, + TAS_LORAWAN_RADIO_RX1, + TAS_LORAWAN_RADIO_RX2 +}; + +typedef struct LoRaRadioInfo_t { + float frequency; + float bandwidth; + uint8_t spreading_factor; +} LoRaRadioInfo_t; + +/***************************************************************************** + LoraRadioInfo() + Some regional profiles use different radio profiles for the Uplink, RX1, and RX2 transmissions + + Get radio profiles for the Uplink, and RX1 & RX2 downlink transmissions + RX1 & RX2 profiles are derived from Lora->settings + +****************************************************************************/ +const uint8_t RX1DRs[] PROGMEM = {8,9,10,11,12,13,13}; //DR0..6 +const uint8_t SF[] PROGMEM = {12,11,10,9,8,7,8,0,12,11,10,9,8,7}; //DR0..13 + +void LoraRadioInfo(uint8_t mode, void* pInfo) { + LoRaRadioInfo_t* pResult = (LoRaRadioInfo_t*) pInfo; + + switch (Lora->settings.region) { + case TAS_LORA_REGION_AU915: { + //////////////// AU915 //////////////////// + /* ref: https://lora-alliance.org/wp-content/uploads/2020/11/RP_2-1.0.2.pdf page 47 + DR0 LoRa: SF12 / 125 kHz + DR1 LoRa: SF11 / 125 kHz + DR2 LoRa: SF10 / 125 kHz <-- JOIN REQUEST + DR3 LoRa: SF9 / 125 kHz + DR4 LoRa: SF8 / 125 kHz + DR5 LoRa: SF7 / 125 kHz + DR6 LoRa: SF8 / 500 kHz Same as DR12 + DR7 LR-FHSS CR1/3: 1.523 MHz OCW 162 + DR8 LoRa: SF12 / 500 kHz + DR9 LoRa: SF11 / 500 kHz + DR10 LoRa: SF10 / 500 kHz + DR11 LoRa: SF9 / 500 kHz + DR12 LoRa: SF8 / 500 kHz Same as DR6 + DR13 LoRa: SF7 / 500 kHz + + UPLINK (RX) CHANNELS + There are 72 channels + 0-63: DR0 to 5. Starting 915.2, incrementing by 0.2 Mhz to 927.8 <-- JOIN REQUEST + 64-71: DR6 . Starting 915.9, incrementing by 1.6 MHz to 927.1 + NOTE: Testing with two Dragino end devices shows they do not play nice with channels 64-71 + 1) LHT52 will JOIN OK on Ch64, but never sends any sensor messages on same channel + 2) LHT65 will not even broadcast JOIN requests on any of the channels (as required by RP002) + For this reason, channels above 63 are not permitted. + + DOWNLINK (TX) CHANNELS + There are 8 channels + 0-7: DR8 to 13. Starting 923.3, incrementing by 0.6 MHz to 927.5 + + After an uplink: Downlink (TX) link subchannel = Uplink (RX) Channel Number modulo 8 + e.g. --Uplink (RX)-- --Downlink (TX)-- + Freq Channel Channel Frequency + 915.2 0 0 923.3 + 927.8 63 7 927.1 + + After an uplink: + Downlink DR for RX1 must follow this table + Uplink Downlink + DR0 DR8 + DR1 DR8 + DR2 DR10 <----- channels 1-62 + DR3 DR11 + DR4 DR12 + DR5 DR13 + DR6 DR13 <------ channels 63-71 + + Downlink DR for RX2 must be DR8 + + Downlink + Reference: https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf) + Assume this is in response to an uplink RX, so we already know RX freq & bw & sf + TX channel depends on RX freq + DR for RX1 depends on incoming DR (and RX1DROffset) + DR for RX2 is fixed ar DR8 + + Tasmota does not support different RX1 & RX2 DRs (yet), so just use DR8 and rely on RX2 arriving at end device OK. + */ + uint32_t uChannel = LoraChannel(); + uint8_t UplinkChannelBand = uChannel %8; //0..7 + switch (mode) { + case TAS_LORAWAN_RADIO_UPLINK: { + // if (uChannel > 71) uChannel = 71; See note above + if (uChannel > 63) uChannel = 63; + if (uChannel < 64) { + (*pResult).frequency = TAS_LORAWAN_AU915_FREQUENCY_UP1 + (uChannel * 0.2); + (*pResult).bandwidth = TAS_LORAWAN_AU915_BANDWIDTH_UP1; //DR2 + (*pResult).spreading_factor = TAS_LORAWAN_AU915_SPREADING_FACTOR_UP1; //DR2 + } else { + (*pResult).frequency = TAS_LORAWAN_AU915_FREQUENCY_UP2 + ((uChannel-64) * 1.6); + (*pResult).bandwidth = TAS_LORAWAN_AU915_BANDWIDTH_UP2; //DR6 + (*pResult).spreading_factor = TAS_LORAWAN_AU915_SPREADING_FACTOR_UP2; //DR6 + } + break; + } + case TAS_LORAWAN_RADIO_RX1: { + // RX1 DR depends on the Uplink settings + // https://lora-alliance.org/wp-content/uploads/2020/11/lorawan_regional_parameters_v1.0.3reva_0.pdf + // Page 41 + uint32_t UplinkDR = (125.0 == Lora->settings.bandwidth) ? (12 - Lora->settings.spreading_factor) : 6; // 0 .. 6 + uint32_t RX1DR = pgm_read_byte(&RX1DRs[UplinkDR]); + uint32_t RX1SF = pgm_read_byte(&SF[RX1DR]); + float RX1BW = (RX1DR > 5) ? 500.0 : 125.0; + (*pResult).frequency = TAS_LORAWAN_AU915_FREQUENCY_DN + (UplinkChannelBand * 0.6); + (*pResult).bandwidth = RX1BW; + (*pResult).spreading_factor = RX1SF; + break; + } + case TAS_LORAWAN_RADIO_RX2: { + (*pResult).frequency = TAS_LORAWAN_AU915_FREQUENCY_DN; + (*pResult).bandwidth = TAS_LORAWAN_AU915_BANDWIDTH_RX2; + (*pResult).spreading_factor = TAS_LORAWAN_AU915_SPREADING_FACTOR_RX2; + break; + } +// default: +// not implemented + } + break; + } + default: { // TAS_LORA_REGION_EU868 + //Default TX/RX1/TX1 same + (*pResult).frequency = TAS_LORAWAN_FREQUENCY; + (*pResult).bandwidth = TAS_LORAWAN_BANDWIDTH; + (*pResult).spreading_factor = TAS_LORAWAN_SPREADING_FACTOR; + } + } +} + +bool LoraWanDefaults(uint32_t region = TAS_LORA_REGION_EU868, LoRaRadioMode_t mode = TAS_LORAWAN_RADIO_UPLINK) { + bool multi_profile = false; + Lora->settings.region = region; + switch (region) { + case TAS_LORA_REGION_AU915: + // TO DO: Need 3 profiles: Uplink, RX1, RX2 + // Works OK for now as RX2 always received by end device. + multi_profile = true; + LoRaRadioInfo_t RadioInfo; + LoraRadioInfo(mode, &RadioInfo); // Region specific + Lora->settings.frequency = RadioInfo.frequency; + Lora->settings.bandwidth = RadioInfo.bandwidth; + Lora->settings.spreading_factor = RadioInfo.spreading_factor; + break; + default: // TAS_LORA_REGION_EU868 + Lora->settings.frequency = TAS_LORAWAN_FREQUENCY; + Lora->settings.bandwidth = TAS_LORAWAN_BANDWIDTH; + Lora->settings.spreading_factor = TAS_LORAWAN_SPREADING_FACTOR; + } + Lora->settings.coding_rate = TAS_LORAWAN_CODING_RATE; + Lora->settings.sync_word = TAS_LORAWAN_SYNC_WORD; + Lora->settings.output_power = TAS_LORAWAN_OUTPUT_POWER; + Lora->settings.preamble_length = TAS_LORAWAN_PREAMBLE_LENGTH; + Lora->settings.current_limit = TAS_LORAWAN_CURRENT_LIMIT; + Lora->settings.implicit_header = TAS_LORAWAN_HEADER; + Lora->settings.crc_bytes = TAS_LORAWAN_CRC_BYTES; + return multi_profile; +} + +void LoraSettings2Json(bool show = false) { + if (show) { + char region[8]; + ResponseAppend_P(PSTR("\"" D_JSON_REGION "\":\"%s\""), GetTextIndexed(region, sizeof(region), Lora->settings.region, kLoraRegions)); + } else { + ResponseAppend_P(PSTR("\"" D_JSON_REGION "\":%d"), Lora->settings.region); // enum 0 = EU868, 1 = AU915 + } + if (show && (Lora->settings.region == TAS_LORA_REGION_AU915)) { + LoRaRadioInfo_t Rx1Info; + LoraRadioInfo(TAS_LORAWAN_RADIO_RX1, &Rx1Info); // Get Rx1Info with values used for RX1 transmit window. (Region specific, calculated from Uplink radio settings) + LoRaRadioInfo_t Rx2Info; + LoraRadioInfo(TAS_LORAWAN_RADIO_RX2, &Rx2Info); // Get Rx2Info + ResponseAppend_P(PSTR(",\"" D_JSON_FREQUENCY "\":[%1_f,%1_f,%1_f]"), &Lora->settings.frequency, &Rx1Info.frequency, &Rx2Info.frequency); // xxx.x MHz + ResponseAppend_P(PSTR(",\"" D_JSON_BANDWIDTH "\":[%1_f,%1_f,%1_f]"), &Lora->settings.bandwidth, &Rx1Info.bandwidth, &Rx2Info.bandwidth); // xxx.x kHz + ResponseAppend_P(PSTR(",\"" D_JSON_SPREADING_FACTOR "\":[%d,%d,%d]"), Lora->settings.spreading_factor, Rx1Info.spreading_factor, Rx2Info.spreading_factor); + } else { + ResponseAppend_P(PSTR(",\"" D_JSON_FREQUENCY "\":%1_f"), &Lora->settings.frequency); // xxx.x MHz + ResponseAppend_P(PSTR(",\"" D_JSON_BANDWIDTH "\":%1_f"), &Lora->settings.bandwidth); // xxx.x kHz + ResponseAppend_P(PSTR(",\"" D_JSON_SPREADING_FACTOR "\":%d"), Lora->settings.spreading_factor); + } ResponseAppend_P(PSTR(",\"" D_JSON_CODINGRATE4 "\":%d"), Lora->settings.coding_rate); ResponseAppend_P(PSTR(",\"" D_JSON_SYNCWORD "\":%d"), Lora->settings.sync_word); ResponseAppend_P(PSTR(",\"" D_JSON_OUTPUT_POWER "\":%d"), Lora->settings.output_power); // dBm @@ -56,6 +262,7 @@ void LoraSettings2Json(void) { } void LoraJson2Settings(JsonParserObject root) { + Lora->settings.region = root.getUInt(PSTR(D_JSON_REGION), Lora->settings.region); Lora->settings.frequency = root.getFloat(PSTR(D_JSON_FREQUENCY), Lora->settings.frequency); Lora->settings.bandwidth = root.getFloat(PSTR(D_JSON_BANDWIDTH), Lora->settings.bandwidth); Lora->settings.spreading_factor = root.getUInt(PSTR(D_JSON_SPREADING_FACTOR), Lora->settings.spreading_factor); @@ -104,7 +311,7 @@ bool LoraSaveData(void) { "\"Flags\":%u,"), Lora->settings.crc32, Lora->settings.flags); - LoraSettings2Json(); + LoraSettings2Json(false); ResponseAppend_P(PSTR("}}")); if (!UfsJsonSettingsWrite(ResponseData())) { @@ -174,11 +381,26 @@ void LoraSettingsSave(void) { /*********************************************************************************************/ -bool LoraSend(uint8_t* data, uint32_t len, bool invert) { +bool LoraSend(uint8_t* data, uint32_t len, bool invert, bool uplink_profile = false); +bool LoraSend(uint8_t* data, uint32_t len, bool invert, bool uplink_profile) { + LoraSettings_t RXsettings; + if (uplink_profile) { + // Different TX/RX profiles allowed. (e.g. LoRaWAN) + // For CmndLoraSend() ... do not allow changes. + RXsettings = Lora->settings; // Make a copy; + LoraWanDefaults(Lora->settings.region, TAS_LORAWAN_RADIO_RX2); // Set Downlink profile TO DO: Support different RX1 & RX2 profiles + Lora->Config(); + } + uint32_t lora_time = millis(); // Time is important for LoRaWan RX windows 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)); + + if (uplink_profile) { + Lora->settings = RXsettings; // Restore copy + Lora->Config(); + } return result; } @@ -190,11 +412,10 @@ void LoraInput(void) { 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); - #ifdef USE_LORAWAN_BRIDGE if (bitRead(Lora->settings.flags, TAS_LORA_FLAG_BRIDGE_ENABLED)) { if (LoraWanInput((uint8_t*)data, packet_size)) { - return; + return; } } #endif // USE_LORAWAN_BRIDGE @@ -272,10 +493,11 @@ void LoraInit(void) { else if (PinUsed(GPIO_LORA_DI0)) { // SX1276, RFM95W if (LoraSx127xInit()) { - Lora->Config = &LoraSx127xConfig; + Lora->Config = &LoraSx127xConfig; Lora->Available = &LoraSx127xAvailable; - Lora->Receive = &LoraSx127xReceive; - Lora->Send = &LoraSx127xSend; + Lora->Receive = &LoraSx127xReceive; + Lora->Send = &LoraSx127xSend; + Lora->Init = &LoraSx127xInit; strcpy_P(hardware, PSTR("SX127x")); present = true; } @@ -285,10 +507,11 @@ void LoraInit(void) { else if (PinUsed(GPIO_LORA_DI1) && PinUsed(GPIO_LORA_BUSY)) { // SX1262, LilyGoT3S3 if (LoraSx126xInit()) { - Lora->Config = &LoraSx126xConfig; + Lora->Config = &LoraSx126xConfig; Lora->Available = &LoraSx126xAvailable; - Lora->Receive = &LoraSx126xReceive; - Lora->Send = &LoraSx126xSend; + Lora->Receive = &LoraSx126xReceive; + Lora->Send = &LoraSx126xSend; + Lora->Init = &LoraSx126xInit; strcpy_P(hardware, PSTR("SX126x")); present = true; } @@ -366,25 +589,25 @@ 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; #ifdef USE_LORA_DEBUG -// AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Len %d, Send %*_H"), len, len, XdrvMailbox.data); + AddLog(LOG_LEVEL_DEBUG, PSTR("DBG: Len %d, Send %*_H"), len, len, XdrvMailbox.data); #endif - if (1 == XdrvMailbox.index) { // "Hello Tiger\n" + if (1 == XdrvMailbox.index) { // "Hello Tiger\n" memcpy(data, XdrvMailbox.data, len); data[len++] = '\n'; } - else if ((2 == XdrvMailbox.index) || (4 == XdrvMailbox.index)) { // "Hello Tiger" or "A0" + else if ((2 == XdrvMailbox.index) || (4 == XdrvMailbox.index)) { // "Hello Tiger" or "A0" memcpy(data, XdrvMailbox.data, len); } - else if (3 == XdrvMailbox.index) { // "Hello\f" + else if (3 == XdrvMailbox.index) { // "Hello\f" Unescape(XdrvMailbox.data, &len); memcpy(data, XdrvMailbox.data, len); } - else if (5 == XdrvMailbox.index) { // "AA004566" as hex values + else if (5 == XdrvMailbox.index) { // "AA004566" as hex values char *p; char stemp[3]; @@ -400,7 +623,7 @@ void CmndLoraSend(void) { codes += 2; } } - else if (6 == XdrvMailbox.index) { // "72,101,108,108" + else if (6 == XdrvMailbox.index) { // "72,101,108,108" char *p; uint8_t code; char *values = XdrvMailbox.data; @@ -423,17 +646,24 @@ void CmndLoraSend(void) { void CmndLoraConfig(void) { // LoRaConfig - Show all parameters - // LoRaConfig 1 - Set default parameters - // LoRaConfig 2 - Set default LoRaWan bridge parameters + // LoRaConfig 1 - Set EU868 default parameters + // LoRaConfig 2 - Set EU868 default LoRaWan bridge parameters + // LoRaConfig 41 - Set AU915 default parameters + // LoRaConfig 42 - Set AU915 default LoRaWan bridge parameters // LoRaConfig {"Frequency":868.0,"Bandwidth":125.0} - Enter float parameters // LoRaConfig {"SyncWord":18} - Enter decimal parameter (=0x12) if (XdrvMailbox.data_len > 0) { - if (XdrvMailbox.payload == 1) { - LoraDefaults(); - Lora->Config(); - } - else if (XdrvMailbox.payload == 2) { - LoraWanDefaults(); + if (XdrvMailbox.payload > 0) { + uint32_t region = XdrvMailbox.payload / 10; + uint32_t option = ((XdrvMailbox.payload -1) &1) +1; // Option 1 or 2 + switch (option) { + case 1: + LoraDefaults(region); // Default region LoRa values + break; + case 2: + LoraWanDefaults(region); // Default region LoRaWan values + break; + } Lora->Config(); } else { @@ -447,7 +677,7 @@ void CmndLoraConfig(void) { } ResponseCmnd(); // {"LoRaConfig": ResponseAppend_P(PSTR("{")); - LoraSettings2Json(); + LoraSettings2Json(true); ResponseAppend_P(PSTR("}}")); } @@ -490,4 +720,4 @@ bool Xdrv73(uint32_t function) { } #endif // USE_SPI_LORA -#endif // USE_SPI +#endif // USE_SPI \ No newline at end of file