[LoRaWAN] Implement requested changes

pull/918/head
StevenCellist 2024-01-08 22:33:34 +01:00
rodzic 2da09b5adc
commit 7c676f9393
6 zmienionych plików z 72 dodań i 93 usunięć

Wyświetl plik

@ -157,7 +157,7 @@ void loop() {
// wait before sending another packet
uint32_t minimumDelay = 60000; // try to send once every minute
uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per law!)
uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows
uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows
delay(delayMs);
}

Wyświetl plik

@ -165,7 +165,7 @@ void loop() {
// wait before sending another packet
uint32_t minimumDelay = 60000; // try to send once every minute
uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per law!)
uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows
uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows
delay(delayMs);
}

Wyświetl plik

@ -77,7 +77,7 @@ void setup() {
if(state >= RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
Serial.print(F("Restored an "));
if(state == RADIOLIB_LORAWAN_MODE_OTAA)
if(state == RADIOLIB_LORAWAN_MODE_OTAA)
Serial.println(F("OTAA session."));
else {
Serial.println(F("ABP session."));
@ -142,7 +142,7 @@ void loop() {
// make sure to send the radio to sleep as well using radio.sleep()
uint32_t minimumDelay = 60000; // try to send once every minute
uint32_t interval = node.timeUntilUplink(); // calculate minimum duty cycle delay (per law!)
uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows
uint32_t delayMs = max(interval, minimumDelay); // cannot send faster than duty cycle allows
delay(delayMs);
}

Wyświetl plik

@ -28,39 +28,6 @@ uint8_t getDownlinkDataRate(uint8_t uplink, uint8_t offset, uint8_t base, uint8_
return(dr);
}
uint16_t checkSum16(uint32_t key) {
uint8_t bufLen = 2;
uint16_t buf16[bufLen];
memcpy(buf16, &key, bufLen);
uint16_t checkSum = 0;
for(int i = 0; i < bufLen; i++) {
checkSum ^= buf16[i];
}
return(checkSum);
}
uint16_t checkSum16(uint64_t key) {
uint8_t bufLen = 4;
uint16_t buf16[bufLen];
memcpy(buf16, &key, bufLen);
uint16_t checkSum = 0;
for(int i = 0; i < bufLen; i++) {
checkSum ^= buf16[i];
}
return(checkSum);
}
uint16_t checkSum16(uint8_t *key, uint8_t keyLen) {
uint8_t bufLen = keyLen / 2;
uint16_t buf16[bufLen];
memcpy(buf16, key, bufLen);
uint16_t checkSum = 0;
for(int i = 0; i < bufLen; i++) {
checkSum ^= buf16[i];
}
return(checkSum);
}
LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band) {
this->phyLayer = phy;
this->band = band;
@ -395,8 +362,8 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
#if !defined(RADIOLIB_EEPROM_UNSUPPORTED)
uint16_t checkSum = 0;
checkSum ^= checkSum16(joinEUI);
checkSum ^= checkSum16(devEUI);
checkSum ^= checkSum16((uint8_t*)joinEUI, 8);
checkSum ^= checkSum16((uint8_t*)devEUI, 8);
checkSum ^= checkSum16(nwkKey, 16);
checkSum ^= checkSum16(appKey, 16);
@ -666,13 +633,11 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey,
#if !defined(RADIOLIB_EEPROM_UNSUPPORTED)
// check if we actually need to restart from a clean session
uint16_t checkSum = 0;
checkSum ^= checkSum16(addr);
checkSum ^= checkSum16((uint8_t*)addr, 4);
checkSum ^= checkSum16(nwkSKey, 16);
checkSum ^= checkSum16(appSKey, 16);
if(fNwkSIntKey)
checkSum ^= checkSum16(fNwkSIntKey, 16);
if(sNwkSIntKey)
checkSum ^= checkSum16(sNwkSIntKey, 16);
if(fNwkSIntKey) { checkSum ^= checkSum16(fNwkSIntKey, 16); }
if(sNwkSIntKey) { checkSum ^= checkSum16(sNwkSIntKey, 16); }
bool validCheckSum = mod->hal->getPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum;
bool validMode = mod->hal->getPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_ABP;
@ -904,10 +869,9 @@ int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t port, bool isConf
// check maximum payload len as defined in phy
if(len > this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]) {
len = this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]];
// return(RADIOLIB_ERR_PACKET_TOO_LONG);
// len = this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]];
return(RADIOLIB_ERR_PACKET_TOO_LONG);
}
if(RADIOLIB_LORAWAN_FRAME_LEN(len, foptsLen))
// increase frame counter by one
this->fcntUp += 1;
@ -2575,10 +2539,10 @@ bool LoRaWANNode::execMacCommand(LoRaWANMacCommand_t* cmd, bool saveToEeprom) {
RADIOLIB_DEBUG_PRINTLN("TX timing: dlDwell = %d, ulDwell = %d, maxEirp = %d dBm", dlDwell, ulDwell, this->txPowerMax);
this->dwellTimeEnabledUp = ulDwell ? true : false;
this->dwellTimeUp = ulDwell ? 400 : 0;
this->dwellTimeUp = ulDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0;
this->dwellTimeEnabledDn = dlDwell ? true : false;
this->dwellTimeDn = dlDwell ? 400 : 0;
this->dwellTimeDn = dlDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0;
#if !defined(RADIOLIB_EEPROM_UNSUPPORTED)
if(saveToEeprom) {
@ -2673,31 +2637,32 @@ uint8_t LoRaWANNode::getMacPayloadLength(uint8_t cid) {
return 0;
}
bool LoRaWANNode::getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt) {
int16_t LoRaWANNode::getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt) {
uint8_t payload[5];
int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_LINK_CHECK_REQ, &this->commandsDown, payload);
if(state != RADIOLIB_ERR_NONE)
return false;
RADIOLIB_ASSERT(state);
*margin = payload[0];
*gwCnt = payload[1];
RADIOLIB_DEBUG_PRINTLN("Link check: margin = %d dB, gwCnt = %d", margin, gwCnt);
return(true);
if(margin) { *margin = payload[0]; }
if(gwCnt) { *gwCnt = payload[1]; }
// RADIOLIB_DEBUG_PRINTLN("Link check: margin = %d dB, gwCnt = %d", margin, gwCnt);
return(RADIOLIB_ERR_NONE);
}
bool LoRaWANNode::getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix) {
int16_t LoRaWANNode::getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix) {
uint8_t payload[5];
int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_MAC_DEVICE_TIME, &this->commandsDown, payload);
if(state != RADIOLIB_ERR_NONE)
return false;
RADIOLIB_ASSERT(state);
*gpsEpoch = LoRaWANNode::ntoh<uint32_t>(&payload[0]);
*fraction = payload[4];
RADIOLIB_DEBUG_PRINTLN("Network time: gpsEpoch = %d s, delayExp = %f", gpsEpoch, (float)(*fraction)/256.0f);
uint32_t unixOffset = 315964800;
*gpsEpoch += unixOffset;
return(true);
if(gpsEpoch) {
*gpsEpoch = LoRaWANNode::ntoh<uint32_t>(&payload[0]);
if(returnUnix) {
uint32_t unixOffset = 315964800;
*gpsEpoch += unixOffset;
}
}
if(fraction) { *fraction = payload[4]; }
// RADIOLIB_DEBUG_PRINTLN("Network time: gpsEpoch = %d s, delayExp = %f", gpsEpoch, (float)(*fraction)/256.0f);
return(RADIOLIB_ERR_NONE);
}
@ -2786,6 +2751,17 @@ void LoRaWANNode::processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out
}
}
uint16_t LoRaWANNode::checkSum16(uint8_t *key, uint8_t keyLen) {
uint16_t buf16[RADIOLIB_AES128_KEY_SIZE/2];
uint8_t bufLen = keyLen / 2;
memcpy(buf16, key, bufLen);
uint16_t checkSum = 0;
for(int i = 0; i < bufLen; i++) {
checkSum ^= buf16[i];
}
return(checkSum);
}
template<typename T>
T LoRaWANNode::ntoh(uint8_t* buff, size_t size) {
uint8_t* buffPtr = buff;

Wyświetl plik

@ -159,9 +159,6 @@
#define RADIOLIB_LORAWAN_MIC_DATA_RATE_POS (3)
#define RADIOLIB_LORAWAN_MIC_CH_INDEX_POS (4)
// magic word saved in persistent memory upon activation
#define RADIOLIB_LORAWAN_MAGIC (0x39EA)
// MAC commands
#define RADIOLIB_LORAWAN_NUM_MAC_COMMANDS (16)
@ -191,6 +188,9 @@
// the maximum number of simultaneously available channels
#define RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS (16)
// maximum allowed dwell time on bands that implement dwell time limitations
#define RADIOLIB_LORAWAN_DWELL_TIME (400)
struct LoRaWANMacSpec_t {
const uint8_t cid;
const uint8_t lenDn;
@ -199,23 +199,23 @@ struct LoRaWANMacSpec_t {
};
const LoRaWANMacSpec_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS + 1] = {
{ 0x00, 0, 0, false }, // not an actual MAC command, exists for offsetting
{ 0x01, 1, 1, false }, // RADIOLIB_LORAWAN_MAC_RESET
{ 0x02, 2, 0, true }, // RADIOLIB_LORAWAN_MAC_LINK_CHECK
{ 0x03, 4, 1, false }, // RADIOLIB_LORAWAN_MAC_LINK_ADR
{ 0x04, 1, 0, false }, // RADIOLIB_LORAWAN_MAC_DUTY_CYCLE
{ 0x05, 4, 1, false }, // RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP
{ 0x06, 0, 2, false }, // RADIOLIB_LORAWAN_MAC_DEV_STATUS
{ 0x07, 5, 1, false }, // RADIOLIB_LORAWAN_MAC_NEW_CHANNEL
{ 0x08, 1, 0, false }, // RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP
{ 0x09, 1, 0, false }, // RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP
{ 0x0A, 4, 1, false }, // RADIOLIB_LORAWAN_MAC_DL_CHANNEL
{ 0x0B, 1, 1, false }, // RADIOLIB_LORAWAN_MAC_REKEY
{ 0x0C, 1, 0, false }, // RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP
{ 0x0D, 5, 0, true }, // RADIOLIB_LORAWAN_MAC_DEVICE_TIME
{ 0x0E, 2, 0, false }, // RADIOLIB_LORAWAN_MAC_FORCE_REJOIN
{ 0x0F, 1, 1, false }, // RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP
{ 0x80, 5, 0, true } // RADIOLIB_LORAWAN_MAC_PROPRIETARY
{ 0x00, 0, 0, false }, // not an actual MAC command, exists for index offsetting
{ RADIOLIB_LORAWAN_MAC_RESET, 1, 1, false },
{ RADIOLIB_LORAWAN_MAC_LINK_CHECK, 2, 0, true },
{ RADIOLIB_LORAWAN_MAC_LINK_ADR, 4, 1, false },
{ RADIOLIB_LORAWAN_MAC_DUTY_CYCLE, 1, 0, false },
{ RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, 4, 1, false },
{ RADIOLIB_LORAWAN_MAC_DEV_STATUS, 0, 2, false },
{ RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, 5, 1, false },
{ RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP, 1, 0, false },
{ RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, 1, 0, false },
{ RADIOLIB_LORAWAN_MAC_DL_CHANNEL, 4, 1, false },
{ RADIOLIB_LORAWAN_MAC_REKEY, 1, 1, false },
{ RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP, 1, 0, false },
{ RADIOLIB_LORAWAN_MAC_DEVICE_TIME, 5, 0, true },
{ RADIOLIB_LORAWAN_MAC_FORCE_REJOIN, 2, 0, false },
{ RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP, 1, 1, false },
{ RADIOLIB_LORAWAN_MAC_PROPRIETARY, 5, 0, true }
};
/*!
@ -681,9 +681,9 @@ class LoRaWANNode {
Returns 'false' if there was no network response / parsing failed.
\param margin Link margin in dB of LinkCheckReq demodulation at gateway side.
\param gwCnt Number of gateways that received the LinkCheckReq.
\returns Whether the parameters where succesfully parsed.
\returns \ref status_codes
*/
bool getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt);
int16_t getMacLinkCheckAns(uint8_t* margin, uint8_t* gwCnt);
/*!
\brief Returns the network time after requesting a DeviceTime MAC command.
@ -692,9 +692,9 @@ class LoRaWANNode {
\param gpsEpoch Number of seconds since GPS epoch (Jan. 6th 1980)
\param fraction Fractional-second, in 1/256-second steps
\param returnUnix If true, returns Unix timestamp instead of GPS (default true)
\returns Whether the parameters where succesfully parsed.
\returns \ref status_codes
*/
bool getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix = true);
int16_t getMacDeviceTimeAns(uint32_t* gpsEpoch, uint8_t* fraction, bool returnUnix = true);
#if !RADIOLIB_GODMODE
private:
@ -876,6 +876,9 @@ class LoRaWANNode {
// function to encrypt and decrypt payloads
void processAES(uint8_t* in, size_t len, uint8_t* key, uint8_t* out, uint32_t fcnt, uint8_t dir, uint8_t ctrId, bool counter);
// 16-bit checksum method that takes a uint8_t array of even length and calculates the checksum
static uint16_t checkSum16(uint8_t *key, uint8_t keyLen);
// network-to-host conversion method - takes data from network packet and converts it to the host endians
template<typename T>
static T ntoh(uint8_t* buff, size_t size = 0);

Wyświetl plik

@ -53,7 +53,7 @@ const LoRaWANBand_t US915 = {
.powerMax = 30,
.powerNumSteps = 10,
.dutyCycle = 0,
.dwellTimeUp = 400,
.dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME,
.dwellTimeDn = 0,
.txFreqs = {
RADIOLIB_LORAWAN_CHANNEL_NONE,
@ -334,8 +334,8 @@ const LoRaWANBand_t AS923 = {
.powerMax = 16,
.powerNumSteps = 7,
.dutyCycle = 36000,
.dwellTimeUp = 400,
.dwellTimeDn = 400,
.dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME,
.dwellTimeDn = RADIOLIB_LORAWAN_DWELL_TIME,
.txFreqs = {
{ .enabled = true, .idx = 0, .freq = 923.200, .drMin = 0, .drMax = 5},
{ .enabled = true, .idx = 1, .freq = 923.400, .drMin = 0, .drMax = 5},