[LoRaWAN] Implement requested changes
This commit is contained in:
parent
2da09b5adc
commit
7c676f9393
6 changed files with 72 additions and 93 deletions
|
@ -28,39 +28,6 @@ uint8_t getDownlinkDataRate(uint8_t uplink, uint8_t offset, uint8_t base, uint8_
|
||||||
return(dr);
|
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) {
|
LoRaWANNode::LoRaWANNode(PhysicalLayer* phy, const LoRaWANBand_t* band) {
|
||||||
this->phyLayer = phy;
|
this->phyLayer = phy;
|
||||||
this->band = band;
|
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)
|
#if !defined(RADIOLIB_EEPROM_UNSUPPORTED)
|
||||||
uint16_t checkSum = 0;
|
uint16_t checkSum = 0;
|
||||||
checkSum ^= checkSum16(joinEUI);
|
checkSum ^= checkSum16((uint8_t*)joinEUI, 8);
|
||||||
checkSum ^= checkSum16(devEUI);
|
checkSum ^= checkSum16((uint8_t*)devEUI, 8);
|
||||||
checkSum ^= checkSum16(nwkKey, 16);
|
checkSum ^= checkSum16(nwkKey, 16);
|
||||||
checkSum ^= checkSum16(appKey, 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)
|
#if !defined(RADIOLIB_EEPROM_UNSUPPORTED)
|
||||||
// check if we actually need to restart from a clean session
|
// check if we actually need to restart from a clean session
|
||||||
uint16_t checkSum = 0;
|
uint16_t checkSum = 0;
|
||||||
checkSum ^= checkSum16(addr);
|
checkSum ^= checkSum16((uint8_t*)addr, 4);
|
||||||
checkSum ^= checkSum16(nwkSKey, 16);
|
checkSum ^= checkSum16(nwkSKey, 16);
|
||||||
checkSum ^= checkSum16(appSKey, 16);
|
checkSum ^= checkSum16(appSKey, 16);
|
||||||
if(fNwkSIntKey)
|
if(fNwkSIntKey) { checkSum ^= checkSum16(fNwkSIntKey, 16); }
|
||||||
checkSum ^= checkSum16(fNwkSIntKey, 16);
|
if(sNwkSIntKey) { checkSum ^= checkSum16(sNwkSIntKey, 16); }
|
||||||
if(sNwkSIntKey)
|
|
||||||
checkSum ^= checkSum16(sNwkSIntKey, 16);
|
|
||||||
|
|
||||||
bool validCheckSum = mod->hal->getPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum;
|
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;
|
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
|
// check maximum payload len as defined in phy
|
||||||
if(len > this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]) {
|
if(len > this->band->payloadLenMax[this->dataRates[RADIOLIB_LORAWAN_CHANNEL_DIR_UPLINK]]) {
|
||||||
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);
|
return(RADIOLIB_ERR_PACKET_TOO_LONG);
|
||||||
}
|
}
|
||||||
if(RADIOLIB_LORAWAN_FRAME_LEN(len, foptsLen))
|
|
||||||
|
|
||||||
// increase frame counter by one
|
// increase frame counter by one
|
||||||
this->fcntUp += 1;
|
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);
|
RADIOLIB_DEBUG_PRINTLN("TX timing: dlDwell = %d, ulDwell = %d, maxEirp = %d dBm", dlDwell, ulDwell, this->txPowerMax);
|
||||||
|
|
||||||
this->dwellTimeEnabledUp = ulDwell ? true : false;
|
this->dwellTimeEnabledUp = ulDwell ? true : false;
|
||||||
this->dwellTimeUp = ulDwell ? 400 : 0;
|
this->dwellTimeUp = ulDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0;
|
||||||
|
|
||||||
this->dwellTimeEnabledDn = dlDwell ? true : false;
|
this->dwellTimeEnabledDn = dlDwell ? true : false;
|
||||||
this->dwellTimeDn = dlDwell ? 400 : 0;
|
this->dwellTimeDn = dlDwell ? RADIOLIB_LORAWAN_DWELL_TIME : 0;
|
||||||
|
|
||||||
#if !defined(RADIOLIB_EEPROM_UNSUPPORTED)
|
#if !defined(RADIOLIB_EEPROM_UNSUPPORTED)
|
||||||
if(saveToEeprom) {
|
if(saveToEeprom) {
|
||||||
|
@ -2673,31 +2637,32 @@ uint8_t LoRaWANNode::getMacPayloadLength(uint8_t cid) {
|
||||||
return 0;
|
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];
|
uint8_t payload[5];
|
||||||
int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_LINK_CHECK_REQ, &this->commandsDown, payload);
|
int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_LINK_CHECK_REQ, &this->commandsDown, payload);
|
||||||
if(state != RADIOLIB_ERR_NONE)
|
RADIOLIB_ASSERT(state);
|
||||||
return false;
|
|
||||||
|
|
||||||
*margin = payload[0];
|
if(margin) { *margin = payload[0]; }
|
||||||
*gwCnt = payload[1];
|
if(gwCnt) { *gwCnt = payload[1]; }
|
||||||
RADIOLIB_DEBUG_PRINTLN("Link check: margin = %d dB, gwCnt = %d", margin, gwCnt);
|
// RADIOLIB_DEBUG_PRINTLN("Link check: margin = %d dB, gwCnt = %d", margin, gwCnt);
|
||||||
return(true);
|
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];
|
uint8_t payload[5];
|
||||||
int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_MAC_DEVICE_TIME, &this->commandsDown, payload);
|
int16_t state = deleteMacCommand(RADIOLIB_LORAWAN_MAC_DEVICE_TIME, &this->commandsDown, payload);
|
||||||
if(state != RADIOLIB_ERR_NONE)
|
RADIOLIB_ASSERT(state);
|
||||||
return false;
|
|
||||||
|
|
||||||
|
if(gpsEpoch) {
|
||||||
*gpsEpoch = LoRaWANNode::ntoh<uint32_t>(&payload[0]);
|
*gpsEpoch = LoRaWANNode::ntoh<uint32_t>(&payload[0]);
|
||||||
*fraction = payload[4];
|
if(returnUnix) {
|
||||||
RADIOLIB_DEBUG_PRINTLN("Network time: gpsEpoch = %d s, delayExp = %f", gpsEpoch, (float)(*fraction)/256.0f);
|
|
||||||
|
|
||||||
uint32_t unixOffset = 315964800;
|
uint32_t unixOffset = 315964800;
|
||||||
*gpsEpoch += unixOffset;
|
*gpsEpoch += unixOffset;
|
||||||
return(true);
|
}
|
||||||
|
}
|
||||||
|
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>
|
template<typename T>
|
||||||
T LoRaWANNode::ntoh(uint8_t* buff, size_t size) {
|
T LoRaWANNode::ntoh(uint8_t* buff, size_t size) {
|
||||||
uint8_t* buffPtr = buff;
|
uint8_t* buffPtr = buff;
|
||||||
|
|
|
@ -159,9 +159,6 @@
|
||||||
#define RADIOLIB_LORAWAN_MIC_DATA_RATE_POS (3)
|
#define RADIOLIB_LORAWAN_MIC_DATA_RATE_POS (3)
|
||||||
#define RADIOLIB_LORAWAN_MIC_CH_INDEX_POS (4)
|
#define RADIOLIB_LORAWAN_MIC_CH_INDEX_POS (4)
|
||||||
|
|
||||||
// magic word saved in persistent memory upon activation
|
|
||||||
#define RADIOLIB_LORAWAN_MAGIC (0x39EA)
|
|
||||||
|
|
||||||
// MAC commands
|
// MAC commands
|
||||||
#define RADIOLIB_LORAWAN_NUM_MAC_COMMANDS (16)
|
#define RADIOLIB_LORAWAN_NUM_MAC_COMMANDS (16)
|
||||||
|
|
||||||
|
@ -191,6 +188,9 @@
|
||||||
// the maximum number of simultaneously available channels
|
// the maximum number of simultaneously available channels
|
||||||
#define RADIOLIB_LORAWAN_NUM_AVAILABLE_CHANNELS (16)
|
#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 {
|
struct LoRaWANMacSpec_t {
|
||||||
const uint8_t cid;
|
const uint8_t cid;
|
||||||
const uint8_t lenDn;
|
const uint8_t lenDn;
|
||||||
|
@ -199,23 +199,23 @@ struct LoRaWANMacSpec_t {
|
||||||
};
|
};
|
||||||
|
|
||||||
const LoRaWANMacSpec_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS + 1] = {
|
const LoRaWANMacSpec_t MacTable[RADIOLIB_LORAWAN_NUM_MAC_COMMANDS + 1] = {
|
||||||
{ 0x00, 0, 0, false }, // not an actual MAC command, exists for offsetting
|
{ 0x00, 0, 0, false }, // not an actual MAC command, exists for index offsetting
|
||||||
{ 0x01, 1, 1, false }, // RADIOLIB_LORAWAN_MAC_RESET
|
{ RADIOLIB_LORAWAN_MAC_RESET, 1, 1, false },
|
||||||
{ 0x02, 2, 0, true }, // RADIOLIB_LORAWAN_MAC_LINK_CHECK
|
{ RADIOLIB_LORAWAN_MAC_LINK_CHECK, 2, 0, true },
|
||||||
{ 0x03, 4, 1, false }, // RADIOLIB_LORAWAN_MAC_LINK_ADR
|
{ RADIOLIB_LORAWAN_MAC_LINK_ADR, 4, 1, false },
|
||||||
{ 0x04, 1, 0, false }, // RADIOLIB_LORAWAN_MAC_DUTY_CYCLE
|
{ RADIOLIB_LORAWAN_MAC_DUTY_CYCLE, 1, 0, false },
|
||||||
{ 0x05, 4, 1, false }, // RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP
|
{ RADIOLIB_LORAWAN_MAC_RX_PARAM_SETUP, 4, 1, false },
|
||||||
{ 0x06, 0, 2, false }, // RADIOLIB_LORAWAN_MAC_DEV_STATUS
|
{ RADIOLIB_LORAWAN_MAC_DEV_STATUS, 0, 2, false },
|
||||||
{ 0x07, 5, 1, false }, // RADIOLIB_LORAWAN_MAC_NEW_CHANNEL
|
{ RADIOLIB_LORAWAN_MAC_NEW_CHANNEL, 5, 1, false },
|
||||||
{ 0x08, 1, 0, false }, // RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP
|
{ RADIOLIB_LORAWAN_MAC_RX_TIMING_SETUP, 1, 0, false },
|
||||||
{ 0x09, 1, 0, false }, // RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP
|
{ RADIOLIB_LORAWAN_MAC_TX_PARAM_SETUP, 1, 0, false },
|
||||||
{ 0x0A, 4, 1, false }, // RADIOLIB_LORAWAN_MAC_DL_CHANNEL
|
{ RADIOLIB_LORAWAN_MAC_DL_CHANNEL, 4, 1, false },
|
||||||
{ 0x0B, 1, 1, false }, // RADIOLIB_LORAWAN_MAC_REKEY
|
{ RADIOLIB_LORAWAN_MAC_REKEY, 1, 1, false },
|
||||||
{ 0x0C, 1, 0, false }, // RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP
|
{ RADIOLIB_LORAWAN_MAC_ADR_PARAM_SETUP, 1, 0, false },
|
||||||
{ 0x0D, 5, 0, true }, // RADIOLIB_LORAWAN_MAC_DEVICE_TIME
|
{ RADIOLIB_LORAWAN_MAC_DEVICE_TIME, 5, 0, true },
|
||||||
{ 0x0E, 2, 0, false }, // RADIOLIB_LORAWAN_MAC_FORCE_REJOIN
|
{ RADIOLIB_LORAWAN_MAC_FORCE_REJOIN, 2, 0, false },
|
||||||
{ 0x0F, 1, 1, false }, // RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP
|
{ RADIOLIB_LORAWAN_MAC_REJOIN_PARAM_SETUP, 1, 1, false },
|
||||||
{ 0x80, 5, 0, true } // RADIOLIB_LORAWAN_MAC_PROPRIETARY
|
{ RADIOLIB_LORAWAN_MAC_PROPRIETARY, 5, 0, true }
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -681,9 +681,9 @@ class LoRaWANNode {
|
||||||
Returns 'false' if there was no network response / parsing failed.
|
Returns 'false' if there was no network response / parsing failed.
|
||||||
\param margin Link margin in dB of LinkCheckReq demodulation at gateway side.
|
\param margin Link margin in dB of LinkCheckReq demodulation at gateway side.
|
||||||
\param gwCnt Number of gateways that received the LinkCheckReq.
|
\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.
|
\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 gpsEpoch Number of seconds since GPS epoch (Jan. 6th 1980)
|
||||||
\param fraction Fractional-second, in 1/256-second steps
|
\param fraction Fractional-second, in 1/256-second steps
|
||||||
\param returnUnix If true, returns Unix timestamp instead of GPS (default true)
|
\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
|
#if !RADIOLIB_GODMODE
|
||||||
private:
|
private:
|
||||||
|
@ -876,6 +876,9 @@ class LoRaWANNode {
|
||||||
// function to encrypt and decrypt payloads
|
// 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);
|
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
|
// network-to-host conversion method - takes data from network packet and converts it to the host endians
|
||||||
template<typename T>
|
template<typename T>
|
||||||
static T ntoh(uint8_t* buff, size_t size = 0);
|
static T ntoh(uint8_t* buff, size_t size = 0);
|
||||||
|
|
|
@ -53,7 +53,7 @@ const LoRaWANBand_t US915 = {
|
||||||
.powerMax = 30,
|
.powerMax = 30,
|
||||||
.powerNumSteps = 10,
|
.powerNumSteps = 10,
|
||||||
.dutyCycle = 0,
|
.dutyCycle = 0,
|
||||||
.dwellTimeUp = 400,
|
.dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME,
|
||||||
.dwellTimeDn = 0,
|
.dwellTimeDn = 0,
|
||||||
.txFreqs = {
|
.txFreqs = {
|
||||||
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
RADIOLIB_LORAWAN_CHANNEL_NONE,
|
||||||
|
@ -334,8 +334,8 @@ const LoRaWANBand_t AS923 = {
|
||||||
.powerMax = 16,
|
.powerMax = 16,
|
||||||
.powerNumSteps = 7,
|
.powerNumSteps = 7,
|
||||||
.dutyCycle = 36000,
|
.dutyCycle = 36000,
|
||||||
.dwellTimeUp = 400,
|
.dwellTimeUp = RADIOLIB_LORAWAN_DWELL_TIME,
|
||||||
.dwellTimeDn = 400,
|
.dwellTimeDn = RADIOLIB_LORAWAN_DWELL_TIME,
|
||||||
.txFreqs = {
|
.txFreqs = {
|
||||||
{ .enabled = true, .idx = 0, .freq = 923.200, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 0, .freq = 923.200, .drMin = 0, .drMax = 5},
|
||||||
{ .enabled = true, .idx = 1, .freq = 923.400, .drMin = 0, .drMax = 5},
|
{ .enabled = true, .idx = 1, .freq = 923.400, .drMin = 0, .drMax = 5},
|
||||||
|
|
Loading…
Add table
Reference in a new issue