mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-22 02:06:31 +00:00
Add support for AU915 (#23372)
This commit is contained in:
parent
5d8b90d83b
commit
b5ae6bc035
@ -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;
|
||||
|
@ -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
|
@ -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
|
Loading…
x
Reference in New Issue
Block a user