Amir Chaudhary
/
Hexmodal-firmware_v3-1_hex_w_3d_14
Implemented LED Indicator Patterns
Revision 30:c186bf174348, committed 2019-09-04
- Comitter:
- amirchaudhary
- Date:
- Wed Sep 04 15:42:07 2019 +0000
- Parent:
- 29:ca6caa47ef38
- Commit message:
- Anish code for RTC
Changed in this revision
--- a/app/main.cpp Thu Apr 25 15:49:17 2019 +0000 +++ b/app/main.cpp Wed Sep 04 15:42:07 2019 +0000 @@ -975,14 +975,14 @@ break; } - // Measure voltage preval - float battery_reading = BAT_PIN.read()*1000; - measurements[0] = (uint8_t) rintf(battery_reading/10); - // Start test relayPin = 1; AppLedStateOn = 1; Led3StateChanged = true; + + // Measure voltage preval + float battery_reading = BAT_PIN.read()*1000; + measurements[0] = (uint8_t) rintf(battery_reading/10); } void endTest(uint8_t *measurements) { @@ -994,9 +994,9 @@ int rh_reading = RH_PIN.read()*1000 - vce_reading; measurements[1] = (uint8_t) rintf(battery_reading/10); - measurements[2] = (uint8_t) light_1_reading/2; - measurements[3] = (uint8_t) light_2_reading/2; - measurements[4] = (uint8_t) rh_reading/2; + measurements[2] = (uint8_t) (light_1_reading/2); + measurements[3] = (uint8_t) (light_2_reading/2); + measurements[4] = (uint8_t) (rh_reading/2); // End test // relayPin = 0; @@ -1038,6 +1038,12 @@ RCC_ClkInitTypeDef RCC_ClkInitStruct; RCC_OscInitTypeDef RCC_OscInitStruct; + /* configure RTC clock for HSE */ + SET_BIT(PWR->CR, PWR_CR_DBP); // enable RTC register access as they are in backup domain + __HAL_RCC_BACKUPRESET_FORCE(); // force reset RTC subsystem + __HAL_RCC_BACKUPRESET_RELEASE(); + __HAL_RCC_RTC_CONFIG(RCC_RTCCLKSOURCE_HSE_DIV8); // HSE=8MHZ and RTC clock input is 1MHz(when using HSE as source) + /* Enable HSE and activate PLL with HSE as source */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; /* External 8 MHz xtal on OSC_IN/OSC_OUT */ @@ -1070,7 +1076,11 @@ if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { return (-3); // FAIL } - + + // enable rtc hardware + __HAL_RCC_RTC_ENABLE(); + wait(1.0); + return 0; // OK } @@ -1099,14 +1109,14 @@ } } - int main( void ) { - pc.printf("mbed-os-rev: %d.%d.%d lib-rev: %d\r\n", \ - MBED_MAJOR_VERSION, MBED_MINOR_VERSION,MBED_PATCH_VERSION,MBED_LIBRARY_VERSION); - pc.printf("BUILD= %s, SysClock= %d, RCC= %0X\r\n", __TIME__, SystemCoreClock, RCC->CR); + pc.printf("BUILD: %s mbed-os-rev: %d.%d.%d lib-rev: %d\r\n", \ + __TIME__, MBED_MAJOR_VERSION, MBED_MINOR_VERSION,MBED_PATCH_VERSION,MBED_LIBRARY_VERSION); + pc.printf("OLD: SysClock= %d RCC= %08X CSR= %08X CIER= %08X\r\n", SystemCoreClock, RCC->CR, RCC->CSR, RCC->CIER); my_patch(); - pc.printf("NEW SysClock= %d, NEW RCC= %0X\r\n", SystemCoreClock, RCC->CR); + pc.printf("\r\nNEW: SysClock= %d RCC= %08X CSR= %08X CIER= %08X\r\n", SystemCoreClock, RCC->CR, RCC->CSR, RCC->CIER); + wait(3); LoRaMacPrimitives_t LoRaMacPrimitives; LoRaMacCallback_t LoRaMacCallbacks; @@ -1236,6 +1246,17 @@ mibReq.Param.EnablePublicNetwork = LORAWAN_PUBLIC_NETWORK; LoRaMacMibSetRequestConfirm( &mibReq ); + // Limiting to just 2nd subband of 8 channels + static uint16_t GatewayChannelsMask[] = {0xFF00, 0x0000, 0x0000, 0x0000, 0x0002, 0x0000}; + mibReq.Type = MIB_CHANNELS_DEFAULT_MASK; + mibReq.Param.ChannelsDefaultMask = GatewayChannelsMask; + LoRaMacMibSetRequestConfirm( &mibReq ); + + mibReq.Type = MIB_CHANNELS_MASK; + mibReq.Param.ChannelsMask = GatewayChannelsMask; + LoRaMacMibSetRequestConfirm( &mibReq ); + + #if defined( USE_BAND_868 ) LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON ); SerialDisplayUpdateDutyCycle( LORAWAN_DUTYCYCLE_ON );
--- a/mac/LoRaWAN-lib.lib Thu Apr 25 15:49:17 2019 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://developer.mbed.org/teams/Semtech/code/LoRaWAN-lib/#26002607de9c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mac/LoRaWAN-lib/LoRaMac-definitions.h Wed Sep 04 15:42:07 2019 +0000 @@ -0,0 +1,608 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C)2013 Semtech + +Description: LoRa MAC layer global definitions + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainer: Miguel Luis and Gregory Cristian +*/ +#ifndef __LORAMAC_BOARD_H__ +#define __LORAMAC_BOARD_H__ + +/*! + * Returns individual channel mask + * + * \param[IN] channelIndex Channel index 1 based + * \retval channelMask + */ +#define LC( channelIndex ) ( uint16_t )( 1 << ( channelIndex - 1 ) ) + +#if defined( USE_BAND_433 ) + +/*! + * LoRaMac maximum number of channels + */ +#define LORA_MAX_NB_CHANNELS 16 + +/*! + * Minimal datarate that can be used by the node + */ +#define LORAMAC_TX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define LORAMAC_TX_MAX_DATARATE DR_7 + +/*! + * Minimal datarate that can be used by the node + */ +#define LORAMAC_RX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define LORAMAC_RX_MAX_DATARATE DR_7 + +/*! + * Default datarate used by the node + */ +#define LORAMAC_DEFAULT_DATARATE DR_0 + +/*! + * Minimal Rx1 receive datarate offset + */ +#define LORAMAC_MIN_RX1_DR_OFFSET 0 + +/*! + * Maximal Rx1 receive datarate offset + */ +#define LORAMAC_MAX_RX1_DR_OFFSET 5 + +/*! + * Minimal Tx output power that can be used by the node + */ +#define LORAMAC_MIN_TX_POWER TX_POWER_M5_DBM + +/*! + * Maximal Tx output power that can be used by the node + */ +#define LORAMAC_MAX_TX_POWER TX_POWER_10_DBM + +/*! + * Default Tx output power used by the node + */ +#define LORAMAC_DEFAULT_TX_POWER TX_POWER_10_DBM + +/*! + * LoRaMac TxPower definition + */ +#define TX_POWER_10_DBM 0 +#define TX_POWER_07_DBM 1 +#define TX_POWER_04_DBM 2 +#define TX_POWER_01_DBM 3 +#define TX_POWER_M2_DBM 4 +#define TX_POWER_M5_DBM 5 + +/*! + * LoRaMac datarates definition + */ +#define DR_0 0 // SF12 - BW125 +#define DR_1 1 // SF11 - BW125 +#define DR_2 2 // SF10 - BW125 +#define DR_3 3 // SF9 - BW125 +#define DR_4 4 // SF8 - BW125 +#define DR_5 5 // SF7 - BW125 +#define DR_6 6 // SF7 - BW250 +#define DR_7 7 // FSK + +/*! + * Verification of default datarate + */ +#if ( LORAMAC_DEFAULT_DATARATE > DR_5 ) +#error "A default DR higher than DR_5 may lead to connectivity loss." +#endif + +/*! + * Second reception window channel definition. + */ +// Channel = { Frequency [Hz], Datarate } +#define RX_WND_2_CHANNEL { 434665000, DR_0 } + +/*! + * LoRaMac maximum number of bands + */ +#define LORA_MAX_NB_BANDS 1 + +// Band = { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } +#define BAND0 { 100, TX_POWER_10_DBM, 0, 0 } // 1.0 % + +/*! + * LoRaMac default channels + */ +// Channel = { Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } +#define LC1 { 433175000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } +#define LC2 { 433375000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } +#define LC3 { 433575000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } + +/*! + * LoRaMac channels which are allowed for the join procedure + */ +#define JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) ) + +#elif defined( USE_BAND_470 ) + +/*! + * LoRaMac maximum number of channels + */ +#define LORA_MAX_NB_CHANNELS 96 + +/*! + * Minimal datarate that can be used by the node + */ +#define LORAMAC_TX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define LORAMAC_TX_MAX_DATARATE DR_5 + +/*! + * Minimal datarate that can be used by the node + */ +#define LORAMAC_RX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define LORAMAC_RX_MAX_DATARATE DR_5 + +/*! + * Default datarate used by the node + */ +#define LORAMAC_DEFAULT_DATARATE DR_0 + +/*! + * Minimal Rx1 receive datarate offset + */ +#define LORAMAC_MIN_RX1_DR_OFFSET 0 + +/*! + * Maximal Rx1 receive datarate offset + */ +#define LORAMAC_MAX_RX1_DR_OFFSET 3 + +/*! + * Minimal Tx output power that can be used by the node + */ +#define LORAMAC_MIN_TX_POWER TX_POWER_2_DBM + +/*! + * Maximal Tx output power that can be used by the node + */ +#define LORAMAC_MAX_TX_POWER TX_POWER_17_DBM + +/*! + * Default Tx output power used by the node + */ +#define LORAMAC_DEFAULT_TX_POWER TX_POWER_14_DBM + +/*! + * LoRaMac TxPower definition + */ +#define TX_POWER_17_DBM 0 +#define TX_POWER_16_DBM 1 +#define TX_POWER_14_DBM 2 +#define TX_POWER_12_DBM 3 +#define TX_POWER_10_DBM 4 +#define TX_POWER_7_DBM 5 +#define TX_POWER_5_DBM 6 +#define TX_POWER_2_DBM 7 + + +/*! + * LoRaMac datarates definition + */ +#define DR_0 0 // SF12 - BW125 | +#define DR_1 1 // SF11 - BW125 | +#define DR_2 2 // SF10 - BW125 | +#define DR_3 3 // SF9 - BW125 | +#define DR_4 4 // SF8 - BW125 | +#define DR_5 5 // SF7 - BW125 | + +/*! + * Second reception window channel definition. + */ +// Channel = { Frequency [Hz], Datarate } +#define RX_WND_2_CHANNEL { 505300000, DR_0 } + +/*! + * LoRaMac maximum number of bands + */ +#define LORA_MAX_NB_BANDS 1 + +// Band = { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } +#define BAND0 { 1, TX_POWER_17_DBM, 0, 0 } // 100.0 % + +#elif defined( USE_BAND_780 ) + +/*! + * LoRaMac maximum number of channels + */ +#define LORA_MAX_NB_CHANNELS 16 + +/*! + * Minimal datarate that can be used by the node + */ +#define LORAMAC_TX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define LORAMAC_TX_MAX_DATARATE DR_7 + +/*! + * Minimal datarate that can be used by the node + */ +#define LORAMAC_RX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define LORAMAC_RX_MAX_DATARATE DR_7 + +/*! + * Default datarate used by the node + */ +#define LORAMAC_DEFAULT_DATARATE DR_0 + +/*! + * Minimal Rx1 receive datarate offset + */ +#define LORAMAC_MIN_RX1_DR_OFFSET 0 + +/*! + * Maximal Rx1 receive datarate offset + */ +#define LORAMAC_MAX_RX1_DR_OFFSET 5 + +/*! + * Minimal Tx output power that can be used by the node + */ +#define LORAMAC_MIN_TX_POWER TX_POWER_M5_DBM + +/*! + * Maximal Tx output power that can be used by the node + */ +#define LORAMAC_MAX_TX_POWER TX_POWER_10_DBM + +/*! + * Default Tx output power used by the node + */ +#define LORAMAC_DEFAULT_TX_POWER TX_POWER_10_DBM + +/*! + * LoRaMac TxPower definition + */ +#define TX_POWER_10_DBM 0 +#define TX_POWER_07_DBM 1 +#define TX_POWER_04_DBM 2 +#define TX_POWER_01_DBM 3 +#define TX_POWER_M2_DBM 4 +#define TX_POWER_M5_DBM 5 + +/*! + * LoRaMac datarates definition + */ +#define DR_0 0 // SF12 - BW125 +#define DR_1 1 // SF11 - BW125 +#define DR_2 2 // SF10 - BW125 +#define DR_3 3 // SF9 - BW125 +#define DR_4 4 // SF8 - BW125 +#define DR_5 5 // SF7 - BW125 +#define DR_6 6 // SF7 - BW250 +#define DR_7 7 // FSK + +/*! + * Verification of default datarate + */ +#if ( LORAMAC_DEFAULT_DATARATE > DR_5 ) +#error "A default DR higher than DR_5 may lead to connectivity loss." +#endif + +/*! + * Second reception window channel definition. + */ +// Channel = { Frequency [Hz], Datarate } +#define RX_WND_2_CHANNEL { 786000000, DR_0 } + +/*! + * LoRaMac maximum number of bands + */ +#define LORA_MAX_NB_BANDS 1 + +// Band = { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } +#define BAND0 { 100, TX_POWER_10_DBM, 0, 0 } // 1.0 % + +/*! + * LoRaMac default channels + */ +// Channel = { Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } +#define LC1 { 779500000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } +#define LC2 { 779700000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } +#define LC3 { 779900000, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 } + +/*! + * LoRaMac channels which are allowed for the join procedure + */ +#define JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) ) + +#elif defined( USE_BAND_868 ) + +/*! + * LoRaMac maximum number of channels + */ +#define LORA_MAX_NB_CHANNELS 16 + +/*! + * Minimal datarate that can be used by the node + */ +#define LORAMAC_TX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define LORAMAC_TX_MAX_DATARATE DR_7 + +/*! + * Minimal datarate that can be used by the node + */ +#define LORAMAC_RX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define LORAMAC_RX_MAX_DATARATE DR_7 + +/*! + * Default datarate used by the node + */ +#define LORAMAC_DEFAULT_DATARATE DR_0 + +/*! + * Minimal Rx1 receive datarate offset + */ +#define LORAMAC_MIN_RX1_DR_OFFSET 0 + +/*! + * Maximal Rx1 receive datarate offset + */ +#define LORAMAC_MAX_RX1_DR_OFFSET 5 + +/*! + * Minimal Tx output power that can be used by the node + */ +#define LORAMAC_MIN_TX_POWER TX_POWER_02_DBM + +/*! + * Maximal Tx output power that can be used by the node + */ +#define LORAMAC_MAX_TX_POWER TX_POWER_20_DBM + +/*! + * Default Tx output power used by the node + */ +#define LORAMAC_DEFAULT_TX_POWER TX_POWER_14_DBM + +/*! + * LoRaMac TxPower definition + */ +#define TX_POWER_20_DBM 0 +#define TX_POWER_14_DBM 1 +#define TX_POWER_11_DBM 2 +#define TX_POWER_08_DBM 3 +#define TX_POWER_05_DBM 4 +#define TX_POWER_02_DBM 5 + +/*! + * LoRaMac datarates definition + */ +#define DR_0 0 // SF12 - BW125 +#define DR_1 1 // SF11 - BW125 +#define DR_2 2 // SF10 - BW125 +#define DR_3 3 // SF9 - BW125 +#define DR_4 4 // SF8 - BW125 +#define DR_5 5 // SF7 - BW125 +#define DR_6 6 // SF7 - BW250 +#define DR_7 7 // FSK + +/*! + * Verification of default datarate + */ +#if ( LORAMAC_DEFAULT_DATARATE > DR_5 ) +#error "A default DR higher than DR_5 may lead to connectivity loss." +#endif + +/*! + * Second reception window channel definition. + */ +// Channel = { Frequency [Hz], Datarate } +#define RX_WND_2_CHANNEL { 869525000, DR_0 } + +/*! + * LoRaMac maximum number of bands + */ +#define LORA_MAX_NB_BANDS 5 + +/*! + * LoRaMac EU868 default bands + */ +typedef enum +{ + BAND_G1_0, + BAND_G1_1, + BAND_G1_2, + BAND_G1_3, + BAND_G1_4, +}BandId_t; + +// Band = { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } +#define BAND0 { 100 , TX_POWER_14_DBM, 0, 0 } // 1.0 % +#define BAND1 { 100 , TX_POWER_14_DBM, 0, 0 } // 1.0 % +#define BAND2 { 1000, TX_POWER_14_DBM, 0, 0 } // 0.1 % +#define BAND3 { 10 , TX_POWER_14_DBM, 0, 0 } // 10.0 % +#define BAND4 { 100 , TX_POWER_14_DBM, 0, 0 } // 1.0 % + +/*! + * LoRaMac default channels + */ +// Channel = { Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } +#define LC1 { 868100000, { ( ( DR_5 << 4 ) | DR_0 ) }, 1 } +#define LC2 { 868300000, { ( ( DR_5 << 4 ) | DR_0 ) }, 1 } +#define LC3 { 868500000, { ( ( DR_5 << 4 ) | DR_0 ) }, 1 } + +/*! + * LoRaMac channels which are allowed for the join procedure + */ +#define JOIN_CHANNELS ( uint16_t )( LC( 1 ) | LC( 2 ) | LC( 3 ) ) + +#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) + +/*! + * LoRaMac maximum number of channels + */ +#define LORA_MAX_NB_CHANNELS 72 + +/*! + * Minimal datarate that can be used by the node + */ +#define LORAMAC_TX_MIN_DATARATE DR_0 + +/*! + * Maximal datarate that can be used by the node + */ +#define LORAMAC_TX_MAX_DATARATE DR_4 + +/*! + * Minimal datarate that can be used by the node + */ +#define LORAMAC_RX_MIN_DATARATE DR_8 + +/*! + * Maximal datarate that can be used by the node + */ +#define LORAMAC_RX_MAX_DATARATE DR_13 + +/*! + * Default datarate used by the node + */ +#define LORAMAC_DEFAULT_DATARATE DR_0 + +/*! + * Minimal Rx1 receive datarate offset + */ +#define LORAMAC_MIN_RX1_DR_OFFSET 0 + +/*! + * Maximal Rx1 receive datarate offset + */ +#define LORAMAC_MAX_RX1_DR_OFFSET 3 + +/*! + * Minimal Tx output power that can be used by the node + */ +#define LORAMAC_MIN_TX_POWER TX_POWER_10_DBM + +/*! + * Maximal Tx output power that can be used by the node + */ +#define LORAMAC_MAX_TX_POWER TX_POWER_30_DBM + +/*! + * Default Tx output power used by the node + */ +#define LORAMAC_DEFAULT_TX_POWER TX_POWER_20_DBM + +/*! + * LoRaMac TxPower definition + */ +#define TX_POWER_30_DBM 0 +#define TX_POWER_28_DBM 1 +#define TX_POWER_26_DBM 2 +#define TX_POWER_24_DBM 3 +#define TX_POWER_22_DBM 4 +#define TX_POWER_20_DBM 5 +#define TX_POWER_18_DBM 6 +#define TX_POWER_16_DBM 7 +#define TX_POWER_14_DBM 8 +#define TX_POWER_12_DBM 9 +#define TX_POWER_10_DBM 10 + +/*! + * LoRaMac datarates definition + */ +#define DR_0 0 // SF10 - BW125 | +#define DR_1 1 // SF9 - BW125 | +#define DR_2 2 // SF8 - BW125 +-> Up link +#define DR_3 3 // SF7 - BW125 | +#define DR_4 4 // SF8 - BW500 | +#define DR_5 5 // RFU +#define DR_6 6 // RFU +#define DR_7 7 // RFU +#define DR_8 8 // SF12 - BW500 | +#define DR_9 9 // SF11 - BW500 | +#define DR_10 10 // SF10 - BW500 | +#define DR_11 11 // SF9 - BW500 | +#define DR_12 12 // SF8 - BW500 +-> Down link +#define DR_13 13 // SF7 - BW500 | +#define DR_14 14 // RFU | +#define DR_15 15 // RFU | + +/*! + * Second reception window channel definition. + */ +// Channel = { Frequency [Hz], Datarate } +#define RX_WND_2_CHANNEL { 923300000, DR_8 } + +/*! + * LoRaMac maximum number of bands + */ +#define LORA_MAX_NB_BANDS 1 + +// Band = { DutyCycle, TxMaxPower, LastTxDoneTime, TimeOff } +#define BAND0 { 1, TX_POWER_20_DBM, 0, 0 } // 100.0 % + +/*! + * LoRaMac default channels + */ +// Channel = { Frequency [Hz], { ( ( DrMax << 4 ) | DrMin ) }, Band } +/* + * US band channels are initialized using a loop in LoRaMacInit function + * \code + * // 125 kHz channels + * for( uint8_t i = 0; i < LORA_MAX_NB_CHANNELS - 8; i++ ) + * { + * Channels[i].Frequency = 902.3e6 + i * 200e3; + * Channels[i].DrRange.Value = ( DR_3 << 4 ) | DR_0; + * Channels[i].Band = 0; + * } + * // 500 kHz channels + * for( uint8_t i = LORA_MAX_NB_CHANNELS - 8; i < LORA_MAX_NB_CHANNELS; i++ ) + * { + * Channels[i].Frequency = 903.0e6 + ( i - ( LORA_MAX_NB_CHANNELS - 8 ) ) * 1.6e6; + * Channels[i].DrRange.Value = ( DR_4 << 4 ) | DR_4; + * Channels[i].Band = 0; + * } + * \endcode + */ +#else + #error "Please define a frequency band in the compiler options." +#endif + +#endif // __LORAMAC_BOARD_H__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mac/LoRaWAN-lib/LoRaMac.cpp Wed Sep 04 15:42:07 2019 +0000 @@ -0,0 +1,4531 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C)2013 Semtech + ___ _____ _ ___ _ _____ ___ ___ ___ ___ +/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| +\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| +|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| +embedded.connectivity.solutions=============== + +Description: LoRa MAC layer implementation + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jäckle ( STACKFORCE ) +*/ +#include <math.h> +#include "board.h" + +#include "LoRaMacCrypto.h" +#include "LoRaMac.h" +#include "LoRaMacTest.h" + +/*! + * Maximum PHY layer payload size + */ +#define LORAMAC_PHY_MAXPAYLOAD 255 + +/*! + * Maximum MAC commands buffer size + */ +#define LORA_MAC_COMMAND_MAX_LENGTH 15 + +/*! + * FRMPayload overhead to be used when setting the Radio.SetMaxPayloadLength + * in RxWindowSetup function. + * Maximum PHYPayload = MaxPayloadOfDatarate/MaxPayloadOfDatarateRepeater + LORA_MAC_FRMPAYLOAD_OVERHEAD + */ +#define LORA_MAC_FRMPAYLOAD_OVERHEAD 13 // MHDR(1) + FHDR(7) + Port(1) + MIC(4) + +/*! + * LoRaMac duty cycle for the back-off procedure during the first hour. + */ +#define BACKOFF_DC_1_HOUR 100 + +/*! + * LoRaMac duty cycle for the back-off procedure during the next 10 hours. + */ +#define BACKOFF_DC_10_HOURS 1000 + +/*! + * LoRaMac duty cycle for the back-off procedure during the next 24 hours. + */ +#define BACKOFF_DC_24_HOURS 10000 + +/*! + * Device IEEE EUI + */ +static uint8_t *LoRaMacDevEui; + +/*! + * Application IEEE EUI + */ +static uint8_t *LoRaMacAppEui; + +/*! + * AES encryption/decryption cipher application key + */ +static uint8_t *LoRaMacAppKey; + +/*! + * AES encryption/decryption cipher network session key + */ +static uint8_t LoRaMacNwkSKey[] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/*! + * AES encryption/decryption cipher application session key + */ +static uint8_t LoRaMacAppSKey[] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/*! + * Device nonce is a random value extracted by issuing a sequence of RSSI + * measurements + */ +static uint16_t LoRaMacDevNonce; + +/*! + * Network ID ( 3 bytes ) + */ +static uint32_t LoRaMacNetID; + +/*! + * Mote Address + */ +static uint32_t LoRaMacDevAddr; + +/*! + * Multicast channels linked list + */ +static MulticastParams_t *MulticastChannels = NULL; + +/*! + * Actual device class + */ +static DeviceClass_t LoRaMacDeviceClass; + +/*! + * Indicates if the node is connected to a private or public network + */ +static bool PublicNetwork; + +/*! + * Indicates if the node supports repeaters + */ +static bool RepeaterSupport; + +/*! + * Buffer containing the data to be sent or received. + */ +static uint8_t LoRaMacBuffer[LORAMAC_PHY_MAXPAYLOAD]; + +/*! + * Length of packet in LoRaMacBuffer + */ +static uint16_t LoRaMacBufferPktLen = 0; + +/*! + * Length of the payload in LoRaMacBuffer + */ +static uint8_t LoRaMacTxPayloadLen = 0; + +/*! + * Buffer containing the upper layer data. + */ +static uint8_t LoRaMacRxPayload[LORAMAC_PHY_MAXPAYLOAD]; + +/*! + * LoRaMAC frame counter. Each time a packet is sent the counter is incremented. + * Only the 16 LSB bits are sent + */ +static uint32_t UpLinkCounter = 0; + +/*! + * LoRaMAC frame counter. Each time a packet is received the counter is incremented. + * Only the 16 LSB bits are received + */ +static uint32_t DownLinkCounter = 0; + +/*! + * IsPacketCounterFixed enables the MIC field tests by fixing the + * UpLinkCounter value + */ +static bool IsUpLinkCounterFixed = false; + +/*! + * Used for test purposes. Disables the opening of the reception windows. + */ +static bool IsRxWindowsEnabled = true; + +/*! + * Indicates if the MAC layer has already joined a network. + */ +static bool IsLoRaMacNetworkJoined = false; + +/*! + * LoRaMac ADR control status + */ +static bool AdrCtrlOn = false; + +/*! + * Counts the number of missed ADR acknowledgements + */ +static uint32_t AdrAckCounter = 0; + +/*! + * If the node has sent a FRAME_TYPE_DATA_CONFIRMED_UP this variable indicates + * if the nodes needs to manage the server acknowledgement. + */ +static bool NodeAckRequested = false; + +/*! + * If the server has sent a FRAME_TYPE_DATA_CONFIRMED_DOWN this variable indicates + * if the ACK bit must be set for the next transmission + */ +static bool SrvAckRequested = false; + +/*! + * Indicates if the MAC layer wants to send MAC commands + */ +static bool MacCommandsInNextTx = false; + +/*! + * Contains the current MacCommandsBuffer index + */ +static uint8_t MacCommandsBufferIndex = 0; + +/*! + * Contains the current MacCommandsBuffer index for MAC commands to repeat + */ +static uint8_t MacCommandsBufferToRepeatIndex = 0; + +/*! + * Buffer containing the MAC layer commands + */ +static uint8_t MacCommandsBuffer[LORA_MAC_COMMAND_MAX_LENGTH]; + +/*! + * Buffer containing the MAC layer commands which must be repeated + */ +static uint8_t MacCommandsBufferToRepeat[LORA_MAC_COMMAND_MAX_LENGTH]; + +#if defined( USE_BAND_433 ) +/*! + * Data rates table definition + */ +const uint8_t Datarates[] = { 12, 11, 10, 9, 8, 7, 7, 50 }; + +/*! + * Bandwidths table definition in Hz + */ +const uint32_t Bandwidths[] = { 125e3, 125e3, 125e3, 125e3, 125e3, 125e3, 250e3, 0 }; + +/*! + * Maximum payload with respect to the datarate index. Cannot operate with repeater. + */ +const uint8_t MaxPayloadOfDatarate[] = { 51, 51, 51, 115, 242, 242, 242, 242 }; + +/*! + * Maximum payload with respect to the datarate index. Can operate with repeater. + */ +const uint8_t MaxPayloadOfDatarateRepeater[] = { 51, 51, 51, 115, 222, 222, 222, 222 }; + +/*! + * Tx output powers table definition + */ +const int8_t TxPowers[] = { 10, 7, 4, 1, -2, -5 }; + +/*! + * LoRaMac bands + */ +static Band_t Bands[LORA_MAX_NB_BANDS] = +{ + BAND0, +}; + +/*! + * LoRaMAC channels + */ +static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS] = +{ + LC1, + LC2, + LC3, +}; +#elif defined( USE_BAND_470 ) + +/*! + * Data rates table definition + */ +const uint8_t Datarates[] = { 12, 11, 10, 9, 8, 7 }; + +/*! + * Bandwidths table definition in Hz + */ +const uint32_t Bandwidths[] = { 125e3, 125e3, 125e3, 125e3, 125e3, 125e3 }; + +/*! + * Maximum payload with respect to the datarate index. Cannot operate with repeater. + */ +const uint8_t MaxPayloadOfDatarate[] = { 51, 51, 51, 115, 222, 222 }; + +/*! + * Maximum payload with respect to the datarate index. Can operate with repeater. + */ +const uint8_t MaxPayloadOfDatarateRepeater[] = { 51, 51, 51, 115, 222, 222 }; + +/*! + * Tx output powers table definition + */ +const int8_t TxPowers[] = { 17, 16, 14, 12, 10, 7, 5, 2 }; + +/*! + * LoRaMac bands + */ +static Band_t Bands[LORA_MAX_NB_BANDS] = +{ + BAND0, +}; + +/*! + * LoRaMAC channels + */ +static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS]; + +/*! + * Defines the first channel for RX window 1 for CN470 band + */ +#define LORAMAC_FIRST_RX1_CHANNEL ( (uint32_t) 500.3e6 ) + +/*! + * Defines the last channel for RX window 1 for CN470 band + */ +#define LORAMAC_LAST_RX1_CHANNEL ( (uint32_t) 509.7e6 ) + +/*! + * Defines the step width of the channels for RX window 1 + */ +#define LORAMAC_STEPWIDTH_RX1_CHANNEL ( (uint32_t) 200e3 ) + +#elif defined( USE_BAND_780 ) +/*! + * Data rates table definition + */ +const uint8_t Datarates[] = { 12, 11, 10, 9, 8, 7, 7, 50 }; + +/*! + * Bandwidths table definition in Hz + */ +const uint32_t Bandwidths[] = { 125e3, 125e3, 125e3, 125e3, 125e3, 125e3, 250e3, 0 }; + +/*! + * Maximum payload with respect to the datarate index. Cannot operate with repeater. + */ +const uint8_t MaxPayloadOfDatarate[] = { 51, 51, 51, 115, 242, 242, 242, 242 }; + +/*! + * Maximum payload with respect to the datarate index. Can operate with repeater. + */ +const uint8_t MaxPayloadOfDatarateRepeater[] = { 51, 51, 51, 115, 222, 222, 222, 222 }; + +/*! + * Tx output powers table definition + */ +const int8_t TxPowers[] = { 10, 7, 4, 1, -2, -5 }; + +/*! + * LoRaMac bands + */ +static Band_t Bands[LORA_MAX_NB_BANDS] = +{ + BAND0, +}; + +/*! + * LoRaMAC channels + */ +static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS] = +{ + LC1, + LC2, + LC3, +}; +#elif defined( USE_BAND_868 ) +/*! + * Data rates table definition + */ +const uint8_t Datarates[] = { 12, 11, 10, 9, 8, 7, 7, 50 }; + +/*! + * Bandwidths table definition in Hz + */ +const uint32_t Bandwidths[] = { 125e3, 125e3, 125e3, 125e3, 125e3, 125e3, 250e3, 0 }; + +/*! + * Maximum payload with respect to the datarate index. Cannot operate with repeater. + */ +const uint8_t MaxPayloadOfDatarate[] = { 51, 51, 51, 115, 242, 242, 242, 242 }; + +/*! + * Maximum payload with respect to the datarate index. Can operate with repeater. + */ +const uint8_t MaxPayloadOfDatarateRepeater[] = { 51, 51, 51, 115, 222, 222, 222, 222 }; + +/*! + * Tx output powers table definition + */ +const int8_t TxPowers[] = { 20, 14, 11, 8, 5, 2 }; + +/*! + * LoRaMac bands + */ +static Band_t Bands[LORA_MAX_NB_BANDS] = +{ + BAND0, + BAND1, + BAND2, + BAND3, + BAND4, +}; + +/*! + * LoRaMAC channels + */ +static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS] = +{ + LC1, + LC2, + LC3, +}; +#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) +/*! + * Data rates table definition + */ +const uint8_t Datarates[] = { 10, 9, 8, 7, 8, 0, 0, 0, 12, 11, 10, 9, 8, 7, 0, 0 }; + +/*! + * Bandwidths table definition in Hz + */ +const uint32_t Bandwidths[] = { 125e3, 125e3, 125e3, 125e3, 500e3, 0, 0, 0, 500e3, 500e3, 500e3, 500e3, 500e3, 500e3, 0, 0 }; + +/*! + * Up/Down link data rates offset definition + */ +const int8_t DatarateOffsets[5][4] = +{ + { DR_10, DR_9 , DR_8 , DR_8 }, // DR_0 + { DR_11, DR_10, DR_9 , DR_8 }, // DR_1 + { DR_12, DR_11, DR_10, DR_9 }, // DR_2 + { DR_13, DR_12, DR_11, DR_10 }, // DR_3 + { DR_13, DR_13, DR_12, DR_11 }, // DR_4 +}; + +/*! + * Maximum payload with respect to the datarate index. Cannot operate with repeater. + */ +const uint8_t MaxPayloadOfDatarate[] = { 11, 53, 125, 242, 242, 0, 0, 0, 53, 129, 242, 242, 242, 242, 0, 0 }; + +/*! + * Maximum payload with respect to the datarate index. Can operate with repeater. + */ +const uint8_t MaxPayloadOfDatarateRepeater[] = { 11, 53, 125, 242, 242, 0, 0, 0, 33, 109, 222, 222, 222, 222, 0, 0 }; + +/*! + * Tx output powers table definition + */ +const int8_t TxPowers[] = { 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10 }; + +/*! + * LoRaMac bands + */ +static Band_t Bands[LORA_MAX_NB_BANDS] = +{ + BAND0, +}; + +/*! + * LoRaMAC channels + */ +static ChannelParams_t Channels[LORA_MAX_NB_CHANNELS]; + +/*! + * Contains the channels which remain to be applied. + */ +static uint16_t ChannelsMaskRemaining[6]; + +/*! + * Defines the first channel for RX window 1 for US band + */ +#define LORAMAC_FIRST_RX1_CHANNEL ( (uint32_t) 923.3e6 ) + +/*! + * Defines the last channel for RX window 1 for US band + */ +#define LORAMAC_LAST_RX1_CHANNEL ( (uint32_t) 927.5e6 ) + +/*! + * Defines the step width of the channels for RX window 1 + */ +#define LORAMAC_STEPWIDTH_RX1_CHANNEL ( (uint32_t) 600e3 ) + +#else + #error "Please define a frequency band in the compiler options." +#endif + +/*! + * LoRaMac parameters + */ +LoRaMacParams_t LoRaMacParams; + +/*! + * LoRaMac default parameters + */ +LoRaMacParams_t LoRaMacParamsDefaults; + +/*! + * Uplink messages repetitions counter + */ +static uint8_t ChannelsNbRepCounter = 0; + +/*! + * Maximum duty cycle + * \remark Possibility to shutdown the device. + */ +static uint8_t MaxDCycle = 0; + +/*! + * Aggregated duty cycle management + */ +static uint16_t AggregatedDCycle; +static TimerTime_t AggregatedLastTxDoneTime; +static TimerTime_t AggregatedTimeOff; + +/*! + * Enables/Disables duty cycle management (Test only) + */ +static bool DutyCycleOn; + +/*! + * Current channel index + */ +static uint8_t Channel; + +/*! + * Stores the time at LoRaMac initialization. + * + * \remark Used for the BACKOFF_DC computation. + */ +static TimerTime_t LoRaMacInitializationTime = 0; + +/*! + * LoRaMac internal states + */ +enum eLoRaMacState +{ + LORAMAC_IDLE = 0x00000000, + LORAMAC_TX_RUNNING = 0x00000001, + LORAMAC_RX = 0x00000002, + LORAMAC_ACK_REQ = 0x00000004, + LORAMAC_ACK_RETRY = 0x00000008, + LORAMAC_TX_DELAYED = 0x00000010, + LORAMAC_TX_CONFIG = 0x00000020, + LORAMAC_RX_ABORT = 0x00000040, +}; + +/*! + * LoRaMac internal state + */ +uint32_t LoRaMacState = LORAMAC_IDLE; + +/*! + * LoRaMac timer used to check the LoRaMacState (runs every second) + */ +static TimerEvent_t MacStateCheckTimer; + +/*! + * LoRaMac upper layer event functions + */ +static LoRaMacPrimitives_t *LoRaMacPrimitives; + +/*! + * LoRaMac upper layer callback functions + */ +static LoRaMacCallback_t *LoRaMacCallbacks; + +/*! + * Radio events function pointer + */ +static RadioEvents_t RadioEvents; + +/*! + * LoRaMac duty cycle delayed Tx timer + */ +static TimerEvent_t TxDelayedTimer; + +/*! + * LoRaMac reception windows timers + */ +static TimerEvent_t RxWindowTimer1; +static TimerEvent_t RxWindowTimer2; + +/*! + * LoRaMac reception windows delay + * \remark normal frame: RxWindowXDelay = ReceiveDelayX - RADIO_WAKEUP_TIME + * join frame : RxWindowXDelay = JoinAcceptDelayX - RADIO_WAKEUP_TIME + */ +static uint32_t RxWindow1Delay; +static uint32_t RxWindow2Delay; + +/*! + * Rx window parameters + */ +typedef struct +{ + int8_t Datarate; + uint8_t Bandwidth; + uint32_t RxWindowTimeout; + int32_t RxOffset; +}RxConfigParams_t; + +/*! + * Rx windows params + */ +static RxConfigParams_t RxWindowsParams[2]; + +/*! + * Acknowledge timeout timer. Used for packet retransmissions. + */ +static TimerEvent_t AckTimeoutTimer; + +/*! + * Number of trials to get a frame acknowledged + */ +static uint8_t AckTimeoutRetries = 1; + +/*! + * Number of trials to get a frame acknowledged + */ +static uint8_t AckTimeoutRetriesCounter = 1; + +/*! + * Indicates if the AckTimeout timer has expired or not + */ +static bool AckTimeoutRetry = false; + +/*! + * Last transmission time on air + */ +TimerTime_t TxTimeOnAir = 0; + +/*! + * Number of trials for the Join Request + */ +static uint8_t JoinRequestTrials; + +/*! + * Maximum number of trials for the Join Request + */ +static uint8_t MaxJoinRequestTrials; + +/*! + * Structure to hold an MCPS indication data. + */ +static McpsIndication_t McpsIndication; + +/*! + * Structure to hold MCPS confirm data. + */ +static McpsConfirm_t McpsConfirm; + +/*! + * Structure to hold MLME confirm data. + */ +static MlmeConfirm_t MlmeConfirm; + +/*! + * Holds the current rx window slot + */ +static uint8_t RxSlot = 0; + +/*! + * LoRaMac tx/rx operation state + */ +LoRaMacFlags_t LoRaMacFlags; + +/*! + * \brief Function to be executed on Radio Tx Done event + */ +static void OnRadioTxDone( void ); + +/*! + * \brief This function prepares the MAC to abort the execution of function + * OnRadioRxDone in case of a reception error. + */ +static void PrepareRxDoneAbort( void ); + +/*! + * \brief Function to be executed on Radio Rx Done event + */ +static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); + +/*! + * \brief Function executed on Radio Tx Timeout event + */ +static void OnRadioTxTimeout( void ); + +/*! + * \brief Function executed on Radio Rx error event + */ +static void OnRadioRxError( void ); + +/*! + * \brief Function executed on Radio Rx Timeout event + */ +static void OnRadioRxTimeout( void ); + +/*! + * \brief Function executed on Resend Frame timer event. + */ +static void OnMacStateCheckTimerEvent( void ); + +/*! + * \brief Function executed on duty cycle delayed Tx timer event + */ +static void OnTxDelayedTimerEvent( void ); + +/*! + * \brief Function executed on first Rx window timer event + */ +static void OnRxWindow1TimerEvent( void ); + +/*! + * \brief Function executed on second Rx window timer event + */ +static void OnRxWindow2TimerEvent( void ); + +/*! + * \brief Function executed on AckTimeout timer event + */ +static void OnAckTimeoutTimerEvent( void ); + +/*! + * \brief Searches and set the next random available channel + * + * \param [OUT] Time to wait for the next transmission according to the duty + * cycle. + * + * \retval status Function status [1: OK, 0: Unable to find a channel on the + * current datarate] + */ +static bool SetNextChannel( TimerTime_t* time ); + +/*! + * \brief Initializes and opens the reception window + * + * \param [IN] freq window channel frequency + * \param [IN] datarate window channel datarate + * \param [IN] bandwidth window channel bandwidth + * \param [IN] timeout window channel timeout + * + * \retval status Operation status [true: Success, false: Fail] + */ +static bool RxWindowSetup( uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout, bool rxContinuous ); + +/*! + * \brief Verifies if the RX window 2 frequency is in range + * + * \param [IN] freq window channel frequency + * + * \retval status Function status [1: OK, 0: Frequency not applicable] + */ +static bool Rx2FreqInRange( uint32_t freq ); + +/*! + * \brief Adds a new MAC command to be sent. + * + * \Remark MAC layer internal function + * + * \param [in] cmd MAC command to be added + * [MOTE_MAC_LINK_CHECK_REQ, + * MOTE_MAC_LINK_ADR_ANS, + * MOTE_MAC_DUTY_CYCLE_ANS, + * MOTE_MAC_RX2_PARAM_SET_ANS, + * MOTE_MAC_DEV_STATUS_ANS + * MOTE_MAC_NEW_CHANNEL_ANS] + * \param [in] p1 1st parameter ( optional depends on the command ) + * \param [in] p2 2nd parameter ( optional depends on the command ) + * + * \retval status Function status [0: OK, 1: Unknown command, 2: Buffer full] + */ +static LoRaMacStatus_t AddMacCommand( uint8_t cmd, uint8_t p1, uint8_t p2 ); + +/*! + * \brief Parses the MAC commands which must be repeated. + * + * \Remark MAC layer internal function + * + * \param [IN] cmdBufIn Buffer which stores the MAC commands to send + * \param [IN] length Length of the input buffer to parse + * \param [OUT] cmdBufOut Buffer which stores the MAC commands which must be + * repeated. + * + * \retval Size of the MAC commands to repeat. + */ +static uint8_t ParseMacCommandsToRepeat( uint8_t* cmdBufIn, uint8_t length, uint8_t* cmdBufOut ); + +/*! + * \brief Validates if the payload fits into the frame, taking the datarate + * into account. + * + * \details Refer to chapter 4.3.2 of the LoRaWAN specification, v1.0 + * + * \param lenN Length of the application payload. The length depends on the + * datarate and is region specific + * + * \param datarate Current datarate + * + * \param fOptsLen Length of the fOpts field + * + * \retval [false: payload does not fit into the frame, true: payload fits into + * the frame] + */ +static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate, uint8_t fOptsLen ); + +/*! + * \brief Counts the number of bits in a mask. + * + * \param [IN] mask A mask from which the function counts the active bits. + * \param [IN] nbBits The number of bits to check. + * + * \retval Number of enabled bits in the mask. + */ +static uint8_t CountBits( uint16_t mask, uint8_t nbBits ); + +#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) +/*! + * \brief Counts the number of enabled 125 kHz channels in the channel mask. + * This function can only be applied to US915 band. + * + * \param [IN] channelsMask Pointer to the first element of the channel mask + * + * \retval Number of enabled channels in the channel mask + */ +static uint8_t CountNbEnabled125kHzChannels( uint16_t *channelsMask ); + +#if defined( USE_BAND_915_HYBRID ) +/*! + * \brief Validates the correctness of the channel mask for US915, hybrid mode. + * + * \param [IN] mask Block definition to set. + * \param [OUT] channelsMask Pointer to the first element of the channel mask + */ +static void ReenableChannels( uint16_t mask, uint16_t* channelsMask ); + +/*! + * \brief Validates the correctness of the channel mask for US915, hybrid mode. + * + * \param [IN] channelsMask Pointer to the first element of the channel mask + * + * \retval [true: channel mask correct, false: channel mask not correct] + */ +static bool ValidateChannelMask( uint16_t* channelsMask ); +#endif + +#endif + +/*! + * \brief Validates the correctness of the datarate against the enable channels. + * + * \param [IN] datarate Datarate to be check + * \param [IN] channelsMask Pointer to the first element of the channel mask + * + * \retval [true: datarate can be used, false: datarate can not be used] + */ +static bool ValidateDatarate( int8_t datarate, uint16_t* channelsMask ); + +/*! + * \brief Limits the Tx power according to the number of enabled channels + * + * \param [IN] txPower txPower to limit + * \param [IN] maxBandTxPower Maximum band allowed TxPower + * + * \retval Returns the maximum valid tx power + */ +static int8_t LimitTxPower( int8_t txPower, int8_t maxBandTxPower ); + +/*! + * \brief Verifies, if a value is in a given range. + * + * \param value Value to verify, if it is in range + * + * \param min Minimum possible value + * + * \param max Maximum possible value + * + * \retval Returns the maximum valid tx power + */ +static bool ValueInRange( int8_t value, int8_t min, int8_t max ); + +/*! + * \brief Calculates the next datarate to set, when ADR is on or off + * + * \param [IN] adrEnabled Specify whether ADR is on or off + * + * \param [IN] updateChannelMask Set to true, if the channel masks shall be updated + * + * \param [OUT] datarateOut Reports the datarate which will be used next + * + * \retval Returns the state of ADR ack request + */ +static bool AdrNextDr( bool adrEnabled, bool updateChannelMask, int8_t* datarateOut ); + +/*! + * \brief Disables channel in a specified channel mask + * + * \param [IN] id - Id of the channel + * + * \param [IN] mask - Pointer to the channel mask to edit + * + * \retval [true, if disable was successful, false if not] + */ +static bool DisableChannelInMask( uint8_t id, uint16_t* mask ); + +/*! + * \brief Decodes MAC commands in the fOpts field and in the payload + */ +static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, uint8_t snr ); + +/*! + * \brief LoRaMAC layer generic send frame + * + * \param [IN] macHdr MAC header field + * \param [IN] fPort MAC payload port + * \param [IN] fBuffer MAC data buffer to be sent + * \param [IN] fBufferSize MAC data buffer size + * \retval status Status of the operation. + */ +LoRaMacStatus_t Send( LoRaMacHeader_t *macHdr, uint8_t fPort, void *fBuffer, uint16_t fBufferSize ); + +/*! + * \brief LoRaMAC layer frame buffer initialization + * + * \param [IN] macHdr MAC header field + * \param [IN] fCtrl MAC frame control field + * \param [IN] fOpts MAC commands buffer + * \param [IN] fPort MAC payload port + * \param [IN] fBuffer MAC data buffer to be sent + * \param [IN] fBufferSize MAC data buffer size + * \retval status Status of the operation. + */ +LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort, void *fBuffer, uint16_t fBufferSize ); + +/* + * \brief Schedules the frame according to the duty cycle + * + * \retval Status of the operation + */ +static LoRaMacStatus_t ScheduleTx( void ); + +/* + * \brief Sets the duty cycle for the join procedure. + * + * \retval Duty cycle + */ +static uint16_t JoinDutyCycle( void ); + +/* + * \brief Calculates the back-off time for the band of a channel. + * + * \param [IN] channel The last Tx channel index + */ +static void CalculateBackOff( uint8_t channel ); + +/* + * \brief Alternates the datarate of the channel for the join request. + * + * \param [IN] nbTrials Number of performed join requests. + * \retval Datarate to apply + */ +static int8_t AlternateDatarate( uint16_t nbTrials ); + +/*! + * \brief LoRaMAC layer prepared frame buffer transmission with channel specification + * + * \remark PrepareFrame must be called at least once before calling this + * function. + * + * \param [IN] channel Channel parameters + * \retval status Status of the operation. + */ +LoRaMacStatus_t SendFrameOnChannel( ChannelParams_t channel ); + +/*! + * \brief Sets the radio in continuous transmission mode + * + * \remark Uses the radio parameters set on the previous transmission. + * + * \param [IN] timeout Time in seconds while the radio is kept in continuous wave mode + * \retval status Status of the operation. + */ +LoRaMacStatus_t SetTxContinuousWave( uint16_t timeout ); + +/*! + * \brief Sets the radio in continuous transmission mode + * + * \remark Uses the radio parameters set on the previous transmission. + * + * \param [IN] timeout Time in seconds while the radio is kept in continuous wave mode + * \param [IN] frequency RF frequency to be set. + * \param [IN] power RF ouptput power to be set. + * \retval status Status of the operation. + */ +LoRaMacStatus_t SetTxContinuousWave1( uint16_t timeout, uint32_t frequency, uint8_t power ); + +/*! + * \brief Resets MAC specific parameters to default + */ +static void ResetMacParameters( void ); + +/* + * Rx window precise timing + * + * For more details please consult the following document, chapter 3.1.2. + * http://www.semtech.com/images/datasheet/SX1272_settings_for_LoRaWAN_v2.0.pdf + * or + * http://www.semtech.com/images/datasheet/SX1276_settings_for_LoRaWAN_v2.0.pdf + * + * Downlink start: T = Tx + 1s (+/- 20 us) + * | + * TRxEarly | TRxLate + * | | | + * | | +---+---+---+---+---+---+---+---+ + * | | | Latest Rx window | + * | | +---+---+---+---+---+---+---+---+ + * | | | + * +---+---+---+---+---+---+---+---+ + * | Earliest Rx window | + * +---+---+---+---+---+---+---+---+ + * | + * +---+---+---+---+---+---+---+---+ + *Downlink preamble 8 symbols | | | | | | | | | + * +---+---+---+---+---+---+---+---+ + * + * Worst case Rx window timings + * + * TRxLate = DEFAULT_MIN_RX_SYMBOLS * tSymbol - RADIO_WAKEUP_TIME + * TRxEarly = 8 - DEFAULT_MIN_RX_SYMBOLS * tSymbol - RxWindowTimeout - RADIO_WAKEUP_TIME + * + * TRxLate - TRxEarly = 2 * DEFAULT_SYSTEM_MAX_RX_ERROR + * + * RxOffset = ( TRxLate + TRxEarly ) / 2 + * + * RxWindowTimeout = ( 2 * DEFAULT_MIN_RX_SYMBOLS - 8 ) * tSymbol + 2 * DEFAULT_SYSTEM_MAX_RX_ERROR + * RxOffset = 4 * tSymbol - RxWindowTimeout / 2 - RADIO_WAKE_UP_TIME + * + * Minimal value of RxWindowTimeout must be 5 symbols which implies that the system always tolerates at least an error of 1.5 * tSymbol + */ +/*! + * Computes the Rx window parameters. + * + * \param [IN] datarate Rx window datarate to be used + * \param [IN] rxError Maximum timing error of the receiver. in milliseconds + * The receiver will turn on in a [-rxError : +rxError] ms + * interval around RxOffset + * + * \retval rxConfigParams Returns a RxConfigParams_t structure. + */ +static RxConfigParams_t ComputeRxWindowParameters( int8_t datarate, uint32_t rxError ); + +static void OnRadioTxDone( void ) +{ + TimerTime_t curTime = TimerGetCurrentTime( ); + + if( LoRaMacDeviceClass != CLASS_C ) + { + Radio.Sleep( ); + } + else + { + OnRxWindow2TimerEvent( ); + } + + // Setup timers + if( IsRxWindowsEnabled == true ) + { + TimerSetValue( &RxWindowTimer1, RxWindow1Delay ); + TimerStart( &RxWindowTimer1 ); + if( LoRaMacDeviceClass != CLASS_C ) + { + TimerSetValue( &RxWindowTimer2, RxWindow2Delay ); + TimerStart( &RxWindowTimer2 ); + } + if( ( LoRaMacDeviceClass == CLASS_C ) || ( NodeAckRequested == true ) ) + { + TimerSetValue( &AckTimeoutTimer, RxWindow2Delay + ACK_TIMEOUT + + randr( -ACK_TIMEOUT_RND, ACK_TIMEOUT_RND ) ); + TimerStart( &AckTimeoutTimer ); + } + } + else + { + McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK; + MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT; + + if( LoRaMacFlags.Value == 0 ) + { + LoRaMacFlags.Bits.McpsReq = 1; + } + LoRaMacFlags.Bits.MacDone = 1; + } + + // Update last tx done time for the current channel + Bands[Channels[Channel].Band].LastTxDoneTime = curTime; + // Update Aggregated last tx done time + AggregatedLastTxDoneTime = curTime; + // Update Backoff + CalculateBackOff( Channel ); + + if( NodeAckRequested == false ) + { + McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK; + ChannelsNbRepCounter++; + } +} + +static void PrepareRxDoneAbort( void ) +{ + LoRaMacState |= LORAMAC_RX_ABORT; + + if( NodeAckRequested ) + { + OnAckTimeoutTimerEvent( ); + } + + LoRaMacFlags.Bits.McpsInd = 1; + LoRaMacFlags.Bits.MacDone = 1; + + // Trig OnMacCheckTimerEvent call as soon as possible + TimerSetValue( &MacStateCheckTimer, 1 ); + TimerStart( &MacStateCheckTimer ); +} + +static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ) +{ + LoRaMacHeader_t macHdr; + LoRaMacFrameCtrl_t fCtrl; + bool skipIndication = false; + + uint8_t pktHeaderLen = 0; + uint32_t address = 0; + uint8_t appPayloadStartIndex = 0; + uint8_t port = 0xFF; + uint8_t frameLen = 0; + uint32_t mic = 0; + uint32_t micRx = 0; + + uint16_t sequenceCounter = 0; + uint16_t sequenceCounterPrev = 0; + uint16_t sequenceCounterDiff = 0; + uint32_t downLinkCounter = 0; + + MulticastParams_t *curMulticastParams = NULL; + uint8_t *nwkSKey = LoRaMacNwkSKey; + uint8_t *appSKey = LoRaMacAppSKey; + + uint8_t multicast = 0; + + bool isMicOk = false; + + McpsConfirm.AckReceived = false; + McpsIndication.Rssi = rssi; + McpsIndication.Snr = snr; + McpsIndication.RxSlot = RxSlot; + McpsIndication.Port = 0; + McpsIndication.Multicast = 0; + McpsIndication.FramePending = 0; + McpsIndication.Buffer = NULL; + McpsIndication.BufferSize = 0; + McpsIndication.RxData = false; + McpsIndication.AckReceived = false; + McpsIndication.DownLinkCounter = 0; + McpsIndication.McpsIndication = MCPS_UNCONFIRMED; + + Radio.Sleep( ); + TimerStop( &RxWindowTimer2 ); + + macHdr.Value = payload[pktHeaderLen++]; + + switch( macHdr.Bits.MType ) + { + case FRAME_TYPE_JOIN_ACCEPT: + if( IsLoRaMacNetworkJoined == true ) + { + McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR; + PrepareRxDoneAbort( ); + return; + } + LoRaMacJoinDecrypt( payload + 1, size - 1, LoRaMacAppKey, LoRaMacRxPayload + 1 ); + + LoRaMacRxPayload[0] = macHdr.Value; + + LoRaMacJoinComputeMic( LoRaMacRxPayload, size - LORAMAC_MFR_LEN, LoRaMacAppKey, &mic ); + + micRx |= ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN]; + micRx |= ( ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 1] << 8 ); + micRx |= ( ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 2] << 16 ); + micRx |= ( ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 3] << 24 ); + + if( micRx == mic ) + { + LoRaMacJoinComputeSKeys( LoRaMacAppKey, LoRaMacRxPayload + 1, LoRaMacDevNonce, LoRaMacNwkSKey, LoRaMacAppSKey ); + + LoRaMacNetID = ( uint32_t )LoRaMacRxPayload[4]; + LoRaMacNetID |= ( ( uint32_t )LoRaMacRxPayload[5] << 8 ); + LoRaMacNetID |= ( ( uint32_t )LoRaMacRxPayload[6] << 16 ); + + LoRaMacDevAddr = ( uint32_t )LoRaMacRxPayload[7]; + LoRaMacDevAddr |= ( ( uint32_t )LoRaMacRxPayload[8] << 8 ); + LoRaMacDevAddr |= ( ( uint32_t )LoRaMacRxPayload[9] << 16 ); + LoRaMacDevAddr |= ( ( uint32_t )LoRaMacRxPayload[10] << 24 ); + + // DLSettings + LoRaMacParams.Rx1DrOffset = ( LoRaMacRxPayload[11] >> 4 ) & 0x07; + LoRaMacParams.Rx2Channel.Datarate = LoRaMacRxPayload[11] & 0x0F; + + // RxDelay + LoRaMacParams.ReceiveDelay1 = ( LoRaMacRxPayload[12] & 0x0F ); + if( LoRaMacParams.ReceiveDelay1 == 0 ) + { + LoRaMacParams.ReceiveDelay1 = 1; + } + LoRaMacParams.ReceiveDelay1 *= 1e3; + LoRaMacParams.ReceiveDelay2 = LoRaMacParams.ReceiveDelay1 + 1e3; + +#if !( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) + //CFList + if( ( size - 1 ) > 16 ) + { + ChannelParams_t param; + param.DrRange.Value = ( DR_5 << 4 ) | DR_0; + + LoRaMacState |= LORAMAC_TX_CONFIG; + for( uint8_t i = 3, j = 0; i < ( 5 + 3 ); i++, j += 3 ) + { + param.Frequency = ( ( uint32_t )LoRaMacRxPayload[13 + j] | ( ( uint32_t )LoRaMacRxPayload[14 + j] << 8 ) | ( ( uint32_t )LoRaMacRxPayload[15 + j] << 16 ) ) * 100; + if( param.Frequency != 0 ) + { + LoRaMacChannelAdd( i, param ); + } + else + { + LoRaMacChannelRemove( i ); + } + } + LoRaMacState &= ~LORAMAC_TX_CONFIG; + } +#endif + MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK; + IsLoRaMacNetworkJoined = true; + LoRaMacParams.ChannelsDatarate = LoRaMacParamsDefaults.ChannelsDatarate; + } + else + { + MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL; + } + break; + case FRAME_TYPE_DATA_CONFIRMED_DOWN: + case FRAME_TYPE_DATA_UNCONFIRMED_DOWN: + { + address = payload[pktHeaderLen++]; + address |= ( (uint32_t)payload[pktHeaderLen++] << 8 ); + address |= ( (uint32_t)payload[pktHeaderLen++] << 16 ); + address |= ( (uint32_t)payload[pktHeaderLen++] << 24 ); + + if( address != LoRaMacDevAddr ) + { + curMulticastParams = MulticastChannels; + while( curMulticastParams != NULL ) + { + if( address == curMulticastParams->Address ) + { + multicast = 1; + nwkSKey = curMulticastParams->NwkSKey; + appSKey = curMulticastParams->AppSKey; + downLinkCounter = curMulticastParams->DownLinkCounter; + break; + } + curMulticastParams = curMulticastParams->Next; + } + if( multicast == 0 ) + { + // We are not the destination of this frame. + McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL; + PrepareRxDoneAbort( ); + return; + } + } + else + { + multicast = 0; + nwkSKey = LoRaMacNwkSKey; + appSKey = LoRaMacAppSKey; + downLinkCounter = DownLinkCounter; + } + + fCtrl.Value = payload[pktHeaderLen++]; + + sequenceCounter = ( uint16_t )payload[pktHeaderLen++]; + sequenceCounter |= ( uint16_t )payload[pktHeaderLen++] << 8; + + appPayloadStartIndex = 8 + fCtrl.Bits.FOptsLen; + + micRx |= ( uint32_t )payload[size - LORAMAC_MFR_LEN]; + micRx |= ( ( uint32_t )payload[size - LORAMAC_MFR_LEN + 1] << 8 ); + micRx |= ( ( uint32_t )payload[size - LORAMAC_MFR_LEN + 2] << 16 ); + micRx |= ( ( uint32_t )payload[size - LORAMAC_MFR_LEN + 3] << 24 ); + + sequenceCounterPrev = ( uint16_t )downLinkCounter; + sequenceCounterDiff = ( sequenceCounter - sequenceCounterPrev ); + + if( sequenceCounterDiff < ( 1 << 15 ) ) + { + downLinkCounter += sequenceCounterDiff; + LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounter, &mic ); + if( micRx == mic ) + { + isMicOk = true; + } + } + else + { + // check for sequence roll-over + uint32_t downLinkCounterTmp = downLinkCounter + 0x10000 + ( int16_t )sequenceCounterDiff; + LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounterTmp, &mic ); + if( micRx == mic ) + { + isMicOk = true; + downLinkCounter = downLinkCounterTmp; + } + } + + // Check for a the maximum allowed counter difference + if( sequenceCounterDiff >= MAX_FCNT_GAP ) + { + McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS; + McpsIndication.DownLinkCounter = downLinkCounter; + PrepareRxDoneAbort( ); + return; + } + + if( isMicOk == true ) + { + McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK; + McpsIndication.Multicast = multicast; + McpsIndication.FramePending = fCtrl.Bits.FPending; + McpsIndication.Buffer = NULL; + McpsIndication.BufferSize = 0; + McpsIndication.DownLinkCounter = downLinkCounter; + + McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK; + + AdrAckCounter = 0; + MacCommandsBufferToRepeatIndex = 0; + + // Update 32 bits downlink counter + if( multicast == 1 ) + { + McpsIndication.McpsIndication = MCPS_MULTICAST; + + if( ( curMulticastParams->DownLinkCounter == downLinkCounter ) && + ( curMulticastParams->DownLinkCounter != 0 ) ) + { + McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED; + McpsIndication.DownLinkCounter = downLinkCounter; + PrepareRxDoneAbort( ); + return; + } + curMulticastParams->DownLinkCounter = downLinkCounter; + } + else + { + if( macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_DOWN ) + { + SrvAckRequested = true; + McpsIndication.McpsIndication = MCPS_CONFIRMED; + + if( ( DownLinkCounter == downLinkCounter ) && + ( DownLinkCounter != 0 ) ) + { + // Duplicated confirmed downlink. Skip indication. + // In this case, the MAC layer shall accept the MAC commands + // which are included in the downlink retransmission. + // It should not provide the same frame to the application + // layer again. + skipIndication = true; + } + } + else + { + SrvAckRequested = false; + McpsIndication.McpsIndication = MCPS_UNCONFIRMED; + + if( ( DownLinkCounter == downLinkCounter ) && + ( DownLinkCounter != 0 ) ) + { + McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED; + McpsIndication.DownLinkCounter = downLinkCounter; + PrepareRxDoneAbort( ); + return; + } + } + DownLinkCounter = downLinkCounter; + } + + // This must be done before parsing the payload and the MAC commands. + // We need to reset the MacCommandsBufferIndex here, since we need + // to take retransmissions and repititions into account. Error cases + // will be handled in function OnMacStateCheckTimerEvent. + if( McpsConfirm.McpsRequest == MCPS_CONFIRMED ) + { + if( fCtrl.Bits.Ack == 1 ) + {// Reset MacCommandsBufferIndex when we have received an ACK. + MacCommandsBufferIndex = 0; + } + } + else + {// Reset the variable if we have received any valid frame. + MacCommandsBufferIndex = 0; + } + + // Process payload and MAC commands + if( ( ( size - 4 ) - appPayloadStartIndex ) > 0 ) + { + port = payload[appPayloadStartIndex++]; + frameLen = ( size - 4 ) - appPayloadStartIndex; + + McpsIndication.Port = port; + + if( port == 0 ) + { + // Only allow frames which do not have fOpts + if( fCtrl.Bits.FOptsLen == 0 ) + { + LoRaMacPayloadDecrypt( payload + appPayloadStartIndex, + frameLen, + nwkSKey, + address, + DOWN_LINK, + downLinkCounter, + LoRaMacRxPayload ); + + // Decode frame payload MAC commands + ProcessMacCommands( LoRaMacRxPayload, 0, frameLen, snr ); + } + else + { + skipIndication = true; + } + } + else + { + if( fCtrl.Bits.FOptsLen > 0 ) + { + // Decode Options field MAC commands. Omit the fPort. + ProcessMacCommands( payload, 8, appPayloadStartIndex - 1, snr ); + } + + LoRaMacPayloadDecrypt( payload + appPayloadStartIndex, + frameLen, + appSKey, + address, + DOWN_LINK, + downLinkCounter, + LoRaMacRxPayload ); + + if( skipIndication == false ) + { + McpsIndication.Buffer = LoRaMacRxPayload; + McpsIndication.BufferSize = frameLen; + McpsIndication.RxData = true; + } + } + } + else + { + if( fCtrl.Bits.FOptsLen > 0 ) + { + // Decode Options field MAC commands + ProcessMacCommands( payload, 8, appPayloadStartIndex, snr ); + } + } + + if( skipIndication == false ) + { + // Check if the frame is an acknowledgement + if( fCtrl.Bits.Ack == 1 ) + { + McpsConfirm.AckReceived = true; + McpsIndication.AckReceived = true; + + // Stop the AckTimeout timer as no more retransmissions + // are needed. + TimerStop( &AckTimeoutTimer ); + } + else + { + McpsConfirm.AckReceived = false; + + if( AckTimeoutRetriesCounter > AckTimeoutRetries ) + { + // Stop the AckTimeout timer as no more retransmissions + // are needed. + TimerStop( &AckTimeoutTimer ); + } + } + } + // Provide always an indication, skip the callback to the user application, + // in case of a confirmed downlink retransmission. + LoRaMacFlags.Bits.McpsInd = 1; + LoRaMacFlags.Bits.McpsIndSkip = skipIndication; + } + else + { + McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL; + + PrepareRxDoneAbort( ); + return; + } + } + break; + case FRAME_TYPE_PROPRIETARY: + { + memcpy1( LoRaMacRxPayload, &payload[pktHeaderLen], size ); + + McpsIndication.McpsIndication = MCPS_PROPRIETARY; + McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK; + McpsIndication.Buffer = LoRaMacRxPayload; + McpsIndication.BufferSize = size - pktHeaderLen; + + LoRaMacFlags.Bits.McpsInd = 1; + break; + } + default: + McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR; + PrepareRxDoneAbort( ); + break; + } + LoRaMacFlags.Bits.MacDone = 1; + + // Trig OnMacCheckTimerEvent call as soon as possible + TimerSetValue( &MacStateCheckTimer, 1 ); + TimerStart( &MacStateCheckTimer ); +} + +static void OnRadioTxTimeout( void ) +{ + if( LoRaMacDeviceClass != CLASS_C ) + { + Radio.Sleep( ); + } + else + { + OnRxWindow2TimerEvent( ); + } + + McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; + MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT; + LoRaMacFlags.Bits.MacDone = 1; +} + +static void OnRadioRxError( void ) +{ + if( LoRaMacDeviceClass != CLASS_C ) + { + Radio.Sleep( ); + } + else + { + OnRxWindow2TimerEvent( ); + } + + if( RxSlot == 0 ) + { + if( NodeAckRequested == true ) + { + McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX1_ERROR; + } + MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX1_ERROR; + + if( TimerGetElapsedTime( AggregatedLastTxDoneTime ) >= RxWindow2Delay ) + { + LoRaMacFlags.Bits.MacDone = 1; + } + } + else + { + if( NodeAckRequested == true ) + { + McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR; + } + MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_ERROR; + LoRaMacFlags.Bits.MacDone = 1; + } +} + +static void OnRadioRxTimeout( void ) +{ + if( LoRaMacDeviceClass != CLASS_C ) + { + Radio.Sleep( ); + } + else + { + OnRxWindow2TimerEvent( ); + } + + if( RxSlot == 1 ) + { + if( NodeAckRequested == true ) + { + McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT; + } + MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT; + LoRaMacFlags.Bits.MacDone = 1; + } +} + +static void OnMacStateCheckTimerEvent( void ) +{ + TimerStop( &MacStateCheckTimer ); + bool txTimeout = false; + + if( LoRaMacFlags.Bits.MacDone == 1 ) + { + if( ( LoRaMacState & LORAMAC_RX_ABORT ) == LORAMAC_RX_ABORT ) + { + LoRaMacState &= ~LORAMAC_RX_ABORT; + LoRaMacState &= ~LORAMAC_TX_RUNNING; + } + + if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) || ( ( LoRaMacFlags.Bits.McpsReq == 1 ) ) ) + { + if( ( McpsConfirm.Status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT ) || + ( MlmeConfirm.Status == LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT ) ) + { + // Stop transmit cycle due to tx timeout. + LoRaMacState &= ~LORAMAC_TX_RUNNING; + MacCommandsBufferIndex = 0; + McpsConfirm.NbRetries = AckTimeoutRetriesCounter; + McpsConfirm.AckReceived = false; + McpsConfirm.TxTimeOnAir = 0; + txTimeout = true; + } + } + + if( ( NodeAckRequested == false ) && ( txTimeout == false ) ) + { + if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) || ( ( LoRaMacFlags.Bits.McpsReq == 1 ) ) ) + { + if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) && ( MlmeConfirm.MlmeRequest == MLME_JOIN ) ) + {// Procedure for the join request + MlmeConfirm.NbRetries = JoinRequestTrials; + + if( MlmeConfirm.Status == LORAMAC_EVENT_INFO_STATUS_OK ) + {// Node joined successfully + UpLinkCounter = 0; + ChannelsNbRepCounter = 0; + LoRaMacState &= ~LORAMAC_TX_RUNNING; + } + else + { + if( JoinRequestTrials >= MaxJoinRequestTrials ) + { + LoRaMacState &= ~LORAMAC_TX_RUNNING; + } + else + { + LoRaMacFlags.Bits.MacDone = 0; + // Sends the same frame again + OnTxDelayedTimerEvent( ); + } + } + } + else + {// Procedure for all other frames + if( ( ChannelsNbRepCounter >= LoRaMacParams.ChannelsNbRep ) || ( LoRaMacFlags.Bits.McpsInd == 1 ) ) + { + if( LoRaMacFlags.Bits.McpsInd == 0 ) + { // Maximum repititions without downlink. Reset MacCommandsBufferIndex. Increase ADR Ack counter. + // Only process the case when the MAC did not receive a downlink. + MacCommandsBufferIndex = 0; + AdrAckCounter++; + } + + ChannelsNbRepCounter = 0; + + if( IsUpLinkCounterFixed == false ) + { + UpLinkCounter++; + } + + LoRaMacState &= ~LORAMAC_TX_RUNNING; + } + else + { + LoRaMacFlags.Bits.MacDone = 0; + // Sends the same frame again + OnTxDelayedTimerEvent( ); + } + } + } + } + + if( LoRaMacFlags.Bits.McpsInd == 1 ) + {// Procedure if we received a frame + if( ( McpsConfirm.AckReceived == true ) || ( AckTimeoutRetriesCounter > AckTimeoutRetries ) ) + { + AckTimeoutRetry = false; + NodeAckRequested = false; + if( IsUpLinkCounterFixed == false ) + { + UpLinkCounter++; + } + McpsConfirm.NbRetries = AckTimeoutRetriesCounter; + + LoRaMacState &= ~LORAMAC_TX_RUNNING; + } + } + + if( ( AckTimeoutRetry == true ) && ( ( LoRaMacState & LORAMAC_TX_DELAYED ) == 0 ) ) + {// Retransmissions procedure for confirmed uplinks + AckTimeoutRetry = false; + if( ( AckTimeoutRetriesCounter < AckTimeoutRetries ) && ( AckTimeoutRetriesCounter <= MAX_ACK_RETRIES ) ) + { + AckTimeoutRetriesCounter++; + + if( ( AckTimeoutRetriesCounter % 2 ) == 1 ) + { + LoRaMacParams.ChannelsDatarate = MAX( LoRaMacParams.ChannelsDatarate - 1, LORAMAC_TX_MIN_DATARATE ); + } + // Try to send the frame again + if( ScheduleTx( ) == LORAMAC_STATUS_OK ) + { + LoRaMacFlags.Bits.MacDone = 0; + } + else + { + // The DR is not applicable for the payload size + McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR; + + MacCommandsBufferIndex = 0; + LoRaMacState &= ~LORAMAC_TX_RUNNING; + NodeAckRequested = false; + McpsConfirm.AckReceived = false; + McpsConfirm.NbRetries = AckTimeoutRetriesCounter; + McpsConfirm.Datarate = LoRaMacParams.ChannelsDatarate; + if( IsUpLinkCounterFixed == false ) + { + UpLinkCounter++; + } + } + } + else + { +#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) + // Re-enable default channels LC1, LC2, LC3 + LoRaMacParams.ChannelsMask[0] = LoRaMacParams.ChannelsMask[0] | ( LC( 1 ) + LC( 2 ) + LC( 3 ) ); +#elif defined( USE_BAND_470 ) + // Re-enable default channels + memcpy1( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) ); +#elif defined( USE_BAND_915 ) + // Re-enable default channels + memcpy1( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) ); +#elif defined( USE_BAND_915_HYBRID ) + // Re-enable default channels + ReenableChannels( LoRaMacParamsDefaults.ChannelsMask[4], LoRaMacParams.ChannelsMask ); +#else + #error "Please define a frequency band in the compiler options." +#endif + LoRaMacState &= ~LORAMAC_TX_RUNNING; + + MacCommandsBufferIndex = 0; + NodeAckRequested = false; + McpsConfirm.AckReceived = false; + McpsConfirm.NbRetries = AckTimeoutRetriesCounter; + if( IsUpLinkCounterFixed == false ) + { + UpLinkCounter++; + } + } + } + } + // Handle reception for Class B and Class C + if( ( LoRaMacState & LORAMAC_RX ) == LORAMAC_RX ) + { + LoRaMacState &= ~LORAMAC_RX; + } + if( LoRaMacState == LORAMAC_IDLE ) + { + if( LoRaMacFlags.Bits.McpsReq == 1 ) + { + LoRaMacPrimitives->MacMcpsConfirm( &McpsConfirm ); + LoRaMacFlags.Bits.McpsReq = 0; + } + + if( LoRaMacFlags.Bits.MlmeReq == 1 ) + { + LoRaMacPrimitives->MacMlmeConfirm( &MlmeConfirm ); + LoRaMacFlags.Bits.MlmeReq = 0; + } + + // Procedure done. Reset variables. + LoRaMacFlags.Bits.MacDone = 0; + } + else + { + // Operation not finished restart timer + TimerSetValue( &MacStateCheckTimer, MAC_STATE_CHECK_TIMEOUT ); + TimerStart( &MacStateCheckTimer ); + } + + if( LoRaMacFlags.Bits.McpsInd == 1 ) + { + if( LoRaMacDeviceClass == CLASS_C ) + {// Activate RX2 window for Class C + OnRxWindow2TimerEvent( ); + } + if( LoRaMacFlags.Bits.McpsIndSkip == 0 ) + { + LoRaMacPrimitives->MacMcpsIndication( &McpsIndication ); + } + LoRaMacFlags.Bits.McpsIndSkip = 0; + LoRaMacFlags.Bits.McpsInd = 0; + } +} + +static void OnTxDelayedTimerEvent( void ) +{ + LoRaMacHeader_t macHdr; + LoRaMacFrameCtrl_t fCtrl; + + TimerStop( &TxDelayedTimer ); + LoRaMacState &= ~LORAMAC_TX_DELAYED; + + if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) && ( MlmeConfirm.MlmeRequest == MLME_JOIN ) ) + { + ResetMacParameters( ); + // Add a +1, since we start to count from 0 + LoRaMacParams.ChannelsDatarate = AlternateDatarate( JoinRequestTrials + 1 ); + + macHdr.Value = 0; + macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ; + + fCtrl.Value = 0; + fCtrl.Bits.Adr = AdrCtrlOn; + + /* In case of join request retransmissions, the stack must prepare + * the frame again, because the network server keeps track of the random + * LoRaMacDevNonce values to prevent reply attacks. */ + PrepareFrame( &macHdr, &fCtrl, 0, NULL, 0 ); + } + + ScheduleTx( ); +} + +static void OnRxWindow1TimerEvent( void ) +{ + TimerStop( &RxWindowTimer1 ); + RxSlot = 0; + + if( LoRaMacDeviceClass == CLASS_C ) + { + Radio.Standby( ); + } + +#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) + RxWindowSetup( Channels[Channel].Frequency, RxWindowsParams[0].Datarate, RxWindowsParams[0].Bandwidth, RxWindowsParams[0].RxWindowTimeout, false ); +#elif defined( USE_BAND_470 ) + RxWindowSetup( LORAMAC_FIRST_RX1_CHANNEL + ( Channel % 48 ) * LORAMAC_STEPWIDTH_RX1_CHANNEL, RxWindowsParams[0].Datarate, RxWindowsParams[0].Bandwidth, RxWindowsParams[0].RxWindowTimeout, false ); +#elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) + RxWindowSetup( LORAMAC_FIRST_RX1_CHANNEL + ( Channel % 8 ) * LORAMAC_STEPWIDTH_RX1_CHANNEL, RxWindowsParams[0].Datarate, RxWindowsParams[0].Bandwidth, RxWindowsParams[0].RxWindowTimeout, false ); +#else + #error "Please define a frequency band in the compiler options." +#endif +} + +static void OnRxWindow2TimerEvent( void ) +{ + bool rxContinuousMode = false; + + TimerStop( &RxWindowTimer2 ); + + if( LoRaMacDeviceClass == CLASS_C ) + { + rxContinuousMode = true; + } + if( RxWindowSetup( LoRaMacParams.Rx2Channel.Frequency, RxWindowsParams[1].Datarate, RxWindowsParams[1].Bandwidth, RxWindowsParams[1].RxWindowTimeout, rxContinuousMode ) == true ) + { + RxSlot = 1; + } +} + +static void OnAckTimeoutTimerEvent( void ) +{ + TimerStop( &AckTimeoutTimer ); + + if( NodeAckRequested == true ) + { + AckTimeoutRetry = true; + LoRaMacState &= ~LORAMAC_ACK_REQ; + } + if( LoRaMacDeviceClass == CLASS_C ) + { + LoRaMacFlags.Bits.MacDone = 1; + } +} + +static bool SetNextChannel( TimerTime_t* time ) +{ + uint8_t nbEnabledChannels = 0; + uint8_t delayTx = 0; + uint8_t enabledChannels[LORA_MAX_NB_CHANNELS]; + TimerTime_t nextTxDelay = ( TimerTime_t )( -1 ); + + memset1( enabledChannels, 0, LORA_MAX_NB_CHANNELS ); + +#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) + if( CountNbEnabled125kHzChannels( ChannelsMaskRemaining ) == 0 ) + { // Restore default channels + memcpy1( ( uint8_t* ) ChannelsMaskRemaining, ( uint8_t* ) LoRaMacParams.ChannelsMask, 8 ); + } + if( ( LoRaMacParams.ChannelsDatarate >= DR_4 ) && ( ( ChannelsMaskRemaining[4] & 0x00FF ) == 0 ) ) + { // Make sure, that the channels are activated + ChannelsMaskRemaining[4] = LoRaMacParams.ChannelsMask[4]; + } +#elif defined( USE_BAND_470 ) + if( ( CountBits( LoRaMacParams.ChannelsMask[0], 16 ) == 0 ) && + ( CountBits( LoRaMacParams.ChannelsMask[1], 16 ) == 0 ) && + ( CountBits( LoRaMacParams.ChannelsMask[2], 16 ) == 0 ) && + ( CountBits( LoRaMacParams.ChannelsMask[3], 16 ) == 0 ) && + ( CountBits( LoRaMacParams.ChannelsMask[4], 16 ) == 0 ) && + ( CountBits( LoRaMacParams.ChannelsMask[5], 16 ) == 0 ) ) + { + memcpy1( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) ); + } +#else + if( CountBits( LoRaMacParams.ChannelsMask[0], 16 ) == 0 ) + { + // Re-enable default channels, if no channel is enabled + LoRaMacParams.ChannelsMask[0] = LoRaMacParams.ChannelsMask[0] | ( LC( 1 ) + LC( 2 ) + LC( 3 ) ); + } +#endif + + // Update Aggregated duty cycle + if( AggregatedTimeOff <= TimerGetElapsedTime( AggregatedLastTxDoneTime ) ) + { + AggregatedTimeOff = 0; + + // Update bands Time OFF + for( uint8_t i = 0; i < LORA_MAX_NB_BANDS; i++ ) + { + if( ( IsLoRaMacNetworkJoined == false ) || ( DutyCycleOn == true ) ) + { + if( Bands[i].TimeOff <= TimerGetElapsedTime( Bands[i].LastTxDoneTime ) ) + { + Bands[i].TimeOff = 0; + } + if( Bands[i].TimeOff != 0 ) + { + nextTxDelay = MIN( Bands[i].TimeOff - TimerGetElapsedTime( Bands[i].LastTxDoneTime ), nextTxDelay ); + } + } + else + { + if( DutyCycleOn == false ) + { + Bands[i].TimeOff = 0; + } + } + } + + // Search how many channels are enabled + for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS; i += 16, k++ ) + { + for( uint8_t j = 0; j < 16; j++ ) + { +#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) + if( ( ChannelsMaskRemaining[k] & ( 1 << j ) ) != 0 ) +#else + if( ( LoRaMacParams.ChannelsMask[k] & ( 1 << j ) ) != 0 ) +#endif + { + if( Channels[i + j].Frequency == 0 ) + { // Check if the channel is enabled + continue; + } +#if defined( USE_BAND_868 ) || defined( USE_BAND_433 ) || defined( USE_BAND_780 ) + if( IsLoRaMacNetworkJoined == false ) + { + if( ( JOIN_CHANNELS & ( 1 << j ) ) == 0 ) + { + continue; + } + } +#endif + if( ( ( Channels[i + j].DrRange.Fields.Min <= LoRaMacParams.ChannelsDatarate ) && + ( LoRaMacParams.ChannelsDatarate <= Channels[i + j].DrRange.Fields.Max ) ) == false ) + { // Check if the current channel selection supports the given datarate + continue; + } + if( Bands[Channels[i + j].Band].TimeOff > 0 ) + { // Check if the band is available for transmission + delayTx++; + continue; + } + enabledChannels[nbEnabledChannels++] = i + j; + } + } + } + } + else + { + delayTx++; + nextTxDelay = AggregatedTimeOff - TimerGetElapsedTime( AggregatedLastTxDoneTime ); + } + + if( nbEnabledChannels > 0 ) + { + Channel = enabledChannels[randr( 0, nbEnabledChannels - 1 )]; +#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) + if( Channel < ( LORA_MAX_NB_CHANNELS - 8 ) ) + { + DisableChannelInMask( Channel, ChannelsMaskRemaining ); + } +#endif + *time = 0; + return true; + } + else + { + if( delayTx > 0 ) + { + // Delay transmission due to AggregatedTimeOff or to a band time off + *time = nextTxDelay; + return true; + } + // Datarate not supported by any channel + *time = 0; + return false; + } +} + +static bool RxWindowSetup( uint32_t freq, int8_t datarate, uint32_t bandwidth, uint16_t timeout, bool rxContinuous ) +{ + uint8_t downlinkDatarate = Datarates[datarate]; + RadioModems_t modem; + + if( Radio.GetStatus( ) == RF_IDLE ) + { + Radio.SetChannel( freq ); + + // Store downlink datarate + McpsIndication.RxDatarate = ( uint8_t ) datarate; + +#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) + if( datarate == DR_7 ) + { + modem = MODEM_FSK; + Radio.SetRxConfig( modem, 50e3, downlinkDatarate * 1e3, 0, 83.333e3, 5, timeout, false, 0, true, 0, 0, false, rxContinuous ); + } + else + { + modem = MODEM_LORA; + Radio.SetRxConfig( modem, bandwidth, downlinkDatarate, 1, 0, 8, timeout, false, 0, false, 0, 0, true, rxContinuous ); + } +#elif defined( USE_BAND_470 ) || defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) + modem = MODEM_LORA; + Radio.SetRxConfig( modem, bandwidth, downlinkDatarate, 1, 0, 8, timeout, false, 0, false, 0, 0, true, rxContinuous ); +#endif + + if( RepeaterSupport == true ) + { + Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarateRepeater[datarate] + LORA_MAC_FRMPAYLOAD_OVERHEAD ); + } + else + { + Radio.SetMaxPayloadLength( modem, MaxPayloadOfDatarate[datarate] + LORA_MAC_FRMPAYLOAD_OVERHEAD ); + } + + if( rxContinuous == false ) + { + Radio.Rx( LoRaMacParams.MaxRxWindow ); + } + else + { + Radio.Rx( 0 ); // Continuous mode + } + return true; + } + return false; +} + +static bool Rx2FreqInRange( uint32_t freq ) +{ +#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) + if( Radio.CheckRfFrequency( freq ) == true ) +#elif defined( USE_BAND_470 ) || defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) + if( ( Radio.CheckRfFrequency( freq ) == true ) && + ( freq >= LORAMAC_FIRST_RX1_CHANNEL ) && + ( freq <= LORAMAC_LAST_RX1_CHANNEL ) && + ( ( ( freq - ( uint32_t ) LORAMAC_FIRST_RX1_CHANNEL ) % ( uint32_t ) LORAMAC_STEPWIDTH_RX1_CHANNEL ) == 0 ) ) +#endif + { + return true; + } + return false; +} + +static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate, uint8_t fOptsLen ) +{ + uint16_t maxN = 0; + uint16_t payloadSize = 0; + + // Get the maximum payload length + if( RepeaterSupport == true ) + { + maxN = MaxPayloadOfDatarateRepeater[datarate]; + } + else + { + maxN = MaxPayloadOfDatarate[datarate]; + } + + // Calculate the resulting payload size + payloadSize = ( lenN + fOptsLen ); + + // Validation of the application payload size + if( ( payloadSize <= maxN ) && ( payloadSize <= LORAMAC_PHY_MAXPAYLOAD ) ) + { + return true; + } + return false; +} + +static uint8_t CountBits( uint16_t mask, uint8_t nbBits ) +{ + uint8_t nbActiveBits = 0; + + for( uint8_t j = 0; j < nbBits; j++ ) + { + if( ( mask & ( 1 << j ) ) == ( 1 << j ) ) + { + nbActiveBits++; + } + } + return nbActiveBits; +} + +#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) +static uint8_t CountNbEnabled125kHzChannels( uint16_t *channelsMask ) +{ + uint8_t nb125kHzChannels = 0; + + for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS - 8; i += 16, k++ ) + { + nb125kHzChannels += CountBits( channelsMask[k], 16 ); + } + + return nb125kHzChannels; +} + +#if defined( USE_BAND_915_HYBRID ) +static void ReenableChannels( uint16_t mask, uint16_t* channelsMask ) +{ + uint16_t blockMask = mask; + + for( uint8_t i = 0, j = 0; i < 4; i++, j += 2 ) + { + channelsMask[i] = 0; + if( ( blockMask & ( 1 << j ) ) != 0 ) + { + channelsMask[i] |= 0x00FF; + } + if( ( blockMask & ( 1 << ( j + 1 ) ) ) != 0 ) + { + channelsMask[i] |= 0xFF00; + } + } + channelsMask[4] = blockMask; + channelsMask[5] = 0x0000; +} + +static bool ValidateChannelMask( uint16_t* channelsMask ) +{ + bool chanMaskState = false; + uint16_t block1 = 0; + uint16_t block2 = 0; + uint8_t index = 0; + + for( uint8_t i = 0; i < 4; i++ ) + { + block1 = channelsMask[i] & 0x00FF; + block2 = channelsMask[i] & 0xFF00; + + if( ( CountBits( block1, 16 ) > 5 ) && ( chanMaskState == false ) ) + { + channelsMask[i] &= block1; + channelsMask[4] = 1 << ( i * 2 ); + chanMaskState = true; + index = i; + } + else if( ( CountBits( block2, 16 ) > 5 ) && ( chanMaskState == false ) ) + { + channelsMask[i] &= block2; + channelsMask[4] = 1 << ( i * 2 + 1 ); + chanMaskState = true; + index = i; + } + } + + // Do only change the channel mask, if we have found a valid block. + if( chanMaskState == true ) + { + for( uint8_t i = 0; i < 4; i++ ) + { + if( i != index ) + { + channelsMask[i] = 0; + } + } + } + return chanMaskState; +} +#endif +#endif + +static bool ValidateDatarate( int8_t datarate, uint16_t* channelsMask ) +{ + if( ValueInRange( datarate, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) == false ) + { + return false; + } + for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS; i += 16, k++ ) + { + for( uint8_t j = 0; j < 16; j++ ) + { + if( ( ( channelsMask[k] & ( 1 << j ) ) != 0 ) ) + {// Check datarate validity for enabled channels + if( ValueInRange( datarate, Channels[i + j].DrRange.Fields.Min, Channels[i + j].DrRange.Fields.Max ) == true ) + { + // At least 1 channel has been found we can return OK. + return true; + } + } + } + } + return false; +} + +static int8_t LimitTxPower( int8_t txPower, int8_t maxBandTxPower ) +{ + int8_t resultTxPower = txPower; + + // Limit tx power to the band max + resultTxPower = MAX( txPower, maxBandTxPower ); + +#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) + if( ( LoRaMacParams.ChannelsDatarate == DR_4 ) || + ( ( LoRaMacParams.ChannelsDatarate >= DR_8 ) && ( LoRaMacParams.ChannelsDatarate <= DR_13 ) ) ) + {// Limit tx power to max 26dBm + resultTxPower = MAX( txPower, TX_POWER_26_DBM ); + } + else + { + if( CountNbEnabled125kHzChannels( LoRaMacParams.ChannelsMask ) < 50 ) + {// Limit tx power to max 21dBm + resultTxPower = MAX( txPower, TX_POWER_20_DBM ); + } + } +#endif + return resultTxPower; +} + +static bool ValueInRange( int8_t value, int8_t min, int8_t max ) +{ + if( ( value >= min ) && ( value <= max ) ) + { + return true; + } + return false; +} + +static bool DisableChannelInMask( uint8_t id, uint16_t* mask ) +{ + uint8_t index = 0; + index = id / 16; + + if( ( index > 4 ) || ( id >= LORA_MAX_NB_CHANNELS ) ) + { + return false; + } + + // Deactivate channel + mask[index] &= ~( 1 << ( id % 16 ) ); + + return true; +} + +static bool AdrNextDr( bool adrEnabled, bool updateChannelMask, int8_t* datarateOut ) +{ + bool adrAckReq = false; + int8_t datarate = LoRaMacParams.ChannelsDatarate; + + if( adrEnabled == true ) + { + if( datarate == LORAMAC_TX_MIN_DATARATE ) + { + AdrAckCounter = 0; + adrAckReq = false; + } + else + { + if( AdrAckCounter >= ADR_ACK_LIMIT ) + { + adrAckReq = true; + LoRaMacParams.ChannelsTxPower = LORAMAC_MAX_TX_POWER; + } + else + { + adrAckReq = false; + } + if( AdrAckCounter >= ( ADR_ACK_LIMIT + ADR_ACK_DELAY ) ) + { + if( ( AdrAckCounter % ADR_ACK_DELAY ) == 1 ) + { +#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) + if( datarate > LORAMAC_TX_MIN_DATARATE ) + { + datarate--; + } + if( datarate == LORAMAC_TX_MIN_DATARATE ) + { + if( updateChannelMask == true ) + { + // Re-enable default channels LC1, LC2, LC3 + LoRaMacParams.ChannelsMask[0] = LoRaMacParams.ChannelsMask[0] | ( LC( 1 ) + LC( 2 ) + LC( 3 ) ); + } + } +#elif defined( USE_BAND_470 ) + if( datarate > LORAMAC_TX_MIN_DATARATE ) + { + datarate--; + } + if( datarate == LORAMAC_TX_MIN_DATARATE ) + { + if( updateChannelMask == true ) + { + // Re-enable default channels + memcpy1( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) ); + } + } +#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) + if( ( datarate > LORAMAC_TX_MIN_DATARATE ) && ( datarate == DR_8 ) ) + { + datarate = DR_4; + } + else if( datarate > LORAMAC_TX_MIN_DATARATE ) + { + datarate--; + } + if( datarate == LORAMAC_TX_MIN_DATARATE ) + { + if( updateChannelMask == true ) + { +#if defined( USE_BAND_915 ) + // Re-enable default channels + memcpy1( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) ); +#else // defined( USE_BAND_915_HYBRID ) + // Re-enable default channels + ReenableChannels( LoRaMacParamsDefaults.ChannelsMask[4], LoRaMacParams.ChannelsMask ); +#endif + } + } +#else +#error "Please define a frequency band in the compiler options." +#endif + } + } + } + } + + *datarateOut = datarate; + + return adrAckReq; +} + +static LoRaMacStatus_t AddMacCommand( uint8_t cmd, uint8_t p1, uint8_t p2 ) +{ + LoRaMacStatus_t status = LORAMAC_STATUS_BUSY; + // The maximum buffer length must take MAC commands to re-send into account. + uint8_t bufLen = LORA_MAC_COMMAND_MAX_LENGTH - MacCommandsBufferToRepeatIndex; + + switch( cmd ) + { + case MOTE_MAC_LINK_CHECK_REQ: + if( MacCommandsBufferIndex < bufLen ) + { + MacCommandsBuffer[MacCommandsBufferIndex++] = cmd; + // No payload for this command + status = LORAMAC_STATUS_OK; + } + break; + case MOTE_MAC_LINK_ADR_ANS: + if( MacCommandsBufferIndex < ( bufLen - 1 ) ) + { + MacCommandsBuffer[MacCommandsBufferIndex++] = cmd; + // Margin + MacCommandsBuffer[MacCommandsBufferIndex++] = p1; + status = LORAMAC_STATUS_OK; + } + break; + case MOTE_MAC_DUTY_CYCLE_ANS: + if( MacCommandsBufferIndex < bufLen ) + { + MacCommandsBuffer[MacCommandsBufferIndex++] = cmd; + // No payload for this answer + status = LORAMAC_STATUS_OK; + } + break; + case MOTE_MAC_RX_PARAM_SETUP_ANS: + if( MacCommandsBufferIndex < ( bufLen - 1 ) ) + { + MacCommandsBuffer[MacCommandsBufferIndex++] = cmd; + // Status: Datarate ACK, Channel ACK + MacCommandsBuffer[MacCommandsBufferIndex++] = p1; + status = LORAMAC_STATUS_OK; + } + break; + case MOTE_MAC_DEV_STATUS_ANS: + if( MacCommandsBufferIndex < ( bufLen - 2 ) ) + { + MacCommandsBuffer[MacCommandsBufferIndex++] = cmd; + // 1st byte Battery + // 2nd byte Margin + MacCommandsBuffer[MacCommandsBufferIndex++] = p1; + MacCommandsBuffer[MacCommandsBufferIndex++] = p2; + status = LORAMAC_STATUS_OK; + } + break; + case MOTE_MAC_NEW_CHANNEL_ANS: + if( MacCommandsBufferIndex < ( bufLen - 1 ) ) + { + MacCommandsBuffer[MacCommandsBufferIndex++] = cmd; + // Status: Datarate range OK, Channel frequency OK + MacCommandsBuffer[MacCommandsBufferIndex++] = p1; + status = LORAMAC_STATUS_OK; + } + break; + case MOTE_MAC_RX_TIMING_SETUP_ANS: + if( MacCommandsBufferIndex < bufLen ) + { + MacCommandsBuffer[MacCommandsBufferIndex++] = cmd; + // No payload for this answer + status = LORAMAC_STATUS_OK; + } + break; + default: + return LORAMAC_STATUS_SERVICE_UNKNOWN; + } + if( status == LORAMAC_STATUS_OK ) + { + MacCommandsInNextTx = true; + } + return status; +} + +static uint8_t ParseMacCommandsToRepeat( uint8_t* cmdBufIn, uint8_t length, uint8_t* cmdBufOut ) +{ + uint8_t i = 0; + uint8_t cmdCount = 0; + + if( ( cmdBufIn == NULL ) || ( cmdBufOut == NULL ) ) + { + return 0; + } + + for( i = 0; i < length; i++ ) + { + switch( cmdBufIn[i] ) + { + // STICKY + case MOTE_MAC_RX_PARAM_SETUP_ANS: + { + cmdBufOut[cmdCount++] = cmdBufIn[i++]; + cmdBufOut[cmdCount++] = cmdBufIn[i]; + break; + } + case MOTE_MAC_RX_TIMING_SETUP_ANS: + { + cmdBufOut[cmdCount++] = cmdBufIn[i]; + break; + } + // NON-STICKY + case MOTE_MAC_DEV_STATUS_ANS: + { // 2 bytes payload + i += 2; + break; + } + case MOTE_MAC_LINK_ADR_ANS: + case MOTE_MAC_NEW_CHANNEL_ANS: + { // 1 byte payload + i++; + break; + } + case MOTE_MAC_DUTY_CYCLE_ANS: + case MOTE_MAC_LINK_CHECK_REQ: + { // 0 byte payload + break; + } + default: + break; + } + } + + return cmdCount; +} + +static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, uint8_t snr ) +{ + while( macIndex < commandsSize ) + { + // Decode Frame MAC commands + switch( payload[macIndex++] ) + { + case SRV_MAC_LINK_CHECK_ANS: + MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK; + MlmeConfirm.DemodMargin = payload[macIndex++]; + MlmeConfirm.NbGateways = payload[macIndex++]; + break; + case SRV_MAC_LINK_ADR_REQ: + { + uint8_t i; + uint8_t status = 0x07; + uint16_t chMask; + int8_t txPower = 0; + int8_t datarate = 0; + uint8_t nbRep = 0; + uint8_t chMaskCntl = 0; + uint16_t channelsMask[6] = { 0, 0, 0, 0, 0, 0 }; + + // Initialize local copy of the channels mask array + for( i = 0; i < 6; i++ ) + { + channelsMask[i] = LoRaMacParams.ChannelsMask[i]; + } + datarate = payload[macIndex++]; + txPower = datarate & 0x0F; + datarate = ( datarate >> 4 ) & 0x0F; + + if( ( AdrCtrlOn == false ) && + ( ( LoRaMacParams.ChannelsDatarate != datarate ) || ( LoRaMacParams.ChannelsTxPower != txPower ) ) ) + { // ADR disabled don't handle ADR requests if server tries to change datarate or txpower + // Answer the server with fail status + // Power ACK = 0 + // Data rate ACK = 0 + // Channel mask = 0 + AddMacCommand( MOTE_MAC_LINK_ADR_ANS, 0, 0 ); + macIndex += 3; // Skip over the remaining bytes of the request + break; + } + chMask = ( uint16_t )payload[macIndex++]; + chMask |= ( uint16_t )payload[macIndex++] << 8; + + nbRep = payload[macIndex++]; + chMaskCntl = ( nbRep >> 4 ) & 0x07; + nbRep &= 0x0F; + if( nbRep == 0 ) + { + nbRep = 1; + } +#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) + if( ( chMaskCntl == 0 ) && ( chMask == 0 ) ) + { + status &= 0xFE; // Channel mask KO + } + else if( ( ( chMaskCntl >= 1 ) && ( chMaskCntl <= 5 )) || + ( chMaskCntl >= 7 ) ) + { + // RFU + status &= 0xFE; // Channel mask KO + } + else + { + for( i = 0; i < LORA_MAX_NB_CHANNELS; i++ ) + { + if( chMaskCntl == 6 ) + { + if( Channels[i].Frequency != 0 ) + { + chMask |= 1 << i; + } + } + else + { + if( ( ( chMask & ( 1 << i ) ) != 0 ) && + ( Channels[i].Frequency == 0 ) ) + {// Trying to enable an undefined channel + status &= 0xFE; // Channel mask KO + } + } + } + channelsMask[0] = chMask; + } +#elif defined( USE_BAND_470 ) + if( chMaskCntl == 6 ) + { + // Enable all 125 kHz channels + for( uint8_t i = 0, k = 0; i < LORA_MAX_NB_CHANNELS; i += 16, k++ ) + { + for( uint8_t j = 0; j < 16; j++ ) + { + if( Channels[i + j].Frequency != 0 ) + { + channelsMask[k] |= 1 << j; + } + } + } + } + else if( chMaskCntl == 7 ) + { + status &= 0xFE; // Channel mask KO + } + else + { + for( uint8_t i = 0; i < 16; i++ ) + { + if( ( ( chMask & ( 1 << i ) ) != 0 ) && + ( Channels[chMaskCntl * 16 + i].Frequency == 0 ) ) + {// Trying to enable an undefined channel + status &= 0xFE; // Channel mask KO + } + } + channelsMask[chMaskCntl] = chMask; + } +#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) + if( chMaskCntl == 6 ) + { + // Enable all 125 kHz channels + channelsMask[0] = 0xFFFF; + channelsMask[1] = 0xFFFF; + channelsMask[2] = 0xFFFF; + channelsMask[3] = 0xFFFF; + // Apply chMask to channels 64 to 71 + channelsMask[4] = chMask; + } + else if( chMaskCntl == 7 ) + { + // Disable all 125 kHz channels + channelsMask[0] = 0x0000; + channelsMask[1] = 0x0000; + channelsMask[2] = 0x0000; + channelsMask[3] = 0x0000; + // Apply chMask to channels 64 to 71 + channelsMask[4] = chMask; + } + else if( chMaskCntl == 5 ) + { + // RFU + status &= 0xFE; // Channel mask KO + } + else + { + channelsMask[chMaskCntl] = chMask; + + // FCC 15.247 paragraph F mandates to hop on at least 2 125 kHz channels + if( ( datarate < DR_4 ) && ( CountNbEnabled125kHzChannels( channelsMask ) < 2 ) ) + { + status &= 0xFE; // Channel mask KO + } + +#if defined( USE_BAND_915_HYBRID ) + if( ValidateChannelMask( channelsMask ) == false ) + { + status &= 0xFE; // Channel mask KO + } +#endif + } +#else + #error "Please define a frequency band in the compiler options." +#endif + if( ValidateDatarate( datarate, channelsMask ) == false ) + { + status &= 0xFD; // Datarate KO + } + + // + // Remark MaxTxPower = 0 and MinTxPower = 5 + // + if( ValueInRange( txPower, LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) == false ) + { + status &= 0xFB; // TxPower KO + } + if( ( status & 0x07 ) == 0x07 ) + { + LoRaMacParams.ChannelsDatarate = datarate; + LoRaMacParams.ChannelsTxPower = txPower; + + memcpy1( ( uint8_t* )LoRaMacParams.ChannelsMask, ( uint8_t* )channelsMask, sizeof( LoRaMacParams.ChannelsMask ) ); + + LoRaMacParams.ChannelsNbRep = nbRep; +#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) + // Reset ChannelsMaskRemaining to the new ChannelsMask + ChannelsMaskRemaining[0] &= channelsMask[0]; + ChannelsMaskRemaining[1] &= channelsMask[1]; + ChannelsMaskRemaining[2] &= channelsMask[2]; + ChannelsMaskRemaining[3] &= channelsMask[3]; + ChannelsMaskRemaining[4] = channelsMask[4]; + ChannelsMaskRemaining[5] = channelsMask[5]; +#endif + } + AddMacCommand( MOTE_MAC_LINK_ADR_ANS, status, 0 ); + } + break; + case SRV_MAC_DUTY_CYCLE_REQ: + MaxDCycle = payload[macIndex++]; + AggregatedDCycle = 1 << MaxDCycle; + AddMacCommand( MOTE_MAC_DUTY_CYCLE_ANS, 0, 0 ); + break; + case SRV_MAC_RX_PARAM_SETUP_REQ: + { + uint8_t status = 0x07; + int8_t datarate = 0; + int8_t drOffset = 0; + uint32_t freq = 0; + + drOffset = ( payload[macIndex] >> 4 ) & 0x07; + datarate = payload[macIndex] & 0x0F; + macIndex++; + + freq = ( uint32_t )payload[macIndex++]; + freq |= ( uint32_t )payload[macIndex++] << 8; + freq |= ( uint32_t )payload[macIndex++] << 16; + freq *= 100; + + if( Rx2FreqInRange( freq ) == false ) + { + status &= 0xFE; // Channel frequency KO + } + + if( ValueInRange( datarate, LORAMAC_RX_MIN_DATARATE, LORAMAC_RX_MAX_DATARATE ) == false ) + { + status &= 0xFD; // Datarate KO + } +#if ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) + if( ( ValueInRange( datarate, DR_5, DR_7 ) == true ) || + ( datarate > DR_13 ) ) + { + status &= 0xFD; // Datarate KO + } +#endif + if( ValueInRange( drOffset, LORAMAC_MIN_RX1_DR_OFFSET, LORAMAC_MAX_RX1_DR_OFFSET ) == false ) + { + status &= 0xFB; // Rx1DrOffset range KO + } + + if( ( status & 0x07 ) == 0x07 ) + { + LoRaMacParams.Rx2Channel.Datarate = datarate; + LoRaMacParams.Rx2Channel.Frequency = freq; + LoRaMacParams.Rx1DrOffset = drOffset; + } + AddMacCommand( MOTE_MAC_RX_PARAM_SETUP_ANS, status, 0 ); + } + break; + case SRV_MAC_DEV_STATUS_REQ: + { + uint8_t batteryLevel = BAT_LEVEL_NO_MEASURE; + if( ( LoRaMacCallbacks != NULL ) && ( LoRaMacCallbacks->GetBatteryLevel != NULL ) ) + { + batteryLevel = LoRaMacCallbacks->GetBatteryLevel( ); + } + AddMacCommand( MOTE_MAC_DEV_STATUS_ANS, batteryLevel, snr ); + break; + } + case SRV_MAC_NEW_CHANNEL_REQ: + { + uint8_t status = 0x03; + +#if defined( USE_BAND_470 ) || defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) + status &= 0xFC; // Channel frequency and datarate KO + macIndex += 5; +#else + int8_t channelIndex = 0; + ChannelParams_t chParam; + + channelIndex = payload[macIndex++]; + chParam.Frequency = ( uint32_t )payload[macIndex++]; + chParam.Frequency |= ( uint32_t )payload[macIndex++] << 8; + chParam.Frequency |= ( uint32_t )payload[macIndex++] << 16; + chParam.Frequency *= 100; + chParam.DrRange.Value = payload[macIndex++]; + + LoRaMacState |= LORAMAC_TX_CONFIG; + if( chParam.Frequency == 0 ) + { + if( channelIndex < 3 ) + { + status &= 0xFC; + } + else + { + if( LoRaMacChannelRemove( channelIndex ) != LORAMAC_STATUS_OK ) + { + status &= 0xFC; + } + } + } + else + { + switch( LoRaMacChannelAdd( channelIndex, chParam ) ) + { + case LORAMAC_STATUS_OK: + { + break; + } + case LORAMAC_STATUS_FREQUENCY_INVALID: + { + status &= 0xFE; + break; + } + case LORAMAC_STATUS_DATARATE_INVALID: + { + status &= 0xFD; + break; + } + case LORAMAC_STATUS_FREQ_AND_DR_INVALID: + { + status &= 0xFC; + break; + } + default: + { + status &= 0xFC; + break; + } + } + } + LoRaMacState &= ~LORAMAC_TX_CONFIG; +#endif + AddMacCommand( MOTE_MAC_NEW_CHANNEL_ANS, status, 0 ); + } + break; + case SRV_MAC_RX_TIMING_SETUP_REQ: + { + uint8_t delay = payload[macIndex++] & 0x0F; + + if( delay == 0 ) + { + delay++; + } + LoRaMacParams.ReceiveDelay1 = delay * 1e3; + LoRaMacParams.ReceiveDelay2 = LoRaMacParams.ReceiveDelay1 + 1e3; + AddMacCommand( MOTE_MAC_RX_TIMING_SETUP_ANS, 0, 0 ); + } + break; + default: + // Unknown command. ABORT MAC commands processing + return; + } + } +} + +LoRaMacStatus_t Send( LoRaMacHeader_t *macHdr, uint8_t fPort, void *fBuffer, uint16_t fBufferSize ) +{ + LoRaMacFrameCtrl_t fCtrl; + LoRaMacStatus_t status = LORAMAC_STATUS_PARAMETER_INVALID; + + fCtrl.Value = 0; + fCtrl.Bits.FOptsLen = 0; + fCtrl.Bits.FPending = 0; + fCtrl.Bits.Ack = false; + fCtrl.Bits.AdrAckReq = false; + fCtrl.Bits.Adr = AdrCtrlOn; + + // Prepare the frame + status = PrepareFrame( macHdr, &fCtrl, fPort, fBuffer, fBufferSize ); + + // Validate status + if( status != LORAMAC_STATUS_OK ) + { + return status; + } + + // Reset confirm parameters + McpsConfirm.NbRetries = 0; + McpsConfirm.AckReceived = false; + McpsConfirm.UpLinkCounter = UpLinkCounter; + + status = ScheduleTx( ); + + return status; +} + +static LoRaMacStatus_t ScheduleTx( void ) +{ + TimerTime_t dutyCycleTimeOff = 0; + + // Check if the device is off + if( MaxDCycle == 255 ) + { + return LORAMAC_STATUS_DEVICE_OFF; + } + if( MaxDCycle == 0 ) + { + AggregatedTimeOff = 0; + } + + // Select channel + while( SetNextChannel( &dutyCycleTimeOff ) == false ) + { + // Set the default datarate + LoRaMacParams.ChannelsDatarate = LoRaMacParamsDefaults.ChannelsDatarate; + +#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) + // Re-enable default channels LC1, LC2, LC3 + LoRaMacParams.ChannelsMask[0] = LoRaMacParams.ChannelsMask[0] | ( LC( 1 ) + LC( 2 ) + LC( 3 ) ); +#endif + } + + // Compute Rx1 windows parameters +#if ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) + RxWindowsParams[0] = ComputeRxWindowParameters( DatarateOffsets[LoRaMacParams.ChannelsDatarate][LoRaMacParams.Rx1DrOffset], LoRaMacParams.SystemMaxRxError ); +#else + RxWindowsParams[0] = ComputeRxWindowParameters( MAX( DR_0, LoRaMacParams.ChannelsDatarate - LoRaMacParams.Rx1DrOffset ), LoRaMacParams.SystemMaxRxError ); +#endif + // Compute Rx2 windows parameters + RxWindowsParams[1] = ComputeRxWindowParameters( LoRaMacParams.Rx2Channel.Datarate, LoRaMacParams.SystemMaxRxError ); + + if( IsLoRaMacNetworkJoined == false ) + { + RxWindow1Delay = LoRaMacParams.JoinAcceptDelay1 + RxWindowsParams[0].RxOffset; + RxWindow2Delay = LoRaMacParams.JoinAcceptDelay2 + RxWindowsParams[1].RxOffset; + } + else + { + if( ValidatePayloadLength( LoRaMacTxPayloadLen, LoRaMacParams.ChannelsDatarate, MacCommandsBufferIndex ) == false ) + { + return LORAMAC_STATUS_LENGTH_ERROR; + } + RxWindow1Delay = LoRaMacParams.ReceiveDelay1 + RxWindowsParams[0].RxOffset; + RxWindow2Delay = LoRaMacParams.ReceiveDelay2 + RxWindowsParams[1].RxOffset; + } + + // Schedule transmission of frame + if( dutyCycleTimeOff == 0 ) + { + // Try to send now + return SendFrameOnChannel( Channels[Channel] ); + } + else + { + // Send later - prepare timer + LoRaMacState |= LORAMAC_TX_DELAYED; + TimerSetValue( &TxDelayedTimer, dutyCycleTimeOff ); + TimerStart( &TxDelayedTimer ); + + return LORAMAC_STATUS_OK; + } +} + +static uint16_t JoinDutyCycle( void ) +{ + uint16_t dutyCycle = 0; + TimerTime_t timeElapsed = TimerGetElapsedTime( LoRaMacInitializationTime ); + + if( timeElapsed < 3600e3 ) + { + dutyCycle = BACKOFF_DC_1_HOUR; + } + else if( timeElapsed < ( 3600e3 + 36000e3 ) ) + { + dutyCycle = BACKOFF_DC_10_HOURS; + } + else + { + dutyCycle = BACKOFF_DC_24_HOURS; + } + return dutyCycle; +} + +static void CalculateBackOff( uint8_t channel ) +{ + uint16_t dutyCycle = Bands[Channels[channel].Band].DCycle; + uint16_t joinDutyCycle = 0; + + // Reset time-off to initial value. + Bands[Channels[channel].Band].TimeOff = 0; + + if( IsLoRaMacNetworkJoined == false ) + { + // The node has not joined yet. Apply join duty cycle to all regions. + joinDutyCycle = JoinDutyCycle( ); + dutyCycle = MAX( dutyCycle, joinDutyCycle ); + + // Update Band time-off. + Bands[Channels[channel].Band].TimeOff = TxTimeOnAir * dutyCycle - TxTimeOnAir; + } + else + { + if( DutyCycleOn == true ) + { + Bands[Channels[channel].Band].TimeOff = TxTimeOnAir * dutyCycle - TxTimeOnAir; + } + } + + // Update Aggregated Time OFF + AggregatedTimeOff = AggregatedTimeOff + ( TxTimeOnAir * AggregatedDCycle - TxTimeOnAir ); +} + +static int8_t AlternateDatarate( uint16_t nbTrials ) +{ + int8_t datarate = LORAMAC_TX_MIN_DATARATE; +#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) +#if defined( USE_BAND_915 ) + // Re-enable 500 kHz default channels + LoRaMacParams.ChannelsMask[4] = 0x00FF; +#else // defined( USE_BAND_915_HYBRID ) + // Re-enable 500 kHz default channels + ReenableChannels( LoRaMacParamsDefaults.ChannelsMask[4], LoRaMacParams.ChannelsMask ); +#endif + + if( ( nbTrials & 0x01 ) == 0x01 ) + { + datarate = DR_4; + } + else + { + datarate = DR_0; + } +#else + if( ( nbTrials % 48 ) == 0 ) + { + datarate = DR_0; + } + else if( ( nbTrials % 32 ) == 0 ) + { + datarate = DR_1; + } + else if( ( nbTrials % 24 ) == 0 ) + { + datarate = DR_2; + } + else if( ( nbTrials % 16 ) == 0 ) + { + datarate = DR_3; + } + else if( ( nbTrials % 8 ) == 0 ) + { + datarate = DR_4; + } + else + { + datarate = DR_5; + } +#endif + return datarate; +} + +static void ResetMacParameters( void ) +{ + IsLoRaMacNetworkJoined = false; + + // Counters + UpLinkCounter = 0; + DownLinkCounter = 0; + AdrAckCounter = 0; + + ChannelsNbRepCounter = 0; + + AckTimeoutRetries = 1; + AckTimeoutRetriesCounter = 1; + AckTimeoutRetry = false; + + MaxDCycle = 0; + AggregatedDCycle = 1; + + MacCommandsBufferIndex = 0; + MacCommandsBufferToRepeatIndex = 0; + + IsRxWindowsEnabled = true; + + LoRaMacParams.ChannelsTxPower = LoRaMacParamsDefaults.ChannelsTxPower; + LoRaMacParams.ChannelsDatarate = LoRaMacParamsDefaults.ChannelsDatarate; + + LoRaMacParams.Rx1DrOffset = LoRaMacParamsDefaults.Rx1DrOffset; + LoRaMacParams.Rx2Channel = LoRaMacParamsDefaults.Rx2Channel; + + memcpy1( ( uint8_t* ) LoRaMacParams.ChannelsMask, ( uint8_t* ) LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) ); + +#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) + memcpy1( ( uint8_t* ) ChannelsMaskRemaining, ( uint8_t* ) LoRaMacParamsDefaults.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) ); +#endif + + + NodeAckRequested = false; + SrvAckRequested = false; + MacCommandsInNextTx = false; + + // Reset Multicast downlink counters + MulticastParams_t *cur = MulticastChannels; + while( cur != NULL ) + { + cur->DownLinkCounter = 0; + cur = cur->Next; + } + + // Initialize channel index. + Channel = LORA_MAX_NB_CHANNELS; +} + +LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort, void *fBuffer, uint16_t fBufferSize ) +{ + uint16_t i; + uint8_t pktHeaderLen = 0; + uint32_t mic = 0; + const void* payload = fBuffer; + uint8_t framePort = fPort; + + LoRaMacBufferPktLen = 0; + + NodeAckRequested = false; + + if( fBuffer == NULL ) + { + fBufferSize = 0; + } + + LoRaMacTxPayloadLen = fBufferSize; + + LoRaMacBuffer[pktHeaderLen++] = macHdr->Value; + + switch( macHdr->Bits.MType ) + { + case FRAME_TYPE_JOIN_REQ: + LoRaMacBufferPktLen = pktHeaderLen; + + memcpyr( LoRaMacBuffer + LoRaMacBufferPktLen, LoRaMacAppEui, 8 ); + LoRaMacBufferPktLen += 8; + memcpyr( LoRaMacBuffer + LoRaMacBufferPktLen, LoRaMacDevEui, 8 ); + LoRaMacBufferPktLen += 8; + + LoRaMacDevNonce = Radio.Random( ); + + LoRaMacBuffer[LoRaMacBufferPktLen++] = LoRaMacDevNonce & 0xFF; + LoRaMacBuffer[LoRaMacBufferPktLen++] = ( LoRaMacDevNonce >> 8 ) & 0xFF; + + LoRaMacJoinComputeMic( LoRaMacBuffer, LoRaMacBufferPktLen & 0xFF, LoRaMacAppKey, &mic ); + + LoRaMacBuffer[LoRaMacBufferPktLen++] = mic & 0xFF; + LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 8 ) & 0xFF; + LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 16 ) & 0xFF; + LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 24 ) & 0xFF; + + break; + case FRAME_TYPE_DATA_CONFIRMED_UP: + NodeAckRequested = true; + //Intentional fallthrough + case FRAME_TYPE_DATA_UNCONFIRMED_UP: + if( IsLoRaMacNetworkJoined == false ) + { + return LORAMAC_STATUS_NO_NETWORK_JOINED; // No network has been joined yet + } + + fCtrl->Bits.AdrAckReq = AdrNextDr( fCtrl->Bits.Adr, true, &LoRaMacParams.ChannelsDatarate ); + + if( SrvAckRequested == true ) + { + SrvAckRequested = false; + fCtrl->Bits.Ack = 1; + } + + LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr ) & 0xFF; + LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 8 ) & 0xFF; + LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 16 ) & 0xFF; + LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 24 ) & 0xFF; + + LoRaMacBuffer[pktHeaderLen++] = fCtrl->Value; + + LoRaMacBuffer[pktHeaderLen++] = UpLinkCounter & 0xFF; + LoRaMacBuffer[pktHeaderLen++] = ( UpLinkCounter >> 8 ) & 0xFF; + + // Copy the MAC commands which must be re-send into the MAC command buffer + memcpy1( &MacCommandsBuffer[MacCommandsBufferIndex], MacCommandsBufferToRepeat, MacCommandsBufferToRepeatIndex ); + MacCommandsBufferIndex += MacCommandsBufferToRepeatIndex; + + if( ( payload != NULL ) && ( LoRaMacTxPayloadLen > 0 ) ) + { + if( ( MacCommandsBufferIndex <= LORA_MAC_COMMAND_MAX_LENGTH ) && ( MacCommandsInNextTx == true ) ) + { + fCtrl->Bits.FOptsLen += MacCommandsBufferIndex; + + // Update FCtrl field with new value of OptionsLength + LoRaMacBuffer[0x05] = fCtrl->Value; + for( i = 0; i < MacCommandsBufferIndex; i++ ) + { + LoRaMacBuffer[pktHeaderLen++] = MacCommandsBuffer[i]; + } + } + } + else + { + if( ( MacCommandsBufferIndex > 0 ) && ( MacCommandsInNextTx ) ) + { + LoRaMacTxPayloadLen = MacCommandsBufferIndex; + payload = MacCommandsBuffer; + framePort = 0; + } + } + MacCommandsInNextTx = false; + // Store MAC commands which must be re-send in case the device does not receive a downlink anymore + MacCommandsBufferToRepeatIndex = ParseMacCommandsToRepeat( MacCommandsBuffer, MacCommandsBufferIndex, MacCommandsBufferToRepeat ); + if( MacCommandsBufferToRepeatIndex > 0 ) + { + MacCommandsInNextTx = true; + } + + if( ( payload != NULL ) && ( LoRaMacTxPayloadLen > 0 ) ) + { + LoRaMacBuffer[pktHeaderLen++] = framePort; + + if( framePort == 0 ) + { + LoRaMacPayloadEncrypt( (uint8_t* ) payload, LoRaMacTxPayloadLen, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &LoRaMacBuffer[pktHeaderLen] ); + } + else + { + LoRaMacPayloadEncrypt( (uint8_t* ) payload, LoRaMacTxPayloadLen, LoRaMacAppSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &LoRaMacBuffer[pktHeaderLen] ); + } + } + LoRaMacBufferPktLen = pktHeaderLen + LoRaMacTxPayloadLen; + + LoRaMacComputeMic( LoRaMacBuffer, LoRaMacBufferPktLen, LoRaMacNwkSKey, LoRaMacDevAddr, UP_LINK, UpLinkCounter, &mic ); + + LoRaMacBuffer[LoRaMacBufferPktLen + 0] = mic & 0xFF; + LoRaMacBuffer[LoRaMacBufferPktLen + 1] = ( mic >> 8 ) & 0xFF; + LoRaMacBuffer[LoRaMacBufferPktLen + 2] = ( mic >> 16 ) & 0xFF; + LoRaMacBuffer[LoRaMacBufferPktLen + 3] = ( mic >> 24 ) & 0xFF; + + LoRaMacBufferPktLen += LORAMAC_MFR_LEN; + + break; + case FRAME_TYPE_PROPRIETARY: + if( ( fBuffer != NULL ) && ( LoRaMacTxPayloadLen > 0 ) ) + { + memcpy1( LoRaMacBuffer + pktHeaderLen, ( uint8_t* ) fBuffer, LoRaMacTxPayloadLen ); + LoRaMacBufferPktLen = pktHeaderLen + LoRaMacTxPayloadLen; + } + break; + default: + return LORAMAC_STATUS_SERVICE_UNKNOWN; + } + + return LORAMAC_STATUS_OK; +} + +LoRaMacStatus_t SendFrameOnChannel( ChannelParams_t channel ) +{ + int8_t datarate = Datarates[LoRaMacParams.ChannelsDatarate]; + int8_t txPowerIndex = 0; + int8_t txPower = 0; + + txPowerIndex = LimitTxPower( LoRaMacParams.ChannelsTxPower, Bands[channel.Band].TxMaxPower ); + txPower = TxPowers[txPowerIndex]; + + MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR; + McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR; + McpsConfirm.Datarate = LoRaMacParams.ChannelsDatarate; + McpsConfirm.TxPower = txPowerIndex; + McpsConfirm.UpLinkFrequency = channel.Frequency; + + Radio.SetChannel( channel.Frequency ); + +#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) + if( LoRaMacParams.ChannelsDatarate == DR_7 ) + { // High Speed FSK channel + Radio.SetMaxPayloadLength( MODEM_FSK, LoRaMacBufferPktLen ); + Radio.SetTxConfig( MODEM_FSK, txPower, 25e3, 0, datarate * 1e3, 0, 5, false, true, 0, 0, false, 3e3 ); + TxTimeOnAir = Radio.TimeOnAir( MODEM_FSK, LoRaMacBufferPktLen ); + + } + else if( LoRaMacParams.ChannelsDatarate == DR_6 ) + { // High speed LoRa channel + Radio.SetMaxPayloadLength( MODEM_LORA, LoRaMacBufferPktLen ); + Radio.SetTxConfig( MODEM_LORA, txPower, 0, 1, datarate, 1, 8, false, true, 0, 0, false, 3e3 ); + TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen ); + } + else + { // Normal LoRa channel + Radio.SetMaxPayloadLength( MODEM_LORA, LoRaMacBufferPktLen ); + Radio.SetTxConfig( MODEM_LORA, txPower, 0, 0, datarate, 1, 8, false, true, 0, 0, false, 3e3 ); + TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen ); + } +#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) + Radio.SetMaxPayloadLength( MODEM_LORA, LoRaMacBufferPktLen ); + if( LoRaMacParams.ChannelsDatarate >= DR_4 ) + { // High speed LoRa channel BW500 kHz + Radio.SetTxConfig( MODEM_LORA, txPower, 0, 2, datarate, 1, 8, false, true, 0, 0, false, 3e3 ); + TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen ); + } + else + { // Normal LoRa channel + Radio.SetTxConfig( MODEM_LORA, txPower, 0, 0, datarate, 1, 8, false, true, 0, 0, false, 3e3 ); + TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen ); + } +#elif defined( USE_BAND_470 ) + Radio.SetMaxPayloadLength( MODEM_LORA, LoRaMacBufferPktLen ); + Radio.SetTxConfig( MODEM_LORA, txPower, 0, 0, datarate, 1, 8, false, true, 0, 0, false, 3e3 ); + TxTimeOnAir = Radio.TimeOnAir( MODEM_LORA, LoRaMacBufferPktLen ); +#else + #error "Please define a frequency band in the compiler options." +#endif + + // Store the time on air + McpsConfirm.TxTimeOnAir = TxTimeOnAir; + MlmeConfirm.TxTimeOnAir = TxTimeOnAir; + + // Starts the MAC layer status check timer + TimerSetValue( &MacStateCheckTimer, MAC_STATE_CHECK_TIMEOUT ); + TimerStart( &MacStateCheckTimer ); + + if( IsLoRaMacNetworkJoined == false ) + { + JoinRequestTrials++; + } + + // Send now + Radio.Send( LoRaMacBuffer, LoRaMacBufferPktLen ); + + LoRaMacState |= LORAMAC_TX_RUNNING; + + return LORAMAC_STATUS_OK; +} + +LoRaMacStatus_t SetTxContinuousWave( uint16_t timeout ) +{ + int8_t txPowerIndex = 0; + int8_t txPower = 0; + + txPowerIndex = LimitTxPower( LoRaMacParams.ChannelsTxPower, Bands[Channels[Channel].Band].TxMaxPower ); + txPower = TxPowers[txPowerIndex]; + + // Starts the MAC layer status check timer + TimerSetValue( &MacStateCheckTimer, MAC_STATE_CHECK_TIMEOUT ); + TimerStart( &MacStateCheckTimer ); + + Radio.SetTxContinuousWave( Channels[Channel].Frequency, txPower, timeout ); + + LoRaMacState |= LORAMAC_TX_RUNNING; + + return LORAMAC_STATUS_OK; +} + +LoRaMacStatus_t SetTxContinuousWave1( uint16_t timeout, uint32_t frequency, uint8_t power ) +{ + Radio.SetTxContinuousWave( frequency, power, timeout ); + + // Starts the MAC layer status check timer + TimerSetValue( &MacStateCheckTimer, MAC_STATE_CHECK_TIMEOUT ); + TimerStart( &MacStateCheckTimer ); + + LoRaMacState |= LORAMAC_TX_RUNNING; + + return LORAMAC_STATUS_OK; +} + +LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t *primitives, LoRaMacCallback_t *callbacks ) +{ + if( primitives == NULL ) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + + if( ( primitives->MacMcpsConfirm == NULL ) || + ( primitives->MacMcpsIndication == NULL ) || + ( primitives->MacMlmeConfirm == NULL ) ) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + + LoRaMacPrimitives = primitives; + LoRaMacCallbacks = callbacks; + + LoRaMacFlags.Value = 0; + + LoRaMacDeviceClass = CLASS_A; + LoRaMacState = LORAMAC_IDLE; + + JoinRequestTrials = 0; + MaxJoinRequestTrials = 1; + RepeaterSupport = false; + + // Reset duty cycle times + AggregatedLastTxDoneTime = 0; + AggregatedTimeOff = 0; + + // Duty cycle +#if defined( USE_BAND_433 ) + DutyCycleOn = true; +#elif defined( USE_BAND_470 ) + DutyCycleOn = false; +#elif defined( USE_BAND_780 ) + DutyCycleOn = true; +#elif defined( USE_BAND_868 ) + DutyCycleOn = true; +#elif defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) + DutyCycleOn = false; +#else + #error "Please define a frequency band in the compiler options." +#endif + + // Reset to defaults + LoRaMacParamsDefaults.ChannelsTxPower = LORAMAC_DEFAULT_TX_POWER; + LoRaMacParamsDefaults.ChannelsDatarate = LORAMAC_DEFAULT_DATARATE; + + LoRaMacParamsDefaults.SystemMaxRxError = 10; + LoRaMacParamsDefaults.MinRxSymbols = 6; + LoRaMacParamsDefaults.MaxRxWindow = MAX_RX_WINDOW; + LoRaMacParamsDefaults.ReceiveDelay1 = RECEIVE_DELAY1; + LoRaMacParamsDefaults.ReceiveDelay2 = RECEIVE_DELAY2; + LoRaMacParamsDefaults.JoinAcceptDelay1 = JOIN_ACCEPT_DELAY1; + LoRaMacParamsDefaults.JoinAcceptDelay2 = JOIN_ACCEPT_DELAY2; + + LoRaMacParamsDefaults.ChannelsNbRep = 1; + LoRaMacParamsDefaults.Rx1DrOffset = 0; + + LoRaMacParamsDefaults.Rx2Channel = ( Rx2ChannelParams_t )RX_WND_2_CHANNEL; + + // Channel mask +#if defined( USE_BAND_433 ) + LoRaMacParamsDefaults.ChannelsMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 ); +#elif defined ( USE_BAND_470 ) + LoRaMacParamsDefaults.ChannelsMask[0] = 0xFFFF; + LoRaMacParamsDefaults.ChannelsMask[1] = 0xFFFF; + LoRaMacParamsDefaults.ChannelsMask[2] = 0xFFFF; + LoRaMacParamsDefaults.ChannelsMask[3] = 0xFFFF; + LoRaMacParamsDefaults.ChannelsMask[4] = 0xFFFF; + LoRaMacParamsDefaults.ChannelsMask[5] = 0xFFFF; +#elif defined( USE_BAND_780 ) + LoRaMacParamsDefaults.ChannelsMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 ); +#elif defined( USE_BAND_868 ) + LoRaMacParamsDefaults.ChannelsMask[0] = LC( 1 ) + LC( 2 ) + LC( 3 ); +#elif defined( USE_BAND_915 ) + LoRaMacParamsDefaults.ChannelsMask[0] = 0xFFFF; + LoRaMacParamsDefaults.ChannelsMask[1] = 0xFFFF; + LoRaMacParamsDefaults.ChannelsMask[2] = 0xFFFF; + LoRaMacParamsDefaults.ChannelsMask[3] = 0xFFFF; + LoRaMacParamsDefaults.ChannelsMask[4] = 0x00FF; + LoRaMacParamsDefaults.ChannelsMask[5] = 0x0000; +#elif defined( USE_BAND_915_HYBRID ) + LoRaMacParamsDefaults.ChannelsMask[0] = 0x00FF; + LoRaMacParamsDefaults.ChannelsMask[1] = 0x0000; + LoRaMacParamsDefaults.ChannelsMask[2] = 0x0000; + LoRaMacParamsDefaults.ChannelsMask[3] = 0x0000; + LoRaMacParamsDefaults.ChannelsMask[4] = 0x0001; + LoRaMacParamsDefaults.ChannelsMask[5] = 0x0000; +#else + #error "Please define a frequency band in the compiler options." +#endif + +#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) + // 125 kHz channels + for( uint8_t i = 0; i < LORA_MAX_NB_CHANNELS - 8; i++ ) + { + Channels[i].Frequency = 902.3e6 + i * 200e3; + Channels[i].DrRange.Value = ( DR_3 << 4 ) | DR_0; + Channels[i].Band = 0; + } + // 500 kHz channels + for( uint8_t i = LORA_MAX_NB_CHANNELS - 8; i < LORA_MAX_NB_CHANNELS; i++ ) + { + Channels[i].Frequency = 903.0e6 + ( i - ( LORA_MAX_NB_CHANNELS - 8 ) ) * 1.6e6; + Channels[i].DrRange.Value = ( DR_4 << 4 ) | DR_4; + Channels[i].Band = 0; + } +#elif defined( USE_BAND_470 ) + // 125 kHz channels + for( uint8_t i = 0; i < LORA_MAX_NB_CHANNELS; i++ ) + { + Channels[i].Frequency = 470.3e6 + i * 200e3; + Channels[i].DrRange.Value = ( DR_5 << 4 ) | DR_0; + Channels[i].Band = 0; + } +#endif + + // Init parameters which are not set in function ResetMacParameters + LoRaMacParams.SystemMaxRxError = LoRaMacParamsDefaults.SystemMaxRxError; + LoRaMacParams.MinRxSymbols = LoRaMacParamsDefaults.MinRxSymbols; + LoRaMacParams.MaxRxWindow = LoRaMacParamsDefaults.MaxRxWindow; + LoRaMacParams.ReceiveDelay1 = LoRaMacParamsDefaults.ReceiveDelay1; + LoRaMacParams.ReceiveDelay2 = LoRaMacParamsDefaults.ReceiveDelay2; + LoRaMacParams.JoinAcceptDelay1 = LoRaMacParamsDefaults.JoinAcceptDelay1; + LoRaMacParams.JoinAcceptDelay2 = LoRaMacParamsDefaults.JoinAcceptDelay2; + LoRaMacParams.ChannelsNbRep = LoRaMacParamsDefaults.ChannelsNbRep; + + ResetMacParameters( ); + + // Initialize timers + TimerInit( &MacStateCheckTimer, OnMacStateCheckTimerEvent ); + TimerSetValue( &MacStateCheckTimer, MAC_STATE_CHECK_TIMEOUT ); + + TimerInit( &TxDelayedTimer, OnTxDelayedTimerEvent ); + TimerInit( &RxWindowTimer1, OnRxWindow1TimerEvent ); + TimerInit( &RxWindowTimer2, OnRxWindow2TimerEvent ); + TimerInit( &AckTimeoutTimer, OnAckTimeoutTimerEvent ); + + // Store the current initialization time + LoRaMacInitializationTime = TimerGetCurrentTime( ); + + // Initialize Radio driver + RadioEvents.TxDone = OnRadioTxDone; + RadioEvents.RxDone = OnRadioRxDone; + RadioEvents.RxError = OnRadioRxError; + RadioEvents.TxTimeout = OnRadioTxTimeout; + RadioEvents.RxTimeout = OnRadioRxTimeout; + Radio.Init( &RadioEvents ); + + // Random seed initialization + srand1( Radio.Random( ) ); + + PublicNetwork = true; + Radio.SetPublicNetwork( PublicNetwork ); + Radio.Sleep( ); + + return LORAMAC_STATUS_OK; +} + +LoRaMacStatus_t LoRaMacQueryTxPossible( uint8_t size, LoRaMacTxInfo_t* txInfo ) +{ + int8_t datarate = LoRaMacParamsDefaults.ChannelsDatarate; + uint8_t fOptLen = MacCommandsBufferIndex + MacCommandsBufferToRepeatIndex; + + if( txInfo == NULL ) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + + AdrNextDr( AdrCtrlOn, false, &datarate ); + + if( RepeaterSupport == true ) + { + txInfo->CurrentPayloadSize = MaxPayloadOfDatarateRepeater[datarate]; + } + else + { + txInfo->CurrentPayloadSize = MaxPayloadOfDatarate[datarate]; + } + + if( txInfo->CurrentPayloadSize >= fOptLen ) + { + txInfo->MaxPossiblePayload = txInfo->CurrentPayloadSize - fOptLen; + } + else + { + return LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR; + } + + if( ValidatePayloadLength( size, datarate, 0 ) == false ) + { + return LORAMAC_STATUS_LENGTH_ERROR; + } + + if( ValidatePayloadLength( size, datarate, fOptLen ) == false ) + { + return LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR; + } + + return LORAMAC_STATUS_OK; +} + +LoRaMacStatus_t LoRaMacMibGetRequestConfirm( MibRequestConfirm_t *mibGet ) +{ + LoRaMacStatus_t status = LORAMAC_STATUS_OK; + + if( mibGet == NULL ) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + + switch( mibGet->Type ) + { + case MIB_DEVICE_CLASS: + { + mibGet->Param.Class = LoRaMacDeviceClass; + break; + } + case MIB_NETWORK_JOINED: + { + mibGet->Param.IsNetworkJoined = IsLoRaMacNetworkJoined; + break; + } + case MIB_ADR: + { + mibGet->Param.AdrEnable = AdrCtrlOn; + break; + } + case MIB_NET_ID: + { + mibGet->Param.NetID = LoRaMacNetID; + break; + } + case MIB_DEV_ADDR: + { + mibGet->Param.DevAddr = LoRaMacDevAddr; + break; + } + case MIB_NWK_SKEY: + { + mibGet->Param.NwkSKey = LoRaMacNwkSKey; + break; + } + case MIB_APP_SKEY: + { + mibGet->Param.AppSKey = LoRaMacAppSKey; + break; + } + case MIB_PUBLIC_NETWORK: + { + mibGet->Param.EnablePublicNetwork = PublicNetwork; + break; + } + case MIB_REPEATER_SUPPORT: + { + mibGet->Param.EnableRepeaterSupport = RepeaterSupport; + break; + } + case MIB_CHANNELS: + { + mibGet->Param.ChannelList = Channels; + break; + } + case MIB_RX2_CHANNEL: + { + mibGet->Param.Rx2Channel = LoRaMacParams.Rx2Channel; + break; + } + case MIB_RX2_DEFAULT_CHANNEL: + { + mibGet->Param.Rx2Channel = LoRaMacParamsDefaults.Rx2Channel; + break; + } + case MIB_CHANNELS_DEFAULT_MASK: + { + mibGet->Param.ChannelsDefaultMask = LoRaMacParamsDefaults.ChannelsMask; + break; + } + case MIB_CHANNELS_MASK: + { + mibGet->Param.ChannelsMask = LoRaMacParams.ChannelsMask; + break; + } + case MIB_CHANNELS_NB_REP: + { + mibGet->Param.ChannelNbRep = LoRaMacParams.ChannelsNbRep; + break; + } + case MIB_MAX_RX_WINDOW_DURATION: + { + mibGet->Param.MaxRxWindow = LoRaMacParams.MaxRxWindow; + break; + } + case MIB_RECEIVE_DELAY_1: + { + mibGet->Param.ReceiveDelay1 = LoRaMacParams.ReceiveDelay1; + break; + } + case MIB_RECEIVE_DELAY_2: + { + mibGet->Param.ReceiveDelay2 = LoRaMacParams.ReceiveDelay2; + break; + } + case MIB_JOIN_ACCEPT_DELAY_1: + { + mibGet->Param.JoinAcceptDelay1 = LoRaMacParams.JoinAcceptDelay1; + break; + } + case MIB_JOIN_ACCEPT_DELAY_2: + { + mibGet->Param.JoinAcceptDelay2 = LoRaMacParams.JoinAcceptDelay2; + break; + } + case MIB_CHANNELS_DEFAULT_DATARATE: + { + mibGet->Param.ChannelsDefaultDatarate = LoRaMacParamsDefaults.ChannelsDatarate; + break; + } + case MIB_CHANNELS_DATARATE: + { + mibGet->Param.ChannelsDatarate = LoRaMacParams.ChannelsDatarate; + break; + } + case MIB_CHANNELS_DEFAULT_TX_POWER: + { + mibGet->Param.ChannelsDefaultTxPower = LoRaMacParamsDefaults.ChannelsTxPower; + break; + } + case MIB_CHANNELS_TX_POWER: + { + mibGet->Param.ChannelsTxPower = LoRaMacParams.ChannelsTxPower; + break; + } + case MIB_UPLINK_COUNTER: + { + mibGet->Param.UpLinkCounter = UpLinkCounter; + break; + } + case MIB_DOWNLINK_COUNTER: + { + mibGet->Param.DownLinkCounter = DownLinkCounter; + break; + } + case MIB_MULTICAST_CHANNEL: + { + mibGet->Param.MulticastList = MulticastChannels; + break; + } + case MIB_SYSTEM_MAX_RX_ERROR: + { + mibGet->Param.SystemMaxRxError = LoRaMacParams.SystemMaxRxError; + break; + } + case MIB_MIN_RX_SYMBOLS: + { + mibGet->Param.MinRxSymbols = LoRaMacParams.MinRxSymbols; + break; + } + default: + status = LORAMAC_STATUS_SERVICE_UNKNOWN; + break; + } + + return status; +} + +LoRaMacStatus_t LoRaMacMibSetRequestConfirm( MibRequestConfirm_t *mibSet ) +{ + LoRaMacStatus_t status = LORAMAC_STATUS_OK; + + if( mibSet == NULL ) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + if( ( LoRaMacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING ) + { + return LORAMAC_STATUS_BUSY; + } + + switch( mibSet->Type ) + { + case MIB_DEVICE_CLASS: + { + LoRaMacDeviceClass = mibSet->Param.Class; + switch( LoRaMacDeviceClass ) + { + case CLASS_A: + { + // Set the radio into sleep to setup a defined state + Radio.Sleep( ); + break; + } + case CLASS_B: + { + break; + } + case CLASS_C: + { + // Set the NodeAckRequested indicator to default + NodeAckRequested = false; + OnRxWindow2TimerEvent( ); + break; + } + } + break; + } + case MIB_NETWORK_JOINED: + { + IsLoRaMacNetworkJoined = mibSet->Param.IsNetworkJoined; + break; + } + case MIB_ADR: + { + AdrCtrlOn = mibSet->Param.AdrEnable; + break; + } + case MIB_NET_ID: + { + LoRaMacNetID = mibSet->Param.NetID; + break; + } + case MIB_DEV_ADDR: + { + LoRaMacDevAddr = mibSet->Param.DevAddr; + break; + } + case MIB_NWK_SKEY: + { + if( mibSet->Param.NwkSKey != NULL ) + { + memcpy1( LoRaMacNwkSKey, mibSet->Param.NwkSKey, + sizeof( LoRaMacNwkSKey ) ); + } + else + { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + break; + } + case MIB_APP_SKEY: + { + if( mibSet->Param.AppSKey != NULL ) + { + memcpy1( LoRaMacAppSKey, mibSet->Param.AppSKey, + sizeof( LoRaMacAppSKey ) ); + } + else + { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + break; + } + case MIB_PUBLIC_NETWORK: + { + PublicNetwork = mibSet->Param.EnablePublicNetwork; + Radio.SetPublicNetwork( PublicNetwork ); + break; + } + case MIB_REPEATER_SUPPORT: + { + RepeaterSupport = mibSet->Param.EnableRepeaterSupport; + break; + } + case MIB_RX2_CHANNEL: + { + LoRaMacParams.Rx2Channel = mibSet->Param.Rx2Channel; + break; + } + case MIB_RX2_DEFAULT_CHANNEL: + { + LoRaMacParamsDefaults.Rx2Channel = mibSet->Param.Rx2DefaultChannel; + break; + } + case MIB_CHANNELS_DEFAULT_MASK: + { + if( mibSet->Param.ChannelsDefaultMask ) + { +#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) + bool chanMaskState = true; + +#if defined( USE_BAND_915_HYBRID ) + chanMaskState = ValidateChannelMask( mibSet->Param.ChannelsDefaultMask ); +#endif + if( chanMaskState == true ) + { + if( ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) < 2 ) && + ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) > 0 ) ) + { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + else + { + memcpy1( ( uint8_t* ) LoRaMacParamsDefaults.ChannelsMask, + ( uint8_t* ) mibSet->Param.ChannelsDefaultMask, sizeof( LoRaMacParamsDefaults.ChannelsMask ) ); + for ( uint8_t i = 0; i < sizeof( LoRaMacParamsDefaults.ChannelsMask ) / 2; i++ ) + { + // Disable channels which are no longer available + ChannelsMaskRemaining[i] &= LoRaMacParamsDefaults.ChannelsMask[i]; + } + } + } + else + { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } +#elif defined( USE_BAND_470 ) + memcpy1( ( uint8_t* ) LoRaMacParamsDefaults.ChannelsMask, + ( uint8_t* ) mibSet->Param.ChannelsDefaultMask, sizeof( LoRaMacParamsDefaults.ChannelsMask ) ); +#else + memcpy1( ( uint8_t* ) LoRaMacParamsDefaults.ChannelsMask, + ( uint8_t* ) mibSet->Param.ChannelsDefaultMask, 2 ); +#endif + } + else + { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + break; + } + case MIB_CHANNELS_MASK: + { + if( mibSet->Param.ChannelsMask ) + { +#if defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) + bool chanMaskState = true; + +#if defined( USE_BAND_915_HYBRID ) + chanMaskState = ValidateChannelMask( mibSet->Param.ChannelsMask ); +#endif + if( chanMaskState == true ) + { + if( ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) < 2 ) && + ( CountNbEnabled125kHzChannels( mibSet->Param.ChannelsMask ) > 0 ) ) + { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + else + { + memcpy1( ( uint8_t* ) LoRaMacParams.ChannelsMask, + ( uint8_t* ) mibSet->Param.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) ); + for ( uint8_t i = 0; i < sizeof( LoRaMacParams.ChannelsMask ) / 2; i++ ) + { + // Disable channels which are no longer available + ChannelsMaskRemaining[i] &= LoRaMacParams.ChannelsMask[i]; + } + } + } + else + { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } +#elif defined( USE_BAND_470 ) + memcpy1( ( uint8_t* ) LoRaMacParams.ChannelsMask, + ( uint8_t* ) mibSet->Param.ChannelsMask, sizeof( LoRaMacParams.ChannelsMask ) ); +#else + memcpy1( ( uint8_t* ) LoRaMacParams.ChannelsMask, + ( uint8_t* ) mibSet->Param.ChannelsMask, 2 ); +#endif + } + else + { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + break; + } + case MIB_CHANNELS_NB_REP: + { + if( ( mibSet->Param.ChannelNbRep >= 1 ) && + ( mibSet->Param.ChannelNbRep <= 15 ) ) + { + LoRaMacParams.ChannelsNbRep = mibSet->Param.ChannelNbRep; + } + else + { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + break; + } + case MIB_MAX_RX_WINDOW_DURATION: + { + LoRaMacParams.MaxRxWindow = mibSet->Param.MaxRxWindow; + break; + } + case MIB_RECEIVE_DELAY_1: + { + LoRaMacParams.ReceiveDelay1 = mibSet->Param.ReceiveDelay1; + break; + } + case MIB_RECEIVE_DELAY_2: + { + LoRaMacParams.ReceiveDelay2 = mibSet->Param.ReceiveDelay2; + break; + } + case MIB_JOIN_ACCEPT_DELAY_1: + { + LoRaMacParams.JoinAcceptDelay1 = mibSet->Param.JoinAcceptDelay1; + break; + } + case MIB_JOIN_ACCEPT_DELAY_2: + { + LoRaMacParams.JoinAcceptDelay2 = mibSet->Param.JoinAcceptDelay2; + break; + } + case MIB_CHANNELS_DEFAULT_DATARATE: + { +#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) + if( ValueInRange( mibSet->Param.ChannelsDefaultDatarate, + DR_0, DR_5 ) ) + { + LoRaMacParamsDefaults.ChannelsDatarate = mibSet->Param.ChannelsDefaultDatarate; + } +#else + if( ValueInRange( mibSet->Param.ChannelsDefaultDatarate, + LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) ) + { + LoRaMacParamsDefaults.ChannelsDatarate = mibSet->Param.ChannelsDefaultDatarate; + } +#endif + else + { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + break; + } + case MIB_CHANNELS_DATARATE: + { + if( ValueInRange( mibSet->Param.ChannelsDatarate, + LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) ) + { + LoRaMacParams.ChannelsDatarate = mibSet->Param.ChannelsDatarate; + } + else + { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + break; + } + case MIB_CHANNELS_DEFAULT_TX_POWER: + { + if( ValueInRange( mibSet->Param.ChannelsDefaultTxPower, + LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) ) + { + LoRaMacParamsDefaults.ChannelsTxPower = mibSet->Param.ChannelsDefaultTxPower; + } + else + { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + break; + } + case MIB_CHANNELS_TX_POWER: + { + if( ValueInRange( mibSet->Param.ChannelsTxPower, + LORAMAC_MAX_TX_POWER, LORAMAC_MIN_TX_POWER ) ) + { + LoRaMacParams.ChannelsTxPower = mibSet->Param.ChannelsTxPower; + } + else + { + status = LORAMAC_STATUS_PARAMETER_INVALID; + } + break; + } + case MIB_UPLINK_COUNTER: + { + UpLinkCounter = mibSet->Param.UpLinkCounter; + break; + } + case MIB_DOWNLINK_COUNTER: + { + DownLinkCounter = mibSet->Param.DownLinkCounter; + break; + } + case MIB_SYSTEM_MAX_RX_ERROR: + { + LoRaMacParams.SystemMaxRxError = LoRaMacParamsDefaults.SystemMaxRxError = mibSet->Param.SystemMaxRxError; + break; + } + case MIB_MIN_RX_SYMBOLS: + { + LoRaMacParams.MinRxSymbols = LoRaMacParamsDefaults.MinRxSymbols = mibSet->Param.MinRxSymbols; + break; + } + default: + status = LORAMAC_STATUS_SERVICE_UNKNOWN; + break; + } + + return status; +} + +LoRaMacStatus_t LoRaMacChannelAdd( uint8_t id, ChannelParams_t params ) +{ +#if defined( USE_BAND_470 ) || defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) + return LORAMAC_STATUS_PARAMETER_INVALID; +#else + bool datarateInvalid = false; + bool frequencyInvalid = false; + uint8_t band = 0; + + // The id must not exceed LORA_MAX_NB_CHANNELS + if( id >= LORA_MAX_NB_CHANNELS ) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + // Validate if the MAC is in a correct state + if( ( LoRaMacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING ) + { + if( ( LoRaMacState & LORAMAC_TX_CONFIG ) != LORAMAC_TX_CONFIG ) + { + return LORAMAC_STATUS_BUSY; + } + } + // Validate the datarate + if( ( params.DrRange.Fields.Min > params.DrRange.Fields.Max ) || + ( ValueInRange( params.DrRange.Fields.Min, LORAMAC_TX_MIN_DATARATE, + LORAMAC_TX_MAX_DATARATE ) == false ) || + ( ValueInRange( params.DrRange.Fields.Max, LORAMAC_TX_MIN_DATARATE, + LORAMAC_TX_MAX_DATARATE ) == false ) ) + { + datarateInvalid = true; + } + +#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) + if( id < 3 ) + { + if( params.Frequency != Channels[id].Frequency ) + { + frequencyInvalid = true; + } + + if( params.DrRange.Fields.Min > DR_0 ) + { + datarateInvalid = true; + } + if( ValueInRange( params.DrRange.Fields.Max, DR_5, LORAMAC_TX_MAX_DATARATE ) == false ) + { + datarateInvalid = true; + } + } +#endif + + // Validate the frequency + if( ( Radio.CheckRfFrequency( params.Frequency ) == true ) && ( params.Frequency > 0 ) && ( frequencyInvalid == false ) ) + { +#if defined( USE_BAND_868 ) + if( ( params.Frequency >= 863000000 ) && ( params.Frequency < 865000000 ) ) + { + band = BAND_G1_2; + } + else if( ( params.Frequency >= 865000000 ) && ( params.Frequency <= 868000000 ) ) + { + band = BAND_G1_0; + } + else if( ( params.Frequency > 868000000 ) && ( params.Frequency <= 868600000 ) ) + { + band = BAND_G1_1; + } + else if( ( params.Frequency >= 868700000 ) && ( params.Frequency <= 869200000 ) ) + { + band = BAND_G1_2; + } + else if( ( params.Frequency >= 869400000 ) && ( params.Frequency <= 869650000 ) ) + { + band = BAND_G1_3; + } + else if( ( params.Frequency >= 869700000 ) && ( params.Frequency <= 870000000 ) ) + { + band = BAND_G1_4; + } + else + { + frequencyInvalid = true; + } +#endif + } + else + { + frequencyInvalid = true; + } + + if( ( datarateInvalid == true ) && ( frequencyInvalid == true ) ) + { + return LORAMAC_STATUS_FREQ_AND_DR_INVALID; + } + if( datarateInvalid == true ) + { + return LORAMAC_STATUS_DATARATE_INVALID; + } + if( frequencyInvalid == true ) + { + return LORAMAC_STATUS_FREQUENCY_INVALID; + } + + // Every parameter is valid, activate the channel + Channels[id] = params; + Channels[id].Band = band; + LoRaMacParams.ChannelsMask[0] |= ( 1 << id ); + + return LORAMAC_STATUS_OK; +#endif +} + +LoRaMacStatus_t LoRaMacChannelRemove( uint8_t id ) +{ +#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) + if( ( LoRaMacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING ) + { + if( ( LoRaMacState & LORAMAC_TX_CONFIG ) != LORAMAC_TX_CONFIG ) + { + return LORAMAC_STATUS_BUSY; + } + } + + if( ( id < 3 ) || ( id >= LORA_MAX_NB_CHANNELS ) ) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + else + { + // Remove the channel from the list of channels + Channels[id] = ( ChannelParams_t ){ 0, { 0 }, 0 }; + + // Disable the channel as it doesn't exist anymore + if( DisableChannelInMask( id, LoRaMacParams.ChannelsMask ) == false ) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + } + return LORAMAC_STATUS_OK; +#elif ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) || defined( USE_BAND_470 ) ) + return LORAMAC_STATUS_PARAMETER_INVALID; +#endif +} + +LoRaMacStatus_t LoRaMacMulticastChannelLink( MulticastParams_t *channelParam ) +{ + if( channelParam == NULL ) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + if( ( LoRaMacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING ) + { + return LORAMAC_STATUS_BUSY; + } + + // Reset downlink counter + channelParam->DownLinkCounter = 0; + + if( MulticastChannels == NULL ) + { + // New node is the fist element + MulticastChannels = channelParam; + } + else + { + MulticastParams_t *cur = MulticastChannels; + + // Search the last node in the list + while( cur->Next != NULL ) + { + cur = cur->Next; + } + // This function always finds the last node + cur->Next = channelParam; + } + + return LORAMAC_STATUS_OK; +} + +LoRaMacStatus_t LoRaMacMulticastChannelUnlink( MulticastParams_t *channelParam ) +{ + if( channelParam == NULL ) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + if( ( LoRaMacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING ) + { + return LORAMAC_STATUS_BUSY; + } + + if( MulticastChannels != NULL ) + { + if( MulticastChannels == channelParam ) + { + // First element + MulticastChannels = channelParam->Next; + } + else + { + MulticastParams_t *cur = MulticastChannels; + + // Search the node in the list + while( cur->Next && cur->Next != channelParam ) + { + cur = cur->Next; + } + // If we found the node, remove it + if( cur->Next ) + { + cur->Next = channelParam->Next; + } + } + channelParam->Next = NULL; + } + + return LORAMAC_STATUS_OK; +} + +LoRaMacStatus_t LoRaMacMlmeRequest( MlmeReq_t *mlmeRequest ) +{ + LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN; + LoRaMacHeader_t macHdr; + + if( mlmeRequest == NULL ) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + if( ( LoRaMacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING ) + { + return LORAMAC_STATUS_BUSY; + } + + memset1( ( uint8_t* ) &MlmeConfirm, 0, sizeof( MlmeConfirm ) ); + + MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR; + + switch( mlmeRequest->Type ) + { + case MLME_JOIN: + { + if( ( LoRaMacState & LORAMAC_TX_DELAYED ) == LORAMAC_TX_DELAYED ) + { + return LORAMAC_STATUS_BUSY; + } + + if( ( mlmeRequest->Req.Join.DevEui == NULL ) || + ( mlmeRequest->Req.Join.AppEui == NULL ) || + ( mlmeRequest->Req.Join.AppKey == NULL ) || + ( mlmeRequest->Req.Join.NbTrials == 0 ) ) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + +#if ( defined( USE_BAND_915 ) || defined( USE_BAND_915_HYBRID ) ) + // Enables at least the usage of the 2 datarates. + if( mlmeRequest->Req.Join.NbTrials < 2 ) + { + mlmeRequest->Req.Join.NbTrials = 2; + } +#else + // Enables at least the usage of all datarates. + if( mlmeRequest->Req.Join.NbTrials < 48 ) + { + mlmeRequest->Req.Join.NbTrials = 48; + } +#endif + + LoRaMacFlags.Bits.MlmeReq = 1; + MlmeConfirm.MlmeRequest = mlmeRequest->Type; + + LoRaMacDevEui = mlmeRequest->Req.Join.DevEui; + LoRaMacAppEui = mlmeRequest->Req.Join.AppEui; + LoRaMacAppKey = mlmeRequest->Req.Join.AppKey; + MaxJoinRequestTrials = mlmeRequest->Req.Join.NbTrials; + + // Reset variable JoinRequestTrials + JoinRequestTrials = 0; + + // Setup header information + macHdr.Value = 0; + macHdr.Bits.MType = FRAME_TYPE_JOIN_REQ; + + ResetMacParameters( ); + + // Add a +1, since we start to count from 0 + LoRaMacParams.ChannelsDatarate = AlternateDatarate( JoinRequestTrials + 1 ); + + status = Send( &macHdr, 0, NULL, 0 ); + break; + } + case MLME_LINK_CHECK: + { + LoRaMacFlags.Bits.MlmeReq = 1; + // LoRaMac will send this command piggy-pack + MlmeConfirm.MlmeRequest = mlmeRequest->Type; + + status = AddMacCommand( MOTE_MAC_LINK_CHECK_REQ, 0, 0 ); + break; + } + case MLME_TXCW: + { + MlmeConfirm.MlmeRequest = mlmeRequest->Type; + LoRaMacFlags.Bits.MlmeReq = 1; + status = SetTxContinuousWave( mlmeRequest->Req.TxCw.Timeout ); + break; + } + case MLME_TXCW_1: + { + MlmeConfirm.MlmeRequest = mlmeRequest->Type; + LoRaMacFlags.Bits.MlmeReq = 1; + status = SetTxContinuousWave1( mlmeRequest->Req.TxCw.Timeout, mlmeRequest->Req.TxCw.Frequency, mlmeRequest->Req.TxCw.Power ); + break; + } + default: + break; + } + + if( status != LORAMAC_STATUS_OK ) + { + NodeAckRequested = false; + LoRaMacFlags.Bits.MlmeReq = 0; + } + + return status; +} + +LoRaMacStatus_t LoRaMacMcpsRequest( McpsReq_t *mcpsRequest ) +{ + LoRaMacStatus_t status = LORAMAC_STATUS_SERVICE_UNKNOWN; + LoRaMacHeader_t macHdr; + uint8_t fPort = 0; + void *fBuffer; + uint16_t fBufferSize; + int8_t datarate; + bool readyToSend = false; + + if( mcpsRequest == NULL ) + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + if( ( ( LoRaMacState & LORAMAC_TX_RUNNING ) == LORAMAC_TX_RUNNING ) || + ( ( LoRaMacState & LORAMAC_TX_DELAYED ) == LORAMAC_TX_DELAYED ) ) + { + return LORAMAC_STATUS_BUSY; + } + + macHdr.Value = 0; + memset1 ( ( uint8_t* ) &McpsConfirm, 0, sizeof( McpsConfirm ) ); + McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_ERROR; + + switch( mcpsRequest->Type ) + { + case MCPS_UNCONFIRMED: + { + readyToSend = true; + AckTimeoutRetries = 1; + + macHdr.Bits.MType = FRAME_TYPE_DATA_UNCONFIRMED_UP; + fPort = mcpsRequest->Req.Unconfirmed.fPort; + fBuffer = mcpsRequest->Req.Unconfirmed.fBuffer; + fBufferSize = mcpsRequest->Req.Unconfirmed.fBufferSize; + datarate = mcpsRequest->Req.Unconfirmed.Datarate; + break; + } + case MCPS_CONFIRMED: + { + readyToSend = true; + AckTimeoutRetriesCounter = 1; + AckTimeoutRetries = mcpsRequest->Req.Confirmed.NbTrials; + + macHdr.Bits.MType = FRAME_TYPE_DATA_CONFIRMED_UP; + fPort = mcpsRequest->Req.Confirmed.fPort; + fBuffer = mcpsRequest->Req.Confirmed.fBuffer; + fBufferSize = mcpsRequest->Req.Confirmed.fBufferSize; + datarate = mcpsRequest->Req.Confirmed.Datarate; + break; + } + case MCPS_PROPRIETARY: + { + readyToSend = true; + AckTimeoutRetries = 1; + + macHdr.Bits.MType = FRAME_TYPE_PROPRIETARY; + fBuffer = mcpsRequest->Req.Proprietary.fBuffer; + fBufferSize = mcpsRequest->Req.Proprietary.fBufferSize; + datarate = mcpsRequest->Req.Proprietary.Datarate; + break; + } + default: + break; + } + + if( readyToSend == true ) + { + if( AdrCtrlOn == false ) + { + if( ValueInRange( datarate, LORAMAC_TX_MIN_DATARATE, LORAMAC_TX_MAX_DATARATE ) == true ) + { + LoRaMacParams.ChannelsDatarate = datarate; + } + else + { + return LORAMAC_STATUS_PARAMETER_INVALID; + } + } + + status = Send( &macHdr, fPort, fBuffer, fBufferSize ); + if( status == LORAMAC_STATUS_OK ) + { + McpsConfirm.McpsRequest = mcpsRequest->Type; + LoRaMacFlags.Bits.McpsReq = 1; + } + else + { + NodeAckRequested = false; + } + } + + return status; +} + +void LoRaMacTestRxWindowsOn( bool enable ) +{ + IsRxWindowsEnabled = enable; +} + +void LoRaMacTestSetMic( uint16_t txPacketCounter ) +{ + UpLinkCounter = txPacketCounter; + IsUpLinkCounterFixed = true; +} + +void LoRaMacTestSetDutyCycleOn( bool enable ) +{ +#if ( defined( USE_BAND_868 ) || defined( USE_BAND_433 ) || defined( USE_BAND_780 ) ) + DutyCycleOn = enable; +#else + DutyCycleOn = false; +#endif +} + +void LoRaMacTestSetChannel( uint8_t channel ) +{ + Channel = channel; +} + +static RxConfigParams_t ComputeRxWindowParameters( int8_t datarate, uint32_t rxError ) +{ + RxConfigParams_t rxConfigParams = { 0, 0, 0, 0 }; + double tSymbol = 0.0; + + rxConfigParams.Datarate = datarate; + switch( Bandwidths[datarate] ) + { + default: + case 125000: + rxConfigParams.Bandwidth = 0; + break; + case 250000: + rxConfigParams.Bandwidth = 1; + break; + case 500000: + rxConfigParams.Bandwidth = 2; + break; + } + +#if defined( USE_BAND_433 ) || defined( USE_BAND_780 ) || defined( USE_BAND_868 ) + if( datarate == DR_7 ) + { // FSK + tSymbol = ( 1.0 / ( double )Datarates[datarate] ) * 8.0; // 1 symbol equals 1 byte + } + else +#endif + { // LoRa + tSymbol = ( ( double )( 1 << Datarates[datarate] ) / ( double )Bandwidths[datarate] ) * 1e3; + } + + rxConfigParams.RxWindowTimeout = MAX( ( uint32_t )ceil( ( ( 2 * LoRaMacParams.MinRxSymbols - 8 ) * tSymbol + 2 * rxError ) / tSymbol ), LoRaMacParams.MinRxSymbols ); // Computed number of symbols + + rxConfigParams.RxOffset = ( int32_t )ceil( ( 4.0 * tSymbol ) - ( ( rxConfigParams.RxWindowTimeout * tSymbol ) / 2.0 ) - RADIO_WAKEUP_TIME ); + + return rxConfigParams; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mac/LoRaWAN-lib/LoRaMac.h Wed Sep 04 15:42:07 2019 +0000 @@ -0,0 +1,1886 @@ +/*! + * \file LoRaMac.h + * + * \brief LoRa MAC layer implementation + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + * + * \author Gregory Cristian ( Semtech ) + * + * \author Daniel Jäckle ( STACKFORCE ) + * + * \defgroup LORAMAC LoRa MAC layer implementation + * This module specifies the API implementation of the LoRaMAC layer. + * This is a placeholder for a detailed description of the LoRaMac + * layer and the supported features. + * \{ + * + * \example classA/LoRaMote/main.c + * LoRaWAN class A application example for the LoRaMote. + * + * \example classB/LoRaMote/main.c + * LoRaWAN class B application example for the LoRaMote. + * + * \example classC/LoRaMote/main.c + * LoRaWAN class C application example for the LoRaMote. + */ +#ifndef __LORAMAC_H__ +#define __LORAMAC_H__ + +// Includes board dependent definitions such as channels frequencies +#include "LoRaMac-definitions.h" + +/*! + * Beacon interval in ms + */ +#define BEACON_INTERVAL 128000 + +/*! + * Class A&B receive delay 1 in ms + */ +#define RECEIVE_DELAY1 1000 + +/*! + * Class A&B receive delay 2 in ms + */ +#define RECEIVE_DELAY2 2000 + +/*! + * Join accept receive delay 1 in ms + */ +#define JOIN_ACCEPT_DELAY1 5000 + +/*! + * Join accept receive delay 2 in ms + */ +#define JOIN_ACCEPT_DELAY2 6000 + +/*! + * Class A&B maximum receive window delay in ms + */ +#define MAX_RX_WINDOW 3000 + +/*! + * Maximum allowed gap for the FCNT field + */ +#define MAX_FCNT_GAP 16384 + +/*! + * ADR acknowledgement counter limit + */ +#define ADR_ACK_LIMIT 64 + +/*! + * Number of ADR acknowledgement requests before returning to default datarate + */ +#define ADR_ACK_DELAY 32 + +/*! + * Number of seconds after the start of the second reception window without + * receiving an acknowledge. + * AckTimeout = \ref ACK_TIMEOUT + Random( -\ref ACK_TIMEOUT_RND, \ref ACK_TIMEOUT_RND ) + */ +#define ACK_TIMEOUT 2000 + +/*! + * Random number of seconds after the start of the second reception window without + * receiving an acknowledge + * AckTimeout = \ref ACK_TIMEOUT + Random( -\ref ACK_TIMEOUT_RND, \ref ACK_TIMEOUT_RND ) + */ +#define ACK_TIMEOUT_RND 1000 + +/*! + * Check the Mac layer state every MAC_STATE_CHECK_TIMEOUT in ms + */ +#define MAC_STATE_CHECK_TIMEOUT 1000 + +/*! + * Maximum number of times the MAC layer tries to get an acknowledge. + */ +#define MAX_ACK_RETRIES 8 + +/*! + * RSSI free threshold [dBm] + */ +#define RSSI_FREE_TH ( int8_t )( -90 ) + +/*! + * Frame direction definition for up-link communications + */ +#define UP_LINK 0 + +/*! + * Frame direction definition for down-link communications + */ +#define DOWN_LINK 1 + +/*! + * Sets the length of the LoRaMAC footer field. + * Mainly indicates the MIC field length + */ +#define LORAMAC_MFR_LEN 4 + +/*! + * LoRaWAN devices classes definition + */ +typedef enum eDeviceClass +{ + /*! + * LoRaWAN device class A + * + * LoRaWAN Specification V1.0.1, chapter 3ff + */ + CLASS_A, + /*! + * LoRaWAN device class B + * + * LoRaWAN Specification V1.0.1, chapter 8ff + */ + CLASS_B, + /*! + * LoRaWAN device class C + * + * LoRaWAN Specification V1.0.1, chapter 17ff + */ + CLASS_C, +}DeviceClass_t; + +/*! + * LoRaMAC channels parameters definition + */ +typedef union uDrRange +{ + /*! + * Byte-access to the bits + */ + int8_t Value; + /*! + * Structure to store the minimum and the maximum datarate + */ + struct sFields + { + /*! + * Minimum data rate + * + * EU868 - [DR_0, DR_1, DR_2, DR_3, DR_4, DR_5, DR_6, DR_7] + * + * US915 - [DR_0, DR_1, DR_2, DR_3, DR_4] + */ + int8_t Min : 4; + /*! + * Maximum data rate + * + * EU868 - [DR_0, DR_1, DR_2, DR_3, DR_4, DR_5, DR_6, DR_7] + * + * US915 - [DR_0, DR_1, DR_2, DR_3, DR_4] + */ + int8_t Max : 4; + }Fields; +}DrRange_t; + +/*! + * LoRaMAC band parameters definition + */ +typedef struct sBand +{ + /*! + * Duty cycle + */ + uint16_t DCycle; + /*! + * Maximum Tx power + */ + int8_t TxMaxPower; + /*! + * Time stamp of the last Tx frame + */ + TimerTime_t LastTxDoneTime; + /*! + * Holds the time where the device is off + */ + TimerTime_t TimeOff; +}Band_t; + +/*! + * LoRaMAC channel definition + */ +typedef struct sChannelParams +{ + /*! + * Frequency in Hz + */ + uint32_t Frequency; + /*! + * Data rate definition + */ + DrRange_t DrRange; + /*! + * Band index + */ + uint8_t Band; +}ChannelParams_t; + +/*! + * LoRaMAC receive window 2 channel parameters + */ +typedef struct sRx2ChannelParams +{ + /*! + * Frequency in Hz + */ + uint32_t Frequency; + /*! + * Data rate + * + * EU868 - [DR_0, DR_1, DR_2, DR_3, DR_4, DR_5, DR_6, DR_7] + * + * US915 - [DR_8, DR_9, DR_10, DR_11, DR_12, DR_13] + */ + uint8_t Datarate; +}Rx2ChannelParams_t; + +/*! + * Global MAC layer parameters + */ +typedef struct sLoRaMacParams +{ + /*! + * Channels TX power + */ + int8_t ChannelsTxPower; + /*! + * Channels data rate + */ + int8_t ChannelsDatarate; + /*! + * System overall timing error in milliseconds. + * [-SystemMaxRxError : +SystemMaxRxError] + * Default: +/-10 ms + */ + uint32_t SystemMaxRxError; + /*! + * Minimum required number of symbols to detect an Rx frame + * Default: 6 symbols + */ + uint8_t MinRxSymbols; + /*! + * LoRaMac maximum time a reception window stays open + */ + uint32_t MaxRxWindow; + /*! + * Receive delay 1 + */ + uint32_t ReceiveDelay1; + /*! + * Receive delay 2 + */ + uint32_t ReceiveDelay2; + /*! + * Join accept delay 1 + */ + uint32_t JoinAcceptDelay1; + /*! + * Join accept delay 1 + */ + uint32_t JoinAcceptDelay2; + /*! + * Number of uplink messages repetitions [1:15] (unconfirmed messages only) + */ + uint8_t ChannelsNbRep; + /*! + * Datarate offset between uplink and downlink on first window + */ + uint8_t Rx1DrOffset; + /*! + * LoRaMAC 2nd reception window settings + */ + Rx2ChannelParams_t Rx2Channel; + /*! + * Mask indicating which channels are enabled + */ + uint16_t ChannelsMask[6]; +}LoRaMacParams_t; + +/*! + * LoRaMAC multicast channel parameter + */ +typedef struct sMulticastParams +{ + /*! + * Address + */ + uint32_t Address; + /*! + * Network session key + */ + uint8_t NwkSKey[16]; + /*! + * Application session key + */ + uint8_t AppSKey[16]; + /*! + * Downlink counter + */ + uint32_t DownLinkCounter; + /*! + * Reference pointer to the next multicast channel parameters in the list + */ + struct sMulticastParams *Next; +}MulticastParams_t; + +/*! + * LoRaMAC frame types + * + * LoRaWAN Specification V1.0.1, chapter 4.2.1, table 1 + */ +typedef enum eLoRaMacFrameType +{ + /*! + * LoRaMAC join request frame + */ + FRAME_TYPE_JOIN_REQ = 0x00, + /*! + * LoRaMAC join accept frame + */ + FRAME_TYPE_JOIN_ACCEPT = 0x01, + /*! + * LoRaMAC unconfirmed up-link frame + */ + FRAME_TYPE_DATA_UNCONFIRMED_UP = 0x02, + /*! + * LoRaMAC unconfirmed down-link frame + */ + FRAME_TYPE_DATA_UNCONFIRMED_DOWN = 0x03, + /*! + * LoRaMAC confirmed up-link frame + */ + FRAME_TYPE_DATA_CONFIRMED_UP = 0x04, + /*! + * LoRaMAC confirmed down-link frame + */ + FRAME_TYPE_DATA_CONFIRMED_DOWN = 0x05, + /*! + * LoRaMAC RFU frame + */ + FRAME_TYPE_RFU = 0x06, + /*! + * LoRaMAC proprietary frame + */ + FRAME_TYPE_PROPRIETARY = 0x07, +}LoRaMacFrameType_t; + +/*! + * LoRaMAC mote MAC commands + * + * LoRaWAN Specification V1.0.1, chapter 5, table 4 + */ +typedef enum eLoRaMacMoteCmd +{ + /*! + * LinkCheckReq + */ + MOTE_MAC_LINK_CHECK_REQ = 0x02, + /*! + * LinkADRAns + */ + MOTE_MAC_LINK_ADR_ANS = 0x03, + /*! + * DutyCycleAns + */ + MOTE_MAC_DUTY_CYCLE_ANS = 0x04, + /*! + * RXParamSetupAns + */ + MOTE_MAC_RX_PARAM_SETUP_ANS = 0x05, + /*! + * DevStatusAns + */ + MOTE_MAC_DEV_STATUS_ANS = 0x06, + /*! + * NewChannelAns + */ + MOTE_MAC_NEW_CHANNEL_ANS = 0x07, + /*! + * RXTimingSetupAns + */ + MOTE_MAC_RX_TIMING_SETUP_ANS = 0x08, +}LoRaMacMoteCmd_t; + +/*! + * LoRaMAC server MAC commands + * + * LoRaWAN Specification V1.0.1 chapter 5, table 4 + */ +typedef enum eLoRaMacSrvCmd +{ + /*! + * LinkCheckAns + */ + SRV_MAC_LINK_CHECK_ANS = 0x02, + /*! + * LinkADRReq + */ + SRV_MAC_LINK_ADR_REQ = 0x03, + /*! + * DutyCycleReq + */ + SRV_MAC_DUTY_CYCLE_REQ = 0x04, + /*! + * RXParamSetupReq + */ + SRV_MAC_RX_PARAM_SETUP_REQ = 0x05, + /*! + * DevStatusReq + */ + SRV_MAC_DEV_STATUS_REQ = 0x06, + /*! + * NewChannelReq + */ + SRV_MAC_NEW_CHANNEL_REQ = 0x07, + /*! + * RXTimingSetupReq + */ + SRV_MAC_RX_TIMING_SETUP_REQ = 0x08, +}LoRaMacSrvCmd_t; + +/*! + * LoRaMAC Battery level indicator + */ +typedef enum eLoRaMacBatteryLevel +{ + /*! + * External power source + */ + BAT_LEVEL_EXT_SRC = 0x00, + /*! + * Battery level empty + */ + BAT_LEVEL_EMPTY = 0x01, + /*! + * Battery level full + */ + BAT_LEVEL_FULL = 0xFE, + /*! + * Battery level - no measurement available + */ + BAT_LEVEL_NO_MEASURE = 0xFF, +}LoRaMacBatteryLevel_t; + +/*! + * LoRaMAC header field definition (MHDR field) + * + * LoRaWAN Specification V1.0.1, chapter 4.2 + */ +typedef union uLoRaMacHeader +{ + /*! + * Byte-access to the bits + */ + uint8_t Value; + /*! + * Structure containing single access to header bits + */ + struct sHdrBits + { + /*! + * Major version + */ + uint8_t Major : 2; + /*! + * RFU + */ + uint8_t RFU : 3; + /*! + * Message type + */ + uint8_t MType : 3; + }Bits; +}LoRaMacHeader_t; + +/*! + * LoRaMAC frame control field definition (FCtrl) + * + * LoRaWAN Specification V1.0.1, chapter 4.3.1 + */ +typedef union uLoRaMacFrameCtrl +{ + /*! + * Byte-access to the bits + */ + uint8_t Value; + /*! + * Structure containing single access to bits + */ + struct sCtrlBits + { + /*! + * Frame options length + */ + uint8_t FOptsLen : 4; + /*! + * Frame pending bit + */ + uint8_t FPending : 1; + /*! + * Message acknowledge bit + */ + uint8_t Ack : 1; + /*! + * ADR acknowledgment request bit + */ + uint8_t AdrAckReq : 1; + /*! + * ADR control in frame header + */ + uint8_t Adr : 1; + }Bits; +}LoRaMacFrameCtrl_t; + +/*! + * Enumeration containing the status of the operation of a MAC service + */ +typedef enum eLoRaMacEventInfoStatus +{ + /*! + * Service performed successfully + */ + LORAMAC_EVENT_INFO_STATUS_OK = 0, + /*! + * An error occurred during the execution of the service + */ + LORAMAC_EVENT_INFO_STATUS_ERROR, + /*! + * A Tx timeout occurred + */ + LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT, + /*! + * An Rx timeout occurred on receive window 2 + */ + LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT, + /*! + * An Rx error occurred on receive window 1 + */ + LORAMAC_EVENT_INFO_STATUS_RX1_ERROR, + /*! + * An Rx error occurred on receive window 2 + */ + LORAMAC_EVENT_INFO_STATUS_RX2_ERROR, + /*! + * An error occurred in the join procedure + */ + LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL, + /*! + * A frame with an invalid downlink counter was received. The + * downlink counter of the frame was equal to the local copy + * of the downlink counter of the node. + */ + LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED, + /*! + * The MAC could not retransmit a frame since the MAC decreased the datarate. The + * payload size is not applicable for the datarate. + */ + LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR, + /*! + * The node has lost MAX_FCNT_GAP or more frames. + */ + LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS, + /*! + * An address error occurred + */ + LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL, + /*! + * message integrity check failure + */ + LORAMAC_EVENT_INFO_STATUS_MIC_FAIL, +}LoRaMacEventInfoStatus_t; + +/*! + * LoRaMac tx/rx operation state + */ +typedef union eLoRaMacFlags_t +{ + /*! + * Byte-access to the bits + */ + uint8_t Value; + /*! + * Structure containing single access to bits + */ + struct sMacFlagBits + { + /*! + * MCPS-Req pending + */ + uint8_t McpsReq : 1; + /*! + * MCPS-Ind pending + */ + uint8_t McpsInd : 1; + /*! + * MCPS-Ind pending. Skip indication to the application layer + */ + uint8_t McpsIndSkip : 1; + /*! + * MLME-Req pending + */ + uint8_t MlmeReq : 1; + /*! + * MAC cycle done + */ + uint8_t MacDone : 1; + }Bits; +}LoRaMacFlags_t; + +/*! + * + * \brief LoRaMAC data services + * + * \details The following table list the primitives which are supported by the + * specific MAC data service: + * + * Name | Request | Indication | Response | Confirm + * --------------------- | :-----: | :--------: | :------: | :-----: + * \ref MCPS_UNCONFIRMED | YES | YES | NO | YES + * \ref MCPS_CONFIRMED | YES | YES | NO | YES + * \ref MCPS_MULTICAST | NO | YES | NO | NO + * \ref MCPS_PROPRIETARY | YES | YES | NO | YES + * + * The following table provides links to the function implementations of the + * related MCPS primitives: + * + * Primitive | Function + * ---------------- | :---------------------: + * MCPS-Request | \ref LoRaMacMlmeRequest + * MCPS-Confirm | MacMcpsConfirm in \ref LoRaMacPrimitives_t + * MCPS-Indication | MacMcpsIndication in \ref LoRaMacPrimitives_t + */ +typedef enum eMcps +{ + /*! + * Unconfirmed LoRaMAC frame + */ + MCPS_UNCONFIRMED, + /*! + * Confirmed LoRaMAC frame + */ + MCPS_CONFIRMED, + /*! + * Multicast LoRaMAC frame + */ + MCPS_MULTICAST, + /*! + * Proprietary frame + */ + MCPS_PROPRIETARY, +}Mcps_t; + +/*! + * LoRaMAC MCPS-Request for an unconfirmed frame + */ +typedef struct sMcpsReqUnconfirmed +{ + /*! + * Frame port field. Must be set if the payload is not empty. Use the + * application specific frame port values: [1...223] + * + * LoRaWAN Specification V1.0.1, chapter 4.3.2 + */ + uint8_t fPort; + /*! + * Pointer to the buffer of the frame payload + */ + void *fBuffer; + /*! + * Size of the frame payload + */ + uint16_t fBufferSize; + /*! + * Uplink datarate, if ADR is off + */ + int8_t Datarate; +}McpsReqUnconfirmed_t; + +/*! + * LoRaMAC MCPS-Request for a confirmed frame + */ +typedef struct sMcpsReqConfirmed +{ + /*! + * Frame port field. Must be set if the payload is not empty. Use the + * application specific frame port values: [1...223] + * + * LoRaWAN Specification V1.0.1, chapter 4.3.2 + */ + uint8_t fPort; + /*! + * Pointer to the buffer of the frame payload + */ + void *fBuffer; + /*! + * Size of the frame payload + */ + uint16_t fBufferSize; + /*! + * Uplink datarate, if ADR is off + */ + int8_t Datarate; + /*! + * Number of trials to transmit the frame, if the LoRaMAC layer did not + * receive an acknowledgment. The MAC performs a datarate adaptation, + * according to the LoRaWAN Specification V1.0.1, chapter 19.4, according + * to the following table: + * + * Transmission nb | Data Rate + * ----------------|----------- + * 1 (first) | DR + * 2 | DR + * 3 | max(DR-1,0) + * 4 | max(DR-1,0) + * 5 | max(DR-2,0) + * 6 | max(DR-2,0) + * 7 | max(DR-3,0) + * 8 | max(DR-3,0) + * + * Note, that if NbTrials is set to 1 or 2, the MAC will not decrease + * the datarate, in case the LoRaMAC layer did not receive an acknowledgment + */ + uint8_t NbTrials; +}McpsReqConfirmed_t; + +/*! + * LoRaMAC MCPS-Request for a proprietary frame + */ +typedef struct sMcpsReqProprietary +{ + /*! + * Pointer to the buffer of the frame payload + */ + void *fBuffer; + /*! + * Size of the frame payload + */ + uint16_t fBufferSize; + /*! + * Uplink datarate, if ADR is off + */ + int8_t Datarate; +}McpsReqProprietary_t; + +/*! + * LoRaMAC MCPS-Request structure + */ +typedef struct sMcpsReq +{ + /*! + * MCPS-Request type + */ + Mcps_t Type; + + /*! + * MCPS-Request parameters + */ + union uMcpsParam + { + /*! + * MCPS-Request parameters for an unconfirmed frame + */ + McpsReqUnconfirmed_t Unconfirmed; + /*! + * MCPS-Request parameters for a confirmed frame + */ + McpsReqConfirmed_t Confirmed; + /*! + * MCPS-Request parameters for a proprietary frame + */ + McpsReqProprietary_t Proprietary; + }Req; +}McpsReq_t; + +/*! + * LoRaMAC MCPS-Confirm + */ +typedef struct sMcpsConfirm +{ + /*! + * Holds the previously performed MCPS-Request + */ + Mcps_t McpsRequest; + /*! + * Status of the operation + */ + LoRaMacEventInfoStatus_t Status; + /*! + * Uplink datarate + */ + uint8_t Datarate; + /*! + * Transmission power + */ + int8_t TxPower; + /*! + * Set if an acknowledgement was received + */ + bool AckReceived; + /*! + * Provides the number of retransmissions + */ + uint8_t NbRetries; + /*! + * The transmission time on air of the frame + */ + TimerTime_t TxTimeOnAir; + /*! + * The uplink counter value related to the frame + */ + uint32_t UpLinkCounter; + /*! + * The uplink frequency related to the frame + */ + uint32_t UpLinkFrequency; +}McpsConfirm_t; + +/*! + * LoRaMAC MCPS-Indication primitive + */ +typedef struct sMcpsIndication +{ + /*! + * MCPS-Indication type + */ + Mcps_t McpsIndication; + /*! + * Status of the operation + */ + LoRaMacEventInfoStatus_t Status; + /*! + * Multicast + */ + uint8_t Multicast; + /*! + * Application port + */ + uint8_t Port; + /*! + * Downlink datarate + */ + uint8_t RxDatarate; + /*! + * Frame pending status + */ + uint8_t FramePending; + /*! + * Pointer to the received data stream + */ + uint8_t *Buffer; + /*! + * Size of the received data stream + */ + uint8_t BufferSize; + /*! + * Indicates, if data is available + */ + bool RxData; + /*! + * Rssi of the received packet + */ + int16_t Rssi; + /*! + * Snr of the received packet + */ + uint8_t Snr; + /*! + * Receive window + * + * [0: Rx window 1, 1: Rx window 2] + */ + uint8_t RxSlot; + /*! + * Set if an acknowledgement was received + */ + bool AckReceived; + /*! + * The downlink counter value for the received frame + */ + uint32_t DownLinkCounter; +}McpsIndication_t; + +/*! + * \brief LoRaMAC management services + * + * \details The following table list the primitives which are supported by the + * specific MAC management service: + * + * Name | Request | Indication | Response | Confirm + * --------------------- | :-----: | :--------: | :------: | :-----: + * \ref MLME_JOIN | YES | NO | NO | YES + * \ref MLME_LINK_CHECK | YES | NO | NO | YES + * \ref MLME_TXCW | YES | NO | NO | YES + * + * The following table provides links to the function implementations of the + * related MLME primitives. + * + * Primitive | Function + * ---------------- | :---------------------: + * MLME-Request | \ref LoRaMacMlmeRequest + * MLME-Confirm | MacMlmeConfirm in \ref LoRaMacPrimitives_t + */ +typedef enum eMlme +{ + /*! + * Initiates the Over-the-Air activation + * + * LoRaWAN Specification V1.0.1, chapter 6.2 + */ + MLME_JOIN, + /*! + * LinkCheckReq - Connectivity validation + * + * LoRaWAN Specification V1.0.1, chapter 5, table 4 + */ + MLME_LINK_CHECK, + /*! + * Sets Tx continuous wave mode + * + * LoRaWAN end-device certification + */ + MLME_TXCW, + /*! + * Sets Tx continuous wave mode (new LoRa-Alliance CC definition) + * + * LoRaWAN end-device certification + */ + MLME_TXCW_1, +}Mlme_t; + +/*! + * LoRaMAC MLME-Request for the join service + */ +typedef struct sMlmeReqJoin +{ + /*! + * Globally unique end-device identifier + * + * LoRaWAN Specification V1.0.1, chapter 6.2.1 + */ + uint8_t *DevEui; + /*! + * Application identifier + * + * LoRaWAN Specification V1.0.1, chapter 6.1.2 + */ + uint8_t *AppEui; + /*! + * AES-128 application key + * + * LoRaWAN Specification V1.0.1, chapter 6.2.2 + */ + uint8_t *AppKey; + /*! + * Number of trials for the join request. + */ + uint8_t NbTrials; +}MlmeReqJoin_t; + +/*! + * LoRaMAC MLME-Request for Tx continuous wave mode + */ +typedef struct sMlmeReqTxCw +{ + /*! + * Time in seconds while the radio is kept in continuous wave mode + */ + uint16_t Timeout; + /*! + * RF frequency to set (Only used with new way) + */ + uint32_t Frequency; + /*! + * RF output power to set (Only used with new way) + */ + uint8_t Power; +}MlmeReqTxCw_t; + +/*! + * LoRaMAC MLME-Request structure + */ +typedef struct sMlmeReq +{ + /*! + * MLME-Request type + */ + Mlme_t Type; + + /*! + * MLME-Request parameters + */ + union uMlmeParam + { + /*! + * MLME-Request parameters for a join request + */ + MlmeReqJoin_t Join; + /*! + * MLME-Request parameters for Tx continuous mode request + */ + MlmeReqTxCw_t TxCw; + }Req; +}MlmeReq_t; + +/*! + * LoRaMAC MLME-Confirm primitive + */ +typedef struct sMlmeConfirm +{ + /*! + * Holds the previously performed MLME-Request + */ + Mlme_t MlmeRequest; + /*! + * Status of the operation + */ + LoRaMacEventInfoStatus_t Status; + /*! + * The transmission time on air of the frame + */ + TimerTime_t TxTimeOnAir; + /*! + * Demodulation margin. Contains the link margin [dB] of the last + * successfully received LinkCheckReq + */ + uint8_t DemodMargin; + /*! + * Number of gateways which received the last LinkCheckReq + */ + uint8_t NbGateways; + /*! + * Provides the number of retransmissions + */ + uint8_t NbRetries; +}MlmeConfirm_t; + +/*! + * LoRa Mac Information Base (MIB) + * + * The following table lists the MIB parameters and the related attributes: + * + * Attribute | Get | Set + * --------------------------------- | :-: | :-: + * \ref MIB_DEVICE_CLASS | YES | YES + * \ref MIB_NETWORK_JOINED | YES | YES + * \ref MIB_ADR | YES | YES + * \ref MIB_NET_ID | YES | YES + * \ref MIB_DEV_ADDR | YES | YES + * \ref MIB_NWK_SKEY | YES | YES + * \ref MIB_APP_SKEY | YES | YES + * \ref MIB_PUBLIC_NETWORK | YES | YES + * \ref MIB_REPEATER_SUPPORT | YES | YES + * \ref MIB_CHANNELS | YES | NO + * \ref MIB_RX2_CHANNEL | YES | YES + * \ref MIB_CHANNELS_MASK | YES | YES + * \ref MIB_CHANNELS_DEFAULT_MASK | YES | YES + * \ref MIB_CHANNELS_NB_REP | YES | YES + * \ref MIB_MAX_RX_WINDOW_DURATION | YES | YES + * \ref MIB_RECEIVE_DELAY_1 | YES | YES + * \ref MIB_RECEIVE_DELAY_2 | YES | YES + * \ref MIB_JOIN_ACCEPT_DELAY_1 | YES | YES + * \ref MIB_JOIN_ACCEPT_DELAY_2 | YES | YES + * \ref MIB_CHANNELS_DATARATE | YES | YES + * \ref MIB_CHANNELS_DEFAULT_DATARATE| YES | YES + * \ref MIB_CHANNELS_TX_POWER | YES | YES + * \ref MIB_CHANNELS_DEFAULT_TX_POWER| YES | YES + * \ref MIB_UPLINK_COUNTER | YES | YES + * \ref MIB_DOWNLINK_COUNTER | YES | YES + * \ref MIB_MULTICAST_CHANNEL | YES | NO + * \ref MIB_SYSTEM_MAX_RX_ERROR | YES | YES + * \ref MIB_MIN_RX_SYMBOLS | YES | YES + * + * The following table provides links to the function implementations of the + * related MIB primitives: + * + * Primitive | Function + * ---------------- | :---------------------: + * MIB-Set | \ref LoRaMacMibSetRequestConfirm + * MIB-Get | \ref LoRaMacMibGetRequestConfirm + */ +typedef enum eMib +{ + /*! + * LoRaWAN device class + * + * LoRaWAN Specification V1.0.1 + */ + MIB_DEVICE_CLASS, + /*! + * LoRaWAN Network joined attribute + * + * LoRaWAN Specification V1.0.1 + */ + MIB_NETWORK_JOINED, + /*! + * Adaptive data rate + * + * LoRaWAN Specification V1.0.1, chapter 4.3.1.1 + * + * [true: ADR enabled, false: ADR disabled] + */ + MIB_ADR, + /*! + * Network identifier + * + * LoRaWAN Specification V1.0.1, chapter 6.1.1 + */ + MIB_NET_ID, + /*! + * End-device address + * + * LoRaWAN Specification V1.0.1, chapter 6.1.1 + */ + MIB_DEV_ADDR, + /*! + * Network session key + * + * LoRaWAN Specification V1.0.1, chapter 6.1.3 + */ + MIB_NWK_SKEY, + /*! + * Application session key + * + * LoRaWAN Specification V1.0.1, chapter 6.1.4 + */ + MIB_APP_SKEY, + /*! + * Set the network type to public or private + * + * LoRaWAN Specification V1.0.1, chapter 7 + * + * [true: public network, false: private network] + */ + MIB_PUBLIC_NETWORK, + /*! + * Support the operation with repeaters + * + * LoRaWAN Specification V1.0.1, chapter 7 + * + * [true: repeater support enabled, false: repeater support disabled] + */ + MIB_REPEATER_SUPPORT, + /*! + * Communication channels. A get request will return a + * pointer which references the first entry of the channel list. The + * list is of size LORA_MAX_NB_CHANNELS + * + * LoRaWAN Specification V1.0.1, chapter 7 + */ + MIB_CHANNELS, + /*! + * Set receive window 2 channel + * + * LoRaWAN Specification V1.0.1, chapter 3.3.2 + */ + MIB_RX2_CHANNEL, + /*! + * Set receive window 2 channel + * + * LoRaWAN Specification V1.0.1, chapter 3.3.2 + */ + MIB_RX2_DEFAULT_CHANNEL, + /*! + * LoRaWAN channels mask + * + * LoRaWAN Specification V1.0.1, chapter 7 + */ + MIB_CHANNELS_MASK, + /*! + * LoRaWAN default channels mask + * + * LoRaWAN Specification V1.0.1, chapter 7 + */ + MIB_CHANNELS_DEFAULT_MASK, + /*! + * Set the number of repetitions on a channel + * + * LoRaWAN Specification V1.0.1, chapter 5.2 + */ + MIB_CHANNELS_NB_REP, + /*! + * Maximum receive window duration in [ms] + * + * LoRaWAN Specification V1.0.1, chapter 3.3.3 + */ + MIB_MAX_RX_WINDOW_DURATION, + /*! + * Receive delay 1 in [ms] + * + * LoRaWAN Specification V1.0.1, chapter 7 + */ + MIB_RECEIVE_DELAY_1, + /*! + * Receive delay 2 in [ms] + * + * LoRaWAN Specification V1.0.1, chapter 7 + */ + MIB_RECEIVE_DELAY_2, + /*! + * Join accept delay 1 in [ms] + * + * LoRaWAN Specification V1.0.1, chapter 7 + */ + MIB_JOIN_ACCEPT_DELAY_1, + /*! + * Join accept delay 2 in [ms] + * + * LoRaWAN Specification V1.0.1, chapter 7 + */ + MIB_JOIN_ACCEPT_DELAY_2, + /*! + * Default Data rate of a channel + * + * LoRaWAN Specification V1.0.1, chapter 7 + * + * EU868 - [DR_0, DR_1, DR_2, DR_3, DR_4, DR_5, DR_6, DR_7] + * + * US915 - [DR_0, DR_1, DR_2, DR_3, DR_4, DR_8, DR_9, DR_10, DR_11, DR_12, DR_13] + */ + MIB_CHANNELS_DEFAULT_DATARATE, + /*! + * Data rate of a channel + * + * LoRaWAN Specification V1.0.1, chapter 7 + * + * EU868 - [DR_0, DR_1, DR_2, DR_3, DR_4, DR_5, DR_6, DR_7] + * + * US915 - [DR_0, DR_1, DR_2, DR_3, DR_4, DR_8, DR_9, DR_10, DR_11, DR_12, DR_13] + */ + MIB_CHANNELS_DATARATE, + /*! + * Transmission power of a channel + * + * LoRaWAN Specification V1.0.1, chapter 7 + * + * EU868 - [TX_POWER_20_DBM, TX_POWER_14_DBM, TX_POWER_11_DBM, + * TX_POWER_08_DBM, TX_POWER_05_DBM, TX_POWER_02_DBM] + * + * US915 - [TX_POWER_30_DBM, TX_POWER_28_DBM, TX_POWER_26_DBM, + * TX_POWER_24_DBM, TX_POWER_22_DBM, TX_POWER_20_DBM, + * TX_POWER_18_DBM, TX_POWER_14_DBM, TX_POWER_12_DBM, + * TX_POWER_10_DBM] + */ + MIB_CHANNELS_TX_POWER, + /*! + * Transmission power of a channel + * + * LoRaWAN Specification V1.0.1, chapter 7 + * + * EU868 - [TX_POWER_20_DBM, TX_POWER_14_DBM, TX_POWER_11_DBM, + * TX_POWER_08_DBM, TX_POWER_05_DBM, TX_POWER_02_DBM] + * + * US915 - [TX_POWER_30_DBM, TX_POWER_28_DBM, TX_POWER_26_DBM, + * TX_POWER_24_DBM, TX_POWER_22_DBM, TX_POWER_20_DBM, + * TX_POWER_18_DBM, TX_POWER_14_DBM, TX_POWER_12_DBM, + * TX_POWER_10_DBM] + */ + MIB_CHANNELS_DEFAULT_TX_POWER, + /*! + * LoRaWAN Up-link counter + * + * LoRaWAN Specification V1.0.1, chapter 4.3.1.5 + */ + MIB_UPLINK_COUNTER, + /*! + * LoRaWAN Down-link counter + * + * LoRaWAN Specification V1.0.1, chapter 4.3.1.5 + */ + MIB_DOWNLINK_COUNTER, + /*! + * Multicast channels. A get request will return a pointer to the first + * entry of the multicast channel linked list. If the pointer is equal to + * NULL, the list is empty. + */ + MIB_MULTICAST_CHANNEL, + /*! + * System overall timing error in milliseconds. + * [-SystemMaxRxError : +SystemMaxRxError] + * Default: +/-10 ms + */ + MIB_SYSTEM_MAX_RX_ERROR, + /*! + * Minimum required number of symbols to detect an Rx frame + * Default: 6 symbols + */ + MIB_MIN_RX_SYMBOLS, +}Mib_t; + +/*! + * LoRaMAC MIB parameters + */ +typedef union uMibParam +{ + /*! + * LoRaWAN device class + * + * Related MIB type: \ref MIB_DEVICE_CLASS + */ + DeviceClass_t Class; + /*! + * LoRaWAN network joined attribute + * + * Related MIB type: \ref MIB_NETWORK_JOINED + */ + bool IsNetworkJoined; + /*! + * Activation state of ADR + * + * Related MIB type: \ref MIB_ADR + */ + bool AdrEnable; + /*! + * Network identifier + * + * Related MIB type: \ref MIB_NET_ID + */ + uint32_t NetID; + /*! + * End-device address + * + * Related MIB type: \ref MIB_DEV_ADDR + */ + uint32_t DevAddr; + /*! + * Network session key + * + * Related MIB type: \ref MIB_NWK_SKEY + */ + uint8_t *NwkSKey; + /*! + * Application session key + * + * Related MIB type: \ref MIB_APP_SKEY + */ + uint8_t *AppSKey; + /*! + * Enable or disable a public network + * + * Related MIB type: \ref MIB_PUBLIC_NETWORK + */ + bool EnablePublicNetwork; + /*! + * Enable or disable repeater support + * + * Related MIB type: \ref MIB_REPEATER_SUPPORT + */ + bool EnableRepeaterSupport; + /*! + * LoRaWAN Channel + * + * Related MIB type: \ref MIB_CHANNELS + */ + ChannelParams_t* ChannelList; + /*! + * Channel for the receive window 2 + * + * Related MIB type: \ref MIB_RX2_CHANNEL + */ + Rx2ChannelParams_t Rx2Channel; + /*! + * Channel for the receive window 2 + * + * Related MIB type: \ref MIB_RX2_DEFAULT_CHANNEL + */ + Rx2ChannelParams_t Rx2DefaultChannel; + /*! + * Channel mask + * + * Related MIB type: \ref MIB_CHANNELS_MASK + */ + uint16_t* ChannelsMask; + /*! + * Default channel mask + * + * Related MIB type: \ref MIB_CHANNELS_DEFAULT_MASK + */ + uint16_t* ChannelsDefaultMask; + /*! + * Number of frame repetitions + * + * Related MIB type: \ref MIB_CHANNELS_NB_REP + */ + uint8_t ChannelNbRep; + /*! + * Maximum receive window duration + * + * Related MIB type: \ref MIB_MAX_RX_WINDOW_DURATION + */ + uint32_t MaxRxWindow; + /*! + * Receive delay 1 + * + * Related MIB type: \ref MIB_RECEIVE_DELAY_1 + */ + uint32_t ReceiveDelay1; + /*! + * Receive delay 2 + * + * Related MIB type: \ref MIB_RECEIVE_DELAY_2 + */ + uint32_t ReceiveDelay2; + /*! + * Join accept delay 1 + * + * Related MIB type: \ref MIB_JOIN_ACCEPT_DELAY_1 + */ + uint32_t JoinAcceptDelay1; + /*! + * Join accept delay 2 + * + * Related MIB type: \ref MIB_JOIN_ACCEPT_DELAY_2 + */ + uint32_t JoinAcceptDelay2; + /*! + * Channels data rate + * + * Related MIB type: \ref MIB_CHANNELS_DEFAULT_DATARATE + */ + int8_t ChannelsDefaultDatarate; + /*! + * Channels data rate + * + * Related MIB type: \ref MIB_CHANNELS_DATARATE + */ + int8_t ChannelsDatarate; + /*! + * Channels TX power + * + * Related MIB type: \ref MIB_CHANNELS_DEFAULT_TX_POWER + */ + int8_t ChannelsDefaultTxPower; + /*! + * Channels TX power + * + * Related MIB type: \ref MIB_CHANNELS_TX_POWER + */ + int8_t ChannelsTxPower; + /*! + * LoRaWAN Up-link counter + * + * Related MIB type: \ref MIB_UPLINK_COUNTER + */ + uint32_t UpLinkCounter; + /*! + * LoRaWAN Down-link counter + * + * Related MIB type: \ref MIB_DOWNLINK_COUNTER + */ + uint32_t DownLinkCounter; + /*! + * Multicast channel + * + * Related MIB type: \ref MIB_MULTICAST_CHANNEL + */ + MulticastParams_t* MulticastList; + /*! + * System overall timing error in milliseconds. + * + * Related MIB type: \ref MIB_SYSTEM_MAX_RX_ERROR + */ + uint32_t SystemMaxRxError; + /*! + * Minimum required number of symbols to detect an Rx frame + * + * Related MIB type: \ref MIB_MIN_RX_SYMBOLS + */ + uint8_t MinRxSymbols; +}MibParam_t; + +/*! + * LoRaMAC MIB-RequestConfirm structure + */ +typedef struct eMibRequestConfirm +{ + /*! + * MIB-Request type + */ + Mib_t Type; + + /*! + * MLME-RequestConfirm parameters + */ + MibParam_t Param; +}MibRequestConfirm_t; + +/*! + * LoRaMAC tx information + */ +typedef struct sLoRaMacTxInfo +{ + /*! + * Defines the size of the applicative payload which can be processed + */ + uint8_t MaxPossiblePayload; + /*! + * The current payload size, dependent on the current datarate + */ + uint8_t CurrentPayloadSize; +}LoRaMacTxInfo_t; + +/*! + * LoRaMAC Status + */ +typedef enum eLoRaMacStatus +{ + /*! + * Service started successfully + */ + LORAMAC_STATUS_OK, + /*! + * Service not started - LoRaMAC is busy + */ + LORAMAC_STATUS_BUSY, + /*! + * Service unknown + */ + LORAMAC_STATUS_SERVICE_UNKNOWN, + /*! + * Service not started - invalid parameter + */ + LORAMAC_STATUS_PARAMETER_INVALID, + /*! + * Service not started - invalid frequency + */ + LORAMAC_STATUS_FREQUENCY_INVALID, + /*! + * Service not started - invalid datarate + */ + LORAMAC_STATUS_DATARATE_INVALID, + /*! + * Service not started - invalid frequency and datarate + */ + LORAMAC_STATUS_FREQ_AND_DR_INVALID, + /*! + * Service not started - the device is not in a LoRaWAN + */ + LORAMAC_STATUS_NO_NETWORK_JOINED, + /*! + * Service not started - payload lenght error + */ + LORAMAC_STATUS_LENGTH_ERROR, + /*! + * Service not started - payload lenght error + */ + LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR, + /*! + * Service not started - the device is switched off + */ + LORAMAC_STATUS_DEVICE_OFF, +}LoRaMacStatus_t; + +/*! + * LoRaMAC events structure + * Used to notify upper layers of MAC events + */ +typedef struct sLoRaMacPrimitives +{ + /*! + * \brief MCPS-Confirm primitive + * + * \param [OUT] MCPS-Confirm parameters + */ + void ( *MacMcpsConfirm )( McpsConfirm_t *McpsConfirm ); + /*! + * \brief MCPS-Indication primitive + * + * \param [OUT] MCPS-Indication parameters + */ + void ( *MacMcpsIndication )( McpsIndication_t *McpsIndication ); + /*! + * \brief MLME-Confirm primitive + * + * \param [OUT] MLME-Confirm parameters + */ + void ( *MacMlmeConfirm )( MlmeConfirm_t *MlmeConfirm ); +}LoRaMacPrimitives_t; + +typedef struct sLoRaMacCallback +{ + /*! + * \brief Measures the battery level + * + * \retval Battery level [0: node is connected to an external + * power source, 1..254: battery level, where 1 is the minimum + * and 254 is the maximum value, 255: the node was not able + * to measure the battery level] + */ + uint8_t ( *GetBatteryLevel )( void ); +}LoRaMacCallback_t; + +/*! + * \brief LoRaMAC layer initialization + * + * \details In addition to the initialization of the LoRaMAC layer, this + * function initializes the callback primitives of the MCPS and + * MLME services. Every data field of \ref LoRaMacPrimitives_t must be + * set to a valid callback function. + * + * \param [IN] events - Pointer to a structure defining the LoRaMAC + * event functions. Refer to \ref LoRaMacPrimitives_t. + * + * \param [IN] events - Pointer to a structure defining the LoRaMAC + * callback functions. Refer to \ref LoRaMacCallback_t. + * + * \retval LoRaMacStatus_t Status of the operation. Possible returns are: + * returns are: + * \ref LORAMAC_STATUS_OK, + * \ref LORAMAC_STATUS_PARAMETER_INVALID. + */ +LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t *primitives, LoRaMacCallback_t *callbacks ); + +/*! + * \brief Queries the LoRaMAC if it is possible to send the next frame with + * a given payload size. The LoRaMAC takes scheduled MAC commands into + * account and reports, when the frame can be send or not. + * + * \param [IN] size - Size of applicative payload to be send next + * + * \param [OUT] txInfo - The structure \ref LoRaMacTxInfo_t contains + * information about the actual maximum payload possible + * ( according to the configured datarate or the next + * datarate according to ADR ), and the maximum frame + * size, taking the scheduled MAC commands into account. + * + * \retval LoRaMacStatus_t Status of the operation. When the parameters are + * not valid, the function returns \ref LORAMAC_STATUS_PARAMETER_INVALID. + * In case of a length error caused by the applicative payload size, the + * function returns LORAMAC_STATUS_LENGTH_ERROR. In case of a length error + * due to additional MAC commands in the queue, the function returns + * LORAMAC_STATUS_MAC_CMD_LENGTH_ERROR. In case the query is valid, and + * the LoRaMAC is able to send the frame, the function returns LORAMAC_STATUS_OK. * + */ +LoRaMacStatus_t LoRaMacQueryTxPossible( uint8_t size, LoRaMacTxInfo_t* txInfo ); + +/*! + * \brief LoRaMAC channel add service + * + * \details Adds a new channel to the channel list and activates the id in + * the channel mask. For the US915 band, all channels are enabled + * by default. It is not possible to activate less than 6 125 kHz + * channels. + * + * \param [IN] id - Id of the channel. Possible values are: + * + * 0-15 for EU868 + * 0-72 for US915 + * + * \param [IN] params - Channel parameters to set. + * + * \retval LoRaMacStatus_t Status of the operation. Possible returns are: + * \ref LORAMAC_STATUS_OK, + * \ref LORAMAC_STATUS_BUSY, + * \ref LORAMAC_STATUS_PARAMETER_INVALID. + */ +LoRaMacStatus_t LoRaMacChannelAdd( uint8_t id, ChannelParams_t params ); + +/*! + * \brief LoRaMAC channel remove service + * + * \details Deactivates the id in the channel mask. + * + * \param [IN] id - Id of the channel. + * + * \retval LoRaMacStatus_t Status of the operation. Possible returns are: + * \ref LORAMAC_STATUS_OK, + * \ref LORAMAC_STATUS_BUSY, + * \ref LORAMAC_STATUS_PARAMETER_INVALID. + */ +LoRaMacStatus_t LoRaMacChannelRemove( uint8_t id ); + +/*! + * \brief LoRaMAC multicast channel link service + * + * \details Links a multicast channel into the linked list. + * + * \param [IN] channelParam - Multicast channel parameters to link. + * + * \retval LoRaMacStatus_t Status of the operation. Possible returns are: + * \ref LORAMAC_STATUS_OK, + * \ref LORAMAC_STATUS_BUSY, + * \ref LORAMAC_STATUS_PARAMETER_INVALID. + */ +LoRaMacStatus_t LoRaMacMulticastChannelLink( MulticastParams_t *channelParam ); + +/*! + * \brief LoRaMAC multicast channel unlink service + * + * \details Unlinks a multicast channel from the linked list. + * + * \param [IN] channelParam - Multicast channel parameters to unlink. + * + * \retval LoRaMacStatus_t Status of the operation. Possible returns are: + * \ref LORAMAC_STATUS_OK, + * \ref LORAMAC_STATUS_BUSY, + * \ref LORAMAC_STATUS_PARAMETER_INVALID. + */ +LoRaMacStatus_t LoRaMacMulticastChannelUnlink( MulticastParams_t *channelParam ); + +/*! + * \brief LoRaMAC MIB-Get + * + * \details The mac information base service to get attributes of the LoRaMac + * layer. + * + * The following code-snippet shows how to use the API to get the + * parameter AdrEnable, defined by the enumeration type + * \ref MIB_ADR. + * \code + * MibRequestConfirm_t mibReq; + * mibReq.Type = MIB_ADR; + * + * if( LoRaMacMibGetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK ) + * { + * // LoRaMAC updated the parameter mibParam.AdrEnable + * } + * \endcode + * + * \param [IN] mibRequest - MIB-GET-Request to perform. Refer to \ref MibRequestConfirm_t. + * + * \retval LoRaMacStatus_t Status of the operation. Possible returns are: + * \ref LORAMAC_STATUS_OK, + * \ref LORAMAC_STATUS_SERVICE_UNKNOWN, + * \ref LORAMAC_STATUS_PARAMETER_INVALID. + */ +LoRaMacStatus_t LoRaMacMibGetRequestConfirm( MibRequestConfirm_t *mibGet ); + +/*! + * \brief LoRaMAC MIB-Set + * + * \details The mac information base service to set attributes of the LoRaMac + * layer. + * + * The following code-snippet shows how to use the API to set the + * parameter AdrEnable, defined by the enumeration type + * \ref MIB_ADR. + * + * \code + * MibRequestConfirm_t mibReq; + * mibReq.Type = MIB_ADR; + * mibReq.Param.AdrEnable = true; + * + * if( LoRaMacMibGetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK ) + * { + * // LoRaMAC updated the parameter + * } + * \endcode + * + * \param [IN] mibRequest - MIB-SET-Request to perform. Refer to \ref MibRequestConfirm_t. + * + * \retval LoRaMacStatus_t Status of the operation. Possible returns are: + * \ref LORAMAC_STATUS_OK, + * \ref LORAMAC_STATUS_BUSY, + * \ref LORAMAC_STATUS_SERVICE_UNKNOWN, + * \ref LORAMAC_STATUS_PARAMETER_INVALID. + */ +LoRaMacStatus_t LoRaMacMibSetRequestConfirm( MibRequestConfirm_t *mibSet ); + +/*! + * \brief LoRaMAC MLME-Request + * + * \details The Mac layer management entity handles management services. The + * following code-snippet shows how to use the API to perform a + * network join request. + * + * \code + * static uint8_t DevEui[] = + * { + * 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + * }; + * static uint8_t AppEui[] = + * { + * 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + * }; + * static uint8_t AppKey[] = + * { + * 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + * 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C + * }; + * + * MlmeReq_t mlmeReq; + * mlmeReq.Type = MLME_JOIN; + * mlmeReq.Req.Join.DevEui = DevEui; + * mlmeReq.Req.Join.AppEui = AppEui; + * mlmeReq.Req.Join.AppKey = AppKey; + * + * if( LoRaMacMlmeRequest( &mlmeReq ) == LORAMAC_STATUS_OK ) + * { + * // Service started successfully. Waiting for the Mlme-Confirm event + * } + * \endcode + * + * \param [IN] mlmeRequest - MLME-Request to perform. Refer to \ref MlmeReq_t. + * + * \retval LoRaMacStatus_t Status of the operation. Possible returns are: + * \ref LORAMAC_STATUS_OK, + * \ref LORAMAC_STATUS_BUSY, + * \ref LORAMAC_STATUS_SERVICE_UNKNOWN, + * \ref LORAMAC_STATUS_PARAMETER_INVALID, + * \ref LORAMAC_STATUS_NO_NETWORK_JOINED, + * \ref LORAMAC_STATUS_LENGTH_ERROR, + * \ref LORAMAC_STATUS_DEVICE_OFF. + */ +LoRaMacStatus_t LoRaMacMlmeRequest( MlmeReq_t *mlmeRequest ); + +/*! + * \brief LoRaMAC MCPS-Request + * + * \details The Mac Common Part Sublayer handles data services. The following + * code-snippet shows how to use the API to send an unconfirmed + * LoRaMAC frame. + * + * \code + * uint8_t myBuffer[] = { 1, 2, 3 }; + * + * McpsReq_t mcpsReq; + * mcpsReq.Type = MCPS_UNCONFIRMED; + * mcpsReq.Req.Unconfirmed.fPort = 1; + * mcpsReq.Req.Unconfirmed.fBuffer = myBuffer; + * mcpsReq.Req.Unconfirmed.fBufferSize = sizeof( myBuffer ); + * + * if( LoRaMacMcpsRequest( &mcpsReq ) == LORAMAC_STATUS_OK ) + * { + * // Service started successfully. Waiting for the MCPS-Confirm event + * } + * \endcode + * + * \param [IN] mcpsRequest - MCPS-Request to perform. Refer to \ref McpsReq_t. + * + * \retval LoRaMacStatus_t Status of the operation. Possible returns are: + * \ref LORAMAC_STATUS_OK, + * \ref LORAMAC_STATUS_BUSY, + * \ref LORAMAC_STATUS_SERVICE_UNKNOWN, + * \ref LORAMAC_STATUS_PARAMETER_INVALID, + * \ref LORAMAC_STATUS_NO_NETWORK_JOINED, + * \ref LORAMAC_STATUS_LENGTH_ERROR, + * \ref LORAMAC_STATUS_DEVICE_OFF. + */ +LoRaMacStatus_t LoRaMacMcpsRequest( McpsReq_t *mcpsRequest ); + +/*! \} defgroup LORAMAC */ + +#endif // __LORAMAC_H__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mac/LoRaWAN-lib/LoRaMacCrypto.cpp Wed Sep 04 15:42:07 2019 +0000 @@ -0,0 +1,202 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C)2013 Semtech + ___ _____ _ ___ _ _____ ___ ___ ___ ___ +/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| +\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| +|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| +embedded.connectivity.solutions=============== + +Description: LoRa MAC layer implementation + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jäckle ( STACKFORCE ) +*/ +#include <stdlib.h> +#include <stdint.h> +#include "utilities.h" + +#include "aes.h" +#include "cmac.h" + +#include "LoRaMacCrypto.h" + +/*! + * CMAC/AES Message Integrity Code (MIC) Block B0 size + */ +#define LORAMAC_MIC_BLOCK_B0_SIZE 16 + +/*! + * MIC field computation initial data + */ +static uint8_t MicBlockB0[] = { 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + +/*! + * Contains the computed MIC field. + * + * \remark Only the 4 first bytes are used + */ +static uint8_t Mic[16]; + +/*! + * Encryption aBlock and sBlock + */ +static uint8_t aBlock[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; +static uint8_t sBlock[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + +/*! + * AES computation context variable + */ +static aes_context AesContext; + +/*! + * CMAC computation context variable + */ +static AES_CMAC_CTX AesCmacCtx[1]; + +/*! + * \brief Computes the LoRaMAC frame MIC field + * + * \param [IN] buffer Data buffer + * \param [IN] size Data buffer size + * \param [IN] key AES key to be used + * \param [IN] address Frame address + * \param [IN] dir Frame direction [0: uplink, 1: downlink] + * \param [IN] sequenceCounter Frame sequence counter + * \param [OUT] mic Computed MIC field + */ +void LoRaMacComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint32_t *mic ) +{ + MicBlockB0[5] = dir; + + MicBlockB0[6] = ( address ) & 0xFF; + MicBlockB0[7] = ( address >> 8 ) & 0xFF; + MicBlockB0[8] = ( address >> 16 ) & 0xFF; + MicBlockB0[9] = ( address >> 24 ) & 0xFF; + + MicBlockB0[10] = ( sequenceCounter ) & 0xFF; + MicBlockB0[11] = ( sequenceCounter >> 8 ) & 0xFF; + MicBlockB0[12] = ( sequenceCounter >> 16 ) & 0xFF; + MicBlockB0[13] = ( sequenceCounter >> 24 ) & 0xFF; + + MicBlockB0[15] = size & 0xFF; + + AES_CMAC_Init( AesCmacCtx ); + + AES_CMAC_SetKey( AesCmacCtx, key ); + + AES_CMAC_Update( AesCmacCtx, MicBlockB0, LORAMAC_MIC_BLOCK_B0_SIZE ); + + AES_CMAC_Update( AesCmacCtx, buffer, size & 0xFF ); + + AES_CMAC_Final( Mic, AesCmacCtx ); + + *mic = ( uint32_t )( ( uint32_t )Mic[3] << 24 | ( uint32_t )Mic[2] << 16 | ( uint32_t )Mic[1] << 8 | ( uint32_t )Mic[0] ); +} + +void LoRaMacPayloadEncrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *encBuffer ) +{ + uint16_t i; + uint8_t bufferIndex = 0; + uint16_t ctr = 1; + + memset1( AesContext.ksch, '\0', 240 ); + aes_set_key( key, 16, &AesContext ); + + aBlock[5] = dir; + + aBlock[6] = ( address ) & 0xFF; + aBlock[7] = ( address >> 8 ) & 0xFF; + aBlock[8] = ( address >> 16 ) & 0xFF; + aBlock[9] = ( address >> 24 ) & 0xFF; + + aBlock[10] = ( sequenceCounter ) & 0xFF; + aBlock[11] = ( sequenceCounter >> 8 ) & 0xFF; + aBlock[12] = ( sequenceCounter >> 16 ) & 0xFF; + aBlock[13] = ( sequenceCounter >> 24 ) & 0xFF; + + while( size >= 16 ) + { + aBlock[15] = ( ( ctr ) & 0xFF ); + ctr++; + aes_encrypt( aBlock, sBlock, &AesContext ); + for( i = 0; i < 16; i++ ) + { + encBuffer[bufferIndex + i] = buffer[bufferIndex + i] ^ sBlock[i]; + } + size -= 16; + bufferIndex += 16; + } + + if( size > 0 ) + { + aBlock[15] = ( ( ctr ) & 0xFF ); + aes_encrypt( aBlock, sBlock, &AesContext ); + for( i = 0; i < size; i++ ) + { + encBuffer[bufferIndex + i] = buffer[bufferIndex + i] ^ sBlock[i]; + } + } +} + +void LoRaMacPayloadDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *decBuffer ) +{ + LoRaMacPayloadEncrypt( buffer, size, key, address, dir, sequenceCounter, decBuffer ); +} + +void LoRaMacJoinComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t *mic ) +{ + AES_CMAC_Init( AesCmacCtx ); + + AES_CMAC_SetKey( AesCmacCtx, key ); + + AES_CMAC_Update( AesCmacCtx, buffer, size & 0xFF ); + + AES_CMAC_Final( Mic, AesCmacCtx ); + + *mic = ( uint32_t )( ( uint32_t )Mic[3] << 24 | ( uint32_t )Mic[2] << 16 | ( uint32_t )Mic[1] << 8 | ( uint32_t )Mic[0] ); +} + +void LoRaMacJoinDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint8_t *decBuffer ) +{ + memset1( AesContext.ksch, '\0', 240 ); + aes_set_key( key, 16, &AesContext ); + aes_encrypt( buffer, decBuffer, &AesContext ); + // Check if optional CFList is included + if( size >= 16 ) + { + aes_encrypt( buffer + 16, decBuffer + 16, &AesContext ); + } +} + +void LoRaMacJoinComputeSKeys( const uint8_t *key, const uint8_t *appNonce, uint16_t devNonce, uint8_t *nwkSKey, uint8_t *appSKey ) +{ + uint8_t nonce[16]; + uint8_t *pDevNonce = ( uint8_t * )&devNonce; + + memset1( AesContext.ksch, '\0', 240 ); + aes_set_key( key, 16, &AesContext ); + + memset1( nonce, 0, sizeof( nonce ) ); + nonce[0] = 0x01; + memcpy1( nonce + 1, appNonce, 6 ); + memcpy1( nonce + 7, pDevNonce, 2 ); + aes_encrypt( nonce, nwkSKey, &AesContext ); + + memset1( nonce, 0, sizeof( nonce ) ); + nonce[0] = 0x02; + memcpy1( nonce + 1, appNonce, 6 ); + memcpy1( nonce + 7, pDevNonce, 2 ); + aes_encrypt( nonce, appSKey, &AesContext ); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mac/LoRaWAN-lib/LoRaMacCrypto.h Wed Sep 04 15:42:07 2019 +0000 @@ -0,0 +1,111 @@ +/*! + * \file LoRaMacCrypto.h + * + * \brief LoRa MAC layer cryptography implementation + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + * + * \author Gregory Cristian ( Semtech ) + * + * \author Daniel Jäckle ( STACKFORCE ) + * + * \defgroup LORAMAC_CRYPTO LoRa MAC layer cryptography implementation + * This module covers the implementation of cryptographic functions + * of the LoRaMAC layer. + * \{ + */ +#ifndef __LORAMAC_CRYPTO_H__ +#define __LORAMAC_CRYPTO_H__ + +/*! + * Computes the LoRaMAC frame MIC field + * + * \param [IN] buffer - Data buffer + * \param [IN] size - Data buffer size + * \param [IN] key - AES key to be used + * \param [IN] address - Frame address + * \param [IN] dir - Frame direction [0: uplink, 1: downlink] + * \param [IN] sequenceCounter - Frame sequence counter + * \param [OUT] mic - Computed MIC field + */ +void LoRaMacComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint32_t *mic ); + +/*! + * Computes the LoRaMAC payload encryption + * + * \param [IN] buffer - Data buffer + * \param [IN] size - Data buffer size + * \param [IN] key - AES key to be used + * \param [IN] address - Frame address + * \param [IN] dir - Frame direction [0: uplink, 1: downlink] + * \param [IN] sequenceCounter - Frame sequence counter + * \param [OUT] encBuffer - Encrypted buffer + */ +void LoRaMacPayloadEncrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *encBuffer ); + +/*! + * Computes the LoRaMAC payload decryption + * + * \param [IN] buffer - Data buffer + * \param [IN] size - Data buffer size + * \param [IN] key - AES key to be used + * \param [IN] address - Frame address + * \param [IN] dir - Frame direction [0: uplink, 1: downlink] + * \param [IN] sequenceCounter - Frame sequence counter + * \param [OUT] decBuffer - Decrypted buffer + */ +void LoRaMacPayloadDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *decBuffer ); + +/*! + * Computes the LoRaMAC Join Request frame MIC field + * + * \param [IN] buffer - Data buffer + * \param [IN] size - Data buffer size + * \param [IN] key - AES key to be used + * \param [OUT] mic - Computed MIC field + */ +void LoRaMacJoinComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t *mic ); + +/*! + * Computes the LoRaMAC join frame decryption + * + * \param [IN] buffer - Data buffer + * \param [IN] size - Data buffer size + * \param [IN] key - AES key to be used + * \param [OUT] decBuffer - Decrypted buffer + */ +void LoRaMacJoinDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint8_t *decBuffer ); + +/*! + * Computes the LoRaMAC join frame decryption + * + * \param [IN] key - AES key to be used + * \param [IN] appNonce - Application nonce + * \param [IN] devNonce - Device nonce + * \param [OUT] nwkSKey - Network session key + * \param [OUT] appSKey - Application session key + */ +void LoRaMacJoinComputeSKeys( const uint8_t *key, const uint8_t *appNonce, uint16_t devNonce, uint8_t *nwkSKey, uint8_t *appSKey ); + +/*! \} defgroup LORAMAC */ + +#endif // __LORAMAC_CRYPTO_H__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mac/LoRaWAN-lib/LoRaMacTest.h Wed Sep 04 15:42:07 2019 +0000 @@ -0,0 +1,81 @@ +/*! + * \file LoRaMacTest.h + * + * \brief LoRa MAC layer test function implementation + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013 Semtech + * + * ___ _____ _ ___ _ _____ ___ ___ ___ ___ + * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| + * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| + * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| + * embedded.connectivity.solutions=============== + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + * + * \author Gregory Cristian ( Semtech ) + * + * \author Daniel Jäckle ( STACKFORCE ) + * + * \defgroup LORAMACTEST LoRa MAC layer test function implementation + * This module specifies the API implementation of test function of the LoRaMAC layer. + * The functions in this file are only for testing purposes only. + * \{ + */ +#ifndef __LORAMACTEST_H__ +#define __LORAMACTEST_H__ + +/*! + * \brief Enabled or disables the reception windows + * + * \details This is a test function. It shall be used for testing purposes only. + * Changing this attribute may lead to a non-conformance LoRaMac operation. + * + * \param [IN] enable - Enabled or disables the reception windows + */ +void LoRaMacTestRxWindowsOn( bool enable ); + +/*! + * \brief Enables the MIC field test + * + * \details This is a test function. It shall be used for testing purposes only. + * Changing this attribute may lead to a non-conformance LoRaMac operation. + * + * \param [IN] txPacketCounter - Fixed Tx packet counter value + */ +void LoRaMacTestSetMic( uint16_t txPacketCounter ); + +/*! + * \brief Enabled or disables the duty cycle + * + * \details This is a test function. It shall be used for testing purposes only. + * Changing this attribute may lead to a non-conformance LoRaMac operation. + * + * \param [IN] enable - Enabled or disables the duty cycle + */ +void LoRaMacTestSetDutyCycleOn( bool enable ); + +/*! + * \brief Sets the channel index + * + * \details This is a test function. It shall be used for testing purposes only. + * Changing this attribute may lead to a non-conformance LoRaMac operation. + * + * \param [IN] channel - Channel index + */ +void LoRaMacTestSetChannel( uint8_t channel ); + +/*! \} defgroup LORAMACTEST */ + +#endif // __LORAMACTEST_H__
--- a/radio/SX1276Lib.lib Thu Apr 25 15:49:17 2019 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -https://os.mbed.com/users/uss1994/code/SX1276Lib/#72f41e368dad
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/radio/SX1276Lib/LICENSE.txt Wed Sep 04 15:42:07 2019 +0000 @@ -0,0 +1,25 @@ +--- Revised BSD License --- +Copyright (c) 2013, SEMTECH S.A. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Semtech corporation nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL SEMTECH S.A. BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/radio/SX1276Lib/debug/debug.h Wed Sep 04 15:42:07 2019 +0000 @@ -0,0 +1,61 @@ +/* Copyright (c) 2012 mbed.org, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef DEBUG_H +#define DEBUG_H + +/** @file debug.h */ + +#ifndef NDEBUG + +#include <stdarg.h> +#include <stdio.h> + +/** Output a debug message + * + * @param format printf-style format string, followed by variables + */ +static inline void debug(const char *format, ...) { + va_list args; + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); +} + +/** Conditionally output a debug message + * + * @param condition output only if condition is true + * @param format printf-style format string, followed by variables + */ +static inline void debug_if(bool condition, const char *format, ...) { + if(condition) { + va_list args; + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + } +} + +#else + +static inline void debug(const char *format, ...) {} +static inline void debug(bool condition, const char *format, ...) {} + +#endif + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/radio/SX1276Lib/enums/enums.h Wed Sep 04 15:42:07 2019 +0000 @@ -0,0 +1,131 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C) 2014 Semtech + +Description: - + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainers: Miguel Luis, Gregory Cristian and Nicolas Huguenin +*/ +#ifndef __ENUMS_H__ +#define __ENUMS_H__ + +/*! + * Radio driver internal state machine states definition + */ +typedef enum RadioState +{ + RF_IDLE = 0, + RF_RX_RUNNING, + RF_TX_RUNNING, + RF_CAD, +}RadioState_t; + +/*! + * Type of the modem. [LORA / FSK] + */ +typedef enum ModemType +{ + MODEM_FSK = 0, + MODEM_LORA +}RadioModems_t; + +/*! + * Type of the supported board. [SX1276MB1MAS / SX1276MB1LAS] + */ +typedef enum BoardType +{ + SX1276MB1MAS = 0, + SX1276MB1LAS, + UNKNOWN +}BoardType_t; + +/*! + * Radio FSK modem parameters + */ +typedef struct +{ + int8_t Power; + uint32_t Fdev; + uint32_t Bandwidth; + uint32_t BandwidthAfc; + uint32_t Datarate; + uint16_t PreambleLen; + bool FixLen; + uint8_t PayloadLen; + bool CrcOn; + bool IqInverted; + bool RxContinuous; + uint32_t TxTimeout; + uint32_t RxSingleTimeout; +}RadioFskSettings_t; + +/*! + * Radio FSK packet handler state + */ +typedef struct +{ + uint8_t PreambleDetected; + uint8_t SyncWordDetected; + int8_t RssiValue; + int32_t AfcValue; + uint8_t RxGain; + uint16_t Size; + uint16_t NbBytes; + uint8_t FifoThresh; + uint8_t ChunkSize; +}RadioFskPacketHandler_t; + +/*! + * Radio LoRa modem parameters + */ +typedef struct +{ + int8_t Power; + uint32_t Bandwidth; + uint32_t Datarate; + bool LowDatarateOptimize; + uint8_t Coderate; + uint16_t PreambleLen; + bool FixLen; + uint8_t PayloadLen; + bool CrcOn; + bool FreqHopOn; + uint8_t HopPeriod; + bool IqInverted; + bool RxContinuous; + uint32_t TxTimeout; + bool PublicNetwork; +}RadioLoRaSettings_t; + +/*! + * Radio LoRa packet handler state + */ +typedef struct +{ + int8_t SnrValue; + int8_t RssiValue; + uint8_t Size; +}RadioLoRaPacketHandler_t; + +/*! + * Radio Settings + */ +typedef struct +{ + RadioState State; + ModemType Modem; + uint32_t Channel; + RadioFskSettings_t Fsk; + RadioFskPacketHandler_t FskPacketHandler; + RadioLoRaSettings_t LoRa; + RadioLoRaPacketHandler_t LoRaPacketHandler; +}RadioSettings_t; + + +#endif //__ENUMS_H__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/radio/SX1276Lib/radio/radio.cpp Wed Sep 04 15:42:07 2019 +0000 @@ -0,0 +1,20 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C) 2014 Semtech + +Description: Interface for the radios, contains the main functions that a radio needs, and 5 callback functions + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainers: Miguel Luis, Gregory Cristian and Nicolas Huguenin +*/ +#include "radio.h" + +Radio::Radio( RadioEvents_t *events ) +{ + this->RadioEvents = events; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/radio/SX1276Lib/radio/radio.h Wed Sep 04 15:42:07 2019 +0000 @@ -0,0 +1,337 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C) 2014 Semtech + +Description: Interface for the radios, contains the main functions that a radio needs, and 5 callback functions + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainers: Miguel Luis, Gregory Cristian and Nicolas Huguenin +*/ +#ifndef __RADIO_H__ +#define __RADIO_H__ + +#include "mbed.h" + +#include "./enums/enums.h" + +/*! + * @brief Radio driver callback functions + */ +typedef struct +{ + /*! + * @brief Tx Done callback prototype. + */ + void ( *TxDone )( void ); + /*! + * @brief Tx Timeout callback prototype. + */ + void ( *TxTimeout )( void ); + /*! + * @brief Rx Done callback prototype. + * + * @param [IN] payload Received buffer pointer + * @param [IN] size Received buffer size + * @param [IN] rssi RSSI value computed while receiving the frame [dBm] + * @param [IN] snr Raw SNR value given by the radio hardware + * FSK : N/A ( set to 0 ) + * LoRa: SNR value in dB + */ + void ( *RxDone )( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr ); + /*! + * @brief Rx Timeout callback prototype. + */ + void ( *RxTimeout )( void ); + /*! + * @brief Rx Error callback prototype. + */ + void ( *RxError )( void ); + /*! + * \brief FHSS Change Channel callback prototype. + * + * \param [IN] currentChannel Index number of the current channel + */ + void ( *FhssChangeChannel )( uint8_t currentChannel ); + /*! + * @brief CAD Done callback prototype. + * + * @param [IN] channelDetected Channel Activity detected during the CAD + */ + void ( *CadDone ) ( bool channelActivityDetected ); +}RadioEvents_t; + +/*! + * Interface for the radios, contains the main functions that a radio needs, and 5 callback functions + */ +class Radio +{ +protected: + RadioEvents_t* RadioEvents; + +public: + //------------------------------------------------------------------------- + // Constructor + //------------------------------------------------------------------------- + /*! + * @brief Constructor of the radio object, the parameters are the callback functions described in the header. + * + * @param [IN] events Structure containing the driver callback functions + */ + Radio( RadioEvents_t *events ); + virtual ~Radio( ) {}; + + //------------------------------------------------------------------------- + // Pure virtual functions + //------------------------------------------------------------------------- + /*! + * @brief Initializes the radio + * + * @param [IN] events Structure containing the driver callback functions + */ + virtual void Init( RadioEvents_t *events ) = 0; + /*! + * @brief Return current radio status + * + * @param status Radio status.[RF_IDLE, RF_RX_RUNNING, RF_TX_RUNNING] + */ + virtual RadioState GetStatus( void ) = 0; + /*! + * @brief Configures the radio with the given modem + * + * @param [IN] modem Modem to be used [0: FSK, 1: LoRa] + */ + virtual void SetModem( RadioModems_t modem ) = 0; + /*! + * @brief Sets the channel frequency + * + * @param [IN] freq Channel RF frequency + */ + virtual void SetChannel( uint32_t freq ) = 0; + /*! + * @brief Sets the channels configuration + * + * @param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] + * @param [IN] freq Channel RF frequency + * @param [IN] rssiThresh RSSI threshold + * + * @retval isFree [true: Channel is free, false: Channel is not free] + */ + virtual bool IsChannelFree( RadioModems_t modem, uint32_t freq, int16_t rssiThresh ) = 0; + /*! + * @brief Generates a 32 bits random value based on the RSSI readings + * + * \remark This function sets the radio in LoRa modem mode and disables + * all interrupts. + * After calling this function either Radio.SetRxConfig or + * Radio.SetTxConfig functions must be called. + * + * @retval randomValue 32 bits random value + */ + virtual uint32_t Random( void )= 0; + /*! + * @brief Sets the reception parameters + * + * @param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] + * @param [IN] bandwidth Sets the bandwidth + * FSK : >= 2600 and <= 250000 Hz + * LoRa: [0: 125 kHz, 1: 250 kHz, + * 2: 500 kHz, 3: Reserved] + * @param [IN] datarate Sets the Datarate + * FSK : 600..300000 bits/s + * LoRa: [6: 64, 7: 128, 8: 256, 9: 512, + * 10: 1024, 11: 2048, 12: 4096 chips] + * @param [IN] coderate Sets the coding rate ( LoRa only ) + * FSK : N/A ( set to 0 ) + * LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] + * @param [IN] bandwidthAfc Sets the AFC Bandwidth ( FSK only ) + * FSK : >= 2600 and <= 250000 Hz + * LoRa: N/A ( set to 0 ) + * @param [IN] preambleLen Sets the Preamble length ( LoRa only ) + * FSK : N/A ( set to 0 ) + * LoRa: Length in symbols ( the hardware adds 4 more symbols ) + * @param [IN] symbTimeout Sets the RxSingle timeout value + * FSK : timeout number of bytes + * LoRa: timeout in symbols + * @param [IN] fixLen Fixed length packets [0: variable, 1: fixed] + * @param [IN] payloadLen Sets payload length when fixed lenght is used + * @param [IN] crcOn Enables/Disables the CRC [0: OFF, 1: ON] + * @param [IN] freqHopOn Enables disables the intra-packet frequency hopping [0: OFF, 1: ON] (LoRa only) + * @param [IN] hopPeriod Number of symbols bewteen each hop (LoRa only) + * @param [IN] iqInverted Inverts IQ signals ( LoRa only ) + * FSK : N/A ( set to 0 ) + * LoRa: [0: not inverted, 1: inverted] + * @param [IN] rxContinuous Sets the reception in continuous mode + * [false: single mode, true: continuous mode] + */ + virtual void SetRxConfig ( RadioModems_t modem, uint32_t bandwidth, + uint32_t datarate, uint8_t coderate, + uint32_t bandwidthAfc, uint16_t preambleLen, + uint16_t symbTimeout, bool fixLen, + uint8_t payloadLen, + bool crcOn, bool freqHopOn, uint8_t hopPeriod, + bool iqInverted, bool rxContinuous ) = 0; + /*! + * @brief Sets the transmission parameters + * + * @param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] + * @param [IN] power Sets the output power [dBm] + * @param [IN] fdev Sets the frequency deviation ( FSK only ) + * FSK : [Hz] + * LoRa: 0 + * @param [IN] bandwidth Sets the bandwidth ( LoRa only ) + * FSK : 0 + * LoRa: [0: 125 kHz, 1: 250 kHz, + * 2: 500 kHz, 3: Reserved] + * @param [IN] datarate Sets the Datarate + * FSK : 600..300000 bits/s + * LoRa: [6: 64, 7: 128, 8: 256, 9: 512, + * 10: 1024, 11: 2048, 12: 4096 chips] + * @param [IN] coderate Sets the coding rate ( LoRa only ) + * FSK : N/A ( set to 0 ) + * LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] + * @param [IN] preambleLen Sets the preamble length + * @param [IN] fixLen Fixed length packets [0: variable, 1: fixed] + * @param [IN] crcOn Enables disables the CRC [0: OFF, 1: ON] + * @param [IN] freqHopOn Enables disables the intra-packet frequency hopping [0: OFF, 1: ON] (LoRa only) + * @param [IN] hopPeriod Number of symbols bewteen each hop (LoRa only) + * @param [IN] iqInverted Inverts IQ signals ( LoRa only ) + * FSK : N/A ( set to 0 ) + * LoRa: [0: not inverted, 1: inverted] + * @param [IN] timeout Transmission timeout [us] + */ + virtual void SetTxConfig( RadioModems_t modem, int8_t power, uint32_t fdev, + uint32_t bandwidth, uint32_t datarate, + uint8_t coderate, uint16_t preambleLen, + bool fixLen, bool crcOn, bool freqHopOn, + uint8_t hopPeriod, bool iqInverted, uint32_t timeout ) = 0; + /*! + * @brief Checks if the given RF frequency is supported by the hardware + * + * @param [IN] frequency RF frequency to be checked + * @retval isSupported [true: supported, false: unsupported] + */ + virtual bool CheckRfFrequency( uint32_t frequency ) = 0; + /*! + * @brief Computes the packet time on air for the given payload + * + * \Remark Can only be called once SetRxConfig or SetTxConfig have been called + * + * @param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] + * @param [IN] pktLen Packet payload length + * + * @retval airTime Computed airTime for the given packet payload length + */ + virtual uint32_t TimeOnAir ( RadioModems_t modem, uint8_t pktLen ) = 0; + /*! + * @brief Sends the buffer of size. Prepares the packet to be sent and sets + * the radio in transmission + * + * @param [IN]: buffer Buffer pointer + * @param [IN]: size Buffer size + */ + virtual void Send( uint8_t *buffer, uint8_t size ) = 0; + /*! + * @brief Sets the radio in sleep mode + */ + virtual void Sleep( void ) = 0; + /*! + * @brief Sets the radio in standby mode + */ + virtual void Standby( void ) = 0; + /*! + * @brief Sets the radio in CAD mode + */ + virtual void StartCad( void ) = 0; + /*! + * @brief Sets the radio in reception mode for the given time + * @param [IN] timeout Reception timeout [us] + * [0: continuous, others timeout] + */ + virtual void Rx( uint32_t timeout ) = 0; + /*! + * @brief Sets the radio in transmission mode for the given time + * @param [IN] timeout Transmission timeout [us] + * [0: continuous, others timeout] + */ + virtual void Tx( uint32_t timeout ) = 0; + /*! + * @brief Sets the radio in continuous wave transmission mode + * + * @param [IN]: freq Channel RF frequency + * @param [IN]: power Sets the output power [dBm] + * @param [IN]: time Transmission mode timeout [s] + */ + virtual void SetTxContinuousWave( uint32_t freq, int8_t power, uint16_t time ) = 0; + /*! + * @brief Reads the current RSSI value + * + * @retval rssiValue Current RSSI value in [dBm] + */ + virtual int16_t GetRssi ( RadioModems_t modem ) = 0; + /*! + * @brief Writes the radio register at the specified address + * + * @param [IN]: addr Register address + * @param [IN]: data New register value + */ + virtual void Write ( uint8_t addr, uint8_t data ) = 0; + /*! + * @brief Reads the radio register at the specified address + * + * @param [IN]: addr Register address + * @retval data Register value + */ + virtual uint8_t Read ( uint8_t addr ) = 0; + /*! + * @brief Writes multiple radio registers starting at address + * + * @param [IN] addr First Radio register address + * @param [IN] buffer Buffer containing the new register's values + * @param [IN] size Number of registers to be written + */ + virtual void Write( uint8_t addr, uint8_t *buffer, uint8_t size ) = 0; + /*! + * @brief Reads multiple radio registers starting at address + * + * @param [IN] addr First Radio register address + * @param [OUT] buffer Buffer where to copy the registers data + * @param [IN] size Number of registers to be read + */ + virtual void Read ( uint8_t addr, uint8_t *buffer, uint8_t size ) = 0; + /*! + * @brief Writes the buffer contents to the Radio FIFO + * + * @param [IN] buffer Buffer containing data to be put on the FIFO. + * @param [IN] size Number of bytes to be written to the FIFO + */ + virtual void WriteFifo( uint8_t *buffer, uint8_t size ) = 0; + /*! + * @brief Reads the contents of the Radio FIFO + * + * @param [OUT] buffer Buffer where to copy the FIFO read data. + * @param [IN] size Number of bytes to be read from the FIFO + */ + virtual void ReadFifo( uint8_t *buffer, uint8_t size ) = 0; + /*! + * @brief Sets the maximum payload length. + * + * @param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] + * @param [IN] max Maximum payload length in bytes + */ + virtual void SetMaxPayloadLength( RadioModems_t modem, uint8_t max ) = 0; + /*! + * @brief Sets the network to public or private. Updates the sync byte. + * + * @remark Applies to LoRa modem only + * + * @param [IN] enable if true, it enables a public network + */ + virtual void SetPublicNetwork( bool enable ) = 0; +}; + +#endif // __RADIO_H__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/radio/SX1276Lib/registers/sx1276Regs-Fsk.h Wed Sep 04 15:42:07 2019 +0000 @@ -0,0 +1,1134 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C) 2014 Semtech + +Description: SX1276 FSK modem registers and bits definitions + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainer: Miguel Luis and Gregory Cristian +*/ +#ifndef __SX1276_REGS_FSK_H__ +#define __SX1276_REGS_FSK_H__ + +/*! + * ============================================================================ + * SX1276 Internal registers Address + * ============================================================================ + */ +#define REG_FIFO 0x00 +// Common settings +#define REG_OPMODE 0x01 +#define REG_BITRATEMSB 0x02 +#define REG_BITRATELSB 0x03 +#define REG_FDEVMSB 0x04 +#define REG_FDEVLSB 0x05 +#define REG_FRFMSB 0x06 +#define REG_FRFMID 0x07 +#define REG_FRFLSB 0x08 +// Tx settings +#define REG_PACONFIG 0x09 +#define REG_PARAMP 0x0A +#define REG_OCP 0x0B +// Rx settings +#define REG_LNA 0x0C +#define REG_RXCONFIG 0x0D +#define REG_RSSICONFIG 0x0E +#define REG_RSSICOLLISION 0x0F +#define REG_RSSITHRESH 0x10 +#define REG_RSSIVALUE 0x11 +#define REG_RXBW 0x12 +#define REG_AFCBW 0x13 +#define REG_OOKPEAK 0x14 +#define REG_OOKFIX 0x15 +#define REG_OOKAVG 0x16 +#define REG_RES17 0x17 +#define REG_RES18 0x18 +#define REG_RES19 0x19 +#define REG_AFCFEI 0x1A +#define REG_AFCMSB 0x1B +#define REG_AFCLSB 0x1C +#define REG_FEIMSB 0x1D +#define REG_FEILSB 0x1E +#define REG_PREAMBLEDETECT 0x1F +#define REG_RXTIMEOUT1 0x20 +#define REG_RXTIMEOUT2 0x21 +#define REG_RXTIMEOUT3 0x22 +#define REG_RXDELAY 0x23 +// Oscillator settings +#define REG_OSC 0x24 +// Packet handler settings +#define REG_PREAMBLEMSB 0x25 +#define REG_PREAMBLELSB 0x26 +#define REG_SYNCCONFIG 0x27 +#define REG_SYNCVALUE1 0x28 +#define REG_SYNCVALUE2 0x29 +#define REG_SYNCVALUE3 0x2A +#define REG_SYNCVALUE4 0x2B +#define REG_SYNCVALUE5 0x2C +#define REG_SYNCVALUE6 0x2D +#define REG_SYNCVALUE7 0x2E +#define REG_SYNCVALUE8 0x2F +#define REG_PACKETCONFIG1 0x30 +#define REG_PACKETCONFIG2 0x31 +#define REG_PAYLOADLENGTH 0x32 +#define REG_NODEADRS 0x33 +#define REG_BROADCASTADRS 0x34 +#define REG_FIFOTHRESH 0x35 +// SM settings +#define REG_SEQCONFIG1 0x36 +#define REG_SEQCONFIG2 0x37 +#define REG_TIMERRESOL 0x38 +#define REG_TIMER1COEF 0x39 +#define REG_TIMER2COEF 0x3A +// Service settings +#define REG_IMAGECAL 0x3B +#define REG_TEMP 0x3C +#define REG_LOWBAT 0x3D +// Status +#define REG_IRQFLAGS1 0x3E +#define REG_IRQFLAGS2 0x3F +// I/O settings +#define REG_DIOMAPPING1 0x40 +#define REG_DIOMAPPING2 0x41 +// Version +#define REG_VERSION 0x42 +// Additional settings +#define REG_PLLHOP 0x44 +#define REG_TCXO 0x4B +#define REG_PADAC 0x4D +#define REG_FORMERTEMP 0x5B +#define REG_BITRATEFRAC 0x5D +#define REG_AGCREF 0x61 +#define REG_AGCTHRESH1 0x62 +#define REG_AGCTHRESH2 0x63 +#define REG_AGCTHRESH3 0x64 +#define REG_PLL 0x70 + +/*! + * ============================================================================ + * SX1276 FSK bits control definition + * ============================================================================ + */ + +/*! + * RegFifo + */ + +/*! + * RegOpMode + */ +#define RF_OPMODE_LONGRANGEMODE_MASK 0x7F +#define RF_OPMODE_LONGRANGEMODE_OFF 0x00 +#define RF_OPMODE_LONGRANGEMODE_ON 0x80 + +#define RF_OPMODE_MODULATIONTYPE_MASK 0x9F +#define RF_OPMODE_MODULATIONTYPE_FSK 0x00 // Default +#define RF_OPMODE_MODULATIONTYPE_OOK 0x20 + +#define RF_OPMODE_MODULATIONSHAPING_MASK 0xE7 +#define RF_OPMODE_MODULATIONSHAPING_00 0x00 // Default +#define RF_OPMODE_MODULATIONSHAPING_01 0x08 +#define RF_OPMODE_MODULATIONSHAPING_10 0x10 +#define RF_OPMODE_MODULATIONSHAPING_11 0x18 + +#define RF_OPMODE_MASK 0xF8 +#define RF_OPMODE_SLEEP 0x00 +#define RF_OPMODE_STANDBY 0x01 // Default +#define RF_OPMODE_SYNTHESIZER_TX 0x02 +#define RF_OPMODE_TRANSMITTER 0x03 +#define RF_OPMODE_SYNTHESIZER_RX 0x04 +#define RF_OPMODE_RECEIVER 0x05 + +/*! + * RegBitRate (bits/sec) + */ +#define RF_BITRATEMSB_1200_BPS 0x68 +#define RF_BITRATELSB_1200_BPS 0x2B +#define RF_BITRATEMSB_2400_BPS 0x34 +#define RF_BITRATELSB_2400_BPS 0x15 +#define RF_BITRATEMSB_4800_BPS 0x1A // Default +#define RF_BITRATELSB_4800_BPS 0x0B // Default +#define RF_BITRATEMSB_9600_BPS 0x0D +#define RF_BITRATELSB_9600_BPS 0x05 +#define RF_BITRATEMSB_15000_BPS 0x08 +#define RF_BITRATELSB_15000_BPS 0x55 +#define RF_BITRATEMSB_19200_BPS 0x06 +#define RF_BITRATELSB_19200_BPS 0x83 +#define RF_BITRATEMSB_38400_BPS 0x03 +#define RF_BITRATELSB_38400_BPS 0x41 +#define RF_BITRATEMSB_76800_BPS 0x01 +#define RF_BITRATELSB_76800_BPS 0xA1 +#define RF_BITRATEMSB_153600_BPS 0x00 +#define RF_BITRATELSB_153600_BPS 0xD0 +#define RF_BITRATEMSB_57600_BPS 0x02 +#define RF_BITRATELSB_57600_BPS 0x2C +#define RF_BITRATEMSB_115200_BPS 0x01 +#define RF_BITRATELSB_115200_BPS 0x16 +#define RF_BITRATEMSB_12500_BPS 0x0A +#define RF_BITRATELSB_12500_BPS 0x00 +#define RF_BITRATEMSB_25000_BPS 0x05 +#define RF_BITRATELSB_25000_BPS 0x00 +#define RF_BITRATEMSB_50000_BPS 0x02 +#define RF_BITRATELSB_50000_BPS 0x80 +#define RF_BITRATEMSB_100000_BPS 0x01 +#define RF_BITRATELSB_100000_BPS 0x40 +#define RF_BITRATEMSB_150000_BPS 0x00 +#define RF_BITRATELSB_150000_BPS 0xD5 +#define RF_BITRATEMSB_200000_BPS 0x00 +#define RF_BITRATELSB_200000_BPS 0xA0 +#define RF_BITRATEMSB_250000_BPS 0x00 +#define RF_BITRATELSB_250000_BPS 0x80 +#define RF_BITRATEMSB_32768_BPS 0x03 +#define RF_BITRATELSB_32768_BPS 0xD1 + +/*! + * RegFdev (Hz) + */ +#define RF_FDEVMSB_2000_HZ 0x00 +#define RF_FDEVLSB_2000_HZ 0x21 +#define RF_FDEVMSB_5000_HZ 0x00 // Default +#define RF_FDEVLSB_5000_HZ 0x52 // Default +#define RF_FDEVMSB_10000_HZ 0x00 +#define RF_FDEVLSB_10000_HZ 0xA4 +#define RF_FDEVMSB_15000_HZ 0x00 +#define RF_FDEVLSB_15000_HZ 0xF6 +#define RF_FDEVMSB_20000_HZ 0x01 +#define RF_FDEVLSB_20000_HZ 0x48 +#define RF_FDEVMSB_25000_HZ 0x01 +#define RF_FDEVLSB_25000_HZ 0x9A +#define RF_FDEVMSB_30000_HZ 0x01 +#define RF_FDEVLSB_30000_HZ 0xEC +#define RF_FDEVMSB_35000_HZ 0x02 +#define RF_FDEVLSB_35000_HZ 0x3D +#define RF_FDEVMSB_40000_HZ 0x02 +#define RF_FDEVLSB_40000_HZ 0x8F +#define RF_FDEVMSB_45000_HZ 0x02 +#define RF_FDEVLSB_45000_HZ 0xE1 +#define RF_FDEVMSB_50000_HZ 0x03 +#define RF_FDEVLSB_50000_HZ 0x33 +#define RF_FDEVMSB_55000_HZ 0x03 +#define RF_FDEVLSB_55000_HZ 0x85 +#define RF_FDEVMSB_60000_HZ 0x03 +#define RF_FDEVLSB_60000_HZ 0xD7 +#define RF_FDEVMSB_65000_HZ 0x04 +#define RF_FDEVLSB_65000_HZ 0x29 +#define RF_FDEVMSB_70000_HZ 0x04 +#define RF_FDEVLSB_70000_HZ 0x7B +#define RF_FDEVMSB_75000_HZ 0x04 +#define RF_FDEVLSB_75000_HZ 0xCD +#define RF_FDEVMSB_80000_HZ 0x05 +#define RF_FDEVLSB_80000_HZ 0x1F +#define RF_FDEVMSB_85000_HZ 0x05 +#define RF_FDEVLSB_85000_HZ 0x71 +#define RF_FDEVMSB_90000_HZ 0x05 +#define RF_FDEVLSB_90000_HZ 0xC3 +#define RF_FDEVMSB_95000_HZ 0x06 +#define RF_FDEVLSB_95000_HZ 0x14 +#define RF_FDEVMSB_100000_HZ 0x06 +#define RF_FDEVLSB_100000_HZ 0x66 +#define RF_FDEVMSB_110000_HZ 0x07 +#define RF_FDEVLSB_110000_HZ 0x0A +#define RF_FDEVMSB_120000_HZ 0x07 +#define RF_FDEVLSB_120000_HZ 0xAE +#define RF_FDEVMSB_130000_HZ 0x08 +#define RF_FDEVLSB_130000_HZ 0x52 +#define RF_FDEVMSB_140000_HZ 0x08 +#define RF_FDEVLSB_140000_HZ 0xF6 +#define RF_FDEVMSB_150000_HZ 0x09 +#define RF_FDEVLSB_150000_HZ 0x9A +#define RF_FDEVMSB_160000_HZ 0x0A +#define RF_FDEVLSB_160000_HZ 0x3D +#define RF_FDEVMSB_170000_HZ 0x0A +#define RF_FDEVLSB_170000_HZ 0xE1 +#define RF_FDEVMSB_180000_HZ 0x0B +#define RF_FDEVLSB_180000_HZ 0x85 +#define RF_FDEVMSB_190000_HZ 0x0C +#define RF_FDEVLSB_190000_HZ 0x29 +#define RF_FDEVMSB_200000_HZ 0x0C +#define RF_FDEVLSB_200000_HZ 0xCD + +/*! + * RegFrf (MHz) + */ +#define RF_FRFMSB_863_MHZ 0xD7 +#define RF_FRFMID_863_MHZ 0xC0 +#define RF_FRFLSB_863_MHZ 0x00 +#define RF_FRFMSB_864_MHZ 0xD8 +#define RF_FRFMID_864_MHZ 0x00 +#define RF_FRFLSB_864_MHZ 0x00 +#define RF_FRFMSB_865_MHZ 0xD8 +#define RF_FRFMID_865_MHZ 0x40 +#define RF_FRFLSB_865_MHZ 0x00 +#define RF_FRFMSB_866_MHZ 0xD8 +#define RF_FRFMID_866_MHZ 0x80 +#define RF_FRFLSB_866_MHZ 0x00 +#define RF_FRFMSB_867_MHZ 0xD8 +#define RF_FRFMID_867_MHZ 0xC0 +#define RF_FRFLSB_867_MHZ 0x00 +#define RF_FRFMSB_868_MHZ 0xD9 +#define RF_FRFMID_868_MHZ 0x00 +#define RF_FRFLSB_868_MHZ 0x00 +#define RF_FRFMSB_869_MHZ 0xD9 +#define RF_FRFMID_869_MHZ 0x40 +#define RF_FRFLSB_869_MHZ 0x00 +#define RF_FRFMSB_870_MHZ 0xD9 +#define RF_FRFMID_870_MHZ 0x80 +#define RF_FRFLSB_870_MHZ 0x00 + +#define RF_FRFMSB_902_MHZ 0xE1 +#define RF_FRFMID_902_MHZ 0x80 +#define RF_FRFLSB_902_MHZ 0x00 +#define RF_FRFMSB_903_MHZ 0xE1 +#define RF_FRFMID_903_MHZ 0xC0 +#define RF_FRFLSB_903_MHZ 0x00 +#define RF_FRFMSB_904_MHZ 0xE2 +#define RF_FRFMID_904_MHZ 0x00 +#define RF_FRFLSB_904_MHZ 0x00 +#define RF_FRFMSB_905_MHZ 0xE2 +#define RF_FRFMID_905_MHZ 0x40 +#define RF_FRFLSB_905_MHZ 0x00 +#define RF_FRFMSB_906_MHZ 0xE2 +#define RF_FRFMID_906_MHZ 0x80 +#define RF_FRFLSB_906_MHZ 0x00 +#define RF_FRFMSB_907_MHZ 0xE2 +#define RF_FRFMID_907_MHZ 0xC0 +#define RF_FRFLSB_907_MHZ 0x00 +#define RF_FRFMSB_908_MHZ 0xE3 +#define RF_FRFMID_908_MHZ 0x00 +#define RF_FRFLSB_908_MHZ 0x00 +#define RF_FRFMSB_909_MHZ 0xE3 +#define RF_FRFMID_909_MHZ 0x40 +#define RF_FRFLSB_909_MHZ 0x00 +#define RF_FRFMSB_910_MHZ 0xE3 +#define RF_FRFMID_910_MHZ 0x80 +#define RF_FRFLSB_910_MHZ 0x00 +#define RF_FRFMSB_911_MHZ 0xE3 +#define RF_FRFMID_911_MHZ 0xC0 +#define RF_FRFLSB_911_MHZ 0x00 +#define RF_FRFMSB_912_MHZ 0xE4 +#define RF_FRFMID_912_MHZ 0x00 +#define RF_FRFLSB_912_MHZ 0x00 +#define RF_FRFMSB_913_MHZ 0xE4 +#define RF_FRFMID_913_MHZ 0x40 +#define RF_FRFLSB_913_MHZ 0x00 +#define RF_FRFMSB_914_MHZ 0xE4 +#define RF_FRFMID_914_MHZ 0x80 +#define RF_FRFLSB_914_MHZ 0x00 +#define RF_FRFMSB_915_MHZ 0xE4 // Default +#define RF_FRFMID_915_MHZ 0xC0 // Default +#define RF_FRFLSB_915_MHZ 0x00 // Default +#define RF_FRFMSB_916_MHZ 0xE5 +#define RF_FRFMID_916_MHZ 0x00 +#define RF_FRFLSB_916_MHZ 0x00 +#define RF_FRFMSB_917_MHZ 0xE5 +#define RF_FRFMID_917_MHZ 0x40 +#define RF_FRFLSB_917_MHZ 0x00 +#define RF_FRFMSB_918_MHZ 0xE5 +#define RF_FRFMID_918_MHZ 0x80 +#define RF_FRFLSB_918_MHZ 0x00 +#define RF_FRFMSB_919_MHZ 0xE5 +#define RF_FRFMID_919_MHZ 0xC0 +#define RF_FRFLSB_919_MHZ 0x00 +#define RF_FRFMSB_920_MHZ 0xE6 +#define RF_FRFMID_920_MHZ 0x00 +#define RF_FRFLSB_920_MHZ 0x00 +#define RF_FRFMSB_921_MHZ 0xE6 +#define RF_FRFMID_921_MHZ 0x40 +#define RF_FRFLSB_921_MHZ 0x00 +#define RF_FRFMSB_922_MHZ 0xE6 +#define RF_FRFMID_922_MHZ 0x80 +#define RF_FRFLSB_922_MHZ 0x00 +#define RF_FRFMSB_923_MHZ 0xE6 +#define RF_FRFMID_923_MHZ 0xC0 +#define RF_FRFLSB_923_MHZ 0x00 +#define RF_FRFMSB_924_MHZ 0xE7 +#define RF_FRFMID_924_MHZ 0x00 +#define RF_FRFLSB_924_MHZ 0x00 +#define RF_FRFMSB_925_MHZ 0xE7 +#define RF_FRFMID_925_MHZ 0x40 +#define RF_FRFLSB_925_MHZ 0x00 +#define RF_FRFMSB_926_MHZ 0xE7 +#define RF_FRFMID_926_MHZ 0x80 +#define RF_FRFLSB_926_MHZ 0x00 +#define RF_FRFMSB_927_MHZ 0xE7 +#define RF_FRFMID_927_MHZ 0xC0 +#define RF_FRFLSB_927_MHZ 0x00 +#define RF_FRFMSB_928_MHZ 0xE8 +#define RF_FRFMID_928_MHZ 0x00 +#define RF_FRFLSB_928_MHZ 0x00 + +/*! + * RegPaConfig + */ +#define RF_PACONFIG_PASELECT_MASK 0x7F +#define RF_PACONFIG_PASELECT_PABOOST 0x80 +#define RF_PACONFIG_PASELECT_RFO 0x00 // Default + +#define RF_PACONFIG_MAX_POWER_MASK 0x8F + +#define RF_PACONFIG_OUTPUTPOWER_MASK 0xF0 + +/*! + * RegPaRamp + */ +#define RF_PARAMP_MODULATIONSHAPING_MASK 0x9F +#define RF_PARAMP_MODULATIONSHAPING_00 0x00 // Default +#define RF_PARAMP_MODULATIONSHAPING_01 0x20 +#define RF_PARAMP_MODULATIONSHAPING_10 0x40 +#define RF_PARAMP_MODULATIONSHAPING_11 0x60 + +#define RF_PARAMP_LOWPNTXPLL_MASK 0xEF +#define RF_PARAMP_LOWPNTXPLL_OFF 0x10 +#define RF_PARAMP_LOWPNTXPLL_ON 0x00 // Default + +#define RF_PARAMP_MASK 0xF0 +#define RF_PARAMP_3400_US 0x00 +#define RF_PARAMP_2000_US 0x01 +#define RF_PARAMP_1000_US 0x02 +#define RF_PARAMP_0500_US 0x03 +#define RF_PARAMP_0250_US 0x04 +#define RF_PARAMP_0125_US 0x05 +#define RF_PARAMP_0100_US 0x06 +#define RF_PARAMP_0062_US 0x07 +#define RF_PARAMP_0050_US 0x08 +#define RF_PARAMP_0040_US 0x09 // Default +#define RF_PARAMP_0031_US 0x0A +#define RF_PARAMP_0025_US 0x0B +#define RF_PARAMP_0020_US 0x0C +#define RF_PARAMP_0015_US 0x0D +#define RF_PARAMP_0012_US 0x0E +#define RF_PARAMP_0010_US 0x0F + +/*! + * RegOcp + */ +#define RF_OCP_MASK 0xDF +#define RF_OCP_ON 0x20 // Default +#define RF_OCP_OFF 0x00 + +#define RF_OCP_TRIM_MASK 0xE0 +#define RF_OCP_TRIM_045_MA 0x00 +#define RF_OCP_TRIM_050_MA 0x01 +#define RF_OCP_TRIM_055_MA 0x02 +#define RF_OCP_TRIM_060_MA 0x03 +#define RF_OCP_TRIM_065_MA 0x04 +#define RF_OCP_TRIM_070_MA 0x05 +#define RF_OCP_TRIM_075_MA 0x06 +#define RF_OCP_TRIM_080_MA 0x07 +#define RF_OCP_TRIM_085_MA 0x08 +#define RF_OCP_TRIM_090_MA 0x09 +#define RF_OCP_TRIM_095_MA 0x0A +#define RF_OCP_TRIM_100_MA 0x0B // Default +#define RF_OCP_TRIM_105_MA 0x0C +#define RF_OCP_TRIM_110_MA 0x0D +#define RF_OCP_TRIM_115_MA 0x0E +#define RF_OCP_TRIM_120_MA 0x0F +#define RF_OCP_TRIM_130_MA 0x10 +#define RF_OCP_TRIM_140_MA 0x11 +#define RF_OCP_TRIM_150_MA 0x12 +#define RF_OCP_TRIM_160_MA 0x13 +#define RF_OCP_TRIM_170_MA 0x14 +#define RF_OCP_TRIM_180_MA 0x15 +#define RF_OCP_TRIM_190_MA 0x16 +#define RF_OCP_TRIM_200_MA 0x17 +#define RF_OCP_TRIM_210_MA 0x18 +#define RF_OCP_TRIM_220_MA 0x19 +#define RF_OCP_TRIM_230_MA 0x1A +#define RF_OCP_TRIM_240_MA 0x1B + +/*! + * RegLna + */ +#define RF_LNA_GAIN_MASK 0x1F +#define RF_LNA_GAIN_G1 0x20 // Default +#define RF_LNA_GAIN_G2 0x40 +#define RF_LNA_GAIN_G3 0x60 +#define RF_LNA_GAIN_G4 0x80 +#define RF_LNA_GAIN_G5 0xA0 +#define RF_LNA_GAIN_G6 0xC0 + +#define RF_LNA_BOOST_MASK 0xFC +#define RF_LNA_BOOST_OFF 0x00 // Default +#define RF_LNA_BOOST_ON 0x03 + +/*! + * RegRxConfig + */ +#define RF_RXCONFIG_RESTARTRXONCOLLISION_MASK 0x7F +#define RF_RXCONFIG_RESTARTRXONCOLLISION_ON 0x80 +#define RF_RXCONFIG_RESTARTRXONCOLLISION_OFF 0x00 // Default + +#define RF_RXCONFIG_RESTARTRXWITHOUTPLLLOCK 0x40 // Write only + +#define RF_RXCONFIG_RESTARTRXWITHPLLLOCK 0x20 // Write only + +#define RF_RXCONFIG_AFCAUTO_MASK 0xEF +#define RF_RXCONFIG_AFCAUTO_ON 0x10 +#define RF_RXCONFIG_AFCAUTO_OFF 0x00 // Default + +#define RF_RXCONFIG_AGCAUTO_MASK 0xF7 +#define RF_RXCONFIG_AGCAUTO_ON 0x08 // Default +#define RF_RXCONFIG_AGCAUTO_OFF 0x00 + +#define RF_RXCONFIG_RXTRIGER_MASK 0xF8 +#define RF_RXCONFIG_RXTRIGER_OFF 0x00 +#define RF_RXCONFIG_RXTRIGER_RSSI 0x01 +#define RF_RXCONFIG_RXTRIGER_PREAMBLEDETECT 0x06 // Default +#define RF_RXCONFIG_RXTRIGER_RSSI_PREAMBLEDETECT 0x07 + +/*! + * RegRssiConfig + */ +#define RF_RSSICONFIG_OFFSET_MASK 0x07 +#define RF_RSSICONFIG_OFFSET_P_00_DB 0x00 // Default +#define RF_RSSICONFIG_OFFSET_P_01_DB 0x08 +#define RF_RSSICONFIG_OFFSET_P_02_DB 0x10 +#define RF_RSSICONFIG_OFFSET_P_03_DB 0x18 +#define RF_RSSICONFIG_OFFSET_P_04_DB 0x20 +#define RF_RSSICONFIG_OFFSET_P_05_DB 0x28 +#define RF_RSSICONFIG_OFFSET_P_06_DB 0x30 +#define RF_RSSICONFIG_OFFSET_P_07_DB 0x38 +#define RF_RSSICONFIG_OFFSET_P_08_DB 0x40 +#define RF_RSSICONFIG_OFFSET_P_09_DB 0x48 +#define RF_RSSICONFIG_OFFSET_P_10_DB 0x50 +#define RF_RSSICONFIG_OFFSET_P_11_DB 0x58 +#define RF_RSSICONFIG_OFFSET_P_12_DB 0x60 +#define RF_RSSICONFIG_OFFSET_P_13_DB 0x68 +#define RF_RSSICONFIG_OFFSET_P_14_DB 0x70 +#define RF_RSSICONFIG_OFFSET_P_15_DB 0x78 +#define RF_RSSICONFIG_OFFSET_M_16_DB 0x80 +#define RF_RSSICONFIG_OFFSET_M_15_DB 0x88 +#define RF_RSSICONFIG_OFFSET_M_14_DB 0x90 +#define RF_RSSICONFIG_OFFSET_M_13_DB 0x98 +#define RF_RSSICONFIG_OFFSET_M_12_DB 0xA0 +#define RF_RSSICONFIG_OFFSET_M_11_DB 0xA8 +#define RF_RSSICONFIG_OFFSET_M_10_DB 0xB0 +#define RF_RSSICONFIG_OFFSET_M_09_DB 0xB8 +#define RF_RSSICONFIG_OFFSET_M_08_DB 0xC0 +#define RF_RSSICONFIG_OFFSET_M_07_DB 0xC8 +#define RF_RSSICONFIG_OFFSET_M_06_DB 0xD0 +#define RF_RSSICONFIG_OFFSET_M_05_DB 0xD8 +#define RF_RSSICONFIG_OFFSET_M_04_DB 0xE0 +#define RF_RSSICONFIG_OFFSET_M_03_DB 0xE8 +#define RF_RSSICONFIG_OFFSET_M_02_DB 0xF0 +#define RF_RSSICONFIG_OFFSET_M_01_DB 0xF8 + +#define RF_RSSICONFIG_SMOOTHING_MASK 0xF8 +#define RF_RSSICONFIG_SMOOTHING_2 0x00 +#define RF_RSSICONFIG_SMOOTHING_4 0x01 +#define RF_RSSICONFIG_SMOOTHING_8 0x02 // Default +#define RF_RSSICONFIG_SMOOTHING_16 0x03 +#define RF_RSSICONFIG_SMOOTHING_32 0x04 +#define RF_RSSICONFIG_SMOOTHING_64 0x05 +#define RF_RSSICONFIG_SMOOTHING_128 0x06 +#define RF_RSSICONFIG_SMOOTHING_256 0x07 + +/*! + * RegRssiCollision + */ +#define RF_RSSICOLISION_THRESHOLD 0x0A // Default + +/*! + * RegRssiThresh + */ +#define RF_RSSITHRESH_THRESHOLD 0xFF // Default + +/*! + * RegRssiValue (Read Only) + */ + +/*! + * RegRxBw + */ +#define RF_RXBW_MANT_MASK 0xE7 +#define RF_RXBW_MANT_16 0x00 +#define RF_RXBW_MANT_20 0x08 +#define RF_RXBW_MANT_24 0x10 // Default + +#define RF_RXBW_EXP_MASK 0xF8 +#define RF_RXBW_EXP_0 0x00 +#define RF_RXBW_EXP_1 0x01 +#define RF_RXBW_EXP_2 0x02 +#define RF_RXBW_EXP_3 0x03 +#define RF_RXBW_EXP_4 0x04 +#define RF_RXBW_EXP_5 0x05 // Default +#define RF_RXBW_EXP_6 0x06 +#define RF_RXBW_EXP_7 0x07 + +/*! + * RegAfcBw + */ +#define RF_AFCBW_MANTAFC_MASK 0xE7 +#define RF_AFCBW_MANTAFC_16 0x00 +#define RF_AFCBW_MANTAFC_20 0x08 // Default +#define RF_AFCBW_MANTAFC_24 0x10 + +#define RF_AFCBW_EXPAFC_MASK 0xF8 +#define RF_AFCBW_EXPAFC_0 0x00 +#define RF_AFCBW_EXPAFC_1 0x01 +#define RF_AFCBW_EXPAFC_2 0x02 +#define RF_AFCBW_EXPAFC_3 0x03 // Default +#define RF_AFCBW_EXPAFC_4 0x04 +#define RF_AFCBW_EXPAFC_5 0x05 +#define RF_AFCBW_EXPAFC_6 0x06 +#define RF_AFCBW_EXPAFC_7 0x07 + +/*! + * RegOokPeak + */ +#define RF_OOKPEAK_BITSYNC_MASK 0xDF // Default +#define RF_OOKPEAK_BITSYNC_ON 0x20 // Default +#define RF_OOKPEAK_BITSYNC_OFF 0x00 + +#define RF_OOKPEAK_OOKTHRESHTYPE_MASK 0xE7 +#define RF_OOKPEAK_OOKTHRESHTYPE_FIXED 0x00 +#define RF_OOKPEAK_OOKTHRESHTYPE_PEAK 0x08 // Default +#define RF_OOKPEAK_OOKTHRESHTYPE_AVERAGE 0x10 + +#define RF_OOKPEAK_OOKPEAKTHRESHSTEP_MASK 0xF8 +#define RF_OOKPEAK_OOKPEAKTHRESHSTEP_0_5_DB 0x00 // Default +#define RF_OOKPEAK_OOKPEAKTHRESHSTEP_1_0_DB 0x01 +#define RF_OOKPEAK_OOKPEAKTHRESHSTEP_1_5_DB 0x02 +#define RF_OOKPEAK_OOKPEAKTHRESHSTEP_2_0_DB 0x03 +#define RF_OOKPEAK_OOKPEAKTHRESHSTEP_3_0_DB 0x04 +#define RF_OOKPEAK_OOKPEAKTHRESHSTEP_4_0_DB 0x05 +#define RF_OOKPEAK_OOKPEAKTHRESHSTEP_5_0_DB 0x06 +#define RF_OOKPEAK_OOKPEAKTHRESHSTEP_6_0_DB 0x07 + +/*! + * RegOokFix + */ +#define RF_OOKFIX_OOKFIXEDTHRESHOLD 0x0C // Default + +/*! + * RegOokAvg + */ +#define RF_OOKAVG_OOKPEAKTHRESHDEC_MASK 0x1F +#define RF_OOKAVG_OOKPEAKTHRESHDEC_000 0x00 // Default +#define RF_OOKAVG_OOKPEAKTHRESHDEC_001 0x20 +#define RF_OOKAVG_OOKPEAKTHRESHDEC_010 0x40 +#define RF_OOKAVG_OOKPEAKTHRESHDEC_011 0x60 +#define RF_OOKAVG_OOKPEAKTHRESHDEC_100 0x80 +#define RF_OOKAVG_OOKPEAKTHRESHDEC_101 0xA0 +#define RF_OOKAVG_OOKPEAKTHRESHDEC_110 0xC0 +#define RF_OOKAVG_OOKPEAKTHRESHDEC_111 0xE0 + +#define RF_OOKAVG_AVERAGEOFFSET_MASK 0xF3 +#define RF_OOKAVG_AVERAGEOFFSET_0_DB 0x00 // Default +#define RF_OOKAVG_AVERAGEOFFSET_2_DB 0x04 +#define RF_OOKAVG_AVERAGEOFFSET_4_DB 0x08 +#define RF_OOKAVG_AVERAGEOFFSET_6_DB 0x0C + +#define RF_OOKAVG_OOKAVERAGETHRESHFILT_MASK 0xFC +#define RF_OOKAVG_OOKAVERAGETHRESHFILT_00 0x00 +#define RF_OOKAVG_OOKAVERAGETHRESHFILT_01 0x01 +#define RF_OOKAVG_OOKAVERAGETHRESHFILT_10 0x02 // Default +#define RF_OOKAVG_OOKAVERAGETHRESHFILT_11 0x03 + +/*! + * RegAfcFei + */ +#define RF_AFCFEI_AGCSTART 0x10 + +#define RF_AFCFEI_AFCCLEAR 0x02 + +#define RF_AFCFEI_AFCAUTOCLEAR_MASK 0xFE +#define RF_AFCFEI_AFCAUTOCLEAR_ON 0x01 +#define RF_AFCFEI_AFCAUTOCLEAR_OFF 0x00 // Default + +/*! + * RegAfcMsb (Read Only) + */ + +/*! + * RegAfcLsb (Read Only) + */ + +/*! + * RegFeiMsb (Read Only) + */ + +/*! + * RegFeiLsb (Read Only) + */ + +/*! + * RegPreambleDetect + */ +#define RF_PREAMBLEDETECT_DETECTOR_MASK 0x7F +#define RF_PREAMBLEDETECT_DETECTOR_ON 0x80 // Default +#define RF_PREAMBLEDETECT_DETECTOR_OFF 0x00 + +#define RF_PREAMBLEDETECT_DETECTORSIZE_MASK 0x9F +#define RF_PREAMBLEDETECT_DETECTORSIZE_1 0x00 +#define RF_PREAMBLEDETECT_DETECTORSIZE_2 0x20 // Default +#define RF_PREAMBLEDETECT_DETECTORSIZE_3 0x40 +#define RF_PREAMBLEDETECT_DETECTORSIZE_4 0x60 + +#define RF_PREAMBLEDETECT_DETECTORTOL_MASK 0xE0 +#define RF_PREAMBLEDETECT_DETECTORTOL_0 0x00 +#define RF_PREAMBLEDETECT_DETECTORTOL_1 0x01 +#define RF_PREAMBLEDETECT_DETECTORTOL_2 0x02 +#define RF_PREAMBLEDETECT_DETECTORTOL_3 0x03 +#define RF_PREAMBLEDETECT_DETECTORTOL_4 0x04 +#define RF_PREAMBLEDETECT_DETECTORTOL_5 0x05 +#define RF_PREAMBLEDETECT_DETECTORTOL_6 0x06 +#define RF_PREAMBLEDETECT_DETECTORTOL_7 0x07 +#define RF_PREAMBLEDETECT_DETECTORTOL_8 0x08 +#define RF_PREAMBLEDETECT_DETECTORTOL_9 0x09 +#define RF_PREAMBLEDETECT_DETECTORTOL_10 0x0A // Default +#define RF_PREAMBLEDETECT_DETECTORTOL_11 0x0B +#define RF_PREAMBLEDETECT_DETECTORTOL_12 0x0C +#define RF_PREAMBLEDETECT_DETECTORTOL_13 0x0D +#define RF_PREAMBLEDETECT_DETECTORTOL_14 0x0E +#define RF_PREAMBLEDETECT_DETECTORTOL_15 0x0F +#define RF_PREAMBLEDETECT_DETECTORTOL_16 0x10 +#define RF_PREAMBLEDETECT_DETECTORTOL_17 0x11 +#define RF_PREAMBLEDETECT_DETECTORTOL_18 0x12 +#define RF_PREAMBLEDETECT_DETECTORTOL_19 0x13 +#define RF_PREAMBLEDETECT_DETECTORTOL_20 0x14 +#define RF_PREAMBLEDETECT_DETECTORTOL_21 0x15 +#define RF_PREAMBLEDETECT_DETECTORTOL_22 0x16 +#define RF_PREAMBLEDETECT_DETECTORTOL_23 0x17 +#define RF_PREAMBLEDETECT_DETECTORTOL_24 0x18 +#define RF_PREAMBLEDETECT_DETECTORTOL_25 0x19 +#define RF_PREAMBLEDETECT_DETECTORTOL_26 0x1A +#define RF_PREAMBLEDETECT_DETECTORTOL_27 0x1B +#define RF_PREAMBLEDETECT_DETECTORTOL_28 0x1C +#define RF_PREAMBLEDETECT_DETECTORTOL_29 0x1D +#define RF_PREAMBLEDETECT_DETECTORTOL_30 0x1E +#define RF_PREAMBLEDETECT_DETECTORTOL_31 0x1F + +/*! + * RegRxTimeout1 + */ +#define RF_RXTIMEOUT1_TIMEOUTRXRSSI 0x00 // Default + +/*! + * RegRxTimeout2 + */ +#define RF_RXTIMEOUT2_TIMEOUTRXPREAMBLE 0x00 // Default + +/*! + * RegRxTimeout3 + */ +#define RF_RXTIMEOUT3_TIMEOUTSIGNALSYNC 0x00 // Default + +/*! + * RegRxDelay + */ +#define RF_RXDELAY_INTERPACKETRXDELAY 0x00 // Default + +/*! + * RegOsc + */ +#define RF_OSC_RCCALSTART 0x08 + +#define RF_OSC_CLKOUT_MASK 0xF8 +#define RF_OSC_CLKOUT_32_MHZ 0x00 +#define RF_OSC_CLKOUT_16_MHZ 0x01 +#define RF_OSC_CLKOUT_8_MHZ 0x02 +#define RF_OSC_CLKOUT_4_MHZ 0x03 +#define RF_OSC_CLKOUT_2_MHZ 0x04 +#define RF_OSC_CLKOUT_1_MHZ 0x05 // Default +#define RF_OSC_CLKOUT_RC 0x06 +#define RF_OSC_CLKOUT_OFF 0x07 + +/*! + * RegPreambleMsb/RegPreambleLsb + */ +#define RF_PREAMBLEMSB_SIZE 0x00 // Default +#define RF_PREAMBLELSB_SIZE 0x03 // Default + +/*! + * RegSyncConfig + */ +#define RF_SYNCCONFIG_AUTORESTARTRXMODE_MASK 0x3F +#define RF_SYNCCONFIG_AUTORESTARTRXMODE_WAITPLL_ON 0x80 // Default +#define RF_SYNCCONFIG_AUTORESTARTRXMODE_WAITPLL_OFF 0x40 +#define RF_SYNCCONFIG_AUTORESTARTRXMODE_OFF 0x00 + + +#define RF_SYNCCONFIG_PREAMBLEPOLARITY_MASK 0xDF +#define RF_SYNCCONFIG_PREAMBLEPOLARITY_55 0x20 +#define RF_SYNCCONFIG_PREAMBLEPOLARITY_AA 0x00 // Default + +#define RF_SYNCCONFIG_SYNC_MASK 0xEF +#define RF_SYNCCONFIG_SYNC_ON 0x10 // Default +#define RF_SYNCCONFIG_SYNC_OFF 0x00 + + +#define RF_SYNCCONFIG_SYNCSIZE_MASK 0xF8 +#define RF_SYNCCONFIG_SYNCSIZE_1 0x00 +#define RF_SYNCCONFIG_SYNCSIZE_2 0x01 +#define RF_SYNCCONFIG_SYNCSIZE_3 0x02 +#define RF_SYNCCONFIG_SYNCSIZE_4 0x03 // Default +#define RF_SYNCCONFIG_SYNCSIZE_5 0x04 +#define RF_SYNCCONFIG_SYNCSIZE_6 0x05 +#define RF_SYNCCONFIG_SYNCSIZE_7 0x06 +#define RF_SYNCCONFIG_SYNCSIZE_8 0x07 + +/*! + * RegSyncValue1-8 + */ +#define RF_SYNCVALUE1_SYNCVALUE 0x01 // Default +#define RF_SYNCVALUE2_SYNCVALUE 0x01 // Default +#define RF_SYNCVALUE3_SYNCVALUE 0x01 // Default +#define RF_SYNCVALUE4_SYNCVALUE 0x01 // Default +#define RF_SYNCVALUE5_SYNCVALUE 0x01 // Default +#define RF_SYNCVALUE6_SYNCVALUE 0x01 // Default +#define RF_SYNCVALUE7_SYNCVALUE 0x01 // Default +#define RF_SYNCVALUE8_SYNCVALUE 0x01 // Default + +/*! + * RegPacketConfig1 + */ +#define RF_PACKETCONFIG1_PACKETFORMAT_MASK 0x7F +#define RF_PACKETCONFIG1_PACKETFORMAT_FIXED 0x00 +#define RF_PACKETCONFIG1_PACKETFORMAT_VARIABLE 0x80 // Default + +#define RF_PACKETCONFIG1_DCFREE_MASK 0x9F +#define RF_PACKETCONFIG1_DCFREE_OFF 0x00 // Default +#define RF_PACKETCONFIG1_DCFREE_MANCHESTER 0x20 +#define RF_PACKETCONFIG1_DCFREE_WHITENING 0x40 + +#define RF_PACKETCONFIG1_CRC_MASK 0xEF +#define RF_PACKETCONFIG1_CRC_ON 0x10 // Default +#define RF_PACKETCONFIG1_CRC_OFF 0x00 + +#define RF_PACKETCONFIG1_CRCAUTOCLEAR_MASK 0xF7 +#define RF_PACKETCONFIG1_CRCAUTOCLEAR_ON 0x00 // Default +#define RF_PACKETCONFIG1_CRCAUTOCLEAR_OFF 0x08 + +#define RF_PACKETCONFIG1_ADDRSFILTERING_MASK 0xF9 +#define RF_PACKETCONFIG1_ADDRSFILTERING_OFF 0x00 // Default +#define RF_PACKETCONFIG1_ADDRSFILTERING_NODE 0x02 +#define RF_PACKETCONFIG1_ADDRSFILTERING_NODEBROADCAST 0x04 + +#define RF_PACKETCONFIG1_CRCWHITENINGTYPE_MASK 0xFE +#define RF_PACKETCONFIG1_CRCWHITENINGTYPE_CCITT 0x00 // Default +#define RF_PACKETCONFIG1_CRCWHITENINGTYPE_IBM 0x01 + +/*! + * RegPacketConfig2 + */ + +#define RF_PACKETCONFIG2_WMBUS_CRC_ENABLE_MASK 0x7F +#define RF_PACKETCONFIG2_WMBUS_CRC_ENABLE 0x80 +#define RF_PACKETCONFIG2_WMBUS_CRC_DISABLE 0x00 // Default + +#define RF_PACKETCONFIG2_DATAMODE_MASK 0xBF +#define RF_PACKETCONFIG2_DATAMODE_CONTINUOUS 0x00 +#define RF_PACKETCONFIG2_DATAMODE_PACKET 0x40 // Default + +#define RF_PACKETCONFIG2_IOHOME_MASK 0xDF +#define RF_PACKETCONFIG2_IOHOME_ON 0x20 +#define RF_PACKETCONFIG2_IOHOME_OFF 0x00 // Default + +#define RF_PACKETCONFIG2_BEACON_MASK 0xF7 +#define RF_PACKETCONFIG2_BEACON_ON 0x08 +#define RF_PACKETCONFIG2_BEACON_OFF 0x00 // Default + +#define RF_PACKETCONFIG2_PAYLOADLENGTH_MSB_MASK 0xF8 + +/*! + * RegPayloadLength + */ +#define RF_PAYLOADLENGTH_LENGTH 0x40 // Default + +/*! + * RegNodeAdrs + */ +#define RF_NODEADDRESS_ADDRESS 0x00 + +/*! + * RegBroadcastAdrs + */ +#define RF_BROADCASTADDRESS_ADDRESS 0x00 + +/*! + * RegFifoThresh + */ +#define RF_FIFOTHRESH_TXSTARTCONDITION_MASK 0x7F +#define RF_FIFOTHRESH_TXSTARTCONDITION_FIFOTHRESH 0x00 // Default +#define RF_FIFOTHRESH_TXSTARTCONDITION_FIFONOTEMPTY 0x80 + +#define RF_FIFOTHRESH_FIFOTHRESHOLD_MASK 0xC0 +#define RF_FIFOTHRESH_FIFOTHRESHOLD_THRESHOLD 0x0F // Default + +/*! + * RegSeqConfig1 + */ +#define RF_SEQCONFIG1_SEQUENCER_START 0x80 + +#define RF_SEQCONFIG1_SEQUENCER_STOP 0x40 + +#define RF_SEQCONFIG1_IDLEMODE_MASK 0xDF +#define RF_SEQCONFIG1_IDLEMODE_SLEEP 0x20 +#define RF_SEQCONFIG1_IDLEMODE_STANDBY 0x00 // Default + +#define RF_SEQCONFIG1_FROMSTART_MASK 0xE7 +#define RF_SEQCONFIG1_FROMSTART_TOLPS 0x00 // Default +#define RF_SEQCONFIG1_FROMSTART_TORX 0x08 +#define RF_SEQCONFIG1_FROMSTART_TOTX 0x10 +#define RF_SEQCONFIG1_FROMSTART_TOTX_ONFIFOLEVEL 0x18 + +#define RF_SEQCONFIG1_LPS_MASK 0xFB +#define RF_SEQCONFIG1_LPS_SEQUENCER_OFF 0x00 // Default +#define RF_SEQCONFIG1_LPS_IDLE 0x04 + +#define RF_SEQCONFIG1_FROMIDLE_MASK 0xFD +#define RF_SEQCONFIG1_FROMIDLE_TOTX 0x00 // Default +#define RF_SEQCONFIG1_FROMIDLE_TORX 0x02 + +#define RF_SEQCONFIG1_FROMTX_MASK 0xFE +#define RF_SEQCONFIG1_FROMTX_TOLPS 0x00 // Default +#define RF_SEQCONFIG1_FROMTX_TORX 0x01 + +/*! + * RegSeqConfig2 + */ +#define RF_SEQCONFIG2_FROMRX_MASK 0x1F +#define RF_SEQCONFIG2_FROMRX_TOUNUSED_000 0x00 // Default +#define RF_SEQCONFIG2_FROMRX_TORXPKT_ONPLDRDY 0x20 +#define RF_SEQCONFIG2_FROMRX_TOLPS_ONPLDRDY 0x40 +#define RF_SEQCONFIG2_FROMRX_TORXPKT_ONCRCOK 0x60 +#define RF_SEQCONFIG2_FROMRX_TOSEQUENCEROFF_ONRSSI 0x80 +#define RF_SEQCONFIG2_FROMRX_TOSEQUENCEROFF_ONSYNC 0xA0 +#define RF_SEQCONFIG2_FROMRX_TOSEQUENCEROFF_ONPREAMBLE 0xC0 +#define RF_SEQCONFIG2_FROMRX_TOUNUSED_111 0xE0 + +#define RF_SEQCONFIG2_FROMRXTIMEOUT_MASK 0xE7 +#define RF_SEQCONFIG2_FROMRXTIMEOUT_TORXRESTART 0x00 // Default +#define RF_SEQCONFIG2_FROMRXTIMEOUT_TOTX 0x08 +#define RF_SEQCONFIG2_FROMRXTIMEOUT_TOLPS 0x10 +#define RF_SEQCONFIG2_FROMRXTIMEOUT_TOSEQUENCEROFF 0x18 + +#define RF_SEQCONFIG2_FROMRXPKT_MASK 0xF8 +#define RF_SEQCONFIG2_FROMRXPKT_TOSEQUENCEROFF 0x00 // Default +#define RF_SEQCONFIG2_FROMRXPKT_TOTX_ONFIFOEMPTY 0x01 +#define RF_SEQCONFIG2_FROMRXPKT_TOLPS 0x02 +#define RF_SEQCONFIG2_FROMRXPKT_TOSYNTHESIZERRX 0x03 +#define RF_SEQCONFIG2_FROMRXPKT_TORX 0x04 + +/*! + * RegTimerResol + */ +#define RF_TIMERRESOL_TIMER1RESOL_MASK 0xF3 +#define RF_TIMERRESOL_TIMER1RESOL_OFF 0x00 // Default +#define RF_TIMERRESOL_TIMER1RESOL_000064_US 0x04 +#define RF_TIMERRESOL_TIMER1RESOL_004100_US 0x08 +#define RF_TIMERRESOL_TIMER1RESOL_262000_US 0x0C + +#define RF_TIMERRESOL_TIMER2RESOL_MASK 0xFC +#define RF_TIMERRESOL_TIMER2RESOL_OFF 0x00 // Default +#define RF_TIMERRESOL_TIMER2RESOL_000064_US 0x01 +#define RF_TIMERRESOL_TIMER2RESOL_004100_US 0x02 +#define RF_TIMERRESOL_TIMER2RESOL_262000_US 0x03 + +/*! + * RegTimer1Coef + */ +#define RF_TIMER1COEF_TIMER1COEFFICIENT 0xF5 // Default + +/*! + * RegTimer2Coef + */ +#define RF_TIMER2COEF_TIMER2COEFFICIENT 0x20 // Default + +/*! + * RegImageCal + */ +#define RF_IMAGECAL_AUTOIMAGECAL_MASK 0x7F +#define RF_IMAGECAL_AUTOIMAGECAL_ON 0x80 +#define RF_IMAGECAL_AUTOIMAGECAL_OFF 0x00 // Default + +#define RF_IMAGECAL_IMAGECAL_MASK 0xBF +#define RF_IMAGECAL_IMAGECAL_START 0x40 + +#define RF_IMAGECAL_IMAGECAL_RUNNING 0x20 +#define RF_IMAGECAL_IMAGECAL_DONE 0x00 // Default + +#define RF_IMAGECAL_TEMPCHANGE_HIGHER 0x08 +#define RF_IMAGECAL_TEMPCHANGE_LOWER 0x00 + +#define RF_IMAGECAL_TEMPTHRESHOLD_MASK 0xF9 +#define RF_IMAGECAL_TEMPTHRESHOLD_05 0x00 +#define RF_IMAGECAL_TEMPTHRESHOLD_10 0x02 // Default +#define RF_IMAGECAL_TEMPTHRESHOLD_15 0x04 +#define RF_IMAGECAL_TEMPTHRESHOLD_20 0x06 + +#define RF_IMAGECAL_TEMPMONITOR_MASK 0xFE +#define RF_IMAGECAL_TEMPMONITOR_ON 0x00 // Default +#define RF_IMAGECAL_TEMPMONITOR_OFF 0x01 + +/*! + * RegTemp (Read Only) + */ + +/*! + * RegLowBat + */ +#define RF_LOWBAT_MASK 0xF7 +#define RF_LOWBAT_ON 0x08 +#define RF_LOWBAT_OFF 0x00 // Default + +#define RF_LOWBAT_TRIM_MASK 0xF8 +#define RF_LOWBAT_TRIM_1695 0x00 +#define RF_LOWBAT_TRIM_1764 0x01 +#define RF_LOWBAT_TRIM_1835 0x02 // Default +#define RF_LOWBAT_TRIM_1905 0x03 +#define RF_LOWBAT_TRIM_1976 0x04 +#define RF_LOWBAT_TRIM_2045 0x05 +#define RF_LOWBAT_TRIM_2116 0x06 +#define RF_LOWBAT_TRIM_2185 0x07 + +/*! + * RegIrqFlags1 + */ +#define RF_IRQFLAGS1_MODEREADY 0x80 + +#define RF_IRQFLAGS1_RXREADY 0x40 + +#define RF_IRQFLAGS1_TXREADY 0x20 + +#define RF_IRQFLAGS1_PLLLOCK 0x10 + +#define RF_IRQFLAGS1_RSSI 0x08 + +#define RF_IRQFLAGS1_TIMEOUT 0x04 + +#define RF_IRQFLAGS1_PREAMBLEDETECT 0x02 + +#define RF_IRQFLAGS1_SYNCADDRESSMATCH 0x01 + +/*! + * RegIrqFlags2 + */ +#define RF_IRQFLAGS2_FIFOFULL 0x80 + +#define RF_IRQFLAGS2_FIFOEMPTY 0x40 + +#define RF_IRQFLAGS2_FIFOLEVEL 0x20 + +#define RF_IRQFLAGS2_FIFOOVERRUN 0x10 + +#define RF_IRQFLAGS2_PACKETSENT 0x08 + +#define RF_IRQFLAGS2_PAYLOADREADY 0x04 + +#define RF_IRQFLAGS2_CRCOK 0x02 + +#define RF_IRQFLAGS2_LOWBAT 0x01 + +/*! + * RegDioMapping1 + */ +#define RF_DIOMAPPING1_DIO0_MASK 0x3F +#define RF_DIOMAPPING1_DIO0_00 0x00 // Default +#define RF_DIOMAPPING1_DIO0_01 0x40 +#define RF_DIOMAPPING1_DIO0_10 0x80 +#define RF_DIOMAPPING1_DIO0_11 0xC0 + +#define RF_DIOMAPPING1_DIO1_MASK 0xCF +#define RF_DIOMAPPING1_DIO1_00 0x00 // Default +#define RF_DIOMAPPING1_DIO1_01 0x10 +#define RF_DIOMAPPING1_DIO1_10 0x20 +#define RF_DIOMAPPING1_DIO1_11 0x30 + +#define RF_DIOMAPPING1_DIO2_MASK 0xF3 +#define RF_DIOMAPPING1_DIO2_00 0x00 // Default +#define RF_DIOMAPPING1_DIO2_01 0x04 +#define RF_DIOMAPPING1_DIO2_10 0x08 +#define RF_DIOMAPPING1_DIO2_11 0x0C + +#define RF_DIOMAPPING1_DIO3_MASK 0xFC +#define RF_DIOMAPPING1_DIO3_00 0x00 // Default +#define RF_DIOMAPPING1_DIO3_01 0x01 +#define RF_DIOMAPPING1_DIO3_10 0x02 +#define RF_DIOMAPPING1_DIO3_11 0x03 + +/*! + * RegDioMapping2 + */ +#define RF_DIOMAPPING2_DIO4_MASK 0x3F +#define RF_DIOMAPPING2_DIO4_00 0x00 // Default +#define RF_DIOMAPPING2_DIO4_01 0x40 +#define RF_DIOMAPPING2_DIO4_10 0x80 +#define RF_DIOMAPPING2_DIO4_11 0xC0 + +#define RF_DIOMAPPING2_DIO5_MASK 0xCF +#define RF_DIOMAPPING2_DIO5_00 0x00 // Default +#define RF_DIOMAPPING2_DIO5_01 0x10 +#define RF_DIOMAPPING2_DIO5_10 0x20 +#define RF_DIOMAPPING2_DIO5_11 0x30 + +#define RF_DIOMAPPING2_MAP_MASK 0xFE +#define RF_DIOMAPPING2_MAP_PREAMBLEDETECT 0x01 +#define RF_DIOMAPPING2_MAP_RSSI 0x00 // Default + +/*! + * RegVersion (Read Only) + */ + +/*! + * RegPllHop + */ +#define RF_PLLHOP_FASTHOP_MASK 0x7F +#define RF_PLLHOP_FASTHOP_ON 0x80 +#define RF_PLLHOP_FASTHOP_OFF 0x00 // Default + +/*! + * RegTcxo + */ +#define RF_TCXO_TCXOINPUT_MASK 0xEF +#define RF_TCXO_TCXOINPUT_ON 0x10 +#define RF_TCXO_TCXOINPUT_OFF 0x00 // Default + +/*! + * RegPaDac + */ +#define RF_PADAC_20DBM_MASK 0xF8 +#define RF_PADAC_20DBM_ON 0x07 +#define RF_PADAC_20DBM_OFF 0x04 // Default + +/*! + * RegFormerTemp + */ + +/*! + * RegBitrateFrac + */ +#define RF_BITRATEFRAC_MASK 0xF0 + +/*! + * RegAgcRef + */ + +/*! + * RegAgcThresh1 + */ + +/*! + * RegAgcThresh2 + */ + +/*! + * RegAgcThresh3 + */ + +/*! + * RegPll + */ +#define RF_PLL_BANDWIDTH_MASK 0x3F +#define RF_PLL_BANDWIDTH_75 0x00 +#define RF_PLL_BANDWIDTH_150 0x40 +#define RF_PLL_BANDWIDTH_225 0x80 +#define RF_PLL_BANDWIDTH_300 0xC0 // Default + +#endif // __SX1276_REGS_FSK_H__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/radio/SX1276Lib/registers/sx1276Regs-LoRa.h Wed Sep 04 15:42:07 2019 +0000 @@ -0,0 +1,565 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C) 2014 Semtech + +Description: SX1276 LoRa modem registers and bits definitions + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainer: Miguel Luis and Gregory Cristian +*/ +#ifndef __SX1276_REGS_LORA_H__ +#define __SX1276_REGS_LORA_H__ + +/*! + * ============================================================================ + * SX1276 Internal registers Address + * ============================================================================ + */ +#define REG_LR_FIFO 0x00 +// Common settings +#define REG_LR_OPMODE 0x01 +#define REG_LR_FRFMSB 0x06 +#define REG_LR_FRFMID 0x07 +#define REG_LR_FRFLSB 0x08 +// Tx settings +#define REG_LR_PACONFIG 0x09 +#define REG_LR_PARAMP 0x0A +#define REG_LR_OCP 0x0B +// Rx settings +#define REG_LR_LNA 0x0C +// LoRa registers +#define REG_LR_FIFOADDRPTR 0x0D +#define REG_LR_FIFOTXBASEADDR 0x0E +#define REG_LR_FIFORXBASEADDR 0x0F +#define REG_LR_FIFORXCURRENTADDR 0x10 +#define REG_LR_IRQFLAGSMASK 0x11 +#define REG_LR_IRQFLAGS 0x12 +#define REG_LR_RXNBBYTES 0x13 +#define REG_LR_RXHEADERCNTVALUEMSB 0x14 +#define REG_LR_RXHEADERCNTVALUELSB 0x15 +#define REG_LR_RXPACKETCNTVALUEMSB 0x16 +#define REG_LR_RXPACKETCNTVALUELSB 0x17 +#define REG_LR_MODEMSTAT 0x18 +#define REG_LR_PKTSNRVALUE 0x19 +#define REG_LR_PKTRSSIVALUE 0x1A +#define REG_LR_RSSIVALUE 0x1B +#define REG_LR_HOPCHANNEL 0x1C +#define REG_LR_MODEMCONFIG1 0x1D +#define REG_LR_MODEMCONFIG2 0x1E +#define REG_LR_SYMBTIMEOUTLSB 0x1F +#define REG_LR_PREAMBLEMSB 0x20 +#define REG_LR_PREAMBLELSB 0x21 +#define REG_LR_PAYLOADLENGTH 0x22 +#define REG_LR_PAYLOADMAXLENGTH 0x23 +#define REG_LR_HOPPERIOD 0x24 +#define REG_LR_FIFORXBYTEADDR 0x25 +#define REG_LR_MODEMCONFIG3 0x26 +#define REG_LR_FEIMSB 0x28 +#define REG_LR_FEIMID 0x29 +#define REG_LR_FEILSB 0x2A +#define REG_LR_RSSIWIDEBAND 0x2C +#define REG_LR_TEST2F 0x2F +#define REG_LR_TEST30 0x30 +#define REG_LR_DETECTOPTIMIZE 0x31 +#define REG_LR_INVERTIQ 0x33 +#define REG_LR_TEST36 0x36 +#define REG_LR_DETECTIONTHRESHOLD 0x37 +#define REG_LR_SYNCWORD 0x39 +#define REG_LR_TEST3A 0x3A +#define REG_LR_INVERTIQ2 0x3B + +// end of documented register in datasheet +// I/O settings +#define REG_LR_DIOMAPPING1 0x40 +#define REG_LR_DIOMAPPING2 0x41 +// Version +#define REG_LR_VERSION 0x42 +// Additional settings +#define REG_LR_PLLHOP 0x44 +#define REG_LR_TCXO 0x4B +#define REG_LR_PADAC 0x4D +#define REG_LR_FORMERTEMP 0x5B +#define REG_LR_BITRATEFRAC 0x5D +#define REG_LR_AGCREF 0x61 +#define REG_LR_AGCTHRESH1 0x62 +#define REG_LR_AGCTHRESH2 0x63 +#define REG_LR_AGCTHRESH3 0x64 +#define REG_LR_PLL 0x70 + +/*! + * ============================================================================ + * SX1276 LoRa bits control definition + * ============================================================================ + */ + +/*! + * RegFifo + */ + +/*! + * RegOpMode + */ +#define RFLR_OPMODE_LONGRANGEMODE_MASK 0x7F +#define RFLR_OPMODE_LONGRANGEMODE_OFF 0x00 // Default +#define RFLR_OPMODE_LONGRANGEMODE_ON 0x80 + +#define RFLR_OPMODE_ACCESSSHAREDREG_MASK 0xBF +#define RFLR_OPMODE_ACCESSSHAREDREG_ENABLE 0x40 +#define RFLR_OPMODE_ACCESSSHAREDREG_DISABLE 0x00 // Default + +#define RFLR_OPMODE_FREQMODE_ACCESS_MASK 0xF7 +#define RFLR_OPMODE_FREQMODE_ACCESS_LF 0x08 // Default +#define RFLR_OPMODE_FREQMODE_ACCESS_HF 0x00 + +#define RFLR_OPMODE_MASK 0xF8 +#define RFLR_OPMODE_SLEEP 0x00 +#define RFLR_OPMODE_STANDBY 0x01 // Default +#define RFLR_OPMODE_SYNTHESIZER_TX 0x02 +#define RFLR_OPMODE_TRANSMITTER 0x03 +#define RFLR_OPMODE_SYNTHESIZER_RX 0x04 +#define RFLR_OPMODE_RECEIVER 0x05 +// LoRa specific modes +#define RFLR_OPMODE_RECEIVER_SINGLE 0x06 +#define RFLR_OPMODE_CAD 0x07 + +/*! + * RegFrf (MHz) + */ +#define RFLR_FRFMSB_434_MHZ 0x6C // Default +#define RFLR_FRFMID_434_MHZ 0x80 // Default +#define RFLR_FRFLSB_434_MHZ 0x00 // Default + +/*! + * RegPaConfig + */ +#define RFLR_PACONFIG_PASELECT_MASK 0x7F +#define RFLR_PACONFIG_PASELECT_PABOOST 0x80 +#define RFLR_PACONFIG_PASELECT_RFO 0x00 // Default + +#define RFLR_PACONFIG_MAX_POWER_MASK 0x8F + +#define RFLR_PACONFIG_OUTPUTPOWER_MASK 0xF0 + +/*! + * RegPaRamp + */ +#define RFLR_PARAMP_TXBANDFORCE_MASK 0xEF +#define RFLR_PARAMP_TXBANDFORCE_BAND_SEL 0x10 +#define RFLR_PARAMP_TXBANDFORCE_AUTO 0x00 // Default + +#define RFLR_PARAMP_MASK 0xF0 +#define RFLR_PARAMP_3400_US 0x00 +#define RFLR_PARAMP_2000_US 0x01 +#define RFLR_PARAMP_1000_US 0x02 +#define RFLR_PARAMP_0500_US 0x03 +#define RFLR_PARAMP_0250_US 0x04 +#define RFLR_PARAMP_0125_US 0x05 +#define RFLR_PARAMP_0100_US 0x06 +#define RFLR_PARAMP_0062_US 0x07 +#define RFLR_PARAMP_0050_US 0x08 +#define RFLR_PARAMP_0040_US 0x09 // Default +#define RFLR_PARAMP_0031_US 0x0A +#define RFLR_PARAMP_0025_US 0x0B +#define RFLR_PARAMP_0020_US 0x0C +#define RFLR_PARAMP_0015_US 0x0D +#define RFLR_PARAMP_0012_US 0x0E +#define RFLR_PARAMP_0010_US 0x0F + +/*! + * RegOcp + */ +#define RFLR_OCP_MASK 0xDF +#define RFLR_OCP_ON 0x20 // Default +#define RFLR_OCP_OFF 0x00 + +#define RFLR_OCP_TRIM_MASK 0xE0 +#define RFLR_OCP_TRIM_045_MA 0x00 +#define RFLR_OCP_TRIM_050_MA 0x01 +#define RFLR_OCP_TRIM_055_MA 0x02 +#define RFLR_OCP_TRIM_060_MA 0x03 +#define RFLR_OCP_TRIM_065_MA 0x04 +#define RFLR_OCP_TRIM_070_MA 0x05 +#define RFLR_OCP_TRIM_075_MA 0x06 +#define RFLR_OCP_TRIM_080_MA 0x07 +#define RFLR_OCP_TRIM_085_MA 0x08 +#define RFLR_OCP_TRIM_090_MA 0x09 +#define RFLR_OCP_TRIM_095_MA 0x0A +#define RFLR_OCP_TRIM_100_MA 0x0B // Default +#define RFLR_OCP_TRIM_105_MA 0x0C +#define RFLR_OCP_TRIM_110_MA 0x0D +#define RFLR_OCP_TRIM_115_MA 0x0E +#define RFLR_OCP_TRIM_120_MA 0x0F +#define RFLR_OCP_TRIM_130_MA 0x10 +#define RFLR_OCP_TRIM_140_MA 0x11 +#define RFLR_OCP_TRIM_150_MA 0x12 +#define RFLR_OCP_TRIM_160_MA 0x13 +#define RFLR_OCP_TRIM_170_MA 0x14 +#define RFLR_OCP_TRIM_180_MA 0x15 +#define RFLR_OCP_TRIM_190_MA 0x16 +#define RFLR_OCP_TRIM_200_MA 0x17 +#define RFLR_OCP_TRIM_210_MA 0x18 +#define RFLR_OCP_TRIM_220_MA 0x19 +#define RFLR_OCP_TRIM_230_MA 0x1A +#define RFLR_OCP_TRIM_240_MA 0x1B + +/*! + * RegLna + */ +#define RFLR_LNA_GAIN_MASK 0x1F +#define RFLR_LNA_GAIN_G1 0x20 // Default +#define RFLR_LNA_GAIN_G2 0x40 +#define RFLR_LNA_GAIN_G3 0x60 +#define RFLR_LNA_GAIN_G4 0x80 +#define RFLR_LNA_GAIN_G5 0xA0 +#define RFLR_LNA_GAIN_G6 0xC0 + +#define RFLR_LNA_BOOST_LF_MASK 0xE7 +#define RFLR_LNA_BOOST_LF_DEFAULT 0x00 // Default + +#define RFLR_LNA_BOOST_HF_MASK 0xFC +#define RFLR_LNA_BOOST_HF_OFF 0x00 // Default +#define RFLR_LNA_BOOST_HF_ON 0x03 + +/*! + * RegFifoAddrPtr + */ +#define RFLR_FIFOADDRPTR 0x00 // Default + +/*! + * RegFifoTxBaseAddr + */ +#define RFLR_FIFOTXBASEADDR 0x80 // Default + +/*! + * RegFifoTxBaseAddr + */ +#define RFLR_FIFORXBASEADDR 0x00 // Default + +/*! + * RegFifoRxCurrentAddr (Read Only) + */ + +/*! + * RegIrqFlagsMask + */ +#define RFLR_IRQFLAGS_RXTIMEOUT_MASK 0x80 +#define RFLR_IRQFLAGS_RXDONE_MASK 0x40 +#define RFLR_IRQFLAGS_PAYLOADCRCERROR_MASK 0x20 +#define RFLR_IRQFLAGS_VALIDHEADER_MASK 0x10 +#define RFLR_IRQFLAGS_TXDONE_MASK 0x08 +#define RFLR_IRQFLAGS_CADDONE_MASK 0x04 +#define RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL_MASK 0x02 +#define RFLR_IRQFLAGS_CADDETECTED_MASK 0x01 + +/*! + * RegIrqFlags + */ +#define RFLR_IRQFLAGS_RXTIMEOUT 0x80 +#define RFLR_IRQFLAGS_RXDONE 0x40 +#define RFLR_IRQFLAGS_PAYLOADCRCERROR 0x20 +#define RFLR_IRQFLAGS_VALIDHEADER 0x10 +#define RFLR_IRQFLAGS_TXDONE 0x08 +#define RFLR_IRQFLAGS_CADDONE 0x04 +#define RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL 0x02 +#define RFLR_IRQFLAGS_CADDETECTED 0x01 + +/*! + * RegFifoRxNbBytes (Read Only) + */ + +/*! + * RegRxHeaderCntValueMsb (Read Only) + */ + +/*! + * RegRxHeaderCntValueLsb (Read Only) + */ + +/*! + * RegRxPacketCntValueMsb (Read Only) + */ + +/*! + * RegRxPacketCntValueLsb (Read Only) + */ + +/*! + * RegModemStat (Read Only) + */ +#define RFLR_MODEMSTAT_RX_CR_MASK 0x1F +#define RFLR_MODEMSTAT_MODEM_STATUS_MASK 0xE0 + +/*! + * RegPktSnrValue (Read Only) + */ + +/*! + * RegPktRssiValue (Read Only) + */ + +/*! + * RegRssiValue (Read Only) + */ + +/*! + * RegHopChannel (Read Only) + */ +#define RFLR_HOPCHANNEL_PLL_LOCK_TIMEOUT_MASK 0x7F +#define RFLR_HOPCHANNEL_PLL_LOCK_FAIL 0x80 +#define RFLR_HOPCHANNEL_PLL_LOCK_SUCCEED 0x00 // Default + +#define RFLR_HOPCHANNEL_CRCONPAYLOAD_MASK 0xBF +#define RFLR_HOPCHANNEL_CRCONPAYLOAD_ON 0x40 +#define RFLR_HOPCHANNEL_CRCONPAYLOAD_OFF 0x00 // Default + +#define RFLR_HOPCHANNEL_CHANNEL_MASK 0x3F + +/*! + * RegModemConfig1 + */ +#define RFLR_MODEMCONFIG1_BW_MASK 0x0F +#define RFLR_MODEMCONFIG1_BW_7_81_KHZ 0x00 +#define RFLR_MODEMCONFIG1_BW_10_41_KHZ 0x10 +#define RFLR_MODEMCONFIG1_BW_15_62_KHZ 0x20 +#define RFLR_MODEMCONFIG1_BW_20_83_KHZ 0x30 +#define RFLR_MODEMCONFIG1_BW_31_25_KHZ 0x40 +#define RFLR_MODEMCONFIG1_BW_41_66_KHZ 0x50 +#define RFLR_MODEMCONFIG1_BW_62_50_KHZ 0x60 +#define RFLR_MODEMCONFIG1_BW_125_KHZ 0x70 // Default +#define RFLR_MODEMCONFIG1_BW_250_KHZ 0x80 +#define RFLR_MODEMCONFIG1_BW_500_KHZ 0x90 + +#define RFLR_MODEMCONFIG1_CODINGRATE_MASK 0xF1 +#define RFLR_MODEMCONFIG1_CODINGRATE_4_5 0x02 +#define RFLR_MODEMCONFIG1_CODINGRATE_4_6 0x04 // Default +#define RFLR_MODEMCONFIG1_CODINGRATE_4_7 0x06 +#define RFLR_MODEMCONFIG1_CODINGRATE_4_8 0x08 + +#define RFLR_MODEMCONFIG1_IMPLICITHEADER_MASK 0xFE +#define RFLR_MODEMCONFIG1_IMPLICITHEADER_ON 0x01 +#define RFLR_MODEMCONFIG1_IMPLICITHEADER_OFF 0x00 // Default + +/*! + * RegModemConfig2 + */ +#define RFLR_MODEMCONFIG2_SF_MASK 0x0F +#define RFLR_MODEMCONFIG2_SF_6 0x60 +#define RFLR_MODEMCONFIG2_SF_7 0x70 // Default +#define RFLR_MODEMCONFIG2_SF_8 0x80 +#define RFLR_MODEMCONFIG2_SF_9 0x90 +#define RFLR_MODEMCONFIG2_SF_10 0xA0 +#define RFLR_MODEMCONFIG2_SF_11 0xB0 +#define RFLR_MODEMCONFIG2_SF_12 0xC0 + +#define RFLR_MODEMCONFIG2_TXCONTINUOUSMODE_MASK 0xF7 +#define RFLR_MODEMCONFIG2_TXCONTINUOUSMODE_ON 0x08 +#define RFLR_MODEMCONFIG2_TXCONTINUOUSMODE_OFF 0x00 + +#define RFLR_MODEMCONFIG2_RXPAYLOADCRC_MASK 0xFB +#define RFLR_MODEMCONFIG2_RXPAYLOADCRC_ON 0x04 +#define RFLR_MODEMCONFIG2_RXPAYLOADCRC_OFF 0x00 // Default + +#define RFLR_MODEMCONFIG2_SYMBTIMEOUTMSB_MASK 0xFC +#define RFLR_MODEMCONFIG2_SYMBTIMEOUTMSB 0x00 // Default + +/*! + * RegSymbTimeoutLsb + */ +#define RFLR_SYMBTIMEOUTLSB_SYMBTIMEOUT 0x64 // Default + +/*! + * RegPreambleLengthMsb + */ +#define RFLR_PREAMBLELENGTHMSB 0x00 // Default + +/*! + * RegPreambleLengthLsb + */ +#define RFLR_PREAMBLELENGTHLSB 0x08 // Default + +/*! + * RegPayloadLength + */ +#define RFLR_PAYLOADLENGTH 0x0E // Default + +/*! + * RegPayloadMaxLength + */ +#define RFLR_PAYLOADMAXLENGTH 0xFF // Default + +/*! + * RegHopPeriod + */ +#define RFLR_HOPPERIOD_FREQFOPPINGPERIOD 0x00 // Default + +/*! + * RegFifoRxByteAddr (Read Only) + */ + +/*! + * RegModemConfig3 + */ +#define RFLR_MODEMCONFIG3_LOWDATARATEOPTIMIZE_MASK 0xF7 +#define RFLR_MODEMCONFIG3_LOWDATARATEOPTIMIZE_ON 0x08 +#define RFLR_MODEMCONFIG3_LOWDATARATEOPTIMIZE_OFF 0x00 // Default + +#define RFLR_MODEMCONFIG3_AGCAUTO_MASK 0xFB +#define RFLR_MODEMCONFIG3_AGCAUTO_ON 0x04 // Default +#define RFLR_MODEMCONFIG3_AGCAUTO_OFF 0x00 + +/*! + * RegFeiMsb (Read Only) + */ + +/*! + * RegFeiMid (Read Only) + */ + +/*! + * RegFeiLsb (Read Only) + */ + +/*! + * RegRssiWideband (Read Only) + */ + +/*! + * RegDetectOptimize + */ +#define RFLR_DETECTIONOPTIMIZE_MASK 0xF8 +#define RFLR_DETECTIONOPTIMIZE_SF7_TO_SF12 0x03 // Default +#define RFLR_DETECTIONOPTIMIZE_SF6 0x05 + +/*! + * RegInvertIQ + */ +#define RFLR_INVERTIQ_RX_MASK 0xBF +#define RFLR_INVERTIQ_RX_OFF 0x00 +#define RFLR_INVERTIQ_RX_ON 0x40 +#define RFLR_INVERTIQ_TX_MASK 0xFE +#define RFLR_INVERTIQ_TX_OFF 0x01 +#define RFLR_INVERTIQ_TX_ON 0x00 + +/*! + * RegDetectionThreshold + */ +#define RFLR_DETECTIONTHRESH_SF7_TO_SF12 0x0A // Default +#define RFLR_DETECTIONTHRESH_SF6 0x0C + +/*! + * RegInvertIQ2 + */ +#define RFLR_INVERTIQ2_ON 0x19 +#define RFLR_INVERTIQ2_OFF 0x1D + +/*! + * RegDioMapping1 + */ +#define RFLR_DIOMAPPING1_DIO0_MASK 0x3F +#define RFLR_DIOMAPPING1_DIO0_00 0x00 // Default +#define RFLR_DIOMAPPING1_DIO0_01 0x40 +#define RFLR_DIOMAPPING1_DIO0_10 0x80 +#define RFLR_DIOMAPPING1_DIO0_11 0xC0 + +#define RFLR_DIOMAPPING1_DIO1_MASK 0xCF +#define RFLR_DIOMAPPING1_DIO1_00 0x00 // Default +#define RFLR_DIOMAPPING1_DIO1_01 0x10 +#define RFLR_DIOMAPPING1_DIO1_10 0x20 +#define RFLR_DIOMAPPING1_DIO1_11 0x30 + +#define RFLR_DIOMAPPING1_DIO2_MASK 0xF3 +#define RFLR_DIOMAPPING1_DIO2_00 0x00 // Default +#define RFLR_DIOMAPPING1_DIO2_01 0x04 +#define RFLR_DIOMAPPING1_DIO2_10 0x08 +#define RFLR_DIOMAPPING1_DIO2_11 0x0C + +#define RFLR_DIOMAPPING1_DIO3_MASK 0xFC +#define RFLR_DIOMAPPING1_DIO3_00 0x00 // Default +#define RFLR_DIOMAPPING1_DIO3_01 0x01 +#define RFLR_DIOMAPPING1_DIO3_10 0x02 +#define RFLR_DIOMAPPING1_DIO3_11 0x03 + +/*! + * RegDioMapping2 + */ +#define RFLR_DIOMAPPING2_DIO4_MASK 0x3F +#define RFLR_DIOMAPPING2_DIO4_00 0x00 // Default +#define RFLR_DIOMAPPING2_DIO4_01 0x40 +#define RFLR_DIOMAPPING2_DIO4_10 0x80 +#define RFLR_DIOMAPPING2_DIO4_11 0xC0 + +#define RFLR_DIOMAPPING2_DIO5_MASK 0xCF +#define RFLR_DIOMAPPING2_DIO5_00 0x00 // Default +#define RFLR_DIOMAPPING2_DIO5_01 0x10 +#define RFLR_DIOMAPPING2_DIO5_10 0x20 +#define RFLR_DIOMAPPING2_DIO5_11 0x30 + +#define RFLR_DIOMAPPING2_MAP_MASK 0xFE +#define RFLR_DIOMAPPING2_MAP_PREAMBLEDETECT 0x01 +#define RFLR_DIOMAPPING2_MAP_RSSI 0x00 // Default + +/*! + * RegVersion (Read Only) + */ + +/*! + * RegPllHop + */ +#define RFLR_PLLHOP_FASTHOP_MASK 0x7F +#define RFLR_PLLHOP_FASTHOP_ON 0x80 +#define RFLR_PLLHOP_FASTHOP_OFF 0x00 // Default + +/*! + * RegTcxo + */ +#define RFLR_TCXO_TCXOINPUT_MASK 0xEF +#define RFLR_TCXO_TCXOINPUT_ON 0x10 +#define RFLR_TCXO_TCXOINPUT_OFF 0x00 // Default + +/*! + * RegPaDac + */ +#define RFLR_PADAC_20DBM_MASK 0xF8 +#define RFLR_PADAC_20DBM_ON 0x07 +#define RFLR_PADAC_20DBM_OFF 0x04 // Default + +/*! + * RegFormerTemp + */ + +/*! + * RegBitrateFrac + */ +#define RF_BITRATEFRAC_MASK 0xF0 + +/*! + * RegAgcRef + */ + +/*! + * RegAgcThresh1 + */ + +/*! + * RegAgcThresh2 + */ + +/*! + * RegAgcThresh3 + */ + +/*! + * RegPll + */ +#define RF_PLL_BANDWIDTH_MASK 0x3F +#define RF_PLL_BANDWIDTH_75 0x00 +#define RF_PLL_BANDWIDTH_150 0x40 +#define RF_PLL_BANDWIDTH_225 0x80 +#define RF_PLL_BANDWIDTH_300 0xC0 // Default + +#endif // __SX1276_REGS_LORA_H__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/radio/SX1276Lib/sx1276/sx1276-hal.cpp Wed Sep 04 15:42:07 2019 +0000 @@ -0,0 +1,351 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C) 2014 Semtech + +Description: - + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainers: Miguel Luis, Gregory Cristian and Nicolas Huguenin +*/ +#include "sx1276-hal.h" + +const RadioRegisters_t SX1276MB1xAS::RadioRegsInit[] = RADIO_INIT_REGISTERS_VALUE; + +SX1276MB1xAS::SX1276MB1xAS( RadioEvents_t *events, + PinName mosi, PinName miso, PinName sclk, PinName nss, PinName reset, + PinName dio0, PinName dio1, PinName dio2, PinName dio3, PinName dio4, PinName dio5, + PinName antSwitch ) + : SX1276( events, mosi, miso, sclk, nss, reset, dio0, dio1, dio2, dio3, dio4, dio5 ), + AntSwitch( antSwitch ), + #if( defined ( TARGET_NUCLEO_L152RE ) ) + Fake( D8 ) + #else + Fake( A3 ) + #endif +{ + this->RadioEvents = events; + + Reset( ); + + RxChainCalibration( ); + + IoInit( ); + + SetOpMode( RF_OPMODE_SLEEP ); + + IoIrqInit( dioIrq ); + + RadioRegistersInit( ); + + SetModem( MODEM_FSK ); + + this->settings.State = RF_IDLE ; +} + +SX1276MB1xAS::SX1276MB1xAS( RadioEvents_t *events ) + #if defined ( TARGET_NUCLEO_L152RE ) + : SX1276( events, D11, D12, D13, D10, A0, D2, D3, D4, D5, A3, D9 ), // For NUCLEO L152RE dio4 is on port A3 + AntSwitch( A4 ), + Fake( D8 ) + #elif defined( TARGET_LPC11U6X ) + : SX1276( events, D11, D12, D13, D10, A0, D2, D3, D4, D5, D8, D9 ), + AntSwitch( P0_23 ), + Fake( A3 ) + #else + : SX1276( events, D11, D12, D13, D10, A0, D2, D3, D4, D5, D8, D9 ), + AntSwitch( A4 ), + Fake( A3 ) + #endif +{ + this->RadioEvents = events; + + Reset( ); + + boardConnected = UNKNOWN; + + DetectBoardType( ); + + RxChainCalibration( ); + + IoInit( ); + + SetOpMode( RF_OPMODE_SLEEP ); + IoIrqInit( dioIrq ); + + RadioRegistersInit( ); + + SetModem( MODEM_FSK ); + + this->settings.State = RF_IDLE ; +} + +//------------------------------------------------------------------------- +// Board relative functions +//------------------------------------------------------------------------- +uint8_t SX1276MB1xAS::DetectBoardType( void ) +{ + if( boardConnected == UNKNOWN ) + { + this->AntSwitch.input( ); + wait_ms( 1 ); + if( this->AntSwitch == 1 ) + { + boardConnected = SX1276MB1LAS; + } + else + { + boardConnected = SX1276MB1MAS; + } + this->AntSwitch.output( ); + wait_ms( 1 ); + } + return ( boardConnected ); +} + +void SX1276MB1xAS::IoInit( void ) +{ + AntSwInit( ); + SpiInit( ); +} + +void SX1276MB1xAS::RadioRegistersInit( ) +{ + uint8_t i = 0; + for( i = 0; i < sizeof( RadioRegsInit ) / sizeof( RadioRegisters_t ); i++ ) + { + SetModem( RadioRegsInit[i].Modem ); + Write( RadioRegsInit[i].Addr, RadioRegsInit[i].Value ); + } +} + +void SX1276MB1xAS::SpiInit( void ) +{ + nss = 1; + spi.format( 8,0 ); + uint32_t frequencyToSet = 8000000; + #if( defined ( TARGET_NUCLEO_L152RE ) || defined ( TARGET_LPC11U6X ) ) + spi.frequency( frequencyToSet ); + #elif( defined ( TARGET_KL25Z ) ) //busclock frequency is halved -> double the spi frequency to compensate + spi.frequency( frequencyToSet * 2 ); + #else + #warning "Check the board's SPI frequency" + #endif + wait(0.1); +} + +void SX1276MB1xAS::IoIrqInit( DioIrqHandler *irqHandlers ) +{ +#if( defined ( TARGET_NUCLEO_L152RE ) || defined ( TARGET_LPC11U6X ) ) + dio0.mode( PullDown ); + dio1.mode( PullDown ); + dio2.mode( PullDown ); + dio3.mode( PullDown ); + dio4.mode( PullDown ); +#endif + dio0.rise( mbed::callback( this, static_cast< TriggerMB1xAS > ( irqHandlers[0] ) ) ); + dio1.rise( mbed::callback( this, static_cast< TriggerMB1xAS > ( irqHandlers[1] ) ) ); + dio2.rise( mbed::callback( this, static_cast< TriggerMB1xAS > ( irqHandlers[2] ) ) ); + dio3.rise( mbed::callback( this, static_cast< TriggerMB1xAS > ( irqHandlers[3] ) ) ); + dio4.rise( mbed::callback( this, static_cast< TriggerMB1xAS > ( irqHandlers[4] ) ) ); +} + +void SX1276MB1xAS::IoDeInit( void ) +{ + //nothing +} + +void SX1276MB1xAS::SetRfTxPower( int8_t power ) +{ + uint8_t paConfig = 0; + uint8_t paDac = 0; + + paConfig = Read( REG_PACONFIG ); + paDac = Read( REG_PADAC ); + + paConfig = ( paConfig & RF_PACONFIG_PASELECT_MASK ) | GetPaSelect( this->settings.Channel ); + paConfig = ( paConfig & RF_PACONFIG_MAX_POWER_MASK ) | 0x70; + + if( ( paConfig & RF_PACONFIG_PASELECT_PABOOST ) == RF_PACONFIG_PASELECT_PABOOST ) + { + if( power > 17 ) + { + paDac = ( paDac & RF_PADAC_20DBM_MASK ) | RF_PADAC_20DBM_ON; + } + else + { + paDac = ( paDac & RF_PADAC_20DBM_MASK ) | RF_PADAC_20DBM_OFF; + } + if( ( paDac & RF_PADAC_20DBM_ON ) == RF_PADAC_20DBM_ON ) + { + if( power < 5 ) + { + power = 5; + } + if( power > 20 ) + { + power = 20; + } + paConfig = ( paConfig & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power - 5 ) & 0x0F ); + } + else + { + if( power < 2 ) + { + power = 2; + } + if( power > 17 ) + { + power = 17; + } + paConfig = ( paConfig & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power - 2 ) & 0x0F ); + } + } + else + { + if( power < -1 ) + { + power = -1; + } + if( power > 14 ) + { + power = 14; + } + paConfig = ( paConfig & RF_PACONFIG_OUTPUTPOWER_MASK ) | ( uint8_t )( ( uint16_t )( power + 1 ) & 0x0F ); + } + Write( REG_PACONFIG, paConfig ); + Write( REG_PADAC, paDac ); +} + +uint8_t SX1276MB1xAS::GetPaSelect( uint32_t channel ) +{ + if( channel > RF_MID_BAND_THRESH ) + { + if( boardConnected == SX1276MB1LAS ) + { + return RF_PACONFIG_PASELECT_PABOOST; + } + else + { + //return RF_PACONFIG_PASELECT_RFO; + return RF_PACONFIG_PASELECT_PABOOST; + } + } + else + { + //return RF_PACONFIG_PASELECT_RFO; + return RF_PACONFIG_PASELECT_PABOOST; + } +} + +void SX1276MB1xAS::SetAntSwLowPower( bool status ) +{ + if( isRadioActive != status ) + { + isRadioActive = status; + + if( status == false ) + { + AntSwInit( ); + } + else + { + AntSwDeInit( ); + } + } +} + +void SX1276MB1xAS::AntSwInit( void ) +{ + this->AntSwitch = 0; +} + +void SX1276MB1xAS::AntSwDeInit( void ) +{ + this->AntSwitch = 0; +} + +void SX1276MB1xAS::SetAntSw( uint8_t opMode ) +{ + switch( opMode ) + { + case RFLR_OPMODE_TRANSMITTER: + this->AntSwitch = 1; + break; + case RFLR_OPMODE_RECEIVER: + case RFLR_OPMODE_RECEIVER_SINGLE: + case RFLR_OPMODE_CAD: + this->AntSwitch = 0; + break; + default: + this->AntSwitch = 0; + break; + } +} + +bool SX1276MB1xAS::CheckRfFrequency( uint32_t frequency ) +{ + // Implement check. Currently all frequencies are supported + return true; +} + +void SX1276MB1xAS::Reset( void ) +{ + reset.output( ); + reset = 0; + wait_ms( 1 ); + reset.input( ); + wait_ms( 6 ); +} + +void SX1276MB1xAS::Write( uint8_t addr, uint8_t data ) +{ + Write( addr, &data, 1 ); +} + +uint8_t SX1276MB1xAS::Read( uint8_t addr ) +{ + uint8_t data; + Read( addr, &data, 1 ); + return data; +} + +void SX1276MB1xAS::Write( uint8_t addr, uint8_t *buffer, uint8_t size ) +{ + uint8_t i; + + nss = 0; + spi.write( addr | 0x80 ); + for( i = 0; i < size; i++ ) + { + spi.write( buffer[i] ); + } + nss = 1; +} + +void SX1276MB1xAS::Read( uint8_t addr, uint8_t *buffer, uint8_t size ) +{ + uint8_t i; + + nss = 0; + spi.write( addr & 0x7F ); + for( i = 0; i < size; i++ ) + { + buffer[i] = spi.write( 0 ); + } + nss = 1; +} + +void SX1276MB1xAS::WriteFifo( uint8_t *buffer, uint8_t size ) +{ + Write( 0, buffer, size ); +} + +void SX1276MB1xAS::ReadFifo( uint8_t *buffer, uint8_t size ) +{ + Read( 0, buffer, size ); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/radio/SX1276Lib/sx1276/sx1276-hal.h Wed Sep 04 15:42:07 2019 +0000 @@ -0,0 +1,212 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C) 2014 Semtech + +Description: - + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainers: Miguel Luis, Gregory Cristian and Nicolas Huguenin +*/ +#ifndef __SX1276_HAL_H__ +#define __SX1276_HAL_H__ +#include "sx1276.h" + +/*! + * @brief Radio hardware registers initialization definition + * + * @remark Can be automatically generated by the SX1276 GUI (not yet implemented) + */ +#define RADIO_INIT_REGISTERS_VALUE \ +{ \ + { MODEM_FSK , REG_LNA , 0x23 },\ + { MODEM_FSK , REG_RXCONFIG , 0x1E },\ + { MODEM_FSK , REG_RSSICONFIG , 0xD2 },\ + { MODEM_FSK , REG_AFCFEI , 0x01 },\ + { MODEM_FSK , REG_PREAMBLEDETECT , 0xAA },\ + { MODEM_FSK , REG_OSC , 0x07 },\ + { MODEM_FSK , REG_SYNCCONFIG , 0x12 },\ + { MODEM_FSK , REG_SYNCVALUE1 , 0xC1 },\ + { MODEM_FSK , REG_SYNCVALUE2 , 0x94 },\ + { MODEM_FSK , REG_SYNCVALUE3 , 0xC1 },\ + { MODEM_FSK , REG_PACKETCONFIG1 , 0xD8 },\ + { MODEM_FSK , REG_FIFOTHRESH , 0x8F },\ + { MODEM_FSK , REG_IMAGECAL , 0x02 },\ + { MODEM_FSK , REG_DIOMAPPING1 , 0x00 },\ + { MODEM_FSK , REG_DIOMAPPING2 , 0x30 },\ + { MODEM_LORA, REG_LR_PAYLOADMAXLENGTH, 0x40 },\ +} \ + +/*! + * Actual implementation of a SX1276 radio, includes some modifications to make it compatible with the MB1 LAS board + */ +class SX1276MB1xAS : public SX1276 +{ +protected: + /*! + * Antenna switch GPIO pins objects + */ + DigitalInOut AntSwitch; + DigitalIn Fake; + +private: + static const RadioRegisters_t RadioRegsInit[]; + +public: + SX1276MB1xAS( RadioEvents_t *events, + PinName mosi, PinName miso, PinName sclk, PinName nss, PinName reset, + PinName dio0, PinName dio1, PinName dio2, PinName dio3, PinName dio4, PinName dio5, + PinName antSwitch ); + + SX1276MB1xAS( RadioEvents_t *events ); + + virtual ~SX1276MB1xAS( ) { }; + +protected: + /*! + * @brief Initializes the radio I/Os pins interface + */ + virtual void IoInit( void ); + + /*! + * @brief Initializes the radio registers + */ + virtual void RadioRegistersInit( ); + + /*! + * @brief Initializes the radio SPI + */ + virtual void SpiInit( void ); + + /*! + * @brief Initializes DIO IRQ handlers + * + * @param [IN] irqHandlers Array containing the IRQ callback functions + */ + virtual void IoIrqInit( DioIrqHandler *irqHandlers ); + + /*! + * @brief De-initializes the radio I/Os pins interface. + * + * \remark Useful when going in MCU lowpower modes + */ + virtual void IoDeInit( void ); + + /*! + * \brief Sets the radio output power. + * + * @param [IN] power Sets the RF output power + */ + virtual void SetRfTxPower( int8_t power ); + + /*! + * @brief Gets the board PA selection configuration + * + * @param [IN] channel Channel frequency in Hz + * @retval PaSelect RegPaConfig PaSelect value + */ + virtual uint8_t GetPaSelect( uint32_t channel ); + + /*! + * @brief Set the RF Switch I/Os pins in Low Power mode + * + * @param [IN] status enable or disable + */ + virtual void SetAntSwLowPower( bool status ); + + /*! + * @brief Initializes the RF Switch I/Os pins interface + */ + virtual void AntSwInit( void ); + + /*! + * @brief De-initializes the RF Switch I/Os pins interface + * + * @remark Needed to decrease the power consumption in MCU lowpower modes + */ + virtual void AntSwDeInit( void ); + + /*! + * @brief Controls the antena switch if necessary. + * + * @remark see errata note + * + * @param [IN] opMode Current radio operating mode + */ + virtual void SetAntSw( uint8_t opMode ); + +public: + /*! + * @brief Detect the board connected by reading the value of the antenna switch pin + */ + virtual uint8_t DetectBoardType( void ); + + /*! + * @brief Checks if the given RF frequency is supported by the hardware + * + * @param [IN] frequency RF frequency to be checked + * @retval isSupported [true: supported, false: unsupported] + */ + virtual bool CheckRfFrequency( uint32_t frequency ); + + /*! + * @brief Writes the radio register at the specified address + * + * @param [IN]: addr Register address + * @param [IN]: data New register value + */ + virtual void Write ( uint8_t addr, uint8_t data ) ; + + /*! + * @brief Reads the radio register at the specified address + * + * @param [IN]: addr Register address + * @retval data Register value + */ + virtual uint8_t Read ( uint8_t addr ) ; + + /*! + * @brief Writes multiple radio registers starting at address + * + * @param [IN] addr First Radio register address + * @param [IN] buffer Buffer containing the new register's values + * @param [IN] size Number of registers to be written + */ + virtual void Write( uint8_t addr, uint8_t *buffer, uint8_t size ) ; + + /*! + * @brief Reads multiple radio registers starting at address + * + * @param [IN] addr First Radio register address + * @param [OUT] buffer Buffer where to copy the registers data + * @param [IN] size Number of registers to be read + */ + virtual void Read ( uint8_t addr, uint8_t *buffer, uint8_t size ) ; + + /*! + * @brief Writes the buffer contents to the SX1276 FIFO + * + * @param [IN] buffer Buffer containing data to be put on the FIFO. + * @param [IN] size Number of bytes to be written to the FIFO + */ + virtual void WriteFifo( uint8_t *buffer, uint8_t size ) ; + + /*! + * @brief Reads the contents of the SX1276 FIFO + * + * @param [OUT] buffer Buffer where to copy the FIFO read data. + * @param [IN] size Number of bytes to be read from the FIFO + */ + virtual void ReadFifo( uint8_t *buffer, uint8_t size ) ; + + /*! + * @brief Reset the SX1276 + */ + virtual void Reset( void ); +}; + +#endif // __SX1276_HAL_H__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/radio/SX1276Lib/sx1276/sx1276.cpp Wed Sep 04 15:42:07 2019 +0000 @@ -0,0 +1,1561 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C) 2014 Semtech + +Description: Actual implementation of a SX1276 radio, inherits Radio + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainers: Miguel Luis, Gregory Cristian and Nicolas Huguenin +*/ +#include "sx1276.h" + +const FskBandwidth_t SX1276::FskBandwidths[] = +{ + { 2600 , 0x17 }, + { 3100 , 0x0F }, + { 3900 , 0x07 }, + { 5200 , 0x16 }, + { 6300 , 0x0E }, + { 7800 , 0x06 }, + { 10400 , 0x15 }, + { 12500 , 0x0D }, + { 15600 , 0x05 }, + { 20800 , 0x14 }, + { 25000 , 0x0C }, + { 31300 , 0x04 }, + { 41700 , 0x13 }, + { 50000 , 0x0B }, + { 62500 , 0x03 }, + { 83333 , 0x12 }, + { 100000, 0x0A }, + { 125000, 0x02 }, + { 166700, 0x11 }, + { 200000, 0x09 }, + { 250000, 0x01 }, + { 300000, 0x00 }, // Invalid Bandwidth +}; + + +SX1276::SX1276( RadioEvents_t *events, + PinName mosi, PinName miso, PinName sclk, PinName nss, PinName reset, + PinName dio0, PinName dio1, PinName dio2, PinName dio3, PinName dio4, PinName dio5 ) + : Radio( events ), + spi( mosi, miso, sclk ), + nss( nss ), + reset( reset ), + dio0( dio0 ), dio1( dio1 ), dio2( dio2 ), dio3( dio3 ), dio4( dio4 ), dio5( dio5 ), + isRadioActive( false ) +{ + wait_ms( 10 ); + this->rxtxBuffer = new uint8_t[RX_BUFFER_SIZE]; + + this->RadioEvents = events; + + this->dioIrq = new DioIrqHandler[6]; + + this->dioIrq[0] = &SX1276::OnDio0Irq; + this->dioIrq[1] = &SX1276::OnDio1Irq; + this->dioIrq[2] = &SX1276::OnDio2Irq; + this->dioIrq[3] = &SX1276::OnDio3Irq; + this->dioIrq[4] = &SX1276::OnDio4Irq; + this->dioIrq[5] = NULL; + + this->settings.State = RF_IDLE; +} + +SX1276::~SX1276( ) +{ + delete this->rxtxBuffer; + delete this->dioIrq; +} + +void SX1276::Init( RadioEvents_t *events ) +{ + this->RadioEvents = events; +} + +RadioState SX1276::GetStatus( void ) +{ + return this->settings.State; +} + +void SX1276::SetChannel( uint32_t freq ) +{ + this->settings.Channel = freq; + freq = ( uint32_t )( ( double )freq / ( double )FREQ_STEP ); + Write( REG_FRFMSB, ( uint8_t )( ( freq >> 16 ) & 0xFF ) ); + Write( REG_FRFMID, ( uint8_t )( ( freq >> 8 ) & 0xFF ) ); + Write( REG_FRFLSB, ( uint8_t )( freq & 0xFF ) ); +} + +bool SX1276::IsChannelFree( RadioModems_t modem, uint32_t freq, int16_t rssiThresh ) +{ + int16_t rssi = 0; + + SetModem( modem ); + + SetChannel( freq ); + + SetOpMode( RF_OPMODE_RECEIVER ); + + wait_ms( 1 ); + + rssi = GetRssi( modem ); + + Sleep( ); + + if( rssi > rssiThresh ) + { + return false; + } + return true; +} + +uint32_t SX1276::Random( void ) +{ + uint8_t i; + uint32_t rnd = 0; + + /* + * Radio setup for random number generation + */ + // Set LoRa modem ON + SetModem( MODEM_LORA ); + + // Disable LoRa modem interrupts + Write( REG_LR_IRQFLAGSMASK, RFLR_IRQFLAGS_RXTIMEOUT | + RFLR_IRQFLAGS_RXDONE | + RFLR_IRQFLAGS_PAYLOADCRCERROR | + RFLR_IRQFLAGS_VALIDHEADER | + RFLR_IRQFLAGS_TXDONE | + RFLR_IRQFLAGS_CADDONE | + RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL | + RFLR_IRQFLAGS_CADDETECTED ); + + // Set radio in continuous reception + SetOpMode( RF_OPMODE_RECEIVER ); + + for( i = 0; i < 32; i++ ) + { + wait_ms( 1 ); + // Unfiltered RSSI value reading. Only takes the LSB value + rnd |= ( ( uint32_t )Read( REG_LR_RSSIWIDEBAND ) & 0x01 ) << i; + } + + Sleep( ); + + return rnd; +} + +/*! + * Performs the Rx chain calibration for LF and HF bands + * \remark Must be called just after the reset so all registers are at their + * default values + */ +void SX1276::RxChainCalibration( void ) +{ + uint8_t regPaConfigInitVal; + uint32_t initialFreq; + + // Save context + regPaConfigInitVal = this->Read( REG_PACONFIG ); + initialFreq = ( double )( ( ( uint32_t )this->Read( REG_FRFMSB ) << 16 ) | + ( ( uint32_t )this->Read( REG_FRFMID ) << 8 ) | + ( ( uint32_t )this->Read( REG_FRFLSB ) ) ) * ( double )FREQ_STEP; + + // Cut the PA just in case, RFO output, power = -1 dBm + this->Write( REG_PACONFIG, 0x00 ); + + // Launch Rx chain calibration for LF band + Write ( REG_IMAGECAL, ( Read( REG_IMAGECAL ) & RF_IMAGECAL_IMAGECAL_MASK ) | RF_IMAGECAL_IMAGECAL_START ); + while( ( Read( REG_IMAGECAL ) & RF_IMAGECAL_IMAGECAL_RUNNING ) == RF_IMAGECAL_IMAGECAL_RUNNING ) + { + } + + // Sets a Frequency in HF band + SetChannel( 868000000 ); + + // Launch Rx chain calibration for HF band + Write ( REG_IMAGECAL, ( Read( REG_IMAGECAL ) & RF_IMAGECAL_IMAGECAL_MASK ) | RF_IMAGECAL_IMAGECAL_START ); + while( ( Read( REG_IMAGECAL ) & RF_IMAGECAL_IMAGECAL_RUNNING ) == RF_IMAGECAL_IMAGECAL_RUNNING ) + { + } + + // Restore context + this->Write( REG_PACONFIG, regPaConfigInitVal ); + SetChannel( initialFreq ); +} + +/*! + * Returns the known FSK bandwidth registers value + * + * \param [IN] bandwidth Bandwidth value in Hz + * \retval regValue Bandwidth register value. + */ +uint8_t SX1276::GetFskBandwidthRegValue( uint32_t bandwidth ) +{ + uint8_t i; + + for( i = 0; i < ( sizeof( FskBandwidths ) / sizeof( FskBandwidth_t ) ) - 1; i++ ) + { + if( ( bandwidth >= FskBandwidths[i].bandwidth ) && ( bandwidth < FskBandwidths[i + 1].bandwidth ) ) + { + return FskBandwidths[i].RegValue; + } + } + // ERROR: Value not found + while( 1 ); +} + +void SX1276::SetRxConfig( RadioModems_t modem, uint32_t bandwidth, + uint32_t datarate, uint8_t coderate, + uint32_t bandwidthAfc, uint16_t preambleLen, + uint16_t symbTimeout, bool fixLen, + uint8_t payloadLen, + bool crcOn, bool freqHopOn, uint8_t hopPeriod, + bool iqInverted, bool rxContinuous ) +{ + SetModem( modem ); + + switch( modem ) + { + case MODEM_FSK: + { + this->settings.Fsk.Bandwidth = bandwidth; + this->settings.Fsk.Datarate = datarate; + this->settings.Fsk.BandwidthAfc = bandwidthAfc; + this->settings.Fsk.FixLen = fixLen; + this->settings.Fsk.PayloadLen = payloadLen; + this->settings.Fsk.CrcOn = crcOn; + this->settings.Fsk.IqInverted = iqInverted; + this->settings.Fsk.RxContinuous = rxContinuous; + this->settings.Fsk.PreambleLen = preambleLen; + this->settings.Fsk.RxSingleTimeout = symbTimeout * ( ( 1.0 / ( double )datarate ) * 8.0 ) * 1e3; + + datarate = ( uint16_t )( ( double )XTAL_FREQ / ( double )datarate ); + Write( REG_BITRATEMSB, ( uint8_t )( datarate >> 8 ) ); + Write( REG_BITRATELSB, ( uint8_t )( datarate & 0xFF ) ); + + Write( REG_RXBW, GetFskBandwidthRegValue( bandwidth ) ); + Write( REG_AFCBW, GetFskBandwidthRegValue( bandwidthAfc ) ); + + Write( REG_PREAMBLEMSB, ( uint8_t )( ( preambleLen >> 8 ) & 0xFF ) ); + Write( REG_PREAMBLELSB, ( uint8_t )( preambleLen & 0xFF ) ); + + if( fixLen == 1 ) + { + Write( REG_PAYLOADLENGTH, payloadLen ); + } + else + { + Write( REG_PAYLOADLENGTH, 0xFF ); // Set payload length to the maximum + } + + Write( REG_PACKETCONFIG1, + ( Read( REG_PACKETCONFIG1 ) & + RF_PACKETCONFIG1_CRC_MASK & + RF_PACKETCONFIG1_PACKETFORMAT_MASK ) | + ( ( fixLen == 1 ) ? RF_PACKETCONFIG1_PACKETFORMAT_FIXED : RF_PACKETCONFIG1_PACKETFORMAT_VARIABLE ) | + ( crcOn << 4 ) ); + Write( REG_PACKETCONFIG2, ( Read( REG_PACKETCONFIG2 ) | RF_PACKETCONFIG2_DATAMODE_PACKET ) ); + } + break; + case MODEM_LORA: + { + if( bandwidth > 2 ) + { + // Fatal error: When using LoRa modem only bandwidths 125, 250 and 500 kHz are supported + while( 1 ); + } + bandwidth += 7; + this->settings.LoRa.Bandwidth = bandwidth; + this->settings.LoRa.Datarate = datarate; + this->settings.LoRa.Coderate = coderate; + this->settings.LoRa.PreambleLen = preambleLen; + this->settings.LoRa.FixLen = fixLen; + this->settings.LoRa.PayloadLen = payloadLen; + this->settings.LoRa.CrcOn = crcOn; + this->settings.LoRa.FreqHopOn = freqHopOn; + this->settings.LoRa.HopPeriod = hopPeriod; + this->settings.LoRa.IqInverted = iqInverted; + this->settings.LoRa.RxContinuous = rxContinuous; + + if( datarate > 12 ) + { + datarate = 12; + } + else if( datarate < 6 ) + { + datarate = 6; + } + + if( ( ( bandwidth == 7 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) || + ( ( bandwidth == 8 ) && ( datarate == 12 ) ) ) + { + this->settings.LoRa.LowDatarateOptimize = 0x01; + } + else + { + this->settings.LoRa.LowDatarateOptimize = 0x00; + } + + Write( REG_LR_MODEMCONFIG1, + ( Read( REG_LR_MODEMCONFIG1 ) & + RFLR_MODEMCONFIG1_BW_MASK & + RFLR_MODEMCONFIG1_CODINGRATE_MASK & + RFLR_MODEMCONFIG1_IMPLICITHEADER_MASK ) | + ( bandwidth << 4 ) | ( coderate << 1 ) | + fixLen ); + + Write( REG_LR_MODEMCONFIG2, + ( Read( REG_LR_MODEMCONFIG2 ) & + RFLR_MODEMCONFIG2_SF_MASK & + RFLR_MODEMCONFIG2_RXPAYLOADCRC_MASK & + RFLR_MODEMCONFIG2_SYMBTIMEOUTMSB_MASK ) | + ( datarate << 4 ) | ( crcOn << 2 ) | + ( ( symbTimeout >> 8 ) & ~RFLR_MODEMCONFIG2_SYMBTIMEOUTMSB_MASK ) ); + + Write( REG_LR_MODEMCONFIG3, + ( Read( REG_LR_MODEMCONFIG3 ) & + RFLR_MODEMCONFIG3_LOWDATARATEOPTIMIZE_MASK ) | + ( this->settings.LoRa.LowDatarateOptimize << 3 ) ); + + Write( REG_LR_SYMBTIMEOUTLSB, ( uint8_t )( symbTimeout & 0xFF ) ); + + Write( REG_LR_PREAMBLEMSB, ( uint8_t )( ( preambleLen >> 8 ) & 0xFF ) ); + Write( REG_LR_PREAMBLELSB, ( uint8_t )( preambleLen & 0xFF ) ); + + if( fixLen == 1 ) + { + Write( REG_LR_PAYLOADLENGTH, payloadLen ); + } + + if( this->settings.LoRa.FreqHopOn == true ) + { + Write( REG_LR_PLLHOP, ( Read( REG_LR_PLLHOP ) & RFLR_PLLHOP_FASTHOP_MASK ) | RFLR_PLLHOP_FASTHOP_ON ); + Write( REG_LR_HOPPERIOD, this->settings.LoRa.HopPeriod ); + } + + if( ( bandwidth == 9 ) && ( this->settings.Channel > RF_MID_BAND_THRESH ) ) + { + // ERRATA 2.1 - Sensitivity Optimization with a 500 kHz Bandwidth + Write( REG_LR_TEST36, 0x02 ); + Write( REG_LR_TEST3A, 0x64 ); + } + else if( bandwidth == 9 ) + { + // ERRATA 2.1 - Sensitivity Optimization with a 500 kHz Bandwidth + Write( REG_LR_TEST36, 0x02 ); + Write( REG_LR_TEST3A, 0x7F ); + } + else + { + // ERRATA 2.1 - Sensitivity Optimization with a 500 kHz Bandwidth + Write( REG_LR_TEST36, 0x03 ); + } + + if( datarate == 6 ) + { + Write( REG_LR_DETECTOPTIMIZE, + ( Read( REG_LR_DETECTOPTIMIZE ) & + RFLR_DETECTIONOPTIMIZE_MASK ) | + RFLR_DETECTIONOPTIMIZE_SF6 ); + Write( REG_LR_DETECTIONTHRESHOLD, + RFLR_DETECTIONTHRESH_SF6 ); + } + else + { + Write( REG_LR_DETECTOPTIMIZE, + ( Read( REG_LR_DETECTOPTIMIZE ) & + RFLR_DETECTIONOPTIMIZE_MASK ) | + RFLR_DETECTIONOPTIMIZE_SF7_TO_SF12 ); + Write( REG_LR_DETECTIONTHRESHOLD, + RFLR_DETECTIONTHRESH_SF7_TO_SF12 ); + } + } + break; + } +} + +void SX1276::SetTxConfig( RadioModems_t modem, int8_t power, uint32_t fdev, + uint32_t bandwidth, uint32_t datarate, + uint8_t coderate, uint16_t preambleLen, + bool fixLen, bool crcOn, bool freqHopOn, + uint8_t hopPeriod, bool iqInverted, uint32_t timeout ) +{ + SetModem( modem ); + + SetRfTxPower( power ); + + switch( modem ) + { + case MODEM_FSK: + { + this->settings.Fsk.Power = power; + this->settings.Fsk.Fdev = fdev; + this->settings.Fsk.Bandwidth = bandwidth; + this->settings.Fsk.Datarate = datarate; + this->settings.Fsk.PreambleLen = preambleLen; + this->settings.Fsk.FixLen = fixLen; + this->settings.Fsk.CrcOn = crcOn; + this->settings.Fsk.IqInverted = iqInverted; + this->settings.Fsk.TxTimeout = timeout; + + fdev = ( uint16_t )( ( double )fdev / ( double )FREQ_STEP ); + Write( REG_FDEVMSB, ( uint8_t )( fdev >> 8 ) ); + Write( REG_FDEVLSB, ( uint8_t )( fdev & 0xFF ) ); + + datarate = ( uint16_t )( ( double )XTAL_FREQ / ( double )datarate ); + Write( REG_BITRATEMSB, ( uint8_t )( datarate >> 8 ) ); + Write( REG_BITRATELSB, ( uint8_t )( datarate & 0xFF ) ); + + Write( REG_PREAMBLEMSB, ( preambleLen >> 8 ) & 0x00FF ); + Write( REG_PREAMBLELSB, preambleLen & 0xFF ); + + Write( REG_PACKETCONFIG1, + ( Read( REG_PACKETCONFIG1 ) & + RF_PACKETCONFIG1_CRC_MASK & + RF_PACKETCONFIG1_PACKETFORMAT_MASK ) | + ( ( fixLen == 1 ) ? RF_PACKETCONFIG1_PACKETFORMAT_FIXED : RF_PACKETCONFIG1_PACKETFORMAT_VARIABLE ) | + ( crcOn << 4 ) ); + Write( REG_PACKETCONFIG2, ( Read( REG_PACKETCONFIG2 ) | RF_PACKETCONFIG2_DATAMODE_PACKET ) ); + } + break; + case MODEM_LORA: + { + this->settings.LoRa.Power = power; + if( bandwidth > 2 ) + { + // Fatal error: When using LoRa modem only bandwidths 125, 250 and 500 kHz are supported + while( 1 ); + } + bandwidth += 7; + this->settings.LoRa.Bandwidth = bandwidth; + this->settings.LoRa.Datarate = datarate; + this->settings.LoRa.Coderate = coderate; + this->settings.LoRa.PreambleLen = preambleLen; + this->settings.LoRa.FixLen = fixLen; + this->settings.LoRa.FreqHopOn = freqHopOn; + this->settings.LoRa.HopPeriod = hopPeriod; + this->settings.LoRa.CrcOn = crcOn; + this->settings.LoRa.IqInverted = iqInverted; + this->settings.LoRa.TxTimeout = timeout; + + if( datarate > 12 ) + { + datarate = 12; + } + else if( datarate < 6 ) + { + datarate = 6; + } + if( ( ( bandwidth == 7 ) && ( ( datarate == 11 ) || ( datarate == 12 ) ) ) || + ( ( bandwidth == 8 ) && ( datarate == 12 ) ) ) + { + this->settings.LoRa.LowDatarateOptimize = 0x01; + } + else + { + this->settings.LoRa.LowDatarateOptimize = 0x00; + } + + if( this->settings.LoRa.FreqHopOn == true ) + { + Write( REG_LR_PLLHOP, ( Read( REG_LR_PLLHOP ) & RFLR_PLLHOP_FASTHOP_MASK ) | RFLR_PLLHOP_FASTHOP_ON ); + Write( REG_LR_HOPPERIOD, this->settings.LoRa.HopPeriod ); + } + + Write( REG_LR_MODEMCONFIG1, + ( Read( REG_LR_MODEMCONFIG1 ) & + RFLR_MODEMCONFIG1_BW_MASK & + RFLR_MODEMCONFIG1_CODINGRATE_MASK & + RFLR_MODEMCONFIG1_IMPLICITHEADER_MASK ) | + ( bandwidth << 4 ) | ( coderate << 1 ) | + fixLen ); + + Write( REG_LR_MODEMCONFIG2, + ( Read( REG_LR_MODEMCONFIG2 ) & + RFLR_MODEMCONFIG2_SF_MASK & + RFLR_MODEMCONFIG2_RXPAYLOADCRC_MASK ) | + ( datarate << 4 ) | ( crcOn << 2 ) ); + + Write( REG_LR_MODEMCONFIG3, + ( Read( REG_LR_MODEMCONFIG3 ) & + RFLR_MODEMCONFIG3_LOWDATARATEOPTIMIZE_MASK ) | + ( this->settings.LoRa.LowDatarateOptimize << 3 ) ); + + Write( REG_LR_PREAMBLEMSB, ( preambleLen >> 8 ) & 0x00FF ); + Write( REG_LR_PREAMBLELSB, preambleLen & 0xFF ); + + if( datarate == 6 ) + { + Write( REG_LR_DETECTOPTIMIZE, + ( Read( REG_LR_DETECTOPTIMIZE ) & + RFLR_DETECTIONOPTIMIZE_MASK ) | + RFLR_DETECTIONOPTIMIZE_SF6 ); + Write( REG_LR_DETECTIONTHRESHOLD, + RFLR_DETECTIONTHRESH_SF6 ); + } + else + { + Write( REG_LR_DETECTOPTIMIZE, + ( Read( REG_LR_DETECTOPTIMIZE ) & + RFLR_DETECTIONOPTIMIZE_MASK ) | + RFLR_DETECTIONOPTIMIZE_SF7_TO_SF12 ); + Write( REG_LR_DETECTIONTHRESHOLD, + RFLR_DETECTIONTHRESH_SF7_TO_SF12 ); + } + } + break; + } +} + +uint32_t SX1276::TimeOnAir( RadioModems_t modem, uint8_t pktLen ) +{ + uint32_t airTime = 0; + + switch( modem ) + { + case MODEM_FSK: + { + airTime = rint( ( 8 * ( this->settings.Fsk.PreambleLen + + ( ( Read( REG_SYNCCONFIG ) & ~RF_SYNCCONFIG_SYNCSIZE_MASK ) + 1 ) + + ( ( this->settings.Fsk.FixLen == 0x01 ) ? 0.0 : 1.0 ) + + ( ( ( Read( REG_PACKETCONFIG1 ) & ~RF_PACKETCONFIG1_ADDRSFILTERING_MASK ) != 0x00 ) ? 1.0 : 0 ) + + pktLen + + ( ( this->settings.Fsk.CrcOn == 0x01 ) ? 2.0 : 0 ) ) / + this->settings.Fsk.Datarate ) * 1e3 ); + } + break; + case MODEM_LORA: + { + double bw = 0.0; + // REMARK: When using LoRa modem only bandwidths 125, 250 and 500 kHz are supported + switch( this->settings.LoRa.Bandwidth ) + { + //case 0: // 7.8 kHz + // bw = 78e2; + // break; + //case 1: // 10.4 kHz + // bw = 104e2; + // break; + //case 2: // 15.6 kHz + // bw = 156e2; + // break; + //case 3: // 20.8 kHz + // bw = 208e2; + // break; + //case 4: // 31.2 kHz + // bw = 312e2; + // break; + //case 5: // 41.4 kHz + // bw = 414e2; + // break; + //case 6: // 62.5 kHz + // bw = 625e2; + // break; + case 7: // 125 kHz + bw = 125e3; + break; + case 8: // 250 kHz + bw = 250e3; + break; + case 9: // 500 kHz + bw = 500e3; + break; + } + + // Symbol rate : time for one symbol (secs) + double rs = bw / ( 1 << this->settings.LoRa.Datarate ); + double ts = 1 / rs; + // time of preamble + double tPreamble = ( this->settings.LoRa.PreambleLen + 4.25 ) * ts; + // Symbol length of payload and time + double tmp = ceil( ( 8 * pktLen - 4 * this->settings.LoRa.Datarate + + 28 + 16 * this->settings.LoRa.CrcOn - + ( this->settings.LoRa.FixLen ? 20 : 0 ) ) / + ( double )( 4 * ( this->settings.LoRa.Datarate - + ( ( this->settings.LoRa.LowDatarateOptimize > 0 ) ? 2 : 0 ) ) ) ) * + ( this->settings.LoRa.Coderate + 4 ); + double nPayload = 8 + ( ( tmp > 0 ) ? tmp : 0 ); + double tPayload = nPayload * ts; + // Time on air + double tOnAir = tPreamble + tPayload; + // return ms secs + airTime = floor( tOnAir * 1e3 + 0.999 ); + } + break; + } + return airTime; +} + +void SX1276::Send( uint8_t *buffer, uint8_t size ) +{ + uint32_t txTimeout = 0; + + switch( this->settings.Modem ) + { + case MODEM_FSK: + { + this->settings.FskPacketHandler.NbBytes = 0; + this->settings.FskPacketHandler.Size = size; + + if( this->settings.Fsk.FixLen == false ) + { + WriteFifo( ( uint8_t* )&size, 1 ); + } + else + { + Write( REG_PAYLOADLENGTH, size ); + } + + if( ( size > 0 ) && ( size <= 64 ) ) + { + this->settings.FskPacketHandler.ChunkSize = size; + } + else + { + memcpy( rxtxBuffer, buffer, size ); + this->settings.FskPacketHandler.ChunkSize = 32; + } + + // Write payload buffer + WriteFifo( buffer, this->settings.FskPacketHandler.ChunkSize ); + this->settings.FskPacketHandler.NbBytes += this->settings.FskPacketHandler.ChunkSize; + txTimeout = this->settings.Fsk.TxTimeout; + } + break; + case MODEM_LORA: + { + if( this->settings.LoRa.IqInverted == true ) + { + Write( REG_LR_INVERTIQ, ( ( Read( REG_LR_INVERTIQ ) & RFLR_INVERTIQ_TX_MASK & RFLR_INVERTIQ_RX_MASK ) | RFLR_INVERTIQ_RX_OFF | RFLR_INVERTIQ_TX_ON ) ); + Write( REG_LR_INVERTIQ2, RFLR_INVERTIQ2_ON ); + } + else + { + Write( REG_LR_INVERTIQ, ( ( Read( REG_LR_INVERTIQ ) & RFLR_INVERTIQ_TX_MASK & RFLR_INVERTIQ_RX_MASK ) | RFLR_INVERTIQ_RX_OFF | RFLR_INVERTIQ_TX_OFF ) ); + Write( REG_LR_INVERTIQ2, RFLR_INVERTIQ2_OFF ); + } + + this->settings.LoRaPacketHandler.Size = size; + + // Initializes the payload size + Write( REG_LR_PAYLOADLENGTH, size ); + + // Full buffer used for Tx + Write( REG_LR_FIFOTXBASEADDR, 0 ); + Write( REG_LR_FIFOADDRPTR, 0 ); + + // FIFO operations can not take place in Sleep mode + if( ( Read( REG_OPMODE ) & ~RF_OPMODE_MASK ) == RF_OPMODE_SLEEP ) + { + Standby( ); + wait_ms( 1 ); + } + // Write payload buffer + WriteFifo( buffer, size ); + txTimeout = this->settings.LoRa.TxTimeout; + } + break; + } + + Tx( txTimeout ); +} + +void SX1276::Sleep( void ) +{ + txTimeoutTimer.detach( ); + rxTimeoutTimer.detach( ); + + SetOpMode( RF_OPMODE_SLEEP ); + this->settings.State = RF_IDLE; +} + +void SX1276::Standby( void ) +{ + txTimeoutTimer.detach( ); + rxTimeoutTimer.detach( ); + + SetOpMode( RF_OPMODE_STANDBY ); + this->settings.State = RF_IDLE; +} + +void SX1276::Rx( uint32_t timeout ) +{ + bool rxContinuous = false; + + switch( this->settings.Modem ) + { + case MODEM_FSK: + { + rxContinuous = this->settings.Fsk.RxContinuous; + + // DIO0=PayloadReady + // DIO1=FifoLevel + // DIO2=SyncAddr + // DIO3=FifoEmpty + // DIO4=Preamble + // DIO5=ModeReady + Write( REG_DIOMAPPING1, ( Read( REG_DIOMAPPING1 ) & RF_DIOMAPPING1_DIO0_MASK & + RF_DIOMAPPING1_DIO1_MASK & + RF_DIOMAPPING1_DIO2_MASK ) | + RF_DIOMAPPING1_DIO0_00 | + RF_DIOMAPPING1_DIO1_00 | + RF_DIOMAPPING1_DIO2_11 ); + + Write( REG_DIOMAPPING2, ( Read( REG_DIOMAPPING2 ) & RF_DIOMAPPING2_DIO4_MASK & + RF_DIOMAPPING2_MAP_MASK ) | + RF_DIOMAPPING2_DIO4_11 | + RF_DIOMAPPING2_MAP_PREAMBLEDETECT ); + + this->settings.FskPacketHandler.FifoThresh = Read( REG_FIFOTHRESH ) & 0x3F; + + Write( REG_RXCONFIG, RF_RXCONFIG_AFCAUTO_ON | RF_RXCONFIG_AGCAUTO_ON | RF_RXCONFIG_RXTRIGER_PREAMBLEDETECT ); + + this->settings.FskPacketHandler.PreambleDetected = false; + this->settings.FskPacketHandler.SyncWordDetected = false; + this->settings.FskPacketHandler.NbBytes = 0; + this->settings.FskPacketHandler.Size = 0; + } + break; + case MODEM_LORA: + { + if( this->settings.LoRa.IqInverted == true ) + { + Write( REG_LR_INVERTIQ, ( ( Read( REG_LR_INVERTIQ ) & RFLR_INVERTIQ_TX_MASK & RFLR_INVERTIQ_RX_MASK ) | RFLR_INVERTIQ_RX_ON | RFLR_INVERTIQ_TX_OFF ) ); + Write( REG_LR_INVERTIQ2, RFLR_INVERTIQ2_ON ); + } + else + { + Write( REG_LR_INVERTIQ, ( ( Read( REG_LR_INVERTIQ ) & RFLR_INVERTIQ_TX_MASK & RFLR_INVERTIQ_RX_MASK ) | RFLR_INVERTIQ_RX_OFF | RFLR_INVERTIQ_TX_OFF ) ); + Write( REG_LR_INVERTIQ2, RFLR_INVERTIQ2_OFF ); + } + + // ERRATA 2.3 - Receiver Spurious Reception of a LoRa Signal + if( this->settings.LoRa.Bandwidth < 9 ) + { + Write( REG_LR_DETECTOPTIMIZE, Read( REG_LR_DETECTOPTIMIZE ) & 0x7F ); + Write( REG_LR_TEST30, 0x00 ); + switch( this->settings.LoRa.Bandwidth ) + { + case 0: // 7.8 kHz + Write( REG_LR_TEST2F, 0x48 ); + SetChannel(this->settings.Channel + 7.81e3 ); + break; + case 1: // 10.4 kHz + Write( REG_LR_TEST2F, 0x44 ); + SetChannel(this->settings.Channel + 10.42e3 ); + break; + case 2: // 15.6 kHz + Write( REG_LR_TEST2F, 0x44 ); + SetChannel(this->settings.Channel + 15.62e3 ); + break; + case 3: // 20.8 kHz + Write( REG_LR_TEST2F, 0x44 ); + SetChannel(this->settings.Channel + 20.83e3 ); + break; + case 4: // 31.2 kHz + Write( REG_LR_TEST2F, 0x44 ); + SetChannel(this->settings.Channel + 31.25e3 ); + break; + case 5: // 41.4 kHz + Write( REG_LR_TEST2F, 0x44 ); + SetChannel(this->settings.Channel + 41.67e3 ); + break; + case 6: // 62.5 kHz + Write( REG_LR_TEST2F, 0x40 ); + break; + case 7: // 125 kHz + Write( REG_LR_TEST2F, 0x40 ); + break; + case 8: // 250 kHz + Write( REG_LR_TEST2F, 0x40 ); + break; + } + } + else + { + Write( REG_LR_DETECTOPTIMIZE, Read( REG_LR_DETECTOPTIMIZE ) | 0x80 ); + } + + rxContinuous = this->settings.LoRa.RxContinuous; + + if( this->settings.LoRa.FreqHopOn == true ) + { + Write( REG_LR_IRQFLAGSMASK, //RFLR_IRQFLAGS_RXTIMEOUT | + //RFLR_IRQFLAGS_RXDONE | + //RFLR_IRQFLAGS_PAYLOADCRCERROR | + RFLR_IRQFLAGS_VALIDHEADER | + RFLR_IRQFLAGS_TXDONE | + RFLR_IRQFLAGS_CADDONE | + //RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL | + RFLR_IRQFLAGS_CADDETECTED ); + + // DIO0=RxDone, DIO2=FhssChangeChannel + Write( REG_DIOMAPPING1, ( Read( REG_DIOMAPPING1 ) & RFLR_DIOMAPPING1_DIO0_MASK & RFLR_DIOMAPPING1_DIO2_MASK ) | RFLR_DIOMAPPING1_DIO0_00 | RFLR_DIOMAPPING1_DIO2_00 ); + } + else + { + Write( REG_LR_IRQFLAGSMASK, //RFLR_IRQFLAGS_RXTIMEOUT | + //RFLR_IRQFLAGS_RXDONE | + //RFLR_IRQFLAGS_PAYLOADCRCERROR | + RFLR_IRQFLAGS_VALIDHEADER | + RFLR_IRQFLAGS_TXDONE | + RFLR_IRQFLAGS_CADDONE | + RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL | + RFLR_IRQFLAGS_CADDETECTED ); + + // DIO0=RxDone + Write( REG_DIOMAPPING1, ( Read( REG_DIOMAPPING1 ) & RFLR_DIOMAPPING1_DIO0_MASK ) | RFLR_DIOMAPPING1_DIO0_00 ); + } + Write( REG_LR_FIFORXBASEADDR, 0 ); + Write( REG_LR_FIFOADDRPTR, 0 ); + } + break; + } + + memset( rxtxBuffer, 0, ( size_t )RX_BUFFER_SIZE ); + + this->settings.State = RF_RX_RUNNING; + if( timeout != 0 ) + { + rxTimeoutTimer.attach_us( mbed::callback( this, &SX1276::OnTimeoutIrq ), timeout * 1e3 ); + } + + if( this->settings.Modem == MODEM_FSK ) + { + SetOpMode( RF_OPMODE_RECEIVER ); + + if( rxContinuous == false ) + { + rxTimeoutSyncWord.attach_us( mbed::callback( this, &SX1276::OnTimeoutIrq ), + this->settings.Fsk.RxSingleTimeout * 1e3 ); + } + } + else + { + if( rxContinuous == true ) + { + SetOpMode( RFLR_OPMODE_RECEIVER ); + } + else + { + SetOpMode( RFLR_OPMODE_RECEIVER_SINGLE ); + } + } +} + +void SX1276::Tx( uint32_t timeout ) +{ + + switch( this->settings.Modem ) + { + case MODEM_FSK: + { + // DIO0=PacketSent + // DIO1=FifoEmpty + // DIO2=FifoFull + // DIO3=FifoEmpty + // DIO4=LowBat + // DIO5=ModeReady + Write( REG_DIOMAPPING1, ( Read( REG_DIOMAPPING1 ) & RF_DIOMAPPING1_DIO0_MASK & + RF_DIOMAPPING1_DIO1_MASK & + RF_DIOMAPPING1_DIO2_MASK ) | + RF_DIOMAPPING1_DIO1_01 ); + + Write( REG_DIOMAPPING2, ( Read( REG_DIOMAPPING2 ) & RF_DIOMAPPING2_DIO4_MASK & + RF_DIOMAPPING2_MAP_MASK ) ); + this->settings.FskPacketHandler.FifoThresh = Read( REG_FIFOTHRESH ) & 0x3F; + } + break; + case MODEM_LORA: + { + if( this->settings.LoRa.FreqHopOn == true ) + { + Write( REG_LR_IRQFLAGSMASK, RFLR_IRQFLAGS_RXTIMEOUT | + RFLR_IRQFLAGS_RXDONE | + RFLR_IRQFLAGS_PAYLOADCRCERROR | + RFLR_IRQFLAGS_VALIDHEADER | + //RFLR_IRQFLAGS_TXDONE | + RFLR_IRQFLAGS_CADDONE | + //RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL | + RFLR_IRQFLAGS_CADDETECTED ); + + // DIO0=TxDone, DIO2=FhssChangeChannel + Write( REG_DIOMAPPING1, ( Read( REG_DIOMAPPING1 ) & RFLR_DIOMAPPING1_DIO0_MASK & RFLR_DIOMAPPING1_DIO2_MASK ) | RFLR_DIOMAPPING1_DIO0_01 | RFLR_DIOMAPPING1_DIO2_00 ); + } + else + { + Write( REG_LR_IRQFLAGSMASK, RFLR_IRQFLAGS_RXTIMEOUT | + RFLR_IRQFLAGS_RXDONE | + RFLR_IRQFLAGS_PAYLOADCRCERROR | + RFLR_IRQFLAGS_VALIDHEADER | + //RFLR_IRQFLAGS_TXDONE | + RFLR_IRQFLAGS_CADDONE | + RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL | + RFLR_IRQFLAGS_CADDETECTED ); + + // DIO0=TxDone + Write( REG_DIOMAPPING1, ( Read( REG_DIOMAPPING1 ) & RFLR_DIOMAPPING1_DIO0_MASK ) | RFLR_DIOMAPPING1_DIO0_01 ); + } + } + break; + } + + this->settings.State = RF_TX_RUNNING; + txTimeoutTimer.attach_us( mbed::callback( this, &SX1276::OnTimeoutIrq ), timeout * 1e3 ); + SetOpMode( RF_OPMODE_TRANSMITTER ); +} + +void SX1276::StartCad( void ) +{ + switch( this->settings.Modem ) + { + case MODEM_FSK: + { + + } + break; + case MODEM_LORA: + { + Write( REG_LR_IRQFLAGSMASK, RFLR_IRQFLAGS_RXTIMEOUT | + RFLR_IRQFLAGS_RXDONE | + RFLR_IRQFLAGS_PAYLOADCRCERROR | + RFLR_IRQFLAGS_VALIDHEADER | + RFLR_IRQFLAGS_TXDONE | + //RFLR_IRQFLAGS_CADDONE | + RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL // | + //RFLR_IRQFLAGS_CADDETECTED + ); + + // DIO3=CADDone + Write( REG_DIOMAPPING1, ( Read( REG_DIOMAPPING1 ) & RFLR_DIOMAPPING1_DIO3_MASK ) | RFLR_DIOMAPPING1_DIO3_00 ); + + this->settings.State = RF_CAD; + SetOpMode( RFLR_OPMODE_CAD ); + } + break; + default: + break; + } +} + +void SX1276::SetTxContinuousWave( uint32_t freq, int8_t power, uint16_t time ) +{ + uint32_t timeout = ( uint32_t )( time * 1e6 ); + + SetChannel( freq ); + + SetTxConfig( MODEM_FSK, power, 0, 0, 4800, 0, 5, false, false, 0, 0, 0, timeout ); + + Write( REG_PACKETCONFIG2, ( Read( REG_PACKETCONFIG2 ) & RF_PACKETCONFIG2_DATAMODE_MASK ) ); + // Disable radio interrupts + Write( REG_DIOMAPPING1, RF_DIOMAPPING1_DIO0_11 | RF_DIOMAPPING1_DIO1_11 ); + Write( REG_DIOMAPPING2, RF_DIOMAPPING2_DIO4_10 | RF_DIOMAPPING2_DIO5_10 ); + + this->settings.State = RF_TX_RUNNING; + txTimeoutTimer.attach_us( mbed::callback( this, &SX1276::OnTimeoutIrq ), timeout ); + SetOpMode( RF_OPMODE_TRANSMITTER ); +} + +int16_t SX1276::GetRssi( RadioModems_t modem ) +{ + int16_t rssi = 0; + + switch( modem ) + { + case MODEM_FSK: + rssi = -( Read( REG_RSSIVALUE ) >> 1 ); + break; + case MODEM_LORA: + if( this->settings.Channel > RF_MID_BAND_THRESH ) + { + rssi = RSSI_OFFSET_HF + Read( REG_LR_RSSIVALUE ); + } + else + { + rssi = RSSI_OFFSET_LF + Read( REG_LR_RSSIVALUE ); + } + break; + default: + rssi = -1; + break; + } + return rssi; +} + +void SX1276::SetOpMode( uint8_t opMode ) +{ + if( opMode == RF_OPMODE_SLEEP ) + { + SetAntSwLowPower( true ); + } + else + { + SetAntSwLowPower( false ); + SetAntSw( opMode ); + } + Write( REG_OPMODE, ( Read( REG_OPMODE ) & RF_OPMODE_MASK ) | opMode ); +} + +void SX1276::SetModem( RadioModems_t modem ) +{ + if( ( Read( REG_OPMODE ) & RFLR_OPMODE_LONGRANGEMODE_ON ) != 0 ) + { + this->settings.Modem = MODEM_LORA; + } + else + { + this->settings.Modem = MODEM_FSK; + } + + if( this->settings.Modem == modem ) + { + return; + } + + this->settings.Modem = modem; + switch( this->settings.Modem ) + { + default: + case MODEM_FSK: + Sleep( ); + Write( REG_OPMODE, ( Read( REG_OPMODE ) & RFLR_OPMODE_LONGRANGEMODE_MASK ) | RFLR_OPMODE_LONGRANGEMODE_OFF ); + + Write( REG_DIOMAPPING1, 0x00 ); + Write( REG_DIOMAPPING2, 0x30 ); // DIO5=ModeReady + break; + case MODEM_LORA: + Sleep( ); + Write( REG_OPMODE, ( Read( REG_OPMODE ) & RFLR_OPMODE_LONGRANGEMODE_MASK ) | RFLR_OPMODE_LONGRANGEMODE_ON ); + + Write( REG_DIOMAPPING1, 0x00 ); + Write( REG_DIOMAPPING2, 0x00 ); + break; + } +} + +void SX1276::SetMaxPayloadLength( RadioModems_t modem, uint8_t max ) +{ + this->SetModem( modem ); + + switch( modem ) + { + case MODEM_FSK: + if( this->settings.Fsk.FixLen == false ) + { + this->Write( REG_PAYLOADLENGTH, max ); + } + break; + case MODEM_LORA: + this->Write( REG_LR_PAYLOADMAXLENGTH, max ); + break; + } +} + +void SX1276::SetPublicNetwork( bool enable ) +{ + SetModem( MODEM_LORA ); + this->settings.LoRa.PublicNetwork = enable; + if( enable == true ) + { + // Change LoRa modem SyncWord + Write( REG_LR_SYNCWORD, LORA_MAC_PUBLIC_SYNCWORD ); + } + else + { + // Change LoRa modem SyncWord + Write( REG_LR_SYNCWORD, LORA_MAC_PRIVATE_SYNCWORD ); + } +} + +void SX1276::OnTimeoutIrq( void ) +{ + switch( this->settings.State ) + { + case RF_RX_RUNNING: + if( this->settings.Modem == MODEM_FSK ) + { + this->settings.FskPacketHandler.PreambleDetected = false; + this->settings.FskPacketHandler.SyncWordDetected = false; + this->settings.FskPacketHandler.NbBytes = 0; + this->settings.FskPacketHandler.Size = 0; + + // Clear Irqs + Write( REG_IRQFLAGS1, RF_IRQFLAGS1_RSSI | + RF_IRQFLAGS1_PREAMBLEDETECT | + RF_IRQFLAGS1_SYNCADDRESSMATCH ); + Write( REG_IRQFLAGS2, RF_IRQFLAGS2_FIFOOVERRUN ); + + if( this->settings.Fsk.RxContinuous == true ) + { + // Continuous mode restart Rx chain + Write( REG_RXCONFIG, Read( REG_RXCONFIG ) | RF_RXCONFIG_RESTARTRXWITHOUTPLLLOCK ); + rxTimeoutSyncWord.attach_us( mbed::callback( this, &SX1276::OnTimeoutIrq ), + this->settings.Fsk.RxSingleTimeout * 1e3 ); + } + else + { + this->settings.State = RF_IDLE; + rxTimeoutSyncWord.detach( ); + } + } + if( ( this->RadioEvents != NULL ) && ( this->RadioEvents->RxTimeout != NULL ) ) + { + this->RadioEvents->RxTimeout( ); + } + break; + case RF_TX_RUNNING: + // Tx timeout shouldn't happen. + // But it has been observed that when it happens it is a result of a corrupted SPI transfer + // it depends on the platform design. + // + // The workaround is to put the radio in a known state. Thus, we re-initialize it. + + // BEGIN WORKAROUND + + // Reset the radio + Reset( ); + + // Calibrate Rx chain + RxChainCalibration( ); + + // Initialize radio default values + SetOpMode( RF_OPMODE_SLEEP ); + + RadioRegistersInit( ); + + SetModem( MODEM_FSK ); + + // Restore previous network type setting. + SetPublicNetwork( this->settings.LoRa.PublicNetwork ); + // END WORKAROUND + + this->settings.State = RF_IDLE; + if( ( this->RadioEvents != NULL ) && ( this->RadioEvents->TxTimeout != NULL ) ) + { + this->RadioEvents->TxTimeout( ); + } + break; + default: + break; + } +} + +void SX1276::OnDio0Irq( void ) +{ + volatile uint8_t irqFlags = 0; + + switch( this->settings.State ) + { + case RF_RX_RUNNING: + //TimerStop( &RxTimeoutTimer ); + // RxDone interrupt + switch( this->settings.Modem ) + { + case MODEM_FSK: + if( this->settings.Fsk.CrcOn == true ) + { + irqFlags = Read( REG_IRQFLAGS2 ); + if( ( irqFlags & RF_IRQFLAGS2_CRCOK ) != RF_IRQFLAGS2_CRCOK ) + { + // Clear Irqs + Write( REG_IRQFLAGS1, RF_IRQFLAGS1_RSSI | + RF_IRQFLAGS1_PREAMBLEDETECT | + RF_IRQFLAGS1_SYNCADDRESSMATCH ); + Write( REG_IRQFLAGS2, RF_IRQFLAGS2_FIFOOVERRUN ); + + rxTimeoutTimer.detach( ); + + if( this->settings.Fsk.RxContinuous == false ) + { + rxTimeoutSyncWord.detach( ); + this->settings.State = RF_IDLE; + } + else + { + // Continuous mode restart Rx chain + Write( REG_RXCONFIG, Read( REG_RXCONFIG ) | RF_RXCONFIG_RESTARTRXWITHOUTPLLLOCK ); + rxTimeoutSyncWord.attach_us( mbed::callback( this, &SX1276::OnTimeoutIrq ), + this->settings.Fsk.RxSingleTimeout * 1e3 ); + } + + if( ( this->RadioEvents != NULL ) && ( this->RadioEvents->RxError != NULL ) ) + { + this->RadioEvents->RxError( ); + } + this->settings.FskPacketHandler.PreambleDetected = false; + this->settings.FskPacketHandler.SyncWordDetected = false; + this->settings.FskPacketHandler.NbBytes = 0; + this->settings.FskPacketHandler.Size = 0; + break; + } + } + + // Read received packet size + if( ( this->settings.FskPacketHandler.Size == 0 ) && ( this->settings.FskPacketHandler.NbBytes == 0 ) ) + { + if( this->settings.Fsk.FixLen == false ) + { + ReadFifo( ( uint8_t* )&this->settings.FskPacketHandler.Size, 1 ); + } + else + { + this->settings.FskPacketHandler.Size = Read( REG_PAYLOADLENGTH ); + } + ReadFifo( rxtxBuffer + this->settings.FskPacketHandler.NbBytes, this->settings.FskPacketHandler.Size - this->settings.FskPacketHandler.NbBytes ); + this->settings.FskPacketHandler.NbBytes += ( this->settings.FskPacketHandler.Size - this->settings.FskPacketHandler.NbBytes ); + } + else + { + ReadFifo( rxtxBuffer + this->settings.FskPacketHandler.NbBytes, this->settings.FskPacketHandler.Size - this->settings.FskPacketHandler.NbBytes ); + this->settings.FskPacketHandler.NbBytes += ( this->settings.FskPacketHandler.Size - this->settings.FskPacketHandler.NbBytes ); + } + + rxTimeoutTimer.detach( ); + + if( this->settings.Fsk.RxContinuous == false ) + { + this->settings.State = RF_IDLE; + rxTimeoutSyncWord.detach( ); + } + else + { + // Continuous mode restart Rx chain + Write( REG_RXCONFIG, Read( REG_RXCONFIG ) | RF_RXCONFIG_RESTARTRXWITHOUTPLLLOCK ); + rxTimeoutSyncWord.attach_us( mbed::callback( this, &SX1276::OnTimeoutIrq ), + this->settings.Fsk.RxSingleTimeout * 1e3 ); + } + + if( ( this->RadioEvents != NULL ) && ( this->RadioEvents->RxDone != NULL ) ) + { + this->RadioEvents->RxDone( rxtxBuffer, this->settings.FskPacketHandler.Size, this->settings.FskPacketHandler.RssiValue, 0 ); + } + this->settings.FskPacketHandler.PreambleDetected = false; + this->settings.FskPacketHandler.SyncWordDetected = false; + this->settings.FskPacketHandler.NbBytes = 0; + this->settings.FskPacketHandler.Size = 0; + break; + case MODEM_LORA: + { + int8_t snr = 0; + + // Clear Irq + Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_RXDONE ); + + irqFlags = Read( REG_LR_IRQFLAGS ); + if( ( irqFlags & RFLR_IRQFLAGS_PAYLOADCRCERROR_MASK ) == RFLR_IRQFLAGS_PAYLOADCRCERROR ) + { + // Clear Irq + Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_PAYLOADCRCERROR ); + + if( this->settings.LoRa.RxContinuous == false ) + { + this->settings.State = RF_IDLE; + } + rxTimeoutTimer.detach( ); + + if( ( this->RadioEvents != NULL ) && ( this->RadioEvents->RxError != NULL ) ) + { + this->RadioEvents->RxError( ); + } + break; + } + + this->settings.LoRaPacketHandler.SnrValue = Read( REG_LR_PKTSNRVALUE ); + if( this->settings.LoRaPacketHandler.SnrValue & 0x80 ) // The SNR sign bit is 1 + { + // Invert and divide by 4 + snr = ( ( ~this->settings.LoRaPacketHandler.SnrValue + 1 ) & 0xFF ) >> 2; + snr = -snr; + } + else + { + // Divide by 4 + snr = ( this->settings.LoRaPacketHandler.SnrValue & 0xFF ) >> 2; + } + + int16_t rssi = Read( REG_LR_PKTRSSIVALUE ); + if( snr < 0 ) + { + if( this->settings.Channel > RF_MID_BAND_THRESH ) + { + this->settings.LoRaPacketHandler.RssiValue = RSSI_OFFSET_HF + rssi + ( rssi >> 4 ) + + snr; + } + else + { + this->settings.LoRaPacketHandler.RssiValue = RSSI_OFFSET_LF + rssi + ( rssi >> 4 ) + + snr; + } + } + else + { + if( this->settings.Channel > RF_MID_BAND_THRESH ) + { + this->settings.LoRaPacketHandler.RssiValue = RSSI_OFFSET_HF + rssi + ( rssi >> 4 ); + } + else + { + this->settings.LoRaPacketHandler.RssiValue = RSSI_OFFSET_LF + rssi + ( rssi >> 4 ); + } + } + + this->settings.LoRaPacketHandler.Size = Read( REG_LR_RXNBBYTES ); + ReadFifo( rxtxBuffer, this->settings.LoRaPacketHandler.Size ); + + if( this->settings.LoRa.RxContinuous == false ) + { + this->settings.State = RF_IDLE; + } + rxTimeoutTimer.detach( ); + + if( ( this->RadioEvents != NULL ) && ( this->RadioEvents->RxDone != NULL ) ) + { + this->RadioEvents->RxDone( rxtxBuffer, this->settings.LoRaPacketHandler.Size, this->settings.LoRaPacketHandler.RssiValue, this->settings.LoRaPacketHandler.SnrValue ); + } + } + break; + default: + break; + } + break; + case RF_TX_RUNNING: + txTimeoutTimer.detach( ); + // TxDone interrupt + switch( this->settings.Modem ) + { + case MODEM_LORA: + // Clear Irq + Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_TXDONE ); + // Intentional fall through + case MODEM_FSK: + default: + this->settings.State = RF_IDLE; + if( ( this->RadioEvents != NULL ) && ( this->RadioEvents->TxDone != NULL ) ) + { + this->RadioEvents->TxDone( ); + } + break; + } + break; + default: + break; + } +} + +void SX1276::OnDio1Irq( void ) +{ + switch( this->settings.State ) + { + case RF_RX_RUNNING: + switch( this->settings.Modem ) + { + case MODEM_FSK: + // FifoLevel interrupt + // Read received packet size + if( ( this->settings.FskPacketHandler.Size == 0 ) && ( this->settings.FskPacketHandler.NbBytes == 0 ) ) + { + if( this->settings.Fsk.FixLen == false ) + { + ReadFifo( ( uint8_t* )&this->settings.FskPacketHandler.Size, 1 ); + } + else + { + this->settings.FskPacketHandler.Size = Read( REG_PAYLOADLENGTH ); + } + } + + if( ( this->settings.FskPacketHandler.Size - this->settings.FskPacketHandler.NbBytes ) > this->settings.FskPacketHandler.FifoThresh ) + { + ReadFifo( ( rxtxBuffer + this->settings.FskPacketHandler.NbBytes ), this->settings.FskPacketHandler.FifoThresh ); + this->settings.FskPacketHandler.NbBytes += this->settings.FskPacketHandler.FifoThresh; + } + else + { + ReadFifo( ( rxtxBuffer + this->settings.FskPacketHandler.NbBytes ), this->settings.FskPacketHandler.Size - this->settings.FskPacketHandler.NbBytes ); + this->settings.FskPacketHandler.NbBytes += ( this->settings.FskPacketHandler.Size - this->settings.FskPacketHandler.NbBytes ); + } + break; + case MODEM_LORA: + // Sync time out + rxTimeoutTimer.detach( ); + // Clear Irq + Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_RXTIMEOUT ); + + this->settings.State = RF_IDLE; + if( ( this->RadioEvents != NULL ) && ( this->RadioEvents->RxTimeout != NULL ) ) + { + this->RadioEvents->RxTimeout( ); + } + break; + default: + break; + } + break; + case RF_TX_RUNNING: + switch( this->settings.Modem ) + { + case MODEM_FSK: + // FifoEmpty interrupt + if( ( this->settings.FskPacketHandler.Size - this->settings.FskPacketHandler.NbBytes ) > this->settings.FskPacketHandler.ChunkSize ) + { + WriteFifo( ( rxtxBuffer + this->settings.FskPacketHandler.NbBytes ), this->settings.FskPacketHandler.ChunkSize ); + this->settings.FskPacketHandler.NbBytes += this->settings.FskPacketHandler.ChunkSize; + } + else + { + // Write the last chunk of data + WriteFifo( rxtxBuffer + this->settings.FskPacketHandler.NbBytes, this->settings.FskPacketHandler.Size - this->settings.FskPacketHandler.NbBytes ); + this->settings.FskPacketHandler.NbBytes += this->settings.FskPacketHandler.Size - this->settings.FskPacketHandler.NbBytes; + } + break; + case MODEM_LORA: + break; + default: + break; + } + break; + default: + break; + } +} + +void SX1276::OnDio2Irq( void ) +{ + switch( this->settings.State ) + { + case RF_RX_RUNNING: + switch( this->settings.Modem ) + { + case MODEM_FSK: + // Checks if DIO4 is connected. If it is not PreambleDtected is set to true. + if( this->dioIrq[4] == NULL ) + { + this->settings.FskPacketHandler.PreambleDetected = true; + } + + if( ( this->settings.FskPacketHandler.PreambleDetected == true ) && ( this->settings.FskPacketHandler.SyncWordDetected == false ) ) + { + rxTimeoutSyncWord.detach( ); + + this->settings.FskPacketHandler.SyncWordDetected = true; + + this->settings.FskPacketHandler.RssiValue = -( Read( REG_RSSIVALUE ) >> 1 ); + + this->settings.FskPacketHandler.AfcValue = ( int32_t )( double )( ( ( uint16_t )Read( REG_AFCMSB ) << 8 ) | + ( uint16_t )Read( REG_AFCLSB ) ) * + ( double )FREQ_STEP; + this->settings.FskPacketHandler.RxGain = ( Read( REG_LNA ) >> 5 ) & 0x07; + } + break; + case MODEM_LORA: + if( this->settings.LoRa.FreqHopOn == true ) + { + // Clear Irq + Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL ); + + if( ( this->RadioEvents != NULL ) && ( this->RadioEvents->FhssChangeChannel != NULL ) ) + { + this->RadioEvents->FhssChangeChannel( ( Read( REG_LR_HOPCHANNEL ) & RFLR_HOPCHANNEL_CHANNEL_MASK ) ); + } + } + break; + default: + break; + } + break; + case RF_TX_RUNNING: + switch( this->settings.Modem ) + { + case MODEM_FSK: + break; + case MODEM_LORA: + if( this->settings.LoRa.FreqHopOn == true ) + { + // Clear Irq + Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_FHSSCHANGEDCHANNEL ); + + if( ( this->RadioEvents != NULL ) && ( this->RadioEvents->FhssChangeChannel != NULL ) ) + { + this->RadioEvents->FhssChangeChannel( ( Read( REG_LR_HOPCHANNEL ) & RFLR_HOPCHANNEL_CHANNEL_MASK ) ); + } + } + break; + default: + break; + } + break; + default: + break; + } +} + +void SX1276::OnDio3Irq( void ) +{ + switch( this->settings.Modem ) + { + case MODEM_FSK: + break; + case MODEM_LORA: + if( ( Read( REG_LR_IRQFLAGS ) & RFLR_IRQFLAGS_CADDETECTED ) == RFLR_IRQFLAGS_CADDETECTED ) + { + // Clear Irq + Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_CADDETECTED | RFLR_IRQFLAGS_CADDONE ); + if( ( this->RadioEvents != NULL ) && ( this->RadioEvents->CadDone != NULL ) ) + { + this->RadioEvents->CadDone( true ); + } + } + else + { + // Clear Irq + Write( REG_LR_IRQFLAGS, RFLR_IRQFLAGS_CADDONE ); + if( ( this->RadioEvents != NULL ) && ( this->RadioEvents->CadDone != NULL ) ) + { + this->RadioEvents->CadDone( false ); + } + } + break; + default: + break; + } +} + +void SX1276::OnDio4Irq( void ) +{ + switch( this->settings.Modem ) + { + case MODEM_FSK: + { + if( this->settings.FskPacketHandler.PreambleDetected == false ) + { + this->settings.FskPacketHandler.PreambleDetected = true; + } + } + break; + case MODEM_LORA: + break; + default: + break; + } +} + +void SX1276::OnDio5Irq( void ) +{ + switch( this->settings.Modem ) + { + case MODEM_FSK: + break; + case MODEM_LORA: + break; + default: + break; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/radio/SX1276Lib/sx1276/sx1276.h Wed Sep 04 15:42:07 2019 +0000 @@ -0,0 +1,506 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C) 2014 Semtech + +Description: Actual implementation of a SX1276 radio, inherits Radio + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainers: Miguel Luis, Gregory Cristian and Nicolas Huguenin +*/ +#ifndef __SX1276_H__ +#define __SX1276_H__ + +#include "radio.h" +#include "./registers/sx1276Regs-Fsk.h" +#include "./registers/sx1276Regs-LoRa.h" +#include "./typedefs/typedefs.h" + +/*! + * Radio wake-up time from sleep + */ +#define RADIO_WAKEUP_TIME 1 // [ms] + +/*! + * Sync word for Private LoRa networks + */ +#define LORA_MAC_PRIVATE_SYNCWORD 0x12 + +/*! + * Sync word for Public LoRa networks + */ +#define LORA_MAC_PUBLIC_SYNCWORD 0x34 + + +/*! + * SX1276 definitions + */ +#define XTAL_FREQ 32000000 +#define FREQ_STEP 61.03515625 + +#define RX_BUFFER_SIZE 256 + +/*! + * Constant values need to compute the RSSI value + */ +#define RSSI_OFFSET_LF -164.0 +#define RSSI_OFFSET_HF -157.0 + +#define RF_MID_BAND_THRESH 525000000 + +/*! + * Actual implementation of a SX1276 radio, inherits Radio + */ +class SX1276 : public Radio +{ +protected: + /*! + * SPI Interface + */ + SPI spi; // mosi, miso, sclk + DigitalOut nss; + + /*! + * SX1276 Reset pin + */ + DigitalInOut reset; + + /*! + * SX1276 DIO pins + */ + InterruptIn dio0; + InterruptIn dio1; + InterruptIn dio2; + InterruptIn dio3; + InterruptIn dio4; + DigitalIn dio5; + + bool isRadioActive; + + uint8_t boardConnected; //1 = SX1276MB1LAS; 0 = SX1276MB1MAS + + uint8_t *rxtxBuffer; + + /*! + * Hardware DIO IRQ functions + */ + DioIrqHandler *dioIrq; + + /*! + * Tx and Rx timers + */ + Timeout txTimeoutTimer; + Timeout rxTimeoutTimer; + Timeout rxTimeoutSyncWord; + + RadioSettings_t settings; + + static const FskBandwidth_t FskBandwidths[]; +protected: + + /*! + * Performs the Rx chain calibration for LF and HF bands + * \remark Must be called just after the reset so all registers are at their + * default values + */ + void RxChainCalibration( void ); + +public: + SX1276( RadioEvents_t *events, + PinName mosi, PinName miso, PinName sclk, PinName nss, PinName reset, + PinName dio0, PinName dio1, PinName dio2, PinName dio3, PinName dio4, PinName dio5 ); + SX1276( RadioEvents_t *events ); + virtual ~SX1276( ); + + //------------------------------------------------------------------------- + // Redefined Radio functions + //------------------------------------------------------------------------- + /*! + * @brief Initializes the radio + * + * @param [IN] events Structure containing the driver callback functions + */ + virtual void Init( RadioEvents_t *events ); + /*! + * Return current radio status + * + * @param status Radio status. [RF_IDLE, RX_RUNNING, TX_RUNNING] + */ + virtual RadioState GetStatus( void ); + /*! + * @brief Configures the SX1276 with the given modem + * + * @param [IN] modem Modem to be used [0: FSK, 1: LoRa] + */ + virtual void SetModem( RadioModems_t modem ); + /*! + * @brief Sets the channel frequency + * + * @param [IN] freq Channel RF frequency + */ + virtual void SetChannel( uint32_t freq ); + /*! + * @brief Sets the channels configuration + * + * @param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] + * @param [IN] freq Channel RF frequency + * @param [IN] rssiThresh RSSI threshold + * + * @retval isFree [true: Channel is free, false: Channel is not free] + */ + virtual bool IsChannelFree( RadioModems_t modem, uint32_t freq, int16_t rssiThresh ); + /*! + * @brief Generates a 32 bits random value based on the RSSI readings + * + * \remark This function sets the radio in LoRa modem mode and disables + * all interrupts. + * After calling this function either Radio.SetRxConfig or + * Radio.SetTxConfig functions must be called. + * + * @retval randomValue 32 bits random value + */ + virtual uint32_t Random( void ); + /*! + * @brief Sets the reception parameters + * + * @param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] + * @param [IN] bandwidth Sets the bandwidth + * FSK : >= 2600 and <= 250000 Hz + * LoRa: [0: 125 kHz, 1: 250 kHz, + * 2: 500 kHz, 3: Reserved] + * @param [IN] datarate Sets the Datarate + * FSK : 600..300000 bits/s + * LoRa: [6: 64, 7: 128, 8: 256, 9: 512, + * 10: 1024, 11: 2048, 12: 4096 chips] + * @param [IN] coderate Sets the coding rate ( LoRa only ) + * FSK : N/A ( set to 0 ) + * LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] + * @param [IN] bandwidthAfc Sets the AFC Bandwidth ( FSK only ) + * FSK : >= 2600 and <= 250000 Hz + * LoRa: N/A ( set to 0 ) + * @param [IN] preambleLen Sets the Preamble length ( LoRa only ) + * FSK : N/A ( set to 0 ) + * LoRa: Length in symbols ( the hardware adds 4 more symbols ) + * @param [IN] symbTimeout Sets the RxSingle timeout value + * FSK : timeout number of bytes + * LoRa: timeout in symbols + * @param [IN] fixLen Fixed length packets [0: variable, 1: fixed] + * @param [IN] payloadLen Sets payload length when fixed lenght is used + * @param [IN] crcOn Enables/Disables the CRC [0: OFF, 1: ON] + * @param [IN] freqHopOn Enables disables the intra-packet frequency hopping [0: OFF, 1: ON] (LoRa only) + * @param [IN] hopPeriod Number of symbols bewteen each hop (LoRa only) + * @param [IN] iqInverted Inverts IQ signals ( LoRa only ) + * FSK : N/A ( set to 0 ) + * LoRa: [0: not inverted, 1: inverted] + * @param [IN] rxContinuous Sets the reception in continuous mode + * [false: single mode, true: continuous mode] + */ + virtual void SetRxConfig ( RadioModems_t modem, uint32_t bandwidth, + uint32_t datarate, uint8_t coderate, + uint32_t bandwidthAfc, uint16_t preambleLen, + uint16_t symbTimeout, bool fixLen, + uint8_t payloadLen, + bool crcOn, bool freqHopOn, uint8_t hopPeriod, + bool iqInverted, bool rxContinuous ); + /*! + * @brief Sets the transmission parameters + * + * @param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] + * @param [IN] power Sets the output power [dBm] + * @param [IN] fdev Sets the frequency deviation ( FSK only ) + * FSK : [Hz] + * LoRa: 0 + * @param [IN] bandwidth Sets the bandwidth ( LoRa only ) + * FSK : 0 + * LoRa: [0: 125 kHz, 1: 250 kHz, + * 2: 500 kHz, 3: Reserved] + * @param [IN] datarate Sets the Datarate + * FSK : 600..300000 bits/s + * LoRa: [6: 64, 7: 128, 8: 256, 9: 512, + * 10: 1024, 11: 2048, 12: 4096 chips] + * @param [IN] coderate Sets the coding rate ( LoRa only ) + * FSK : N/A ( set to 0 ) + * LoRa: [1: 4/5, 2: 4/6, 3: 4/7, 4: 4/8] + * @param [IN] preambleLen Sets the preamble length + * @param [IN] fixLen Fixed length packets [0: variable, 1: fixed] + * @param [IN] crcOn Enables disables the CRC [0: OFF, 1: ON] + * @param [IN] freqHopOn Enables disables the intra-packet frequency hopping [0: OFF, 1: ON] (LoRa only) + * @param [IN] hopPeriod Number of symbols bewteen each hop (LoRa only) + * @param [IN] iqInverted Inverts IQ signals ( LoRa only ) + * FSK : N/A ( set to 0 ) + * LoRa: [0: not inverted, 1: inverted] + * @param [IN] timeout Transmission timeout [ms] + */ + virtual void SetTxConfig( RadioModems_t modem, int8_t power, uint32_t fdev, + uint32_t bandwidth, uint32_t datarate, + uint8_t coderate, uint16_t preambleLen, + bool fixLen, bool crcOn, bool freqHopOn, + uint8_t hopPeriod, bool iqInverted, uint32_t timeout ); + /*! + * @brief Checks if the given RF frequency is supported by the hardware + * + * @param [IN] frequency RF frequency to be checked + * @retval isSupported [true: supported, false: unsupported] + */ + virtual bool CheckRfFrequency( uint32_t frequency ) = 0; + /*! + * @brief Computes the packet time on air for the given payload + * + * \Remark Can only be called once SetRxConfig or SetTxConfig have been called + * + * @param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] + * @param [IN] pktLen Packet payload length + * + * @retval airTime Computed airTime for the given packet payload length + */ + virtual uint32_t TimeOnAir ( RadioModems_t modem, uint8_t pktLen ); + /*! + * @brief Sends the buffer of size. Prepares the packet to be sent and sets + * the radio in transmission + * + * @param [IN]: buffer Buffer pointer + * @param [IN]: size Buffer size + */ + virtual void Send( uint8_t *buffer, uint8_t size ); + /*! + * @brief Sets the radio in sleep mode + */ + virtual void Sleep( void ); + /*! + * @brief Sets the radio in standby mode + */ + virtual void Standby( void ); + /*! + * @brief Sets the radio in CAD mode + */ + virtual void StartCad( void ); + /*! + * @brief Sets the radio in reception mode for the given time + * @param [IN] timeout Reception timeout [ms] + * [0: continuous, others timeout] + */ + virtual void Rx( uint32_t timeout ); + /*! + * @brief Sets the radio in transmission mode for the given time + * @param [IN] timeout Transmission timeout [ms] + * [0: continuous, others timeout] + */ + virtual void Tx( uint32_t timeout ); + /*! + * @brief Sets the radio in continuous wave transmission mode + * + * @param [IN]: freq Channel RF frequency + * @param [IN]: power Sets the output power [dBm] + * @param [IN]: time Transmission mode timeout [s] + */ + virtual void SetTxContinuousWave( uint32_t freq, int8_t power, uint16_t time ); + /*! + * @brief Reads the current RSSI value + * + * @retval rssiValue Current RSSI value in [dBm] + */ + virtual int16_t GetRssi ( RadioModems_t modem ); + /*! + * @brief Writes the radio register at the specified address + * + * @param [IN]: addr Register address + * @param [IN]: data New register value + */ + virtual void Write ( uint8_t addr, uint8_t data ) = 0; + /*! + * @brief Reads the radio register at the specified address + * + * @param [IN]: addr Register address + * @retval data Register value + */ + virtual uint8_t Read ( uint8_t addr ) = 0; + /*! + * @brief Writes multiple radio registers starting at address + * + * @param [IN] addr First Radio register address + * @param [IN] buffer Buffer containing the new register's values + * @param [IN] size Number of registers to be written + */ + virtual void Write( uint8_t addr, uint8_t *buffer, uint8_t size ) = 0; + /*! + * @brief Reads multiple radio registers starting at address + * + * @param [IN] addr First Radio register address + * @param [OUT] buffer Buffer where to copy the registers data + * @param [IN] size Number of registers to be read + */ + virtual void Read ( uint8_t addr, uint8_t *buffer, uint8_t size ) = 0; + /*! + * @brief Writes the buffer contents to the SX1276 FIFO + * + * @param [IN] buffer Buffer containing data to be put on the FIFO. + * @param [IN] size Number of bytes to be written to the FIFO + */ + virtual void WriteFifo( uint8_t *buffer, uint8_t size ) = 0; + /*! + * @brief Reads the contents of the SX1276 FIFO + * + * @param [OUT] buffer Buffer where to copy the FIFO read data. + * @param [IN] size Number of bytes to be read from the FIFO + */ + virtual void ReadFifo( uint8_t *buffer, uint8_t size ) = 0; + /*! + * @brief Resets the SX1276 + */ + virtual void Reset( void ) = 0; + + /*! + * @brief Sets the maximum payload length. + * + * @param [IN] modem Radio modem to be used [0: FSK, 1: LoRa] + * @param [IN] max Maximum payload length in bytes + */ + virtual void SetMaxPayloadLength( RadioModems_t modem, uint8_t max ); + + /*! + * \brief Sets the network to public or private. Updates the sync byte. + * + * \remark Applies to LoRa modem only + * + * \param [IN] enable if true, it enables a public network + */ + virtual void SetPublicNetwork( bool enable ); + + //------------------------------------------------------------------------- + // Board relative functions + //------------------------------------------------------------------------- + +protected: + /*! + * @brief Initializes the radio I/Os pins interface + */ + virtual void IoInit( void ) = 0; + + /*! + * @brief Initializes the radio registers + */ + virtual void RadioRegistersInit( ) = 0; + + /*! + * @brief Initializes the radio SPI + */ + virtual void SpiInit( void ) = 0; + + /*! + * @brief Initializes DIO IRQ handlers + * + * @param [IN] irqHandlers Array containing the IRQ callback functions + */ + virtual void IoIrqInit( DioIrqHandler *irqHandlers ) = 0; + + /*! + * @brief De-initializes the radio I/Os pins interface. + * + * \remark Useful when going in MCU lowpower modes + */ + virtual void IoDeInit( void ) = 0; + + /*! + * @brief Sets the radio output power. + * + * @param [IN] power Sets the RF output power + */ + virtual void SetRfTxPower( int8_t power ) = 0; + + /*! + * @brief Gets the board PA selection configuration + * + * @param [IN] channel Channel frequency in Hz + * @retval PaSelect RegPaConfig PaSelect value + */ + virtual uint8_t GetPaSelect( uint32_t channel ) = 0; + + /*! + * @brief Set the RF Switch I/Os pins in Low Power mode + * + * @param [IN] status enable or disable + */ + virtual void SetAntSwLowPower( bool status ) = 0; + + /*! + * @brief Initializes the RF Switch I/Os pins interface + */ + virtual void AntSwInit( void ) = 0; + + /*! + * @brief De-initializes the RF Switch I/Os pins interface + * + * \remark Needed to decrease the power consumption in MCU lowpower modes + */ + virtual void AntSwDeInit( void ) = 0; + + /*! + * @brief Controls the antenna switch if necessary. + * + * \remark see errata note + * + * @param [IN] opMode Current radio operating mode + */ + virtual void SetAntSw( uint8_t opMode ) = 0; +protected: + + /*! + * @brief Sets the SX1276 operating mode + * + * @param [IN] opMode New operating mode + */ + virtual void SetOpMode( uint8_t opMode ); + + /* + * SX1276 DIO IRQ callback functions prototype + */ + + /*! + * @brief DIO 0 IRQ callback + */ + virtual void OnDio0Irq( void ); + + /*! + * @brief DIO 1 IRQ callback + */ + virtual void OnDio1Irq( void ); + + /*! + * @brief DIO 2 IRQ callback + */ + virtual void OnDio2Irq( void ); + + /*! + * @brief DIO 3 IRQ callback + */ + virtual void OnDio3Irq( void ); + + /*! + * @brief DIO 4 IRQ callback + */ + virtual void OnDio4Irq( void ); + + /*! + * @brief DIO 5 IRQ callback + */ + virtual void OnDio5Irq( void ); + + /*! + * @brief Tx & Rx timeout timer callback + */ + virtual void OnTimeoutIrq( void ); + + /*! + * Returns the known FSK bandwidth registers value + * + * \param [IN] bandwidth Bandwidth value in Hz + * \retval regValue Bandwidth register value. + */ + static uint8_t GetFskBandwidthRegValue( uint32_t bandwidth ); +}; + +#endif // __SX1276_H__
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/radio/SX1276Lib/typedefs/typedefs.h Wed Sep 04 15:42:07 2019 +0000 @@ -0,0 +1,53 @@ +/* + / _____) _ | | +( (____ _____ ____ _| |_ _____ ____| |__ + \____ \| ___ | (_ _) ___ |/ ___) _ \ + _____) ) ____| | | || |_| ____( (___| | | | +(______/|_____)_|_|_| \__)_____)\____)_| |_| + (C) 2014 Semtech + +Description: - + +License: Revised BSD License, see LICENSE.TXT file include in the project + +Maintainers: Miguel Luis, Gregory Cristian and Nicolas Huguenin +*/ +#ifndef __TYPEDEFS_H__ +#define __TYPEDEFS_H__ + +#include "mbed.h" +#include "./enums/enums.h" + +class SX1276; +class SX1276MB1xAS; +/*! + * Hardware IO IRQ callback function definition + */ +typedef void ( SX1276::*DioIrqHandler )( void ); + +/*! + * triggers definition + */ +typedef void ( SX1276::*Trigger )( void ); +typedef void ( SX1276MB1xAS::*TriggerMB1xAS )( void ); + +/*! + * FSK bandwidth definition + */ +typedef struct +{ + uint32_t bandwidth; + uint8_t RegValue; +}FskBandwidth_t; + +/*! + * Radio registers definition + */ +typedef struct +{ + ModemType Modem; + uint8_t Addr; + uint8_t Value; +}RadioRegisters_t; + +#endif //__TYPEDEFS_H__