Add support for AU915 (#23372)

This commit is contained in:
Theo Arends 2025-05-06 18:30:24 +02:00
parent 5d8b90d83b
commit b5ae6bc035
3 changed files with 561 additions and 145 deletions

View File

@ -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;

View File

@ -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 <vendor provided appkey>
* - 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

View File

@ -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