diff --git a/board/RHF76_STM32L072CBxx_Lora/MDK-ARM/TencentOS_tiny.uvoptx b/board/RHF76_STM32L072CBxx_Lora/MDK-ARM/TencentOS_tiny.uvoptx index 943a2c4e..fdb69616 100644 --- a/board/RHF76_STM32L072CBxx_Lora/MDK-ARM/TencentOS_tiny.uvoptx +++ b/board/RHF76_STM32L072CBxx_Lora/MDK-ARM/TencentOS_tiny.uvoptx @@ -140,7 +140,7 @@ 0 ST-LINKIII-KEIL_SWO - -U066DFF495056805087213734 -O206 -SF4000 -C0 -A0 -I0 -HNlocalhost -HP7184 -P1 -N00("ARM CoreSight SW-DP") -D00(0BC11477) -L00(0) -TO18 -TC10000000 -TP21 -TDS8007 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -FO7 -FD20000000 -FC1000 -FN1 -FF0STM32L0xx_128.FLM -FS08000000 -FL020000 -FP0($$Device:STM32L072CBTx$CMSIS\Flash\STM32L0xx_128.FLM) + -U066DFF495056805087213734 -O206 -SF4000 -C0 -A0 -I0 -HNlocalhost -HP7184 -P1 -N00("ARM CoreSight SW-DP") -D00(0BC11477) -L00(0) -TO18 -TC10000000 -TP21 -TDS8007 -TDT0 -TDC1F -TIEFFFFFFFF -TIP8 -FO15 -FD20000000 -FC1000 -FN1 -FF0STM32L0xx_128.FLM -FS08000000 -FL020000 -FP0($$Device:STM32L072CBTx$CMSIS\Flash\STM32L0xx_128.FLM) 0 @@ -223,7 +223,7 @@ Application/User - 0 + 1 0 0 0 @@ -258,20 +258,8 @@ 0 0 0 - ..\apps\classA\LoRaApi.c - LoRaApi.c - 0 - 0 - - - 2 - 5 - 1 - 0 - 0 - 0 - ..\apps\classA\at_parser.c - at_parser.c + ..\apps\classA\LoRaDemo.c + LoRaDemo.c 0 0 @@ -285,7 +273,7 @@ 0 3 - 6 + 5 1 0 0 @@ -297,7 +285,7 @@ 3 - 7 + 6 1 0 0 @@ -309,7 +297,7 @@ 3 - 8 + 7 1 0 0 @@ -321,7 +309,7 @@ 3 - 9 + 8 1 0 0 @@ -333,7 +321,7 @@ 3 - 10 + 9 1 0 0 @@ -345,7 +333,7 @@ 3 - 11 + 10 1 0 0 @@ -357,7 +345,7 @@ 3 - 12 + 11 1 0 0 @@ -369,7 +357,7 @@ 3 - 13 + 12 1 0 0 @@ -381,7 +369,7 @@ 3 - 14 + 13 1 0 0 @@ -393,7 +381,7 @@ 3 - 15 + 14 1 0 0 @@ -405,7 +393,7 @@ 3 - 16 + 15 1 0 0 @@ -417,7 +405,7 @@ 3 - 17 + 16 1 0 0 @@ -429,7 +417,7 @@ 3 - 18 + 17 1 0 0 @@ -441,7 +429,7 @@ 3 - 19 + 18 1 0 0 @@ -453,7 +441,7 @@ 3 - 20 + 19 1 0 0 @@ -465,7 +453,7 @@ 3 - 21 + 20 1 0 0 @@ -477,7 +465,7 @@ 3 - 22 + 21 1 0 0 @@ -489,7 +477,7 @@ 3 - 23 + 22 1 0 0 @@ -501,7 +489,7 @@ 3 - 24 + 23 1 0 0 @@ -513,7 +501,7 @@ 3 - 25 + 24 1 0 0 @@ -525,7 +513,7 @@ 3 - 26 + 25 1 0 0 @@ -537,7 +525,7 @@ 3 - 27 + 26 1 0 0 @@ -549,7 +537,7 @@ 3 - 28 + 27 1 0 0 @@ -561,7 +549,7 @@ 3 - 29 + 28 1 0 0 @@ -573,7 +561,7 @@ 3 - 30 + 29 1 0 0 @@ -585,7 +573,7 @@ 3 - 31 + 30 1 0 0 @@ -597,7 +585,7 @@ 3 - 32 + 31 1 0 0 @@ -609,7 +597,7 @@ 3 - 33 + 32 1 0 0 @@ -621,7 +609,7 @@ 3 - 34 + 33 1 0 0 @@ -633,7 +621,7 @@ 3 - 35 + 34 1 0 0 @@ -645,7 +633,7 @@ 3 - 36 + 35 1 0 0 @@ -657,7 +645,7 @@ 3 - 37 + 36 1 0 0 @@ -669,7 +657,7 @@ 3 - 38 + 37 1 0 0 @@ -681,7 +669,7 @@ 3 - 39 + 38 1 0 0 @@ -693,7 +681,7 @@ 3 - 40 + 39 1 0 0 @@ -705,7 +693,7 @@ 3 - 41 + 40 1 0 0 @@ -717,7 +705,7 @@ 3 - 42 + 41 1 0 0 @@ -729,7 +717,7 @@ 3 - 43 + 42 1 0 0 @@ -741,7 +729,7 @@ 3 - 44 + 43 1 0 0 @@ -753,7 +741,7 @@ 3 - 45 + 44 1 0 0 @@ -765,7 +753,7 @@ 3 - 46 + 45 1 0 0 @@ -777,7 +765,7 @@ 3 - 47 + 46 1 0 0 @@ -789,7 +777,7 @@ 3 - 48 + 47 1 0 0 @@ -801,7 +789,7 @@ 3 - 49 + 48 1 0 0 @@ -813,7 +801,7 @@ 3 - 50 + 49 1 0 0 @@ -825,7 +813,7 @@ 3 - 51 + 50 1 0 0 @@ -845,7 +833,7 @@ 0 4 - 52 + 51 1 0 0 @@ -857,7 +845,7 @@ 4 - 53 + 52 1 0 0 @@ -869,7 +857,7 @@ 4 - 54 + 53 1 0 0 @@ -881,7 +869,7 @@ 4 - 55 + 54 1 0 0 @@ -893,7 +881,7 @@ 4 - 56 + 55 1 0 0 @@ -905,7 +893,7 @@ 4 - 57 + 56 1 0 0 @@ -917,7 +905,7 @@ 4 - 58 + 57 1 0 0 @@ -929,7 +917,7 @@ 4 - 59 + 58 1 0 0 @@ -941,7 +929,7 @@ 4 - 60 + 59 1 0 0 @@ -953,7 +941,7 @@ 4 - 61 + 60 1 0 0 @@ -965,7 +953,7 @@ 4 - 62 + 61 1 0 0 @@ -977,7 +965,7 @@ 4 - 63 + 62 1 0 0 @@ -989,7 +977,7 @@ 4 - 64 + 63 1 0 0 @@ -1001,7 +989,7 @@ 4 - 65 + 64 1 0 0 @@ -1011,29 +999,17 @@ 0 0 - - 4 - 66 - 1 - 0 - 0 - 0 - ..\Src\atcmd-board.c - atcmd-board.c - 0 - 0 - lorawan/mac - 1 + 0 0 0 0 5 - 67 + 65 1 0 0 @@ -1045,7 +1021,7 @@ 5 - 68 + 66 1 0 0 @@ -1057,7 +1033,7 @@ 5 - 69 + 67 1 0 0 @@ -1069,7 +1045,7 @@ 5 - 70 + 68 1 0 0 @@ -1081,7 +1057,7 @@ 5 - 71 + 69 1 0 0 @@ -1093,7 +1069,7 @@ 5 - 72 + 70 1 0 0 @@ -1105,7 +1081,7 @@ 5 - 73 + 71 1 0 0 @@ -1117,7 +1093,7 @@ 5 - 74 + 72 1 0 0 @@ -1129,7 +1105,7 @@ 5 - 75 + 73 1 0 0 @@ -1141,7 +1117,7 @@ 5 - 76 + 74 1 0 0 @@ -1153,7 +1129,7 @@ 5 - 77 + 75 1 0 0 @@ -1165,7 +1141,7 @@ 5 - 78 + 76 1 0 0 @@ -1185,7 +1161,7 @@ 0 6 - 79 + 77 1 0 0 @@ -1197,7 +1173,7 @@ 6 - 80 + 78 1 0 0 @@ -1209,7 +1185,7 @@ 6 - 81 + 79 1 0 0 @@ -1221,7 +1197,7 @@ 6 - 82 + 80 1 0 0 @@ -1233,7 +1209,7 @@ 6 - 83 + 81 1 0 0 @@ -1245,7 +1221,7 @@ 6 - 84 + 82 1 0 0 @@ -1257,7 +1233,7 @@ 6 - 85 + 83 1 0 0 @@ -1269,7 +1245,7 @@ 6 - 86 + 84 1 0 0 @@ -1281,7 +1257,7 @@ 6 - 87 + 85 1 0 0 @@ -1293,7 +1269,7 @@ 6 - 88 + 86 1 0 0 @@ -1305,7 +1281,7 @@ 6 - 89 + 87 1 0 0 @@ -1317,7 +1293,7 @@ 6 - 90 + 88 1 0 0 @@ -1337,7 +1313,7 @@ 0 7 - 91 + 89 1 0 0 @@ -1357,7 +1333,7 @@ 0 8 - 92 + 90 1 0 0 @@ -1369,7 +1345,7 @@ 8 - 93 + 91 1 0 0 @@ -1381,7 +1357,7 @@ 8 - 94 + 92 1 0 0 @@ -1393,7 +1369,7 @@ 8 - 95 + 93 1 0 0 @@ -1405,7 +1381,7 @@ 8 - 96 + 94 1 0 0 @@ -1417,7 +1393,7 @@ 8 - 97 + 95 1 0 0 @@ -1429,7 +1405,7 @@ 8 - 98 + 96 1 0 0 @@ -1441,7 +1417,7 @@ 8 - 99 + 97 1 0 0 @@ -1453,7 +1429,7 @@ 8 - 100 + 98 1 0 0 @@ -1465,7 +1441,7 @@ 8 - 101 + 99 1 0 0 @@ -1485,7 +1461,7 @@ 0 9 - 102 + 100 1 0 0 @@ -1497,7 +1473,7 @@ 9 - 103 + 101 1 0 0 @@ -1509,7 +1485,7 @@ 9 - 104 + 102 1 0 0 @@ -1521,7 +1497,7 @@ 9 - 105 + 103 1 0 0 @@ -1533,7 +1509,7 @@ 9 - 106 + 104 1 0 0 @@ -1545,7 +1521,7 @@ 9 - 107 + 105 1 0 0 @@ -1557,7 +1533,7 @@ 9 - 108 + 106 1 0 0 @@ -1569,7 +1545,7 @@ 9 - 109 + 107 1 0 0 @@ -1581,7 +1557,7 @@ 9 - 110 + 108 1 0 0 @@ -1593,7 +1569,7 @@ 9 - 111 + 109 1 0 0 @@ -1605,7 +1581,7 @@ 9 - 112 + 110 1 0 0 @@ -1617,7 +1593,7 @@ 9 - 113 + 111 1 0 0 @@ -1629,7 +1605,7 @@ 9 - 114 + 112 1 0 0 @@ -1641,7 +1617,7 @@ 9 - 115 + 113 1 0 0 @@ -1653,7 +1629,7 @@ 9 - 116 + 114 1 0 0 @@ -1665,7 +1641,7 @@ 9 - 117 + 115 1 0 0 @@ -1677,7 +1653,7 @@ 9 - 118 + 116 1 0 0 @@ -1689,7 +1665,7 @@ 9 - 119 + 117 1 0 0 @@ -1701,7 +1677,7 @@ 9 - 120 + 118 1 0 0 @@ -1713,7 +1689,7 @@ 9 - 121 + 119 1 0 0 @@ -1725,7 +1701,7 @@ 9 - 122 + 120 1 0 0 @@ -1737,7 +1713,7 @@ 9 - 123 + 121 1 0 0 @@ -1749,7 +1725,7 @@ 9 - 124 + 122 1 0 0 @@ -1761,7 +1737,7 @@ 9 - 125 + 123 1 0 0 @@ -1781,7 +1757,7 @@ 0 10 - 126 + 124 2 0 0 @@ -1793,7 +1769,7 @@ 10 - 127 + 125 1 0 0 @@ -1805,7 +1781,7 @@ 10 - 128 + 126 1 0 0 @@ -1825,7 +1801,7 @@ 0 11 - 129 + 127 5 0 0 diff --git a/board/RHF76_STM32L072CBxx_Lora/MDK-ARM/TencentOS_tiny.uvprojx b/board/RHF76_STM32L072CBxx_Lora/MDK-ARM/TencentOS_tiny.uvprojx index b6487bbd..d4503199 100644 --- a/board/RHF76_STM32L072CBxx_Lora/MDK-ARM/TencentOS_tiny.uvprojx +++ b/board/RHF76_STM32L072CBxx_Lora/MDK-ARM/TencentOS_tiny.uvprojx @@ -403,14 +403,9 @@ ..\apps\common\NvmCtxMgmt.c - LoRaApi.c + LoRaDemo.c 1 - ..\apps\classA\LoRaApi.c - - - at_parser.c - 1 - ..\apps\classA\at_parser.c + ..\apps\classA\LoRaDemo.c @@ -722,11 +717,6 @@ 1 ..\Src\sysIrqHandlers.c - - atcmd-board.c - 1 - ..\Src\atcmd-board.c - diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/classA/Commissioning.h b/board/RHF76_STM32L072CBxx_Lora/apps/classA/Commissioning.h new file mode 100644 index 00000000..a15e0e4b --- /dev/null +++ b/board/RHF76_STM32L072CBxx_Lora/apps/classA/Commissioning.h @@ -0,0 +1,63 @@ +/*! + * \file Commissioning.h + * + * \brief End-device commissioning parameters + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2020 Semtech + * + * \endcode + */ +#ifndef __COMMISSIONING_H__ +#define __COMMISSIONING_H__ + +/*! + ****************************************************************************** + ********************************** WARNING *********************************** + ****************************************************************************** + + The LoRaWAN AES128 keys are stored and provisionned on secure-elements. + + This project providdes a software emulated secure-element. + The LoRaWAN AES128 keys SHALL be updated under + src/peripherals/-se\se-identity.h file. + + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + */ +#include "se-identity.h" + +/*! + * When set to 1 the application uses the Over-the-Air activation procedure + * When set to 0 the application uses the Personalization activation procedure + */ +#define OVER_THE_AIR_ACTIVATION 1 + +/*! + * When using ABP activation the MAC layer must know in advance to which server + * version it will be connected. + */ +#define ABP_ACTIVATION_LRWAN_VERSION_V10x 0x01000300 // 1.0.3.0 + +#define ABP_ACTIVATION_LRWAN_VERSION ABP_ACTIVATION_LRWAN_VERSION_V10x + +/*! + * Indicates if the end-device is to be connected to a private or public network + */ +#define LORAWAN_PUBLIC_NETWORK true + +/*! + * Current network ID + */ +#define LORAWAN_NETWORK_ID ( uint32_t )0 + +#endif // __COMMISSIONING_H__ diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/classA/LoRaApi.c b/board/RHF76_STM32L072CBxx_Lora/apps/classA/LoRaApi.c deleted file mode 100644 index 5d214ac8..00000000 --- a/board/RHF76_STM32L072CBxx_Lora/apps/classA/LoRaApi.c +++ /dev/null @@ -1,430 +0,0 @@ -#include "LoRaApi.h" - -#if( OVER_THE_AIR_ACTIVATION == 0 ) -uint8_t DevEui[] = { 0x38, 0x37, 0x37, 0x37, 0x71, 0x37, 0x68, 0x07 }; -uint8_t JoinEui[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -uint8_t AppKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }; -uint8_t NwkKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }; -uint32_t DevAddr = 0x008B6CCB; -uint8_t FNwkSIntKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }; -uint8_t SNwkSIntKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }; -uint8_t NwkSEncKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }; -uint8_t AppSKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }; -#else -uint8_t DevEui[] = { 0x47, 0x9B, 0x41, 0xF2, 0x00, 0x45, 0x00, 0x28 }; -uint8_t JoinEui[] = { 0x52, 0x69, 0x73, 0x69, 0x6E, 0x67, 0x48, 0x46 }; -uint8_t AppKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }; -uint8_t NwkKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }; -uint32_t DevAddr = 0x00ADE921; -uint8_t FNwkSIntKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }; -uint8_t SNwkSIntKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }; -uint8_t NwkSEncKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }; -uint8_t AppSKey[] = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }; -#endif - - -bool NextTx = true; -uint8_t IsTxConfirmed = false; -TimerEvent_t TxNextPacketTimer; -uint8_t AppPort = 2; -uint8_t AppDataSize = 13; -uint8_t AppDataBuffer[LORAWAN_APP_DATA_MAX_SIZE]; -LoRaMacPrimitives_t LoRaMacPrimitives; -LoRaMacCallback_t LoRaMacCallbacks; -MibRequestConfirm_t mibReq; -LoRaMacStatus_t status; - -LoRaMacStatus_t SendFrame( void ) -{ - McpsReq_t mcpsReq; - LoRaMacTxInfo_t txInfo; - - if( LoRaMacQueryTxPossible( AppDataSize, &txInfo ) != LORAMAC_STATUS_OK ) - { - // Send empty frame in order to flush MAC commands - mcpsReq.Type = MCPS_UNCONFIRMED; - mcpsReq.Req.Unconfirmed.fBuffer = NULL; - mcpsReq.Req.Unconfirmed.fBufferSize = 0; - mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE; - } - else - { - if( IsTxConfirmed == false ) - { - mcpsReq.Type = MCPS_UNCONFIRMED; - mcpsReq.Req.Unconfirmed.fPort = AppPort; - mcpsReq.Req.Unconfirmed.fBuffer = AppDataBuffer; - mcpsReq.Req.Unconfirmed.fBufferSize = AppDataSize; - mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE; - } - else - { - mcpsReq.Type = MCPS_CONFIRMED; - mcpsReq.Req.Confirmed.fPort = AppPort; - mcpsReq.Req.Confirmed.fBuffer = AppDataBuffer; - mcpsReq.Req.Confirmed.fBufferSize = AppDataSize; - mcpsReq.Req.Confirmed.NbTrials = 8; - mcpsReq.Req.Confirmed.Datarate = LORAWAN_DEFAULT_DATARATE; - } - } - - /*发送数据*/ - return LoRaMacMcpsRequest( &mcpsReq); -} - - -static void McpsConfirm( McpsConfirm_t *mcpsConfirm ) -{ - if( mcpsConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK ) - { - switch( mcpsConfirm->McpsRequest ) - { - case MCPS_UNCONFIRMED: - { - break; - } - case MCPS_CONFIRMED: - { - break; - } - case MCPS_PROPRIETARY: - { - break; - } - default: - break; - } - } -} -static void OnTxNextPacketTimerEvent( void* context) -{ - MibRequestConfirm_t mibReq; - LoRaMacStatus_t status; - TimerStop( &TxNextPacketTimer ); - mibReq.Type = MIB_NETWORK_ACTIVATION; - status = LoRaMacMibGetRequestConfirm( &mibReq ); - - if( status == LORAMAC_STATUS_OK ) - { - if( mibReq.Param.NetworkActivation == ACTIVATION_TYPE_NONE ) - { - // Network not joined yet. Try to join again - LoRa_JoinNetwork(1); - } - else - { - NextTx = true; - } - } - NextTx = true; -} - -static void McpsIndication( McpsIndication_t *mcpsIndication ) -{ - if( mcpsIndication->Status != LORAMAC_EVENT_INFO_STATUS_OK ) - { - return; - } - - switch( mcpsIndication->McpsIndication ) - { - case MCPS_UNCONFIRMED: - { - break; - } - case MCPS_CONFIRMED: - { - break; - } - case MCPS_PROPRIETARY: - { - break; - } - case MCPS_MULTICAST: - { - break; - } - default: - break; - } - if( mcpsIndication->FramePending == true ) - { - // The server signals that it has pending data to be sent. - // We schedule an uplink as soon as possible to flush the server. - OnTxNextPacketTimerEvent( NULL ); - } - if( mcpsIndication->RxData == true ) - { - } -} - -static void MlmeConfirm( MlmeConfirm_t *mlmeConfirm ) -{ - switch( mlmeConfirm->MlmeRequest ) - { - case MLME_JOIN: - { - if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK ) - { - MibRequestConfirm_t mibGet; - printf( "###### ===== JOINED ==== ######\r\n" ); - printf( "\r\nOTAA\r\n\r\n" ); - - mibGet.Type = MIB_DEV_ADDR; - LoRaMacMibGetRequestConfirm( &mibGet ); - printf( "DevAddr : %08X\r\n", mibGet.Param.DevAddr ); - - printf( "\n\r\n" ); - mibGet.Type = MIB_CHANNELS_DATARATE; - LoRaMacMibGetRequestConfirm( &mibGet ); - printf( "DATA RATE : DR_%d\r\n", mibGet.Param.ChannelsDatarate ); - printf( "\r\n" ); - // Status is OK, node has joined the network - NextTx = true; - } - else - { - // Join was not successful. Try to join again - LoRa_JoinNetwork(1); - } - break; - } - case MLME_LINK_CHECK: - { - break; - } - default: - break; - } - -} - - -/*! - * \brief MLME-Indication event function - * - * \param [IN] mlmeIndication - Pointer to the indication structure. - */ -static void MlmeIndication( MlmeIndication_t *mlmeIndication ) -{ - if( mlmeIndication->Status != LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED ) - { - printf( "\r\n###### ===== MLME-Indication ==== ######\r\n" ); - } - if( mlmeIndication->Status != LORAMAC_EVENT_INFO_STATUS_OK ) - { - } - switch( mlmeIndication->MlmeIndication ) - { - case MLME_SCHEDULE_UPLINK: - {// The MAC signals that we shall provide an uplink as soon as possible - OnTxNextPacketTimerEvent( NULL ); - break; - } - default: - break; - } -} -void OnMacProcessNotify( void ) -{ - -} - -void LoRa_Init(void) -{ - LoRaMacPrimitives.MacMcpsConfirm = McpsConfirm; - LoRaMacPrimitives.MacMcpsIndication = McpsIndication; - LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm; - LoRaMacPrimitives.MacMlmeIndication = MlmeIndication; - - LoRaMacCallbacks.GetBatteryLevel = BoardGetBatteryLevel; - LoRaMacCallbacks.GetTemperatureLevel = NULL; - LoRaMacCallbacks.NvmContextChange = NvmCtxMgmtEvent; - LoRaMacCallbacks.MacProcessNotify = OnMacProcessNotify; - LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks, ACTIVE_REGION ); - - mibReq.Type = MIB_APP_KEY; - mibReq.Param.AppKey = AppKey; - LoRaMacMibSetRequestConfirm( &mibReq ); - mibReq.Type = MIB_NWK_KEY; - mibReq.Param.NwkKey = NwkKey; - LoRaMacMibSetRequestConfirm( &mibReq ); - -#if( OVER_THE_AIR_ACTIVATION == 0 ) - mibReq.Type = MIB_NET_ID; - mibReq.Param.NetID = LORAWAN_NETWORK_ID; - LoRaMacMibSetRequestConfirm( &mibReq ); - - mibReq.Type = MIB_DEV_ADDR; - mibReq.Param.DevAddr = DevAddr; - LoRaMacMibSetRequestConfirm( &mibReq ); - - mibReq.Type = MIB_F_NWK_S_INT_KEY; - mibReq.Param.FNwkSIntKey = FNwkSIntKey; - LoRaMacMibSetRequestConfirm( &mibReq ); - - mibReq.Type = MIB_S_NWK_S_INT_KEY; - mibReq.Param.SNwkSIntKey = SNwkSIntKey; - LoRaMacMibSetRequestConfirm( &mibReq ); - - mibReq.Type = MIB_NWK_S_ENC_KEY; - mibReq.Param.NwkSEncKey = NwkSEncKey; - LoRaMacMibSetRequestConfirm( &mibReq ); - - mibReq.Type = MIB_APP_S_KEY; - mibReq.Param.AppSKey = AppSKey; - LoRaMacMibSetRequestConfirm( &mibReq ); -#endif - - LoRaMacStart( ); - mibReq.Type = MIB_NETWORK_ACTIVATION; - status = LoRaMacMibGetRequestConfirm( &mibReq ); - if( status == LORAMAC_STATUS_OK ) - { - if( mibReq.Param.NetworkActivation != ACTIVATION_TYPE_NONE ) - { - NextTx = true; - } - } -#if 0 -#if( OVER_THE_AIR_ACTIVATION == 0 ) - LoRa_JoinNetwork(0); -#else - LoRa_JoinNetwork(1); -#endif - TimerInit( &TxNextPacketTimer, OnTxNextPacketTimerEvent ); - printf_device_info(); - while( 1 ) - { - char *data = "Welcome to Tos Tiny!"; - LoRaMacProcess( ); - - Lora_Send(0,2,(uint8_t *)data,strlen(data)); - //PrepareTxFrame(); - //SendFrame(); - NextTx = false; - TimerSetValue( &TxNextPacketTimer, 15000 ); - TimerStart( &TxNextPacketTimer ); - while(!NextTx); - //tos_sleep_hmsm(0,0,1,400); //延时1.4s - } -#endif -} - -/*lorawan入网操作*/ -void LoRa_JoinNetwork(uint8_t jointype) -{ - /*OTAA模式*/ - if(jointype > 0) - { - MlmeReq_t mlmeReq; - mlmeReq.Type = MLME_JOIN; - mlmeReq.Req.Join.Datarate = LORAWAN_DEFAULT_DATARATE; - LoRaMacMlmeRequest( &mlmeReq ); - } - else - { - /*设置入网状态*/ - MibRequestConfirm_t mibReq; - mibReq.Type = MIB_ABP_LORAWAN_VERSION; - mibReq.Param.AbpLrWanVersion.Value = ABP_ACTIVATION_LRWAN_VERSION; - LoRaMacMibSetRequestConfirm( &mibReq ); - - mibReq.Type = MIB_NETWORK_ACTIVATION; - mibReq.Param.NetworkActivation = ACTIVATION_TYPE_ABP; - LoRaMacMibSetRequestConfirm( &mibReq ); - } -} - -/*lorawan发送*/ -uint8_t Lora_Send(uint8_t type,uint8_t port, uint8_t * psrc, uint16_t len) -{ - /*提取发送报文类型*/ - if(type == 1) - { - IsTxConfirmed = true; - } - else - { - IsTxConfirmed = false; - } - /*提取端口*/ - if(port <1 && port > 233) - { - return 1; - } - else - { - /*更新端口*/ - AppPort = port; - } - /*提取数据*/ - if(len > LORAWAN_APP_DATA_MAX_SIZE) - { - return 1; - } - memcpy1(AppDataBuffer, psrc, len); - AppDataSize = len; - - /*发送数据*/ - //printf("begin to send data\r\n"); - LoRaMacStatus_t res = SendFrame( ); - if(res == LORAMAC_STATUS_OK) - { - printf("SEND OK\r\n"); - return 0; - } - else if(res == LORAMAC_STATUS_NO_NETWORK_JOINED) - { - printf("NO NETWORK JOINED\r\n"); - return 2; - } - else if(res == LORAMAC_STATUS_BUSY) - { - printf("LORAMAC STATUS BUSY\r\n"); - return 3; - } - else - { - return 1; - } -} - -void printf_device_info(void) -{ - printf( "DevEui : %02X", DevEui[0] ); - for( int i = 1; i < 8; i++ ) - { - printf( "-%02X", DevEui[i] ); - } - printf( "\r\n" ); - printf( "AppEui : %02X", JoinEui[0] ); - for( int i = 1; i < 8; i++ ) - { - printf( "-%02X", JoinEui[i] ); - } - printf( "\r\n" ); - printf( "AppKey : %02X", NwkKey[0] ); - for( int i = 1; i < 16; i++ ) - { - printf( " %02X", NwkKey[i] ); - } - printf( "\n\r\n" ); -#if( OVER_THE_AIR_ACTIVATION == 0 ) - printf( "###### ===== JOINED ==== ######\r\n" ); - printf( "\r\nABP\r\n\r\n" ); - printf( "DevAddr : %08X\r\n", DevAddr ); - printf( "NwkSKey : %02X", FNwkSIntKey[0] ); - for( int i = 1; i < 16; i++ ) - { - printf( " %02X", FNwkSIntKey[i] ); - } - printf( "\r\n" ); - printf( "AppSKey : %02X", AppSKey[0] ); - for( int i = 1; i < 16; i++ ) - { - printf( " %02X", AppSKey[i] ); - } - printf( "\n\r\n" ); -#endif -} diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/classA/LoRaApi.h b/board/RHF76_STM32L072CBxx_Lora/apps/classA/LoRaApi.h deleted file mode 100644 index f3db6d4a..00000000 --- a/board/RHF76_STM32L072CBxx_Lora/apps/classA/LoRaApi.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef __LORAAPI_H__ -#define __LORAAPI_H__ - -#include "stdio.h" -#include "string.h" -#include "utilities.h" -#include "board.h" -#include "gpio.h" -#include "LoRaMac.h" -#include "NvmCtxMgmt.h" - -#define ACTIVE_REGION LORAMAC_REGION_CN470 - -#ifndef ACTIVE_REGION - -#warning "No active region defined, LORAMAC_REGION_EU868 will be used as default." - -#define ACTIVE_REGION LORAMAC_REGION_EU868 - -#endif - -/*! - * Defines the application data transmission duty cycle. 5s, value in [ms]. - */ -#define APP_TX_DUTYCYCLE 5000 - -/*! - * Defines a random delay for application data transmission duty cycle. 1s, - * value in [ms]. - */ -#define APP_TX_DUTYCYCLE_RND 1000 - -/*! - * Default datarate - */ -#define LORAWAN_DEFAULT_DATARATE DR_0 - -/*! - * LoRaWAN confirmed messages - */ -#define LORAWAN_CONFIRMED_MSG_ON false - -/*! - * LoRaWAN Adaptive Data Rate - * - * \remark Please note that when ADR is enabled the end-device should be static - */ -#define LORAWAN_ADR_ON 1 - -#define LORAWAN_DUTYCYCLE_ON false - - -#define OVER_THE_AIR_ACTIVATION 0 - -#define ABP_ACTIVATION_LRWAN_VERSION_V10x 0x01000300 // 1.0.3.0 - -#define ABP_ACTIVATION_LRWAN_VERSION ABP_ACTIVATION_LRWAN_VERSION_V10x - -#define LORAWAN_PUBLIC_NETWORK true - -#define LORAWAN_NETWORK_ID ( uint32_t )0 - - -#define LORAWAN_APP_DATA_MAX_SIZE 64 - - - - - - - -extern bool NextTx; -extern TimerEvent_t TxNextPacketTimer; - -void LoRa_Init(void); -void LoRa_JoinNetwork(uint8_t jointype); -uint8_t Lora_Send(uint8_t type,uint8_t port, uint8_t * psrc, uint16_t len); -void printf_device_info(void); - -#endif diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/classA/LoRaDemo.c b/board/RHF76_STM32L072CBxx_Lora/apps/classA/LoRaDemo.c new file mode 100644 index 00000000..1b4ef190 --- /dev/null +++ b/board/RHF76_STM32L072CBxx_Lora/apps/classA/LoRaDemo.c @@ -0,0 +1,1184 @@ +/*! + * \file main.c + * + * \brief LoRaMac classA device implementation + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2017 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + * + * \author Gregory Cristian ( Semtech ) + */ + +/*! \file classA/B-L072Z-LRWAN1/main.c */ + +#include +#include "utilities.h" +#include "board.h" +#include "gpio.h" +#include "LoRaMac.h" +#include "Commissioning.h" +#include "NvmCtxMgmt.h" + +#define ACTIVE_REGION LORAMAC_REGION_CN470 +#ifndef ACTIVE_REGION + +#warning "No active region defined, LORAMAC_REGION_EU868 will be used as default." + +#define ACTIVE_REGION LORAMAC_REGION_EU868 + +#endif + +/*! + * Defines the application data transmission duty cycle. 5s, value in [ms]. + */ +#define APP_TX_DUTYCYCLE 5000 + +/*! + * Defines a random delay for application data transmission duty cycle. 1s, + * value in [ms]. + */ +#define APP_TX_DUTYCYCLE_RND 1000 + +/*! + * Default datarate + */ +#define LORAWAN_DEFAULT_DATARATE DR_0 + +/*! + * LoRaWAN confirmed messages + */ +#define LORAWAN_CONFIRMED_MSG_ON false + +/*! + * LoRaWAN Adaptive Data Rate + * + * \remark Please note that when ADR is enabled the end-device should be static + */ +#define LORAWAN_ADR_ON 1 + +#if defined( REGION_EU868 ) || defined( REGION_RU864 ) || defined( REGION_CN779 ) || defined( REGION_EU433 ) + +#include "LoRaMacTest.h" + +/*! + * LoRaWAN ETSI duty cycle control enable/disable + * + * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes + */ +#define LORAWAN_DUTYCYCLE_ON true + +#endif + +/*! + * LoRaWAN application port + */ +#define LORAWAN_APP_PORT 2 + +#if( OVER_THE_AIR_ACTIVATION == 0 ) +/*! + * Device address + */ +static uint32_t DevAddr = LORAWAN_DEVICE_ADDRESS; +#endif + +/*! + * Application port + */ +static uint8_t AppPort = LORAWAN_APP_PORT; + +/*! + * User application data size + */ +static uint8_t AppDataSize = 1; +static uint8_t AppDataSizeBackup = 1; + +/*! + * User application data buffer size + */ +#define LORAWAN_APP_DATA_MAX_SIZE 242 + +/*! + * User application data + */ +static uint8_t AppDataBuffer[LORAWAN_APP_DATA_MAX_SIZE]; + +/*! + * Indicates if the node is sending confirmed or unconfirmed messages + */ +static uint8_t IsTxConfirmed = LORAWAN_CONFIRMED_MSG_ON; + +/*! + * Defines the application data transmission duty cycle + */ +static uint32_t TxDutyCycleTime; + +/*! + * Timer to handle the application data transmission duty cycle + */ +static TimerEvent_t TxNextPacketTimer; + +/*! + * Specifies the state of the application LED + */ +static bool AppLedStateOn = false; + +/*! + * Timer to handle the state of LED1 + */ +static TimerEvent_t Led1Timer; + +/*! + * Timer to handle the state of LED3 + */ +static TimerEvent_t Led3Timer; + +/*! + * Indicates if a new packet can be sent + */ +static bool NextTx = true; + +/*! + * Indicates if LoRaMacProcess call is pending. + * + * \warning If variable is equal to 0 then the MCU can be set in low power mode + */ +static uint8_t IsMacProcessPending = 0; + +/*! + * Device states + */ +static enum eDeviceState +{ + DEVICE_STATE_RESTORE, + DEVICE_STATE_START, + DEVICE_STATE_JOIN, + DEVICE_STATE_SEND, + DEVICE_STATE_CYCLE, + DEVICE_STATE_SLEEP +}DeviceState; + +/*! + * LoRaWAN compliance tests support data + */ +struct ComplianceTest_s +{ + bool Running; + uint8_t State; + bool IsTxConfirmed; + uint8_t AppPort; + uint8_t AppDataSize; + uint8_t *AppDataBuffer; + uint16_t DownLinkCounter; + bool LinkCheck; + uint8_t DemodMargin; + uint8_t NbGateways; +}ComplianceTest; + +/*! + * + */ +typedef enum +{ + LORAMAC_HANDLER_UNCONFIRMED_MSG = 0, + LORAMAC_HANDLER_CONFIRMED_MSG = !LORAMAC_HANDLER_UNCONFIRMED_MSG +}LoRaMacHandlerMsgTypes_t; + +/*! + * Application data structure + */ +typedef struct LoRaMacHandlerAppData_s +{ + LoRaMacHandlerMsgTypes_t MsgType; + uint8_t Port; + uint8_t BufferSize; + uint8_t *Buffer; +}LoRaMacHandlerAppData_t; + +LoRaMacHandlerAppData_t AppData = +{ + .MsgType = LORAMAC_HANDLER_UNCONFIRMED_MSG, + .Buffer = NULL, + .BufferSize = 0, + .Port = 0 +}; + +/*! + * LED GPIO pins objects + */ +extern Gpio_t Led1; // Tx +extern Gpio_t Led3; // Rx +extern Gpio_t Led4; // App + +/*! + * MAC status strings + */ +const char* MacStatusStrings[] = +{ + "OK", // LORAMAC_STATUS_OK + "Busy", // LORAMAC_STATUS_BUSY + "Service unknown", // LORAMAC_STATUS_SERVICE_UNKNOWN + "Parameter invalid", // LORAMAC_STATUS_PARAMETER_INVALID + "Frequency invalid", // LORAMAC_STATUS_FREQUENCY_INVALID + "Datarate invalid", // LORAMAC_STATUS_DATARATE_INVALID + "Frequency or datarate invalid", // LORAMAC_STATUS_FREQ_AND_DR_INVALID + "No network joined", // LORAMAC_STATUS_NO_NETWORK_JOINED + "Length error", // LORAMAC_STATUS_LENGTH_ERROR + "Region not supported", // LORAMAC_STATUS_REGION_NOT_SUPPORTED + "Skipped APP data", // LORAMAC_STATUS_SKIPPED_APP_DATA + "Duty-cycle restricted", // LORAMAC_STATUS_DUTYCYCLE_RESTRICTED + "No channel found", // LORAMAC_STATUS_NO_CHANNEL_FOUND + "No free channel found", // LORAMAC_STATUS_NO_FREE_CHANNEL_FOUND + "Busy beacon reserved time", // LORAMAC_STATUS_BUSY_BEACON_RESERVED_TIME + "Busy ping-slot window time", // LORAMAC_STATUS_BUSY_PING_SLOT_WINDOW_TIME + "Busy uplink collision", // LORAMAC_STATUS_BUSY_UPLINK_COLLISION + "Crypto error", // LORAMAC_STATUS_CRYPTO_ERROR + "FCnt handler error", // LORAMAC_STATUS_FCNT_HANDLER_ERROR + "MAC command error", // LORAMAC_STATUS_MAC_COMMAD_ERROR + "ClassB error", // LORAMAC_STATUS_CLASS_B_ERROR + "Confirm queue error", // LORAMAC_STATUS_CONFIRM_QUEUE_ERROR + "Multicast group undefined", // LORAMAC_STATUS_MC_GROUP_UNDEFINED + "Unknown error", // LORAMAC_STATUS_ERROR +}; + +/*! + * MAC event info status strings. + */ +const char* EventInfoStatusStrings[] = +{ + "OK", // LORAMAC_EVENT_INFO_STATUS_OK + "Error", // LORAMAC_EVENT_INFO_STATUS_ERROR + "Tx timeout", // LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT + "Rx 1 timeout", // LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT + "Rx 2 timeout", // LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT + "Rx1 error", // LORAMAC_EVENT_INFO_STATUS_RX1_ERROR + "Rx2 error", // LORAMAC_EVENT_INFO_STATUS_RX2_ERROR + "Join failed", // LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL + "Downlink repeated", // LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED + "Tx DR payload size error", // LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR + "Downlink too many frames loss", // LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS + "Address fail", // LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL + "MIC fail", // LORAMAC_EVENT_INFO_STATUS_MIC_FAIL + "Multicast fail", // LORAMAC_EVENT_INFO_STATUS_MULTICAST_FAIL + "Beacon locked", // LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED + "Beacon lost", // LORAMAC_EVENT_INFO_STATUS_BEACON_LOST + "Beacon not found" // LORAMAC_EVENT_INFO_STATUS_BEACON_NOT_FOUND +}; + +/*! + * Prints the provided buffer in HEX + * + * \param buffer Buffer to be printed + * \param size Buffer size to be printed + */ +void PrintHexBuffer( uint8_t *buffer, uint8_t size ) +{ + uint8_t newline = 0; + + for( uint8_t i = 0; i < size; i++ ) + { + if( newline != 0 ) + { + printf( "\n" ); + newline = 0; + } + + printf( "%02X ", buffer[i] ); + + if( ( ( i + 1 ) % 16 ) == 0 ) + { + newline = 1; + } + } + printf( "\n" ); +} + +/*! + * Executes the network Join request + */ +static void JoinNetwork( void ) +{ + LoRaMacStatus_t status; + MlmeReq_t mlmeReq; + mlmeReq.Type = MLME_JOIN; + mlmeReq.Req.Join.Datarate = LORAWAN_DEFAULT_DATARATE; + + // Starts the join procedure + status = LoRaMacMlmeRequest( &mlmeReq ); + printf( "\n###### ===== MLME-Request - MLME_JOIN ==== ######\n" ); + printf( "STATUS : %s\n", MacStatusStrings[status] ); + + if( status == LORAMAC_STATUS_OK ) + { + printf( "###### ===== JOINING ==== ######\n" ); + DeviceState = DEVICE_STATE_SLEEP; + } + else + { + if( status == LORAMAC_STATUS_DUTYCYCLE_RESTRICTED ) + { + printf( "Next Tx in : %lu [ms]\n", mlmeReq.ReqReturn.DutyCycleWaitTime ); + } + DeviceState = DEVICE_STATE_CYCLE; + } +} + +/*! + * \brief Prepares the payload of the frame + */ +static void PrepareTxFrame( uint8_t port ) +{ + switch( port ) + { + case 2: + { + AppDataSizeBackup = AppDataSize = 1; + AppDataBuffer[0] = AppLedStateOn; + } + break; + case 224: + if( ComplianceTest.LinkCheck == true ) + { + ComplianceTest.LinkCheck = false; + AppDataSize = 3; + AppDataBuffer[0] = 5; + AppDataBuffer[1] = ComplianceTest.DemodMargin; + AppDataBuffer[2] = ComplianceTest.NbGateways; + ComplianceTest.State = 1; + } + else + { + switch( ComplianceTest.State ) + { + case 4: + ComplianceTest.State = 1; + break; + case 1: + AppDataSize = 2; + AppDataBuffer[0] = ComplianceTest.DownLinkCounter >> 8; + AppDataBuffer[1] = ComplianceTest.DownLinkCounter; + break; + } + } + break; + default: + break; + } +} + +/*! + * \brief Prepares the payload of the frame + * + * \retval [0: frame could be send, 1: error] + */ +static bool SendFrame( void ) +{ + McpsReq_t mcpsReq; + LoRaMacTxInfo_t txInfo; + + if( LoRaMacQueryTxPossible( AppDataSize, &txInfo ) != LORAMAC_STATUS_OK ) + { + // Send empty frame in order to flush MAC commands + mcpsReq.Type = MCPS_UNCONFIRMED; + mcpsReq.Req.Unconfirmed.fBuffer = NULL; + mcpsReq.Req.Unconfirmed.fBufferSize = 0; + mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE; + } + else + { + if( IsTxConfirmed == false ) + { + mcpsReq.Type = MCPS_UNCONFIRMED; + mcpsReq.Req.Unconfirmed.fPort = AppPort; + mcpsReq.Req.Unconfirmed.fBuffer = AppDataBuffer; + mcpsReq.Req.Unconfirmed.fBufferSize = AppDataSize; + mcpsReq.Req.Unconfirmed.Datarate = LORAWAN_DEFAULT_DATARATE; + } + else + { + mcpsReq.Type = MCPS_CONFIRMED; + mcpsReq.Req.Confirmed.fPort = AppPort; + mcpsReq.Req.Confirmed.fBuffer = AppDataBuffer; + mcpsReq.Req.Confirmed.fBufferSize = AppDataSize; + mcpsReq.Req.Confirmed.NbTrials = 8; + mcpsReq.Req.Confirmed.Datarate = LORAWAN_DEFAULT_DATARATE; + } + } + + // Update global variable + AppData.MsgType = ( mcpsReq.Type == MCPS_CONFIRMED ) ? LORAMAC_HANDLER_CONFIRMED_MSG : LORAMAC_HANDLER_UNCONFIRMED_MSG; + AppData.Port = mcpsReq.Req.Unconfirmed.fPort; + AppData.Buffer = mcpsReq.Req.Unconfirmed.fBuffer; + AppData.BufferSize = mcpsReq.Req.Unconfirmed.fBufferSize; + + LoRaMacStatus_t status; + status = LoRaMacMcpsRequest( &mcpsReq ); + printf( "\n###### ===== MCPS-Request ==== ######\n" ); + printf( "STATUS : %s\n", MacStatusStrings[status] ); + + if( status == LORAMAC_STATUS_DUTYCYCLE_RESTRICTED ) + { + printf( "Next Tx in : %lu [ms]\n", mcpsReq.ReqReturn.DutyCycleWaitTime ); + } + + if( status == LORAMAC_STATUS_OK ) + { + return false; + } + return true; +} + +/*! + * \brief Function executed on TxNextPacket Timeout event + */ +static void OnTxNextPacketTimerEvent( void* context ) +{ + MibRequestConfirm_t mibReq; + LoRaMacStatus_t status; + + TimerStop( &TxNextPacketTimer ); + + mibReq.Type = MIB_NETWORK_ACTIVATION; + status = LoRaMacMibGetRequestConfirm( &mibReq ); + + if( status == LORAMAC_STATUS_OK ) + { + if( mibReq.Param.NetworkActivation == ACTIVATION_TYPE_NONE ) + { + // Network not joined yet. Try to join again + JoinNetwork( ); + } + else + { + DeviceState = DEVICE_STATE_SEND; + NextTx = true; + } + } +} + +/*! + * \brief Function executed on Led 1 Timeout event + */ +static void OnLed1TimerEvent( void* context ) +{ + TimerStop( &Led1Timer ); + // Switch LED 1 OFF + GpioWrite( &Led1, 0 ); +} + +/*! + * \brief Function executed on Led 3 Timeout event + */ +static void OnLed3TimerEvent( void* context ) +{ + TimerStop( &Led3Timer ); + // Switch LED 3 OFF + GpioWrite( &Led3, 0 ); +} + +/*! + * \brief MCPS-Confirm event function + * + * \param [IN] mcpsConfirm - Pointer to the confirm structure, + * containing confirm attributes. + */ +static void McpsConfirm( McpsConfirm_t *mcpsConfirm ) +{ + printf( "\n###### ===== MCPS-Confirm ==== ######\n" ); + printf( "STATUS : %s\n", EventInfoStatusStrings[mcpsConfirm->Status] ); + if( mcpsConfirm->Status != LORAMAC_EVENT_INFO_STATUS_OK ) + { + } + else + { + switch( mcpsConfirm->McpsRequest ) + { + case MCPS_UNCONFIRMED: + { + // Check Datarate + // Check TxPower + break; + } + case MCPS_CONFIRMED: + { + // Check Datarate + // Check TxPower + // Check AckReceived + // Check NbTrials + break; + } + case MCPS_PROPRIETARY: + { + break; + } + default: + break; + } + + // Switch LED 1 ON + GpioWrite( &Led1, 1 ); + TimerStart( &Led1Timer ); + } + MibRequestConfirm_t mibGet; + MibRequestConfirm_t mibReq; + + mibReq.Type = MIB_DEVICE_CLASS; + LoRaMacMibGetRequestConfirm( &mibReq ); + + printf( "\n###### ===== UPLINK FRAME %lu ==== ######\n", mcpsConfirm->UpLinkCounter ); + printf( "\n" ); + + printf( "CLASS : %c\n", "ABC"[mibReq.Param.Class] ); + printf( "\n" ); + printf( "TX PORT : %d\n", AppData.Port ); + + if( AppData.BufferSize != 0 ) + { + printf( "TX DATA : " ); + if( AppData.MsgType == LORAMAC_HANDLER_CONFIRMED_MSG ) + { + printf( "CONFIRMED - %s\n", ( mcpsConfirm->AckReceived != 0 ) ? "ACK" : "NACK" ); + } + else + { + printf( "UNCONFIRMED\n" ); + } + PrintHexBuffer( AppData.Buffer, AppData.BufferSize ); + } + + printf( "\n" ); + printf( "DATA RATE : DR_%d\n", mcpsConfirm->Datarate ); + + mibGet.Type = MIB_CHANNELS; + if( LoRaMacMibGetRequestConfirm( &mibGet ) == LORAMAC_STATUS_OK ) + { + printf( "U/L FREQ : %lu\n", mibGet.Param.ChannelList[mcpsConfirm->Channel].Frequency ); + } + + printf( "TX POWER : %d\n", mcpsConfirm->TxPower ); + + mibGet.Type = MIB_CHANNELS_MASK; + if( LoRaMacMibGetRequestConfirm( &mibGet ) == LORAMAC_STATUS_OK ) + { + printf("CHANNEL MASK: "); +#if defined( REGION_AS923 ) || defined( REGION_CN779 ) || \ + defined( REGION_EU868 ) || defined( REGION_IN865 ) || \ + defined( REGION_KR920 ) || defined( REGION_EU433 ) || \ + defined( REGION_RU864 ) + + for( uint8_t i = 0; i < 1; i++) + +#elif defined( REGION_AU915 ) || defined( REGION_US915 ) || defined( REGION_CN470 ) + + for( uint8_t i = 0; i < 5; i++) +#else + +#error "Please define a region in the compiler options." + +#endif + { + printf("%04X ", mibGet.Param.ChannelsMask[i] ); + } + printf("\n"); + } + + printf( "\n" ); +} + +/*! + * \brief MCPS-Indication event function + * + * \param [IN] mcpsIndication - Pointer to the indication structure, + * containing indication attributes. + */ +static void McpsIndication( McpsIndication_t *mcpsIndication ) +{ + printf( "\n###### ===== MCPS-Indication ==== ######\n" ); + printf( "STATUS : %s\n", EventInfoStatusStrings[mcpsIndication->Status] ); + if( mcpsIndication->Status != LORAMAC_EVENT_INFO_STATUS_OK ) + { + return; + } + + switch( mcpsIndication->McpsIndication ) + { + case MCPS_UNCONFIRMED: + { + break; + } + case MCPS_CONFIRMED: + { + break; + } + case MCPS_PROPRIETARY: + { + break; + } + case MCPS_MULTICAST: + { + break; + } + default: + break; + } + + // Check Multicast + // Check Port + // Check Datarate + // Check FramePending + if( mcpsIndication->FramePending == true ) + { + // The server signals that it has pending data to be sent. + // We schedule an uplink as soon as possible to flush the server. + OnTxNextPacketTimerEvent( NULL ); + } + // Check Buffer + // Check BufferSize + // Check Rssi + // Check Snr + // Check RxSlot + + if( ComplianceTest.Running == true ) + { + ComplianceTest.DownLinkCounter++; + } + + if( mcpsIndication->RxData == true ) + { + switch( mcpsIndication->Port ) + { + case 1: // The application LED can be controlled on port 1 or 2 + case 2: + if( mcpsIndication->BufferSize == 1 ) + { + AppLedStateOn = mcpsIndication->Buffer[0] & 0x01; + GpioWrite( &Led4, ( ( AppLedStateOn & 0x01 ) != 0 ) ? 1 : 0 ); + } + break; + case 224: + if( ComplianceTest.Running == false ) + { + // Check compliance test enable command (i) + if( ( mcpsIndication->BufferSize == 4 ) && + ( mcpsIndication->Buffer[0] == 0x01 ) && + ( mcpsIndication->Buffer[1] == 0x01 ) && + ( mcpsIndication->Buffer[2] == 0x01 ) && + ( mcpsIndication->Buffer[3] == 0x01 ) ) + { + IsTxConfirmed = false; + AppPort = 224; + AppDataSizeBackup = AppDataSize; + AppDataSize = 2; + ComplianceTest.DownLinkCounter = 0; + ComplianceTest.LinkCheck = false; + ComplianceTest.DemodMargin = 0; + ComplianceTest.NbGateways = 0; + ComplianceTest.Running = true; + ComplianceTest.State = 1; + + MibRequestConfirm_t mibReq; + mibReq.Type = MIB_ADR; + mibReq.Param.AdrEnable = true; + LoRaMacMibSetRequestConfirm( &mibReq ); + +#if defined( REGION_EU868 ) || defined( REGION_RU864 ) || defined( REGION_CN779 ) || defined( REGION_EU433 ) + LoRaMacTestSetDutyCycleOn( false ); +#endif + } + } + else + { + ComplianceTest.State = mcpsIndication->Buffer[0]; + switch( ComplianceTest.State ) + { + case 0: // Check compliance test disable command (ii) + IsTxConfirmed = LORAWAN_CONFIRMED_MSG_ON; + AppPort = LORAWAN_APP_PORT; + AppDataSize = AppDataSizeBackup; + ComplianceTest.DownLinkCounter = 0; + ComplianceTest.Running = false; + + MibRequestConfirm_t mibReq; + mibReq.Type = MIB_ADR; + mibReq.Param.AdrEnable = LORAWAN_ADR_ON; + LoRaMacMibSetRequestConfirm( &mibReq ); +#if defined( REGION_EU868 ) || defined( REGION_RU864 ) || defined( REGION_CN779 ) || defined( REGION_EU433 ) + LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON ); +#endif + break; + case 1: // (iii, iv) + AppDataSize = 2; + break; + case 2: // Enable confirmed messages (v) + IsTxConfirmed = true; + ComplianceTest.State = 1; + break; + case 3: // Disable confirmed messages (vi) + IsTxConfirmed = false; + ComplianceTest.State = 1; + break; + case 4: // (vii) + AppDataSize = mcpsIndication->BufferSize; + + AppDataBuffer[0] = 4; + for( uint8_t i = 1; i < MIN( AppDataSize, LORAWAN_APP_DATA_MAX_SIZE ); i++ ) + { + AppDataBuffer[i] = mcpsIndication->Buffer[i] + 1; + } + break; + case 5: // (viii) + { + MlmeReq_t mlmeReq; + mlmeReq.Type = MLME_LINK_CHECK; + LoRaMacStatus_t status = LoRaMacMlmeRequest( &mlmeReq ); + printf( "\n###### ===== MLME-Request - MLME_LINK_CHECK ==== ######\n" ); + printf( "STATUS : %s\n", MacStatusStrings[status] ); + } + break; + case 6: // (ix) + { + // Disable TestMode and revert back to normal operation + IsTxConfirmed = LORAWAN_CONFIRMED_MSG_ON; + AppPort = LORAWAN_APP_PORT; + AppDataSize = AppDataSizeBackup; + ComplianceTest.DownLinkCounter = 0; + ComplianceTest.Running = false; + + MibRequestConfirm_t mibReq; + mibReq.Type = MIB_ADR; + mibReq.Param.AdrEnable = LORAWAN_ADR_ON; + LoRaMacMibSetRequestConfirm( &mibReq ); +#if defined( REGION_EU868 ) || defined( REGION_RU864 ) || defined( REGION_CN779 ) || defined( REGION_EU433 ) + LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON ); +#endif + + JoinNetwork( ); + } + break; + case 7: // (x) + { + if( mcpsIndication->BufferSize == 3 ) + { + MlmeReq_t mlmeReq; + mlmeReq.Type = MLME_TXCW; + mlmeReq.Req.TxCw.Timeout = ( uint16_t )( ( mcpsIndication->Buffer[1] << 8 ) | mcpsIndication->Buffer[2] ); + LoRaMacStatus_t status = LoRaMacMlmeRequest( &mlmeReq ); + printf( "\n###### ===== MLME-Request - MLME_TXCW ==== ######\n" ); + printf( "STATUS : %s\n", MacStatusStrings[status] ); + } + else if( mcpsIndication->BufferSize == 7 ) + { + MlmeReq_t mlmeReq; + mlmeReq.Type = MLME_TXCW_1; + mlmeReq.Req.TxCw.Timeout = ( uint16_t )( ( mcpsIndication->Buffer[1] << 8 ) | mcpsIndication->Buffer[2] ); + mlmeReq.Req.TxCw.Frequency = ( uint32_t )( ( mcpsIndication->Buffer[3] << 16 ) | ( mcpsIndication->Buffer[4] << 8 ) | mcpsIndication->Buffer[5] ) * 100; + mlmeReq.Req.TxCw.Power = mcpsIndication->Buffer[6]; + LoRaMacStatus_t status = LoRaMacMlmeRequest( &mlmeReq ); + printf( "\n###### ===== MLME-Request - MLME_TXCW1 ==== ######\n" ); + printf( "STATUS : %s\n", MacStatusStrings[status] ); + } + ComplianceTest.State = 1; + } + break; + case 8: // Send DeviceTimeReq + { + MlmeReq_t mlmeReq; + + mlmeReq.Type = MLME_DEVICE_TIME; + + LoRaMacStatus_t status = LoRaMacMlmeRequest( &mlmeReq ); + printf( "\n###### ===== MLME-Request - MLME_DEVICE_TIME ==== ######\n" ); + printf( "STATUS : %s\n", MacStatusStrings[status] ); + } + break; + default: + break; + } + } + break; + default: + break; + } + } + + // Switch LED 3 ON for each received downlink + GpioWrite( &Led3, 1 ); + TimerStart( &Led3Timer ); + + const char *slotStrings[] = { "1", "2", "C", "C Multicast", "B Ping-Slot", "B Multicast Ping-Slot" }; + + printf( "\n###### ===== DOWNLINK FRAME %lu ==== ######\n", mcpsIndication->DownLinkCounter ); + + printf( "RX WINDOW : %s\n", slotStrings[mcpsIndication->RxSlot] ); + + printf( "RX PORT : %d\n", mcpsIndication->Port ); + + if( mcpsIndication->BufferSize != 0 ) + { + printf( "RX DATA : \n" ); + PrintHexBuffer( mcpsIndication->Buffer, mcpsIndication->BufferSize ); + } + + printf( "\n" ); + printf( "DATA RATE : DR_%d\n", mcpsIndication->RxDatarate ); + printf( "RX RSSI : %d\n", mcpsIndication->Rssi ); + printf( "RX SNR : %d\n", mcpsIndication->Snr ); + + printf( "\n" ); +} + +/*! + * \brief MLME-Confirm event function + * + * \param [IN] mlmeConfirm - Pointer to the confirm structure, + * containing confirm attributes. + */ +static void MlmeConfirm( MlmeConfirm_t *mlmeConfirm ) +{ + printf( "\n###### ===== MLME-Confirm ==== ######\n" ); + printf( "STATUS : %s\n", EventInfoStatusStrings[mlmeConfirm->Status] ); + if( mlmeConfirm->Status != LORAMAC_EVENT_INFO_STATUS_OK ) + { + } + switch( mlmeConfirm->MlmeRequest ) + { + case MLME_JOIN: + { + if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK ) + { + MibRequestConfirm_t mibGet; + printf( "###### ===== JOINED ==== ######\n" ); + printf( "\nOTAA\n\n" ); + + mibGet.Type = MIB_DEV_ADDR; + LoRaMacMibGetRequestConfirm( &mibGet ); + printf( "DevAddr : %08lX\n", mibGet.Param.DevAddr ); + + printf( "\n\n" ); + mibGet.Type = MIB_CHANNELS_DATARATE; + LoRaMacMibGetRequestConfirm( &mibGet ); + printf( "DATA RATE : DR_%d\n", mibGet.Param.ChannelsDatarate ); + printf( "\n" ); + // Status is OK, node has joined the network + DeviceState = DEVICE_STATE_SEND; + } + else + { + // Join was not successful. Try to join again + JoinNetwork( ); + } + break; + } + case MLME_LINK_CHECK: + { + if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK ) + { + // Check DemodMargin + // Check NbGateways + if( ComplianceTest.Running == true ) + { + ComplianceTest.LinkCheck = true; + ComplianceTest.DemodMargin = mlmeConfirm->DemodMargin; + ComplianceTest.NbGateways = mlmeConfirm->NbGateways; + } + } + break; + } + default: + break; + } +} + +/*! + * \brief MLME-Indication event function + * + * \param [IN] mlmeIndication - Pointer to the indication structure. + */ +static void MlmeIndication( MlmeIndication_t *mlmeIndication ) +{ + if( mlmeIndication->Status != LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED ) + { + printf( "\n###### ===== MLME-Indication ==== ######\n" ); + printf( "STATUS : %s\n", EventInfoStatusStrings[mlmeIndication->Status] ); + } + if( mlmeIndication->Status != LORAMAC_EVENT_INFO_STATUS_OK ) + { + } + switch( mlmeIndication->MlmeIndication ) + { + case MLME_SCHEDULE_UPLINK: + {// The MAC signals that we shall provide an uplink as soon as possible + OnTxNextPacketTimerEvent( NULL ); + break; + } + default: + break; + } +} + +void OnMacProcessNotify( void ) +{ + IsMacProcessPending = 1; +} + +/** + * Main application entry point. + */ +/** 0: Band unknown, 1: LF band, 2: HF band */ +extern uint8_t sx1276_band; + +int lora_main( void ) +{ + LoRaMacPrimitives_t macPrimitives; + LoRaMacCallback_t macCallbacks; + MibRequestConfirm_t mibReq; + LoRaMacStatus_t status; + uint8_t devEui[8] = { 0 }; // Automatically filed from secure-element + uint8_t joinEui[8] = { 0 }; // Automatically filed from secure-element + uint8_t sePin[4] = { 0 }; // Automatically filed from secure-element + + sx1276_band = 2; + + BoardInitMcu( ); + BoardInitPeriph( ); + + macPrimitives.MacMcpsConfirm = McpsConfirm; + macPrimitives.MacMcpsIndication = McpsIndication; + macPrimitives.MacMlmeConfirm = MlmeConfirm; + macPrimitives.MacMlmeIndication = MlmeIndication; + macCallbacks.GetBatteryLevel = BoardGetBatteryLevel; + macCallbacks.GetTemperatureLevel = NULL; + macCallbacks.NvmContextChange = NvmCtxMgmtEvent; + macCallbacks.MacProcessNotify = OnMacProcessNotify; + + status = LoRaMacInitialization( &macPrimitives, &macCallbacks, ACTIVE_REGION ); + if ( status != LORAMAC_STATUS_OK ) + { + printf( "LoRaMac wasn't properly initialized, error: %s", MacStatusStrings[status] ); + // Fatal error, endless loop. + while ( 1 ) + { + } + } + + DeviceState = DEVICE_STATE_RESTORE; + + printf( "###### ===== ClassA demo application v1.0.0 ==== ######\n\n" ); + + while( 1 ) + { + // Process Radio IRQ + if( Radio.IrqProcess != NULL ) + { + Radio.IrqProcess( ); + } + // Processes the LoRaMac events + LoRaMacProcess( ); + + switch( DeviceState ) + { + case DEVICE_STATE_RESTORE: + { + // Try to restore from NVM and query the mac if possible. + if( NvmCtxMgmtRestore( ) == NVMCTXMGMT_STATUS_SUCCESS ) + { + printf( "\n###### ===== CTXS RESTORED ==== ######\n\n" ); + } + else + { + // Read secure-element DEV_EUI, JOI_EUI and SE_PIN values. + mibReq.Type = MIB_DEV_EUI; + LoRaMacMibGetRequestConfirm( &mibReq ); + memcpy1( devEui, mibReq.Param.DevEui, 8 ); + + mibReq.Type = MIB_JOIN_EUI; + LoRaMacMibGetRequestConfirm( &mibReq ); + memcpy1( joinEui, mibReq.Param.JoinEui, 8 ); + + mibReq.Type = MIB_SE_PIN; + LoRaMacMibGetRequestConfirm( &mibReq ); + memcpy1( sePin, mibReq.Param.SePin, 4 ); + +#if( OVER_THE_AIR_ACTIVATION == 0 ) + // Tell the MAC layer which network server version are we connecting too. + mibReq.Type = MIB_ABP_LORAWAN_VERSION; + mibReq.Param.AbpLrWanVersion.Value = ABP_ACTIVATION_LRWAN_VERSION; + LoRaMacMibSetRequestConfirm( &mibReq ); + + mibReq.Type = MIB_NET_ID; + mibReq.Param.NetID = LORAWAN_NETWORK_ID; + LoRaMacMibSetRequestConfirm( &mibReq ); + + // Choose a random device address if not already defined in Commissioning.h +#if( STATIC_DEVICE_ADDRESS != 1 ) + // Random seed initialization + srand1( BoardGetRandomSeed( ) ); + // Choose a random device address + DevAddr = randr( 0, 0x01FFFFFF ); +#endif + + mibReq.Type = MIB_DEV_ADDR; + mibReq.Param.DevAddr = DevAddr; + LoRaMacMibSetRequestConfirm( &mibReq ); +#endif // #if( OVER_THE_AIR_ACTIVATION == 0 ) + } + DeviceState = DEVICE_STATE_START; + break; + } + + case DEVICE_STATE_START: + { + TimerInit( &TxNextPacketTimer, OnTxNextPacketTimerEvent ); + + TimerInit( &Led1Timer, OnLed1TimerEvent ); + TimerSetValue( &Led1Timer, 25 ); + + TimerInit( &Led3Timer, OnLed3TimerEvent ); + TimerSetValue( &Led3Timer, 25 ); + + mibReq.Type = MIB_PUBLIC_NETWORK; + mibReq.Param.EnablePublicNetwork = LORAWAN_PUBLIC_NETWORK; + LoRaMacMibSetRequestConfirm( &mibReq ); + + mibReq.Type = MIB_ADR; + mibReq.Param.AdrEnable = LORAWAN_ADR_ON; + LoRaMacMibSetRequestConfirm( &mibReq ); + +#if defined( REGION_EU868 ) || defined( REGION_RU864 ) || defined( REGION_CN779 ) || defined( REGION_EU433 ) + LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON ); +#endif + mibReq.Type = MIB_SYSTEM_MAX_RX_ERROR; + mibReq.Param.SystemMaxRxError = 20; + LoRaMacMibSetRequestConfirm( &mibReq ); + + LoRaMacStart( ); + + mibReq.Type = MIB_NETWORK_ACTIVATION; + status = LoRaMacMibGetRequestConfirm( &mibReq ); + + if( status == LORAMAC_STATUS_OK ) + { + if( mibReq.Param.NetworkActivation == ACTIVATION_TYPE_NONE ) + { + DeviceState = DEVICE_STATE_JOIN; + } + else + { + DeviceState = DEVICE_STATE_SEND; + NextTx = true; + } + } + break; + } + case DEVICE_STATE_JOIN: + { + mibReq.Type = MIB_DEV_EUI; + LoRaMacMibGetRequestConfirm( &mibReq ); + printf( "DevEui : %02X", mibReq.Param.DevEui[0] ); + for( int i = 1; i < 8; i++ ) + { + printf( "-%02X", mibReq.Param.DevEui[i] ); + } + printf( "\n" ); + mibReq.Type = MIB_JOIN_EUI; + LoRaMacMibGetRequestConfirm( &mibReq ); + printf( "JoinEui : %02X", mibReq.Param.JoinEui[0] ); + for( int i = 1; i < 8; i++ ) + { + printf( "-%02X", mibReq.Param.JoinEui[i] ); + } + printf( "\n" ); + mibReq.Type = MIB_SE_PIN; + LoRaMacMibGetRequestConfirm( &mibReq ); + printf( "Pin : %02X", mibReq.Param.SePin[0] ); + for( int i = 1; i < 4; i++ ) + { + printf( "-%02X", mibReq.Param.SePin[i] ); + } + printf( "\n\n" ); +#if( OVER_THE_AIR_ACTIVATION == 0 ) + printf( "###### ===== JOINED ==== ######\n" ); + printf( "\nABP\n\n" ); + printf( "DevAddr : %08lX\n", DevAddr ); + printf( "\n\n" ); + + mibReq.Type = MIB_NETWORK_ACTIVATION; + mibReq.Param.NetworkActivation = ACTIVATION_TYPE_ABP; + LoRaMacMibSetRequestConfirm( &mibReq ); + + DeviceState = DEVICE_STATE_SEND; +#else + JoinNetwork( ); +#endif + break; + } + case DEVICE_STATE_SEND: + { + if( NextTx == true ) + { + PrepareTxFrame( AppPort ); + + NextTx = SendFrame( ); + } + DeviceState = DEVICE_STATE_CYCLE; + break; + } + case DEVICE_STATE_CYCLE: + { + DeviceState = DEVICE_STATE_SLEEP; + if( ComplianceTest.Running == true ) + { + // Schedule next packet transmission + TxDutyCycleTime = 5000; // 5000 ms + } + else + { + // Schedule next packet transmission + TxDutyCycleTime = APP_TX_DUTYCYCLE + randr( -APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND ); + } + + // Schedule next packet transmission + TimerSetValue( &TxNextPacketTimer, TxDutyCycleTime ); + TimerStart( &TxNextPacketTimer ); + break; + } + case DEVICE_STATE_SLEEP: + { + if( NvmCtxMgmtStore( ) == NVMCTXMGMT_STATUS_SUCCESS ) + { + printf( "\n###### ===== CTXS STORED ==== ######\n" ); + } + + CRITICAL_SECTION_BEGIN( ); + if( IsMacProcessPending == 1 ) + { + // Clear flag and prevent MCU to go into low power modes. + IsMacProcessPending = 0; + } + else + { + // The MCU wakes up through events + BoardLowPowerHandler( ); + } + CRITICAL_SECTION_END( ); + break; + } + default: + { + DeviceState = DEVICE_STATE_START; + break; + } + } + } +} diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/classA/at_parser.c b/board/RHF76_STM32L072CBxx_Lora/apps/classA/at_parser.c deleted file mode 100644 index 596eb593..00000000 --- a/board/RHF76_STM32L072CBxx_Lora/apps/classA/at_parser.c +++ /dev/null @@ -1,77 +0,0 @@ -#include "at_parser.h" -#include "uart-board.h" - -#ifndef AT_CMD_BUF_LEN -#define AT_CMD_BUF_LEN 512 -#endif - -#ifndef UART_RECV_TIMEOUT -#define UART_RECV_TIMEOUT 15000 -#endif - -static at_uart_ops_t *uart_ops; -static at_table_t *cmd_table; - -int at_parser_init(at_uart_ops_t *ops, at_table_t *table) -{ - if (ops && table) - { - uart_ops = ops; - cmd_table = table; - - if(ops->init) - return ops->init(); - else - return 0; - } - else - return -1; -} - -int at_cmd_handle(void) -{ - uint8_t tmp_buf[AT_CMD_BUF_LEN]; - uint16_t len = 0, i; - uint32_t n = 0; - uint16_t cmd_len = 0; - - if(!uart_ops || !cmd_table) - return -1; - - /*收到\r\n或超时,接收完成*/ - while(n++ < UART_RECV_TIMEOUT) - { - if(uart_ops->recv(tmp_buf+len, 1) == 1) - { - len++; - n = 0; - } - } - - /*指令结束标志*/ - if(tmp_buf[len-2] == 0x0D/*'\r'*/ && tmp_buf[len-1] == 0x0A/*'\n'*/) - { - /*长度不包含\r\n*/ - len -= 2; - } - - /*查询AT指令,并执行*/ - for(i = 0; cmd_table[i].cmd; i++) - { - cmd_len = strlen(cmd_table[i].cmd); - if(len >= cmd_len) - { - #ifdef AT_IGNORE_CASE - if(strncasecmp((const char*)cmd_table[i].cmd, (const char*)tmp_buf, cmd_len) == 0) - #else - if(memcmp((const char*)cmd_table[i].cmd, (const char*)tmp_buf, cmd_len) == 0) - #endif - { - /*将=后的参数输入*/ - return cmd_table[i].func(tmp_buf + cmd_len, len - cmd_len); - } - } - } - - return -1; -} diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/classA/at_parser.h b/board/RHF76_STM32L072CBxx_Lora/apps/classA/at_parser.h deleted file mode 100644 index 1cf6b7de..00000000 --- a/board/RHF76_STM32L072CBxx_Lora/apps/classA/at_parser.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef __AT_PARSER_H__ -#define __AT_PARSER_H__ - -#include -#include - -#define AT_CMD_END NULL - -//#define AT_IGNORE_CASE - -/* - * Please declare and register command table as follow before call - * at_cmd_handle. - * NOTE. Add AT_CMD_END as last member to mark the end of command. - * All receive text behind command text would be treated as data text - * pass to func. - * - * at_table_t cmd_table[] = { - * {"AT+VERSION=", ver_handle}, - * {"AT+RESET", reset_handle}, - * ... - * {AT_CMD_END, NULL}, - * }; - */ - -typedef struct -{ - const char *cmd; /* 命令文本 */ - uint8_t (*func)(uint8_t *, uint16_t size); /* 命令处理函数 */ -} at_table_t; - -/* - * Please declare and register uart operations so that AT parser is - * able to receive text from uart. - * - * at_uart_ops_t uart_ops = { - * .init = NULL, - * .deinit = NULL, - * .send = NULL, - * .recv = UartReceive, - * .recv_timeout = UartReceive, - * }; - */ -typedef struct -{ - uint8_t (*init)(void); - uint8_t (*deinit)(void); - uint16_t (*send)(uint8_t *buf, uint16_t size); - uint16_t (*recv)(uint8_t *buf, uint16_t buf_len); - uint16_t (*recv_timeout)(uint8_t *buf, uint16_t buf_len); -}at_uart_ops_t; - -int at_parser_init(at_uart_ops_t *uart_ops, at_table_t *cmd_table); -int at_cmd_handle(void); - -#endif diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/classA/main.c b/board/RHF76_STM32L072CBxx_Lora/apps/classA/main.c index e1cb8355..ac53ba6c 100644 --- a/board/RHF76_STM32L072CBxx_Lora/apps/classA/main.c +++ b/board/RHF76_STM32L072CBxx_Lora/apps/classA/main.c @@ -1,98 +1,35 @@ -#include "LoRaApi.h" #include #include #include "tos_k.h" -#include "atcmd-board.h" -/*LORA入网状态*/ -uint8_t g_join_state = 0; -uint8_t g_st_state = 0; -/*报文计数*/ -uint32_t g_rx_num = 0; -//任务优先级 -#define TASK1_PRIO 3 -//任务堆栈大小 -#define TASK1_STK_SIZE (1024 * 4) -//任务控制块 -k_task_t Task1TCB; -//任务堆栈 -k_stack_t TASK1_STK[TASK1_STK_SIZE]; -//任务函数 -void task1(void *arg); -void lora_send_timer(void* context) +k_task_t task1; +k_stack_t task1_stack[4096]; + +extern int lora_main(void); +void task1_fun(void *arg) { - g_st_state =2; -} -void task1(void *arg) -{ - at_cmd_init(); - LoRa_Init(); - printf_device_info(); - TimerInit( &TxNextPacketTimer, lora_send_timer ); - while(1) - { - LoRaMacProcess(); - if(g_join_state == 0) - { - printf("start join...\r\n"); - /*入网*/ - LoRa_JoinNetwork(1); - g_join_state = 1; - } - if(g_join_state == 2) - { - /*入网后定时发送数据*/ - if(g_st_state == 0) - { - g_st_state = 1; - TimerSetValue( &TxNextPacketTimer, 60000 ); - TimerStart( &TxNextPacketTimer); - printf("\r\ntime to "); - } - else if(g_st_state == 2) - { - g_st_state = 3; - printf("send!\r\n"); - /*发送lora数据*/ - uint8_t tmpbuf[] = "tos tiny!"; - Lora_Send(0, 2, tmpbuf, sizeof(tmpbuf)); - g_rx_num++; - } - } - at_cmd_handle(); - } + lora_main(); } -extern uint8_t sx1276_band; int main(void) { k_err_t err; TOS_CPU_CPSR_ALLOC(); - BoardInitMcu( ); - BoardInitPeriph( ); - sx1276_band = 2; - printf("welcome to tencent IoTOS\r\n"); - err = tos_knl_init(); //初始化TOS - if (err != K_ERR_NONE) - { - printf("tos init failed\r\n"); - return err; - } - TOS_CPU_INT_DISABLE();//进入临界区 - err = tos_task_create((k_task_t * )&Task1TCB, //任务控制块 - (char * )"task1", //任务名字 - (k_task_entry_t )task1, //任务函数 - (void * )0, //传递给任务函数的参数 - (k_prio_t )TASK1_PRIO, //任务优先级 - TASK1_STK, //任务堆栈基地址 - (size_t)TASK1_STK_SIZE, //任务堆栈大小 - (size_t )0); //当使能时间片轮转时的时间片长度,为0时为默认长度, + printf("Welcome to TencentOS Tiny! \r\n"); + tos_knl_init(); + TOS_CPU_INT_DISABLE(); + err = tos_task_create(&task1, + "task1", + task1_fun, + NULL, + 3, + task1_stack, + 4096, + 20); + if(err != K_ERR_NONE) + printf("TencentOS Tiny Create task1 fail! code : %d \r\n",err); - TOS_CPU_INT_ENABLE(); //退出临界区 - tos_knl_start(); //开启TOS - while (1) - { - - } + TOS_CPU_INT_ENABLE(); + tos_knl_start(); } diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/common/CayenneLpp.c b/board/RHF76_STM32L072CBxx_Lora/apps/common/CayenneLpp.c new file mode 100644 index 00000000..ceb2fcd3 --- /dev/null +++ b/board/RHF76_STM32L072CBxx_Lora/apps/common/CayenneLpp.c @@ -0,0 +1,257 @@ +/*! + * \file CayenneLpp.c + * + * \brief Implements the Cayenne Low Power Protocol + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2018 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + */ +#include + +#include "utilities.h" +#include "CayenneLpp.h" + +#define CAYENNE_LPP_MAXBUFFER_SIZE 242 + +static uint8_t CayenneLppBuffer[CAYENNE_LPP_MAXBUFFER_SIZE]; +static uint8_t CayenneLppCursor = 0; + +void CayenneLppInit( void ) +{ + CayenneLppCursor = 0; +} + +void CayenneLppReset( void ) +{ + CayenneLppCursor = 0; +} + +uint8_t CayenneLppGetSize( void ) +{ + return CayenneLppCursor; +} + +uint8_t* CayenneLppGetBuffer( void ) +{ + return CayenneLppBuffer; +} + +uint8_t CayenneLppCopy( uint8_t* dst ) +{ + memcpy1( dst, CayenneLppBuffer, CayenneLppCursor ); + + return CayenneLppCursor; +} + + +uint8_t CayenneLppAddDigitalInput( uint8_t channel, uint8_t value ) +{ + if( ( CayenneLppCursor + LPP_DIGITAL_INPUT_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) + { + return 0; + } + CayenneLppBuffer[CayenneLppCursor++] = channel; + CayenneLppBuffer[CayenneLppCursor++] = LPP_DIGITAL_INPUT; + CayenneLppBuffer[CayenneLppCursor++] = value; + + return CayenneLppCursor; +} + +uint8_t CayenneLppAddDigitalOutput( uint8_t channel, uint8_t value ) +{ + if( ( CayenneLppCursor + LPP_DIGITAL_OUTPUT_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) + { + return 0; + } + CayenneLppBuffer[CayenneLppCursor++] = channel; + CayenneLppBuffer[CayenneLppCursor++] = LPP_DIGITAL_OUTPUT; + CayenneLppBuffer[CayenneLppCursor++] = value; + + return CayenneLppCursor; +} + + +uint8_t CayenneLppAddAnalogInput( uint8_t channel, float value ) +{ + if( ( CayenneLppCursor + LPP_ANALOG_INPUT_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) + { + return 0; + } + + int16_t val = value * 100; + CayenneLppBuffer[CayenneLppCursor++] = channel; + CayenneLppBuffer[CayenneLppCursor++] = LPP_ANALOG_INPUT; + CayenneLppBuffer[CayenneLppCursor++] = val >> 8; + CayenneLppBuffer[CayenneLppCursor++] = val; + + return CayenneLppCursor; +} + +uint8_t CayenneLppAddAnalogOutput( uint8_t channel, float value ) +{ + if( ( CayenneLppCursor + LPP_ANALOG_OUTPUT_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) + { + return 0; + } + int16_t val = value * 100; + CayenneLppBuffer[CayenneLppCursor++] = channel; + CayenneLppBuffer[CayenneLppCursor++] = LPP_ANALOG_OUTPUT; + CayenneLppBuffer[CayenneLppCursor++] = val >> 8; + CayenneLppBuffer[CayenneLppCursor++] = val; + + return CayenneLppCursor; +} + + +uint8_t CayenneLppAddLuminosity( uint8_t channel, uint16_t lux ) +{ + if( ( CayenneLppCursor + LPP_LUMINOSITY_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) + { + return 0; + } + CayenneLppBuffer[CayenneLppCursor++] = channel; + CayenneLppBuffer[CayenneLppCursor++] = LPP_LUMINOSITY; + CayenneLppBuffer[CayenneLppCursor++] = lux >> 8; + CayenneLppBuffer[CayenneLppCursor++] = lux; + + return CayenneLppCursor; +} + +uint8_t CayenneLppAddPresence( uint8_t channel, uint8_t value ) +{ + if( ( CayenneLppCursor + LPP_PRESENCE_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) + { + return 0; + } + CayenneLppBuffer[CayenneLppCursor++] = channel; + CayenneLppBuffer[CayenneLppCursor++] = LPP_PRESENCE; + CayenneLppBuffer[CayenneLppCursor++] = value; + + return CayenneLppCursor; +} + +uint8_t CayenneLppAddTemperature( uint8_t channel, float celsius ) +{ + if( ( CayenneLppCursor + LPP_TEMPERATURE_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) + { + return 0; + } + int16_t val = celsius * 10; + CayenneLppBuffer[CayenneLppCursor++] = channel; + CayenneLppBuffer[CayenneLppCursor++] = LPP_TEMPERATURE; + CayenneLppBuffer[CayenneLppCursor++] = val >> 8; + CayenneLppBuffer[CayenneLppCursor++] = val; + + return CayenneLppCursor; +} + +uint8_t CayenneLppAddRelativeHumidity( uint8_t channel, float rh ) +{ + if( ( CayenneLppCursor + LPP_RELATIVE_HUMIDITY_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) + { + return 0; + } + CayenneLppBuffer[CayenneLppCursor++] = channel; + CayenneLppBuffer[CayenneLppCursor++] = LPP_RELATIVE_HUMIDITY; + CayenneLppBuffer[CayenneLppCursor++] = rh * 2; + + return CayenneLppCursor; +} + +uint8_t CayenneLppAddAccelerometer( uint8_t channel, float x, float y, float z ) +{ + if( ( CayenneLppCursor + LPP_ACCELEROMETER_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) + { + return 0; + } + int16_t vx = x * 1000; + int16_t vy = y * 1000; + int16_t vz = z * 1000; + + CayenneLppBuffer[CayenneLppCursor++] = channel; + CayenneLppBuffer[CayenneLppCursor++] = LPP_ACCELEROMETER; + CayenneLppBuffer[CayenneLppCursor++] = vx >> 8; + CayenneLppBuffer[CayenneLppCursor++] = vx; + CayenneLppBuffer[CayenneLppCursor++] = vy >> 8; + CayenneLppBuffer[CayenneLppCursor++] = vy; + CayenneLppBuffer[CayenneLppCursor++] = vz >> 8; + CayenneLppBuffer[CayenneLppCursor++] = vz; + + return CayenneLppCursor; +} + +uint8_t CayenneLppAddBarometricPressure( uint8_t channel, float hpa ) +{ + if( ( CayenneLppCursor + LPP_BAROMETRIC_PRESSURE_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) + { + return 0; + } + int16_t val = hpa * 10; + + CayenneLppBuffer[CayenneLppCursor++] = channel; + CayenneLppBuffer[CayenneLppCursor++] = LPP_BAROMETRIC_PRESSURE; + CayenneLppBuffer[CayenneLppCursor++] = val >> 8; + CayenneLppBuffer[CayenneLppCursor++] = val; + + return CayenneLppCursor; +} + +uint8_t CayenneLppAddGyrometer( uint8_t channel, float x, float y, float z ) +{ + if( ( CayenneLppCursor + LPP_GYROMETER_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) + { + return 0; + } + int16_t vx = x * 100; + int16_t vy = y * 100; + int16_t vz = z * 100; + + CayenneLppBuffer[CayenneLppCursor++] = channel; + CayenneLppBuffer[CayenneLppCursor++] = LPP_GYROMETER; + CayenneLppBuffer[CayenneLppCursor++] = vx >> 8; + CayenneLppBuffer[CayenneLppCursor++] = vx; + CayenneLppBuffer[CayenneLppCursor++] = vy >> 8; + CayenneLppBuffer[CayenneLppCursor++] = vy; + CayenneLppBuffer[CayenneLppCursor++] = vz >> 8; + CayenneLppBuffer[CayenneLppCursor++] = vz; + + return CayenneLppCursor; +} + +uint8_t CayenneLppAddGps( uint8_t channel, float latitude, float longitude, float meters ) +{ + if( ( CayenneLppCursor + LPP_GPS_SIZE ) > CAYENNE_LPP_MAXBUFFER_SIZE ) + { + return 0; + } + int32_t lat = latitude * 10000; + int32_t lon = longitude * 10000; + int32_t alt = meters * 100; + + CayenneLppBuffer[CayenneLppCursor++] = channel; + CayenneLppBuffer[CayenneLppCursor++] = LPP_GPS; + + CayenneLppBuffer[CayenneLppCursor++] = lat >> 16; + CayenneLppBuffer[CayenneLppCursor++] = lat >> 8; + CayenneLppBuffer[CayenneLppCursor++] = lat; + CayenneLppBuffer[CayenneLppCursor++] = lon >> 16; + CayenneLppBuffer[CayenneLppCursor++] = lon >> 8; + CayenneLppBuffer[CayenneLppCursor++] = lon; + CayenneLppBuffer[CayenneLppCursor++] = alt >> 16; + CayenneLppBuffer[CayenneLppCursor++] = alt >> 8; + CayenneLppBuffer[CayenneLppCursor++] = alt; + + return CayenneLppCursor; +} diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/common/CayenneLpp.h b/board/RHF76_STM32L072CBxx_Lora/apps/common/CayenneLpp.h new file mode 100644 index 00000000..502a0c30 --- /dev/null +++ b/board/RHF76_STM32L072CBxx_Lora/apps/common/CayenneLpp.h @@ -0,0 +1,76 @@ +/*! + * \file CayenneLpp.h + * + * \brief Implements the Cayenne Low Power Protocol + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2018 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + */ +#ifndef __CAYENNE_LPP_H__ +#define __CAYENNE_LPP_H__ + +#include + +#define LPP_DIGITAL_INPUT 0 // 1 byte +#define LPP_DIGITAL_OUTPUT 1 // 1 byte +#define LPP_ANALOG_INPUT 2 // 2 bytes, 0.01 signed +#define LPP_ANALOG_OUTPUT 3 // 2 bytes, 0.01 signed +#define LPP_LUMINOSITY 101 // 2 bytes, 1 lux unsigned +#define LPP_PRESENCE 102 // 1 byte, 1 +#define LPP_TEMPERATURE 103 // 2 bytes, 0.1掳C signed +#define LPP_RELATIVE_HUMIDITY 104 // 1 byte, 0.5% unsigned +#define LPP_ACCELEROMETER 113 // 2 bytes per axis, 0.001G +#define LPP_BAROMETRIC_PRESSURE 115 // 2 bytes 0.1 hPa Unsigned +#define LPP_GYROMETER 134 // 2 bytes per axis, 0.01 掳/s +#define LPP_GPS 136 // 3 byte lon/lat 0.0001 掳, 3 bytes alt 0.01m + + +// Data ID + Data Type + Data Size +#define LPP_DIGITAL_INPUT_SIZE 3 +#define LPP_DIGITAL_OUTPUT_SIZE 3 +#define LPP_ANALOG_INPUT_SIZE 4 +#define LPP_ANALOG_OUTPUT_SIZE 4 +#define LPP_LUMINOSITY_SIZE 4 +#define LPP_PRESENCE_SIZE 3 +#define LPP_TEMPERATURE_SIZE 4 +#define LPP_RELATIVE_HUMIDITY_SIZE 3 +#define LPP_ACCELEROMETER_SIZE 8 +#define LPP_BAROMETRIC_PRESSURE_SIZE 4 +#define LPP_GYROMETER_SIZE 8 +#define LPP_GPS_SIZE 11 + +void CayenneLppInit( void ); + +void CayenneLppReset( void ); +uint8_t CayenneLppGetSize( void ); +uint8_t* CayenneLppGetBuffer( void ); +uint8_t CayenneLppCopy( uint8_t* buffer ); + +uint8_t CayenneLppAddDigitalInput( uint8_t channel, uint8_t value ); +uint8_t CayenneLppAddDigitalOutput( uint8_t channel, uint8_t value ); + +uint8_t CayenneLppAddAnalogInput( uint8_t channel, float value ); +uint8_t CayenneLppAddAnalogOutput( uint8_t channel, float value ); + +uint8_t CayenneLppAddLuminosity( uint8_t channel, uint16_t lux ); +uint8_t CayenneLppAddPresence( uint8_t channel, uint8_t value ); +uint8_t CayenneLppAddTemperature( uint8_t channel, float celsius ); +uint8_t CayenneLppAddRelativeHumidity( uint8_t channel, float rh ); +uint8_t CayenneLppAddAccelerometer( uint8_t channel, float x, float y, float z ); +uint8_t CayenneLppAddBarometricPressure( uint8_t channel, float hpa ); +uint8_t CayenneLppAddGyrometer( uint8_t channel, float x, float y, float z ); +uint8_t CayenneLppAddGps( uint8_t channel, float latitude, float longitude, float meters ); + +#endif // __CAYENNE_LPP_H__ diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/LmHandler.c b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/LmHandler.c new file mode 100644 index 00000000..643317c1 --- /dev/null +++ b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/LmHandler.c @@ -0,0 +1,1011 @@ +/*! + * \file LmHandler.c + * + * \brief Implements the LoRaMac layer handling. + * Provides the possibility to register applicative packages. + * + * \remark Inspired by the examples provided on the en.i-cube_lrwan fork. + * MCD Application Team ( STMicroelectronics International ) + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2018 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + */ +#include +#include +#include +#include "utilities.h" +#include "timer.h" +#include "Commissioning.h" +#include "NvmCtxMgmt.h" +#include "LmHandler.h" +#include "LmhPackage.h" +#include "LmhpCompliance.h" +#include "LmhpClockSync.h" +#include "LmhpRemoteMcastSetup.h" +#include "LmhpFragmentation.h" + +#ifndef ACTIVE_REGION + +#warning "No active region defined, LORAMAC_REGION_EU868 will be used as default." + +#define ACTIVE_REGION LORAMAC_REGION_EU868 + +#endif + +#include "LoRaMacTest.h" + +static CommissioningParams_t CommissioningParams = +{ + .IsOtaaActivation = OVER_THE_AIR_ACTIVATION, + .DevEui = { 0 }, // Automatically filed from secure-element + .JoinEui = { 0 }, // Automatically filed from secure-element + .SePin = { 0 }, // Automatically filed from secure-element + .NetworkId = LORAWAN_NETWORK_ID, + .DevAddr = LORAWAN_DEVICE_ADDRESS, +}; + +static LmhPackage_t *LmHandlerPackages[PKG_MAX_NUMBER]; + +/*! + * Upper layer LoRaMac parameters + */ +static LmHandlerParams_t *LmHandlerParams; + +/*! + * Upper layer callbacks + */ +static LmHandlerCallbacks_t *LmHandlerCallbacks; + +/*! + * Used to notify LmHandler of LoRaMac events + */ +static LoRaMacPrimitives_t LoRaMacPrimitives; + +/*! + * LoRaMac callbacks + */ +static LoRaMacCallback_t LoRaMacCallbacks; + +static LmHandlerJoinParams_t JoinParams = +{ + .CommissioningParams = &CommissioningParams, + .Datarate = DR_0, + .Status = LORAMAC_HANDLER_ERROR +}; + +static LmHandlerTxParams_t TxParams = +{ + .CommissioningParams = &CommissioningParams, + .MsgType = LORAMAC_HANDLER_UNCONFIRMED_MSG, + .AckReceived = 0, + .Datarate = DR_0, + .UplinkCounter = 0, + .AppData = + { + .Port = 0, + .BufferSize = 0, + .Buffer = NULL + }, + .TxPower = TX_POWER_0, + .Channel = 0 +}; + +static LmHandlerRxParams_t RxParams = +{ + .CommissioningParams = &CommissioningParams, + .Rssi = 0, + .Snr = 0, + .DownlinkCounter = 0, + .RxSlot = -1 +}; + +static LoRaMAcHandlerBeaconParams_t BeaconParams = +{ + .State = LORAMAC_HANDLER_BEACON_ACQUIRING, + .Info = + { + .Time = { .Seconds = 0, .SubSeconds = 0 }, + .Frequency = 0, + .Datarate = 0, + .Rssi = 0, + .Snr = 0, + .GwSpecific = + { + .InfoDesc = 0, + .Info = { 0 } + } + } +}; + +/*! + * Indicates if a switch to Class B operation is pending or not. + * + * TODO: Create a new structure to store the current handler states/status + * and add the below variable to it. + */ +static bool IsClassBSwitchPending = false; + +/*! + * \brief MCPS-Confirm event function + * + * \param [IN] mcpsConfirm - Pointer to the confirm structure, + * containing confirm attributes. + */ +static void McpsConfirm( McpsConfirm_t *mcpsConfirm ); + +/*! + * \brief MCPS-Indication event function + * + * \param [IN] mcpsIndication - Pointer to the indication structure, + * containing indication attributes. + */ +static void McpsIndication( McpsIndication_t *mcpsIndication ); + +/*! + * \brief MLME-Confirm event function + * + * \param [IN] MlmeConfirm - Pointer to the confirm structure, + * containing confirm attributes. + */ +static void MlmeConfirm( MlmeConfirm_t *mlmeConfirm ); + +/*! + * \brief MLME-Indication event function + * + * \param [IN] mlmeIndication - Pointer to the indication structure, + * containing indication attributes. + */ +static void MlmeIndication( MlmeIndication_t *mlmeIndication ); + +/*! + * Requests network server time update + * + * \retval status Returns \ref LORAMAC_HANDLER_SET if joined else \ref LORAMAC_HANDLER_RESET + */ +static LmHandlerErrorStatus_t LmHandlerDeviceTimeReq( void ); + +/*! + * Starts the beacon search + * + * \retval status Returns \ref LORAMAC_HANDLER_SET if joined else \ref LORAMAC_HANDLER_RESET + */ +static LmHandlerErrorStatus_t LmHandlerBeaconReq( void ); + +/* + *============================================================================= + * PACKAGES HANDLING + *============================================================================= + */ +typedef enum PackageNotifyTypes_e +{ + PACKAGE_MCPS_CONFIRM, + PACKAGE_MCPS_INDICATION, + PACKAGE_MLME_CONFIRM, + PACKAGE_MLME_INDICATION, +}PackageNotifyTypes_t; + +/*! + * Notifies the package to process the LoRaMac callbacks. + * + * \param [IN] notifyType MAC notification type [PACKAGE_MCPS_CONFIRM, + * PACKAGE_MCPS_INDICATION, + * PACKAGE_MLME_CONFIRM, + * PACKAGE_MLME_INDICATION] + * \param[IN] params Notification parameters. The params type can be + * [McpsConfirm_t, McpsIndication_t, MlmeConfirm_t, MlmeIndication_t] + */ +static void LmHandlerPackagesNotify( PackageNotifyTypes_t notifyType, void *params ); + +static void LmHandlerPackagesProcess( void ); + +LmHandlerErrorStatus_t LmHandlerInit( LmHandlerCallbacks_t *handlerCallbacks, + LmHandlerParams_t *handlerParams ) +{ + // + MibRequestConfirm_t mibReq; + LmHandlerParams = handlerParams; + LmHandlerCallbacks = handlerCallbacks; + + LoRaMacPrimitives.MacMcpsConfirm = McpsConfirm; + LoRaMacPrimitives.MacMcpsIndication = McpsIndication; + LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm; + LoRaMacPrimitives.MacMlmeIndication = MlmeIndication; + LoRaMacCallbacks.GetBatteryLevel = LmHandlerCallbacks->GetBatteryLevel; + LoRaMacCallbacks.GetTemperatureLevel = LmHandlerCallbacks->GetTemperature; + LoRaMacCallbacks.NvmContextChange = NvmCtxMgmtEvent; + LoRaMacCallbacks.MacProcessNotify = LmHandlerCallbacks->OnMacProcess; + + IsClassBSwitchPending = false; + + if( LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks, LmHandlerParams->Region ) != LORAMAC_STATUS_OK ) + { + return LORAMAC_HANDLER_ERROR; + } + + // Try to restore from NVM and query the mac if possible. + if( NvmCtxMgmtRestore( ) == NVMCTXMGMT_STATUS_SUCCESS ) + { + LmHandlerCallbacks->OnNvmContextChange( LORAMAC_HANDLER_NVM_RESTORE ); + } + else + { + // Read secure-element DEV_EUI, JOI_EUI and SE_PIN values. + mibReq.Type = MIB_DEV_EUI; + LoRaMacMibGetRequestConfirm( &mibReq ); + memcpy1( CommissioningParams.DevEui, mibReq.Param.DevEui, 8 ); + + mibReq.Type = MIB_JOIN_EUI; + LoRaMacMibGetRequestConfirm( &mibReq ); + memcpy1( CommissioningParams.JoinEui, mibReq.Param.JoinEui, 8 ); + + mibReq.Type = MIB_SE_PIN; + LoRaMacMibGetRequestConfirm( &mibReq ); + memcpy1( CommissioningParams.SePin, mibReq.Param.SePin, 4 ); + +#if( OVER_THE_AIR_ACTIVATION == 0 ) + // Tell the MAC layer which network server version are we connecting too. + mibReq.Type = MIB_ABP_LORAWAN_VERSION; + mibReq.Param.AbpLrWanVersion.Value = ABP_ACTIVATION_LRWAN_VERSION; + LoRaMacMibSetRequestConfirm( &mibReq ); + + mibReq.Type = MIB_NET_ID; + mibReq.Param.NetID = LORAWAN_NETWORK_ID; + LoRaMacMibSetRequestConfirm( &mibReq ); + +#if( STATIC_DEVICE_ADDRESS != 1 ) + // Random seed initialization + srand1( LmHandlerCallbacks->GetRandomSeed( ) ); + // Choose a random device address + CommissioningParams.DevAddr = randr( 0, 0x01FFFFFF ); +#endif + + mibReq.Type = MIB_DEV_ADDR; + mibReq.Param.DevAddr = CommissioningParams.DevAddr; + LoRaMacMibSetRequestConfirm( &mibReq ); +#endif // #if( OVER_THE_AIR_ACTIVATION == 0 ) + } + mibReq.Type = MIB_PUBLIC_NETWORK; + mibReq.Param.EnablePublicNetwork = LmHandlerParams->PublicNetworkEnable; + LoRaMacMibSetRequestConfirm( &mibReq ); + + mibReq.Type = MIB_ADR; + mibReq.Param.AdrEnable = LmHandlerParams->AdrEnable; + LoRaMacMibSetRequestConfirm( &mibReq ); + + LoRaMacTestSetDutyCycleOn( LmHandlerParams->DutyCycleEnabled ); + + LoRaMacStart( ); + + mibReq.Type = MIB_NETWORK_ACTIVATION; + if( LoRaMacMibGetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK ) + { + if( mibReq.Param.NetworkActivation == ACTIVATION_TYPE_NONE ) + { + LmHandlerCallbacks->OnNetworkParametersChange( &CommissioningParams ); + } + } + return LORAMAC_HANDLER_SUCCESS; +} + +bool LmHandlerIsBusy( void ) +{ + if( LoRaMacIsBusy( ) == true ) + { + return true; + } + if( LmHandlerJoinStatus( ) != LORAMAC_HANDLER_SET ) + { + // The network isn't yet joined, try again later. + LmHandlerJoin( ); + return true; + } + + if( LmHandlerPackages[PACKAGE_ID_COMPLIANCE]->IsRunning( ) == true ) + { + return true; + } + return false; +} + +void LmHandlerProcess( void ) +{ + // Process Radio IRQ + if( Radio.IrqProcess != NULL ) + { + Radio.IrqProcess( ); + } + + // Processes the LoRaMac events + LoRaMacProcess( ); + + // Call all packages process functions + LmHandlerPackagesProcess( ); + + if( NvmCtxMgmtStore( ) == NVMCTXMGMT_STATUS_SUCCESS ) + { + LmHandlerCallbacks->OnNvmContextChange( LORAMAC_HANDLER_NVM_STORE ); + } +} + +/*! + * Join a LoRa Network in classA + * + * \Note if the device is ABP, this is a pass through function + * + * \param [IN] isOtaa Indicates which activation mode must be used + */ +static void LmHandlerJoinRequest( bool isOtaa ) +{ + if( isOtaa == true ) + { + MlmeReq_t mlmeReq; + + mlmeReq.Type = MLME_JOIN; + mlmeReq.Req.Join.Datarate = LmHandlerParams->TxDatarate; + // Update commissioning parameters activation type variable. + CommissioningParams.IsOtaaActivation = true; + + // Starts the OTAA join procedure + LmHandlerCallbacks->OnMacMlmeRequest( LoRaMacMlmeRequest( &mlmeReq ), &mlmeReq, mlmeReq.ReqReturn.DutyCycleWaitTime ); + } + else + { + MibRequestConfirm_t mibReq; + LmHandlerJoinParams_t joinParams = + { + .CommissioningParams = &CommissioningParams, + .Datarate = LmHandlerParams->TxDatarate, + .Status = LORAMAC_HANDLER_SUCCESS + }; + + mibReq.Type = MIB_NETWORK_ACTIVATION; + mibReq.Param.NetworkActivation = ACTIVATION_TYPE_ABP; + LoRaMacMibSetRequestConfirm( &mibReq ); + + // Notify upper layer + LmHandlerCallbacks->OnJoinRequest( &joinParams ); + } +} + +void LmHandlerJoin( void ) +{ + LmHandlerJoinRequest( CommissioningParams.IsOtaaActivation ); +} + +LmHandlerFlagStatus_t LmHandlerJoinStatus( void ) +{ + MibRequestConfirm_t mibReq; + LoRaMacStatus_t status; + + mibReq.Type = MIB_NETWORK_ACTIVATION; + status = LoRaMacMibGetRequestConfirm( &mibReq ); + + if( status == LORAMAC_STATUS_OK ) + { + if( mibReq.Param.NetworkActivation == ACTIVATION_TYPE_NONE ) + { + return LORAMAC_HANDLER_RESET; + } + else + { + return LORAMAC_HANDLER_SET; + } + } + else + { + return LORAMAC_HANDLER_RESET; + } +} + +LmHandlerErrorStatus_t LmHandlerSend( LmHandlerAppData_t *appData, LmHandlerMsgTypes_t isTxConfirmed ) +{ + LoRaMacStatus_t status; + McpsReq_t mcpsReq; + LoRaMacTxInfo_t txInfo; + + if( LmHandlerJoinStatus( ) != LORAMAC_HANDLER_SET ) + { + // The network isn't joined, try again. + LmHandlerJoinRequest( CommissioningParams.IsOtaaActivation ); + return LORAMAC_HANDLER_ERROR; + } + + if( ( LmHandlerPackages[PACKAGE_ID_COMPLIANCE]->IsRunning( ) == true ) && ( appData->Port != LmHandlerPackages[PACKAGE_ID_COMPLIANCE]->Port ) && ( appData->Port != 0 ) ) + { + return LORAMAC_HANDLER_ERROR; + } + + mcpsReq.Req.Unconfirmed.Datarate = LmHandlerParams->TxDatarate; + if( LoRaMacQueryTxPossible( appData->BufferSize, &txInfo ) != LORAMAC_STATUS_OK ) + { + // Send empty frame in order to flush MAC commands + TxParams.MsgType = LORAMAC_HANDLER_UNCONFIRMED_MSG; + mcpsReq.Type = MCPS_UNCONFIRMED; + mcpsReq.Req.Unconfirmed.fBuffer = NULL; + mcpsReq.Req.Unconfirmed.fBufferSize = 0; + } + else + { + TxParams.MsgType = isTxConfirmed; + mcpsReq.Req.Unconfirmed.fPort = appData->Port; + mcpsReq.Req.Unconfirmed.fBufferSize = appData->BufferSize; + mcpsReq.Req.Unconfirmed.fBuffer = appData->Buffer; + if( isTxConfirmed == LORAMAC_HANDLER_UNCONFIRMED_MSG ) + { + mcpsReq.Type = MCPS_UNCONFIRMED; + } + else + { + mcpsReq.Type = MCPS_CONFIRMED; + mcpsReq.Req.Confirmed.NbTrials = 8; + } + } + + TxParams.AppData = *appData; + TxParams.Datarate = LmHandlerParams->TxDatarate; + + status = LoRaMacMcpsRequest( &mcpsReq ); + LmHandlerCallbacks->OnMacMcpsRequest( status, &mcpsReq, mcpsReq.ReqReturn.DutyCycleWaitTime ); + + if( status == LORAMAC_STATUS_OK ) + { + return LORAMAC_HANDLER_SUCCESS; + } + else + { + return LORAMAC_HANDLER_ERROR; + } +} + +static LmHandlerErrorStatus_t LmHandlerDeviceTimeReq( void ) +{ + LoRaMacStatus_t status; + MlmeReq_t mlmeReq; + + mlmeReq.Type = MLME_DEVICE_TIME; + + status = LoRaMacMlmeRequest( &mlmeReq ); + LmHandlerCallbacks->OnMacMlmeRequest( status, &mlmeReq, mlmeReq.ReqReturn.DutyCycleWaitTime ); + + if( status == LORAMAC_STATUS_OK ) + { + return LORAMAC_HANDLER_SUCCESS; + } + else + { + return LORAMAC_HANDLER_ERROR; + } +} + +static LmHandlerErrorStatus_t LmHandlerBeaconReq( void ) +{ + LoRaMacStatus_t status; + MlmeReq_t mlmeReq; + + mlmeReq.Type = MLME_BEACON_ACQUISITION; + + status = LoRaMacMlmeRequest( &mlmeReq ); + LmHandlerCallbacks->OnMacMlmeRequest( status, &mlmeReq, mlmeReq.ReqReturn.DutyCycleWaitTime ); + + if( status == LORAMAC_STATUS_OK ) + { + return LORAMAC_HANDLER_SUCCESS; + } + else + { + return LORAMAC_HANDLER_ERROR; + } +} + +LmHandlerErrorStatus_t LmHandlerPingSlotReq( uint8_t periodicity ) +{ + LoRaMacStatus_t status; + MlmeReq_t mlmeReq; + + mlmeReq.Type = MLME_PING_SLOT_INFO; + mlmeReq.Req.PingSlotInfo.PingSlot.Fields.Periodicity = periodicity; + mlmeReq.Req.PingSlotInfo.PingSlot.Fields.RFU = 0; + + status = LoRaMacMlmeRequest( &mlmeReq ); + LmHandlerCallbacks->OnMacMlmeRequest( status, &mlmeReq, mlmeReq.ReqReturn.DutyCycleWaitTime ); + + if( status == LORAMAC_STATUS_OK ) + { + // Send an empty message + LmHandlerAppData_t appData = + { + .Buffer = NULL, + .BufferSize = 0, + .Port = 0 + }; + return LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); + } + else + { + return LORAMAC_HANDLER_ERROR; + } +} + +LmHandlerErrorStatus_t LmHandlerRequestClass( DeviceClass_t newClass ) +{ + MibRequestConfirm_t mibReq; + DeviceClass_t currentClass; + LmHandlerErrorStatus_t errorStatus = LORAMAC_HANDLER_SUCCESS; + + mibReq.Type = MIB_DEVICE_CLASS; + LoRaMacMibGetRequestConfirm( &mibReq ); + currentClass = mibReq.Param.Class; + + // Attempt to switch only if class update + if( currentClass != newClass ) + { + switch( newClass ) + { + case CLASS_A: + { + if( currentClass != CLASS_A ) + { + mibReq.Param.Class = CLASS_A; + if( LoRaMacMibSetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK ) + { + // Switch is instantaneous + LmHandlerCallbacks->OnClassChange( CLASS_A ); + } + else + { + errorStatus = LORAMAC_HANDLER_ERROR; + } + } + } + break; + case CLASS_B: + { + if( currentClass != CLASS_A ) + { + errorStatus = LORAMAC_HANDLER_ERROR; + } + // Beacon must first be acquired + errorStatus = LmHandlerDeviceTimeReq( ); + IsClassBSwitchPending = true; + } + break; + case CLASS_C: + { + if( currentClass != CLASS_A ) + { + errorStatus = LORAMAC_HANDLER_ERROR; + } + // Switch is instantaneous + mibReq.Param.Class = CLASS_C; + if( LoRaMacMibSetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK ) + { + LmHandlerCallbacks->OnClassChange( CLASS_C ); + } + else + { + errorStatus = LORAMAC_HANDLER_ERROR; + } + } + break; + default: + break; + } + } + return errorStatus; +} + +DeviceClass_t LmHandlerGetCurrentClass( void ) +{ + MibRequestConfirm_t mibReq; + + mibReq.Type = MIB_DEVICE_CLASS; + LoRaMacMibGetRequestConfirm( &mibReq ); + + return mibReq.Param.Class; +} + +int8_t LmHandlerGetCurrentDatarate( void ) +{ + MibRequestConfirm_t mibGet; + + mibGet.Type = MIB_CHANNELS_DATARATE; + LoRaMacMibGetRequestConfirm( &mibGet ); + + return mibGet.Param.ChannelsDatarate; +} + +LoRaMacRegion_t LmHandlerGetActiveRegion( void ) +{ + return LmHandlerParams->Region; +} + +LmHandlerErrorStatus_t LmHandlerSetSystemMaxRxError( uint32_t maxErrorInMs ) +{ + MibRequestConfirm_t mibReq; + + mibReq.Type = MIB_SYSTEM_MAX_RX_ERROR; + mibReq.Param.SystemMaxRxError = maxErrorInMs; + if( LoRaMacMibSetRequestConfirm( &mibReq ) != LORAMAC_STATUS_OK ) + { + return LORAMAC_HANDLER_ERROR; + } + return LORAMAC_HANDLER_SUCCESS; +} + +/* + *============================================================================= + * LORAMAC NOTIFICATIONS HANDLING + *============================================================================= + */ + +static void McpsConfirm( McpsConfirm_t *mcpsConfirm ) +{ + TxParams.IsMcpsConfirm = 1; + TxParams.Status = mcpsConfirm->Status; + TxParams.Datarate = mcpsConfirm->Datarate; + TxParams.UplinkCounter = mcpsConfirm->UpLinkCounter; + TxParams.TxPower = mcpsConfirm->TxPower; + TxParams.Channel = mcpsConfirm->Channel; + TxParams.AckReceived = mcpsConfirm->AckReceived; + + LmHandlerCallbacks->OnTxData( &TxParams ); + + LmHandlerPackagesNotify( PACKAGE_MCPS_CONFIRM, mcpsConfirm ); +} + +static void McpsIndication( McpsIndication_t *mcpsIndication ) +{ + LmHandlerAppData_t appData; + + RxParams.IsMcpsIndication = 1; + RxParams.Status = mcpsIndication->Status; + + if( RxParams.Status != LORAMAC_EVENT_INFO_STATUS_OK ) + { + return; + } + + RxParams.Datarate = mcpsIndication->RxDatarate; + RxParams.Rssi = mcpsIndication->Rssi; + RxParams.Snr = mcpsIndication->Snr; + RxParams.DownlinkCounter = mcpsIndication->DownLinkCounter; + RxParams.RxSlot = mcpsIndication->RxSlot; + + appData.Port = mcpsIndication->Port; + appData.BufferSize = mcpsIndication->BufferSize; + appData.Buffer = mcpsIndication->Buffer; + + LmHandlerCallbacks->OnRxData( &appData, &RxParams ); + + if( mcpsIndication->DeviceTimeAnsReceived == true ) + { +#if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) + // Provide fix values. DeviceTimeAns is accurate + LmHandlerCallbacks->OnSysTimeUpdate( true, 0 ); +#else + LmHandlerCallbacks->OnSysTimeUpdate( ); +#endif + } + // Call packages RxProcess function + LmHandlerPackagesNotify( PACKAGE_MCPS_INDICATION, mcpsIndication ); + + if( ( mcpsIndication->FramePending == true ) && ( LmHandlerGetCurrentClass( ) == CLASS_A ) ) + { + // The server signals that it has pending data to be sent. + // We schedule an uplink as soon as possible to flush the server. + + // Send an empty message + LmHandlerAppData_t appData = + { + .Buffer = NULL, + .BufferSize = 0, + .Port = 0 + }; + LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); + } +} + +static void MlmeConfirm( MlmeConfirm_t *mlmeConfirm ) +{ + TxParams.IsMcpsConfirm = 0; + TxParams.Status = mlmeConfirm->Status; + LmHandlerCallbacks->OnTxData( &TxParams ); + + LmHandlerPackagesNotify( PACKAGE_MLME_CONFIRM, mlmeConfirm ); + + switch( mlmeConfirm->MlmeRequest ) + { + case MLME_JOIN: + { + MibRequestConfirm_t mibReq; + mibReq.Type = MIB_DEV_ADDR; + LoRaMacMibGetRequestConfirm( &mibReq ); + JoinParams.CommissioningParams->DevAddr = mibReq.Param.DevAddr; + JoinParams.Datarate = LmHandlerGetCurrentDatarate( ); + + if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK ) + { + // Status is OK, node has joined the network + JoinParams.Status = LORAMAC_HANDLER_SUCCESS; + } + else + { + // Join was not successful. Try to join again + JoinParams.Status = LORAMAC_HANDLER_ERROR; + } + // Notify upper layer + LmHandlerCallbacks->OnJoinRequest( &JoinParams ); + } + break; + case MLME_LINK_CHECK: + { + // Check DemodMargin + // Check NbGateways + } + break; + case MLME_DEVICE_TIME: + { + if( IsClassBSwitchPending == true ) + { + LmHandlerBeaconReq( ); + } + } + break; + case MLME_BEACON_ACQUISITION: + { + if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK ) + { + // Beacon has been acquired + // Request server for ping slot + LmHandlerPingSlotReq( 0 ); + } + else + { + // Beacon not acquired + // Request Device Time again. + LmHandlerDeviceTimeReq( ); + } + } + break; + case MLME_PING_SLOT_INFO: + { + if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK ) + { + MibRequestConfirm_t mibReq; + + // Class B is now activated + mibReq.Type = MIB_DEVICE_CLASS; + mibReq.Param.Class = CLASS_B; + LoRaMacMibSetRequestConfirm( &mibReq ); + // Notify upper layer + LmHandlerCallbacks->OnClassChange( CLASS_B ); + IsClassBSwitchPending = false; + } + else + { + LmHandlerPingSlotReq( 0 ); + } + } + break; + default: + break; + } +} + +static void MlmeIndication( MlmeIndication_t *mlmeIndication ) +{ + RxParams.IsMcpsIndication = 0; + RxParams.Status = mlmeIndication->Status; + if( RxParams.Status != LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED ) + { + LmHandlerCallbacks->OnRxData( NULL, &RxParams ); + } + + // Call packages RxProcess function + LmHandlerPackagesNotify( PACKAGE_MLME_INDICATION, mlmeIndication ); + + switch( mlmeIndication->MlmeIndication ) + { + case MLME_SCHEDULE_UPLINK: + {// The MAC signals that we shall provide an uplink as soon as possible + // Send an empty message + LmHandlerAppData_t appData = + { + .Buffer = NULL, + .BufferSize = 0, + .Port = 0 + }; + + if( LmHandlerPackages[PACKAGE_ID_COMPLIANCE]->IsRunning( ) == false ) + { + LmHandlerSend( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); + } + } + break; + case MLME_BEACON_LOST: + { + MibRequestConfirm_t mibReq; + // Switch to class A again + mibReq.Type = MIB_DEVICE_CLASS; + mibReq.Param.Class = CLASS_A; + LoRaMacMibSetRequestConfirm( &mibReq ); + + BeaconParams.State = LORAMAC_HANDLER_BEACON_LOST; + BeaconParams.Info.Time.Seconds = 0; + BeaconParams.Info.GwSpecific.InfoDesc = 0; + memset1( BeaconParams.Info.GwSpecific.Info, 0, 6 ); + + LmHandlerCallbacks->OnClassChange( CLASS_A ); + LmHandlerCallbacks->OnBeaconStatusChange( &BeaconParams ); + + LmHandlerDeviceTimeReq( ); + } + break; + case MLME_BEACON: + { + if( mlmeIndication->Status == LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED ) + { + BeaconParams.State = LORAMAC_HANDLER_BEACON_RX; + BeaconParams.Info = mlmeIndication->BeaconInfo; + + LmHandlerCallbacks->OnBeaconStatusChange( &BeaconParams ); + } + else + { + BeaconParams.State = LORAMAC_HANDLER_BEACON_NRX; + BeaconParams.Info = mlmeIndication->BeaconInfo; + + LmHandlerCallbacks->OnBeaconStatusChange( &BeaconParams ); + } + break; + } + default: + break; + } +} + +/* + *============================================================================= + * PACKAGES HANDLING + *============================================================================= + */ + +LmHandlerErrorStatus_t LmHandlerPackageRegister( uint8_t id, void *params ) +{ + LmhPackage_t *package = NULL; + switch( id ) + { + case PACKAGE_ID_COMPLIANCE: + { + package = LmphCompliancePackageFactory( ); + break; + } + case PACKAGE_ID_CLOCK_SYNC: + { + package = LmphClockSyncPackageFactory( ); + break; + } + case PACKAGE_ID_REMOTE_MCAST_SETUP: + { + package = LmhpRemoteMcastSetupPackageFactory( ); + break; + } + case PACKAGE_ID_FRAGMENTATION: + { + package = LmhpFragmentationPackageFactory( ); + break; + } + } + if( package != NULL ) + { + LmHandlerPackages[id] = package; + LmHandlerPackages[id]->OnMacMcpsRequest = LmHandlerCallbacks->OnMacMcpsRequest; + LmHandlerPackages[id]->OnMacMlmeRequest = LmHandlerCallbacks->OnMacMlmeRequest; + LmHandlerPackages[id]->OnJoinRequest = LmHandlerJoinRequest; + LmHandlerPackages[id]->OnSendRequest = LmHandlerSend; + LmHandlerPackages[id]->OnDeviceTimeRequest = LmHandlerDeviceTimeReq; + LmHandlerPackages[id]->OnSysTimeUpdate = LmHandlerCallbacks->OnSysTimeUpdate; + LmHandlerPackages[id]->Init( params, LmHandlerParams->DataBuffer, LmHandlerParams->DataBufferMaxSize ); + + return LORAMAC_HANDLER_SUCCESS; + } + else + { + return LORAMAC_HANDLER_ERROR; + } +} + +bool LmHandlerPackageIsInitialized( uint8_t id ) +{ + if( LmHandlerPackages[id]->IsInitialized != NULL ) + { + return LmHandlerPackages[id]->IsInitialized( ); + } + else + { + return false; + } +} + +bool LmHandlerPackageIsRunning( uint8_t id ) +{ + if( LmHandlerPackages[id]->IsRunning != NULL ) + { + return LmHandlerPackages[id]->IsRunning( ); + } + else + { + return false; + } +} + +static void LmHandlerPackagesNotify( PackageNotifyTypes_t notifyType, void *params ) +{ + for( int8_t i = 0; i < PKG_MAX_NUMBER; i++ ) + { + if( LmHandlerPackages[i] != NULL ) + { + switch( notifyType ) + { + case PACKAGE_MCPS_CONFIRM: + { + if( LmHandlerPackages[i]->OnMcpsConfirmProcess != NULL ) + { + LmHandlerPackages[i]->OnMcpsConfirmProcess( params ); + } + break; + } + case PACKAGE_MCPS_INDICATION: + { + if( ( LmHandlerPackages[i]->OnMcpsIndicationProcess != NULL ) && + ( LmHandlerPackages[i]->Port == ( ( McpsIndication_t* )params )->Port ) ) + { + LmHandlerPackages[i]->OnMcpsIndicationProcess( params ); + } + break; + } + case PACKAGE_MLME_CONFIRM: + { + if( LmHandlerPackages[i]->OnMlmeConfirmProcess != NULL ) + { + LmHandlerPackages[i]->OnMlmeConfirmProcess( params ); + } + break; + } + case PACKAGE_MLME_INDICATION: + { + if( LmHandlerPackages[i]->OnMlmeIndicationProcess != NULL ) + { + LmHandlerPackages[i]->OnMlmeIndicationProcess( params ); + } + break; + } + } + } + } +} + +static void LmHandlerPackagesProcess( void ) +{ + for( int8_t i = 0; i < PKG_MAX_NUMBER; i++ ) + { + if( ( LmHandlerPackages[i] != NULL ) && + ( LmHandlerPackages[i]->Process != NULL ) && + ( LmHandlerPackageIsInitialized( i ) != false ) ) + { + LmHandlerPackages[i]->Process( ); + } + } +} diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/LmHandler.h b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/LmHandler.h new file mode 100644 index 00000000..52a6b8fc --- /dev/null +++ b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/LmHandler.h @@ -0,0 +1,335 @@ +/*! + * \file LmHandler.h + * + * \brief Implements the LoRaMac layer handling. + * Provides the possibility to register applicative packages. + * + * \remark Inspired by the examples provided on the en.i-cube_lrwan fork. + * MCD Application Team ( STMicroelectronics International ) + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2018 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + */ +#ifndef __LORAMAC_HANDLER_H__ +#define __LORAMAC_HANDLER_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "LmHandlerTypes.h" +#include "LmhpCompliance.h" + + +typedef struct LmHandlerJoinParams_s +{ + CommissioningParams_t *CommissioningParams; + int8_t Datarate; + LmHandlerErrorStatus_t Status; +}LmHandlerJoinParams_t; + +typedef struct LmHandlerTxParams_s +{ + uint8_t IsMcpsConfirm; + LoRaMacEventInfoStatus_t Status; + CommissioningParams_t *CommissioningParams; + LmHandlerMsgTypes_t MsgType; + uint8_t AckReceived; + int8_t Datarate; + uint32_t UplinkCounter; + LmHandlerAppData_t AppData; + int8_t TxPower; + uint8_t Channel; +}LmHandlerTxParams_t; + +typedef struct LmHandlerRxParams_s +{ + uint8_t IsMcpsIndication; + LoRaMacEventInfoStatus_t Status; + CommissioningParams_t *CommissioningParams; + int8_t Datarate; + int8_t Rssi; + int8_t Snr; + uint32_t DownlinkCounter; + int8_t RxSlot; +}LmHandlerRxParams_t; + +typedef struct LoRaMAcHandlerBeaconParams_s +{ + LoRaMacEventInfoStatus_t Status; + LmHandlerBeaconState_t State; + BeaconInfo_t Info; +}LoRaMAcHandlerBeaconParams_t; + +typedef struct LmHandlerParams_s +{ + /*! + * Region + */ + LoRaMacRegion_t Region; + /*! + * Holds the ADR state + */ + bool AdrEnable; + /*! + * Uplink datarate, when \ref AdrEnable is OFF + */ + int8_t TxDatarate; + /*! + * Enables/Disables a public network usage + */ + bool PublicNetworkEnable; + /*! + * LoRaWAN ETSI duty cycle control enable/disable + * + * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes + */ + bool DutyCycleEnabled; + /*! + * Application data buffer maximum size + */ + uint8_t DataBufferMaxSize; + /*! + * Application data buffer pointer + */ + uint8_t *DataBuffer; +}LmHandlerParams_t; + +typedef struct LmHandlerCallbacks_s +{ + /*! + * Get the current battery level + * + * \retval value Battery level ( 0: very low, 254: fully charged ) + */ + uint8_t ( *GetBatteryLevel )( void ); + /*! + * Get the current temperature + * + * \retval value Temperature in degree Celsius + */ + float ( *GetTemperature )( void ); + /*! + * Returns a pseudo random seed generated using the MCU Unique ID + * + * \retval seed Generated pseudo random seed + */ + uint32_t ( *GetRandomSeed )( void ); + /*! + *\brief Will be called each time a Radio IRQ is handled by the MAC + * layer. + * + *\warning Runs in a IRQ context. Should only change variables state. + */ + void ( *OnMacProcess )( void ); + /*! + * Notifies the upper layer that the NVM context has changed + * + * \param [IN] stored Indicates if we are storing (true) or + * restoring (false) the NVM context + */ + void ( *OnNvmContextChange )( LmHandlerNvmContextStates_t state ); + /*! + * Notifies the upper layer that a network parameters have been set + * + * \param [IN] params notification parameters + */ + void ( *OnNetworkParametersChange )( CommissioningParams_t *params ); + /*! + * Notifies the upper layer that a MCPS request has been made to the MAC layer + * + * \param [IN] status - Request returned status + * \param [IN] mcpsRequest - Performed MCPS-Request. Refer to \ref McpsReq_t. + * \param [IN] nextTxDelay - Time to wait until another TX is possible. + */ + void ( *OnMacMcpsRequest )( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxDelay ); + /*! + * Notifies the upper layer that a MLME request has been made to the MAC layer + * + * \param [IN] status - Request returned status + * \param [IN] mlmeRequest - Performed MLME-Request. Refer to \ref MlmeReq_t. + * \param [IN] nextTxDelay - Time to wait until another TX is possible. + */ + void ( *OnMacMlmeRequest )( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxDelay ); + /*! + * Notifies the upper layer that a network has been joined + * + * \param [IN] params notification parameters + */ + void ( *OnJoinRequest )( LmHandlerJoinParams_t *params ); + /*! + * Notifies upper layer that a frame has been transmitted + * + * \param [IN] params notification parameters + */ + void ( *OnTxData )( LmHandlerTxParams_t *params ); + /*! + * Notifies the upper layer that an applicative frame has been received + * + * \param [IN] appData Received applicative data + * \param [IN] params notification parameters + */ + void ( *OnRxData )( LmHandlerAppData_t *appData, LmHandlerRxParams_t *params ); + /*! + * Confirms the LoRaWAN device class change + * + * \param [IN] deviceClass New end-device class + */ + void ( *OnClassChange )( DeviceClass_t deviceClass ); + /*! + * Notifies the upper layer that the beacon status has changed + * + * \param [IN] params notification parameters + */ + void ( *OnBeaconStatusChange )( LoRaMAcHandlerBeaconParams_t *params ); +#if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) + /*! + * Notifies the upper layer that the system time has been updated. + * + * \param [in] isSynchronized Indicates if the system time is synchronized in the range +/-1 second + * \param [in] timeCorrection Received time correction value + */ + void ( *OnSysTimeUpdate )( bool isSynchronized, int32_t timeCorrection ); +#else + /*! + * Notifies the upper layer that the system time has been updated. + */ + void ( *OnSysTimeUpdate )( void ); +#endif +}LmHandlerCallbacks_t; + +/*! + * LoRaMac handler initialisation + * + * \param [IN] callbacks LoRaMac handler callbacks + * \param [IN] handlerParams LoRaMac handler parameters + * + * \retval none + */ +LmHandlerErrorStatus_t LmHandlerInit( LmHandlerCallbacks_t *callbacks, + LmHandlerParams_t *handlerParams ); + +/*! + * Indicates if the LoRaMacHandler is busy + * + * \retval status [true] Busy, [false] free + */ +bool LmHandlerIsBusy( void ); + +/*! + * Processes the LoRaMac and Radio events. + * When no pendig operation asks to go in low power mode. + * + * \remark This function must be called in the main loop. + */ +void LmHandlerProcess( void ); + +/*! + * Instructs the MAC layer to send a ClassA uplink + * + * \param [IN] appData Data to be sent + * \param [IN] isTxConfirmed Indicates if the uplink requires an acknowledgement + * + * \retval status Returns \ref LORAMAC_HANDLER_SUCCESS if request has been + * processed else \ref LORAMAC_HANDLER_ERROR + */ +LmHandlerErrorStatus_t LmHandlerSend( LmHandlerAppData_t *appData, LmHandlerMsgTypes_t isTxConfirmed ); + +/*! + * Join a LoRa Network in classA + * + * \Note if the device is ABP, this is a pass through function + */ +void LmHandlerJoin( void ); + +/*! + * Check whether the Device is joined to the network + * + * \param [IN] none + * + * \retval status Returns \ref LORAMAC_HANDLER_SET if joined else \ref LORAMAC_HANDLER_RESET + */ +LmHandlerFlagStatus_t LmHandlerJoinStatus( void ); + +/*! + * Informs the server on the ping-slot periodicity to use + * + * \param [IN] periodicity Is equal to 2^periodicity seconds. + * Example: 2^3 = 8 seconds. The end-device will open an Rx slot every 8 seconds. + * + * \retval status Returns \ref LORAMAC_HANDLER_SUCCESS if request has been + * processed else \ref LORAMAC_HANDLER_ERROR + */ +LmHandlerErrorStatus_t LmHandlerPingSlotReq( uint8_t periodicity ); + +/*! + * Request the MAC layer to change LoRaWAN class + * + * \Note Callback \ref LmHandlerConfirmClass informs upper layer that the change has occurred + * \Note Only switch from class A to class B/C OR from class B/C to class A is allowed + * + * \param [IN] newClass New class to be requested + * + * \retval status Returns \ref LORAMAC_HANDLER_SUCCESS if request has been + * processed else \ref LORAMAC_HANDLER_ERROR + */ +LmHandlerErrorStatus_t LmHandlerRequestClass( DeviceClass_t newClass ); + +/*! + * Gets the current LoRaWAN class + * + * \retval currentClass Current LoRaWAN class + */ +DeviceClass_t LmHandlerGetCurrentClass( void ); + +/*! + * Gets the current datarate + * + * \retval currentDatarate Current datarate + */ +int8_t LmHandlerGetCurrentDatarate( void ); + +/*! + * Gets the current active region + * + * \retval currentRegion Current active region + */ +LoRaMacRegion_t LmHandlerGetActiveRegion( void ); + +/*! + * Set system maximum tolerated rx error in milliseconds + * + * \param [IN] maxErrorInMs Maximum tolerated error in milliseconds + * + * \retval status Returns \ref LORAMAC_HANDLER_SUCCESS if request has been + * processed else \ref LORAMAC_HANDLER_ERROR + */ +LmHandlerErrorStatus_t LmHandlerSetSystemMaxRxError( uint32_t maxErrorInMs ); + +/* + *============================================================================= + * PACKAGES HANDLING + *============================================================================= + */ +LmHandlerErrorStatus_t LmHandlerPackageRegister( uint8_t id, void *params ); +bool LmHandlerPackageIsInitialized( uint8_t id ); +bool LmHandlerPackageIsRunning( uint8_t id ); + +#ifdef __cplusplus +} +#endif + +#endif // __LORAMAC_HANDLER_H__ diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/LmHandlerTypes.h b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/LmHandlerTypes.h new file mode 100644 index 00000000..0920019c --- /dev/null +++ b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/LmHandlerTypes.h @@ -0,0 +1,124 @@ +/*! + * \file LmHandlerTypes.h + * + * \brief Defines the types used by LmHandler + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2018 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + */ +#ifndef __LORAMAC_HANDLER_TYPES_H__ +#define __LORAMAC_HANDLER_TYPES_H__ + +#include "LoRaMac.h" + +/*! + * If set to 1 the new API defining \ref OnSysTimeUpdate callback is used. + */ +#define LMH_SYS_TIME_UPDATE_NEW_API 1 + +/*! + * + */ +typedef enum +{ + LORAMAC_HANDLER_ADR_OFF = 0, + LORAMAC_HANDLER_ADR_ON = !LORAMAC_HANDLER_ADR_OFF +}LmHandlerAdrStates_t; + +/*! + * + */ +typedef enum +{ + LORAMAC_HANDLER_RESET = 0, + LORAMAC_HANDLER_SET = !LORAMAC_HANDLER_RESET +}LmHandlerFlagStatus_t; + +/*! + * + */ +typedef enum +{ + LORAMAC_HANDLER_ERROR = -1, + LORAMAC_HANDLER_SUCCESS = 0 +}LmHandlerErrorStatus_t; + +/*! + * + */ +typedef enum +{ + LORAMAC_HANDLER_UNCONFIRMED_MSG = 0, + LORAMAC_HANDLER_CONFIRMED_MSG = !LORAMAC_HANDLER_UNCONFIRMED_MSG +}LmHandlerMsgTypes_t; + +/*! + * + */ +typedef enum +{ + LORAMAC_HANDLER_FALSE = 0, + LORAMAC_HANDLER_TRUE = !LORAMAC_HANDLER_FALSE +}LmHandlerBoolean_t; + +typedef enum +{ + LORAMAC_HANDLER_BEACON_ACQUIRING, + LORAMAC_HANDLER_BEACON_LOST, + LORAMAC_HANDLER_BEACON_RX, + LORAMAC_HANDLER_BEACON_NRX +}LmHandlerBeaconState_t; + +typedef enum +{ + LORAMAC_HANDLER_NVM_RESTORE, + LORAMAC_HANDLER_NVM_STORE, +}LmHandlerNvmContextStates_t; + +/*! + * Commissioning parameters + */ +typedef struct CommissioningParams_s +{ + bool IsOtaaActivation; + uint8_t DevEui[8]; + uint8_t JoinEui[8]; + uint8_t SePin[4]; + uint32_t NetworkId; + uint32_t DevAddr; +}CommissioningParams_t; + +/*! + * Application data structure + */ +typedef struct LmHandlerAppData_s +{ + uint8_t Port; + uint8_t BufferSize; + uint8_t *Buffer; +}LmHandlerAppData_t; + +typedef struct LmHandlerRequestParams_s +{ + uint8_t IsMcpsRequest; + LoRaMacStatus_t Status; + union + { + Mcps_t Mcps; + Mlme_t Mlme; + }RequestType; +}LmHandlerRequestParams_t; + +#endif // __LORAMAC_HANDLER_TYPES_H__ diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/FragDecoder.c b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/FragDecoder.c new file mode 100644 index 00000000..3988f600 --- /dev/null +++ b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/FragDecoder.c @@ -0,0 +1,750 @@ +/*! + * \file FragDecoder.c + * + * \brief Implements the LoRa-Alliance fragmentation decoder + * Specification: https://lora-alliance.org/sites/default/files/2018-09/fragmented_data_block_transport_v1.0.0.pdf + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2018 Semtech + * + * \endcode + * + * \author Fabien Holin ( Semtech ) + * \author Miguel Luis ( Semtech ) + */ +#include +#include +#include "utilities.h" +#include "FragDecoder.h" + +#define DBG_TRACE 0 + +#if DBG_TRACE == 1 + #include + /*! + * Works in the same way as the printf function does. + */ + #define DBG( ... ) \ + do \ + { \ + printf( __VA_ARGS__ ); \ + }while( 0 ) +#else + #define DBG( fmt, ... ) +#endif + + +/* + *============================================================================= + * Fragmentation decoder algorithm utilities + *============================================================================= + */ + +typedef struct +{ +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) + FragDecoderCallbacks_t *Callbacks; +#else + uint8_t *File; + uint32_t FileSize; +#endif + uint16_t FragNb; + uint8_t FragSize; + + uint32_t M2BLine; + uint8_t MatrixM2B[( ( FRAG_MAX_REDUNDANCY >> 3 ) + 1 ) * FRAG_MAX_REDUNDANCY]; + uint16_t FragNbMissingIndex[FRAG_MAX_NB]; + + uint8_t S[( FRAG_MAX_REDUNDANCY >> 3 ) + 1]; + + FragDecoderStatus_t Status; +}FragDecoder_t; + +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) +/*! + * \brief Sets a row from source into file destination + * + * \param [IN] src Source buffer pointer + * \param [IN] row Destination index of the row to be copied + * \param [IN] size Source number of bytes to be copied + */ +static void SetRow( uint8_t *src, uint16_t row, uint16_t size ); +#else +/*! + * \brief Sets a row from source into destination + * + * \param [IN] dst Destination buffer pointer + * \param [IN] src Source buffer pointer + * \param [IN] row Destination index of the row to be copied + * \param [IN] size Source number of bytes to be copied + */ +static void SetRow( uint8_t *dst, uint8_t *src, uint16_t row, uint16_t size ); +#endif + +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) +/*! + * \brief Gets a row from source and stores it into file destination + * + * \param [IN] src Source buffer pointer + * \param [IN] row Source index of the row to be copied + * \param [IN] size Source number of bytes to be copied + */ +static void GetRow( uint8_t *src, uint16_t row, uint16_t size ); +#else +/*! + * \brief Gets a row from source and stores it into destination + * + * \param [IN] dst Destination buffer pointer + * \param [IN] src Source buffer pointer + * \param [IN] row Source index of the row to be copied + * \param [IN] size Source number of bytes to be copied + */ +static void GetRow( uint8_t *dst, uint8_t *src, uint16_t row, uint16_t size ); +#endif + +/*! + * \brief Gets the parity value from a given row of the parity matrix + * + * \param [IN] index The index of the row to be computed + * \param [IN] matrixRow Pointer to the parity matrix (parity bit array) + * + * \retval parity Parity value at the given index + */ +static uint8_t GetParity( uint16_t index, uint8_t *matrixRow ); + +/*! + * \brief Sets the parity value on the given row of the parity matrix + * + * \param [IN] index The index of the row to be computed + * \param [IN/OUT] matrixRow Pointer to the parity matrix. + * \param [IN] parity The parity value to be set in the parity matrix + */ +static void SetParity( uint16_t index, uint8_t *matrixRow, uint8_t parity ); + +/*! + * \brief Check if the provided value is a power of 2 + * + * \param [IN] x Value to be tested + * + * \retval status Return true if frame is a power of two + */ +static bool IsPowerOfTwo( uint32_t x ); + +/*! + * \brief XOrs two data lines + * + * \param [IN] line1 1st Data line to be XORed + * \param [IN] line2 2nd Data line to be XORed + * \param [IN] size Number of elements in line1 + * + * \param [OUT] result XOR( line1, line2 ) result stored in line1 + */ +static void XorDataLine( uint8_t *line1, uint8_t *line2, int32_t size ); + +/*! + * \brief XORs two parity lines + * + * \param [IN] line1 1st Parity line to be XORed + * \param [IN] line2 2nd Parity line to be XORed + * \param [IN] size Number of elements in line1 + * + * \param [OUT] result XOR( line1, line2 ) result stored in line1 + */ +static void XorParityLine( uint8_t* line1, uint8_t* line2, int32_t size ); + +/*! + * \brief Generates a pseudo random number : PRBS23 + * + * \param [IN] value The input of the PRBS23 generator + * + * \retval nextValue Returns the next pseudo random number + */ +static int32_t FragPrbs23( int32_t value ); + +/*! + * \brief Gets and fills the parity matrix + * + * \param [IN] n Fragment N + * \param [IN] m Fragment number + * \param [OUT] matrixRow Parity matrix + */ +static void FragGetParityMatrixRow( int32_t n, int32_t m, uint8_t *matrixRow ); + +/*! + * \brief Finds the index of the first one in a bit array + * + * \param [IN] bitArray Pointer to the bit array + * \param [IN] size Bit array size + * \retval index The index of the first 1 in the bit array + */ +static uint16_t BitArrayFindFirstOne( uint8_t *bitArray, uint16_t size ); + +/*! + * \brief Checks if the provided bit array only contains zeros + * + * \param [IN] bitArray Pointer to the bit array + * \param [IN] size Bit array size + * \retval isAllZeros [0: Contains ones, 1: Contains all zeros] + */ +static uint8_t BitArrayIsAllZeros( uint8_t *bitArray, uint16_t size ); + +/*! + * \brief Finds & marks missing fragments + * + * \param [IN] counter Current fragment counter + * \param [OUT] FragDecoder.FragNbMissingIndex[] array is updated in place + */ +static void FragFindMissingFrags( uint16_t counter ); + +/*! + * \brief Finds the index (frag counter) of the x th missing frag + * + * \param [IN] x x th missing frag + * + * \retval counter The counter value associated to the x th missing frag + */ +static uint16_t FragFindMissingIndex( uint16_t x ); + +/*! + * \brief Extacts a row from the binary matrix and expands it to a bitArray + * + * \param [IN] bitArray Pointer to the bit array + * \param [IN] rowIndex Matrix row index + * \param [IN] bitsInRow Number of bits in one row + */ +static void FragExtractLineFromBinaryMatrix( uint8_t* bitArray, uint16_t rowIndex, uint16_t bitsInRow ); + +/*! + * \brief Collapses and Pushs a row of a bit array to the matrix + * + * \param [IN] bitArray Pointer to the bit array + * \param [IN] rowIndex Matrix row index + * \param [IN] bitsInRow Number of bits in one row + */ +static void FragPushLineToBinaryMatrix( uint8_t *bitArray, uint16_t rowIndex, uint16_t bitsInRow ); + +/* + *============================================================================= + * Fragmentation decoder algorithm + *============================================================================= + */ + +static FragDecoder_t FragDecoder; + +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) +void FragDecoderInit( uint16_t fragNb, uint8_t fragSize, FragDecoderCallbacks_t *callbacks ) +#else +void FragDecoderInit( uint16_t fragNb, uint8_t fragSize, uint8_t *file, uint32_t fileSize ) +#endif +{ +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) + FragDecoder.Callbacks = callbacks; +#else + FragDecoder.File = file; + FragDecoder.FileSize = fileSize; +#endif + FragDecoder.FragNb = fragNb; // FragNb = FRAG_MAX_SIZE + FragDecoder.FragSize = fragSize; // number of byte on a row + FragDecoder.Status.FragNbLastRx = 0; + FragDecoder.Status.FragNbLost = 0; + FragDecoder.M2BLine = 0; + + // Initialize missing fragments index array + for( uint16_t i = 0; i < FRAG_MAX_NB; i++ ) + { + FragDecoder.FragNbMissingIndex[i] = 1; + } + + // Initialize parity matrix + for( uint32_t i = 0; i < ( ( FRAG_MAX_REDUNDANCY >> 3 ) + 1 ); i++ ) + { + FragDecoder.S[i] = 0; + } + + for( uint32_t i = 0; i < ( ( ( FRAG_MAX_REDUNDANCY >> 3 ) + 1 ) * FRAG_MAX_REDUNDANCY ); i++ ) + { + FragDecoder.MatrixM2B[i] = 0xFF; + } + + // Initialize final uncoded data buffer ( FRAG_MAX_NB * FRAG_MAX_SIZE ) + for( uint32_t i = 0; i < ( fragNb * fragSize ); i++ ) + { +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) + if( ( FragDecoder.Callbacks != NULL ) && ( FragDecoder.Callbacks->FragDecoderWrite != NULL ) ) + { + FragDecoder.Callbacks->FragDecoderWrite( i, ( uint8_t[] ){ 0xFF }, 1 ); + } +#else + FragDecoder.File[i] = 0xFF; +#endif + } + FragDecoder.Status.FragNbLost = 0; + FragDecoder.Status.FragNbLastRx = 0; +} + +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) +uint32_t FragDecoderGetMaxFileSize( void ) +{ + return FRAG_MAX_NB * FRAG_MAX_SIZE; +} +#endif + +int32_t FragDecoderProcess( uint16_t fragCounter, uint8_t *rawData ) +{ + uint16_t firstOneInRow = 0; + int32_t first = 0; + int32_t noInfo = 0; + + uint8_t matrixRow[(FRAG_MAX_NB >> 3 ) + 1]; + uint8_t matrixDataTemp[FRAG_MAX_SIZE]; + uint8_t dataTempVector[( FRAG_MAX_REDUNDANCY >> 3 ) + 1]; + uint8_t dataTempVector2[( FRAG_MAX_REDUNDANCY >> 3 ) + 1]; + + memset1( matrixRow, 0, ( FRAG_MAX_NB >> 3 ) + 1 ); + memset1( matrixDataTemp, 0, FRAG_MAX_SIZE ); + memset1( dataTempVector, 0, ( FRAG_MAX_REDUNDANCY >> 3 ) + 1 ); + memset1( dataTempVector2, 0, ( FRAG_MAX_REDUNDANCY >> 3 ) + 1 ); + + FragDecoder.Status.FragNbRx = fragCounter; + + if( fragCounter < FragDecoder.Status.FragNbLastRx ) + { + return FRAG_SESSION_ONGOING; // Drop frame out of order + } + + // The M (FragNb) first packets aren't encoded or in other words they are + // encoded with the unitary matrix + if( fragCounter < ( FragDecoder.FragNb + 1 ) ) + { + // The M first frame are not encoded store them +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) + SetRow( rawData, fragCounter - 1, FragDecoder.FragSize ); +#else + SetRow( FragDecoder.File, rawData, fragCounter - 1, FragDecoder.FragSize ); +#endif + + FragDecoder.FragNbMissingIndex[fragCounter - 1] = 0; + + // Update the FragDecoder.FragNbMissingIndex with the loosing frame + FragFindMissingFrags( fragCounter ); + } + else + { + if( FragDecoder.Status.FragNbLost > FRAG_MAX_REDUNDANCY ) + { + FragDecoder.Status.MatrixError = 1; + return FRAG_SESSION_FINISHED; + } + // At this point we receive encoded frames and the number of loosing frames + // is well known: FragDecoder.FragNbLost - 1; + + // In case of the end of true data is missing + FragFindMissingFrags( fragCounter ); + + if( FragDecoder.Status.FragNbLost == 0 ) + { + // the case : all the M(FragNb) first rows have been transmitted with no error + return FragDecoder.Status.FragNbLost; + } + + // fragCounter - FragDecoder.FragNb + FragGetParityMatrixRow( fragCounter - FragDecoder.FragNb, FragDecoder.FragNb, matrixRow ); + + for( int32_t i = 0; i < FragDecoder.FragNb; i++ ) + { + if( GetParity( i , matrixRow ) == 1 ) + { + if( FragDecoder.FragNbMissingIndex[i] == 0 ) + { + // XOR with already receive frag + SetParity( i, matrixRow, 0 ); +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) + GetRow( matrixDataTemp, i, FragDecoder.FragSize ); +#else + GetRow( matrixDataTemp, FragDecoder.File, i, FragDecoder.FragSize ); +#endif + XorDataLine( rawData, matrixDataTemp, FragDecoder.FragSize ); + } + else + { + // Fill the "little" boolean matrix m2b + SetParity( FragDecoder.FragNbMissingIndex[i] - 1, dataTempVector, 1 ); + if( first == 0 ) + { + first = 1; + } + } + } + } + + firstOneInRow = BitArrayFindFirstOne( dataTempVector, FragDecoder.Status.FragNbLost ); + + if( first > 0 ) + { + int32_t li; + int32_t lj; + + // Manage a new line in MatrixM2B + while( GetParity( firstOneInRow, FragDecoder.S ) == 1 ) + { + // Row already diagonalized exist & ( FragDecoder.MatrixM2B[firstOneInRow][0] ) + FragExtractLineFromBinaryMatrix( dataTempVector2, firstOneInRow, FragDecoder.Status.FragNbLost ); + XorParityLine( dataTempVector, dataTempVector2, FragDecoder.Status.FragNbLost ); + // Have to store it in the mi th position of the missing frag + li = FragFindMissingIndex( firstOneInRow ); +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) + GetRow( matrixDataTemp, li, FragDecoder.FragSize ); +#else + GetRow( matrixDataTemp, FragDecoder.File, li, FragDecoder.FragSize ); +#endif + XorDataLine( rawData, matrixDataTemp, FragDecoder.FragSize ); + if( BitArrayIsAllZeros( dataTempVector, FragDecoder.Status.FragNbLost ) ) + { + noInfo = 1; + break; + } + firstOneInRow = BitArrayFindFirstOne( dataTempVector, FragDecoder.Status.FragNbLost ); + } + + if( noInfo == 0 ) + { + FragPushLineToBinaryMatrix( dataTempVector, firstOneInRow, FragDecoder.Status.FragNbLost ); + li = FragFindMissingIndex( firstOneInRow ); +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) + SetRow( rawData, li, FragDecoder.FragSize ); +#else + SetRow( FragDecoder.File, rawData, li, FragDecoder.FragSize ); +#endif + SetParity( firstOneInRow, FragDecoder.S, 1 ); + FragDecoder.M2BLine++; + } + + if( FragDecoder.M2BLine == FragDecoder.Status.FragNbLost ) + { + // Then last step diagonalized + if( FragDecoder.Status.FragNbLost > 1 ) + { + int32_t i, j; + + for( i = ( FragDecoder.Status.FragNbLost - 2 ); i >= 0 ; i-- ) + { + li = FragFindMissingIndex( i ); +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) + GetRow( matrixDataTemp, li, FragDecoder.FragSize ); +#else + GetRow( matrixDataTemp, FragDecoder.File, li, FragDecoder.FragSize ); +#endif + for( j = ( FragDecoder.Status.FragNbLost - 1 ); j > i; j--) + { + FragExtractLineFromBinaryMatrix( dataTempVector2, i, FragDecoder.Status.FragNbLost ); + FragExtractLineFromBinaryMatrix( dataTempVector, j, FragDecoder.Status.FragNbLost ); + if( GetParity( j, dataTempVector2 ) == 1 ) + { + XorParityLine( dataTempVector2, dataTempVector, FragDecoder.Status.FragNbLost ); + + lj = FragFindMissingIndex( j ); + +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) + GetRow( rawData, lj, FragDecoder.FragSize ); +#else + GetRow( rawData, FragDecoder.File, lj, FragDecoder.FragSize ); +#endif + XorDataLine( matrixDataTemp , rawData , FragDecoder.FragSize ); + } + } +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) + SetRow( matrixDataTemp, li, FragDecoder.FragSize ); +#else + SetRow( FragDecoder.File, matrixDataTemp, li, FragDecoder.FragSize ); +#endif + } + return FragDecoder.Status.FragNbLost; + } + else + { + //If not ( FragDecoder.FragNbLost > 1 ) + return FragDecoder.Status.FragNbLost; + } + } + } + } + return FRAG_SESSION_ONGOING; +} + +FragDecoderStatus_t FragDecoderGetStatus( void ) +{ + return FragDecoder.Status; +} + +/* + *============================================================================= + * Fragmentation decoder algorithm utilities + *============================================================================= + */ + +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) +static void SetRow( uint8_t *src, uint16_t row, uint16_t size ) +{ + if( ( FragDecoder.Callbacks != NULL ) && ( FragDecoder.Callbacks->FragDecoderWrite != NULL ) ) + { + FragDecoder.Callbacks->FragDecoderWrite( row * size, src, size ); + } +} + +static void GetRow( uint8_t *dst, uint16_t row, uint16_t size ) +{ + if( ( FragDecoder.Callbacks != NULL ) && ( FragDecoder.Callbacks->FragDecoderRead != NULL ) ) + { + FragDecoder.Callbacks->FragDecoderRead( row * size, dst, size ); + } +} +#else +static void SetRow( uint8_t *dst, uint8_t *src, uint16_t row, uint16_t size ) +{ + memcpy1( &dst[row * size], src, size ); +} + +static void GetRow( uint8_t *dst, uint8_t *src, uint16_t row, uint16_t size ) +{ + memcpy1( dst, &src[row * size], size ); +} +#endif + +static uint8_t GetParity( uint16_t index, uint8_t *matrixRow ) +{ + uint8_t parity; + parity = matrixRow[index >> 3]; + parity = ( parity >> ( 7 - ( index % 8 ) ) ) & 0x01; + return parity; +} + +static void SetParity( uint16_t index, uint8_t *matrixRow, uint8_t parity ) +{ + uint8_t mask = 0xFF - ( 1 << ( 7 - ( index % 8 ) ) ); + parity = parity << ( 7 - ( index % 8 ) ); + matrixRow[index >> 3] = ( matrixRow[index >> 3] & mask ) + parity; +} + +static bool IsPowerOfTwo( uint32_t x ) +{ + uint8_t sumBit = 0; + + for( uint8_t i = 0; i < 32; i++ ) + { + sumBit += ( x & ( 1 << i ) ) >> i; + } + if( sumBit == 1 ) + { + return true; + } + return false; +} + +static void XorDataLine( uint8_t *line1, uint8_t *line2, int32_t size ) +{ + for( int32_t i = 0; i < size; i++ ) + { + line1[i] = line1[i] ^ line2[i]; + } +} + +static void XorParityLine( uint8_t* line1, uint8_t* line2, int32_t size ) +{ + for( int32_t i = 0; i < size; i++ ) + { + SetParity( i, line1, ( GetParity( i, line1 ) ^ GetParity( i, line2 ) ) ); + } +} + +static int32_t FragPrbs23( int32_t value ) +{ + int32_t b0 = value & 0x01; + int32_t b1 = ( value & 0x20 ) >> 5; + return ( value >> 1 ) + ( ( b0 ^ b1 ) << 22 );; +} + +static void FragGetParityMatrixRow( int32_t n, int32_t m, uint8_t *matrixRow ) +{ + int32_t mTemp; + int32_t x; + int32_t nbCoeff = 0; + int32_t r; + + if( IsPowerOfTwo( m ) != false ) + { + mTemp = 1; + } + else + { + mTemp = 0; + } + + x = 1 + ( 1001 * n ); + for( uint8_t i = 0; i < ( ( m >> 3 ) + 1 ); i++ ) + { + matrixRow[i] = 0; + } + while( nbCoeff < ( m >> 1 ) ) + { + r = 1 << 16; + while( r >= m ) + { + x = FragPrbs23( x ); + r = x % ( m + mTemp ); + } + SetParity( r, matrixRow, 1 ); + nbCoeff += 1; + } +} + +static uint16_t BitArrayFindFirstOne( uint8_t *bitArray, uint16_t size ) +{ + for( uint16_t i = 0; i < size; i++) + { + if ( GetParity( i, bitArray ) == 1 ) + { + return i; + } + } + return 0; +} + +static uint8_t BitArrayIsAllZeros( uint8_t *bitArray, uint16_t size ) +{ + for( uint16_t i = 0; i < size; i++ ) + { + if( GetParity( i, bitArray ) == 1 ) + { + return 0; + } + } + return 1; +} + +/*! + * \brief Finds & marks missing fragments + * + * \param [IN] counter Current fragment counter + * \param [OUT] FragDecoder.FragNbMissingIndex[] array is updated in place + */ +static void FragFindMissingFrags( uint16_t counter ) +{ + int32_t i; + for( i = FragDecoder.Status.FragNbLastRx; i < ( counter - 1 ); i++ ) + { + if( i < FragDecoder.FragNb ) + { + FragDecoder.Status.FragNbLost++; + FragDecoder.FragNbMissingIndex[i] = FragDecoder.Status.FragNbLost; + } + } + if( i < FragDecoder.FragNb ) + { + FragDecoder.Status.FragNbLastRx = counter; + } + else + { + FragDecoder.Status.FragNbLastRx = FragDecoder.FragNb + 1; + } + DBG( "RECEIVED : %5d / %5d Fragments\n", FragDecoder.Status.FragNbRx, FragDecoder.FragNb ); + DBG( " %5d / %5d Bytes\n", FragDecoder.Status.FragNbRx * FragDecoder.FragSize, FragDecoder.FragNb * FragDecoder.FragSize ); + DBG( "LOST : %7d Fragments\n\n", FragDecoder.Status.FragNbLost ); +} + +/*! + * \brief Finds the index (frag counter) of the x th missing frag + * + * \param [IN] x x th missing frag + * + * \retval counter The counter value associated to the x th missing frag + */ +static uint16_t FragFindMissingIndex( uint16_t x ) +{ + for( uint16_t i = 0; i < FragDecoder.FragNb; i++ ) + { + if( FragDecoder.FragNbMissingIndex[i] == ( x + 1 ) ) + { + return i; + } + } + return 0; +} + +/*! + * \brief Extacts a row from the binary matrix and expands it to a bitArray + * + * \param [IN] bitArray Pointer to the bit array + * \param [IN] rowIndex Matrix row index + * \param [IN] bitsInRow Number of bits in one row + */ +static void FragExtractLineFromBinaryMatrix( uint8_t* bitArray, uint16_t rowIndex, uint16_t bitsInRow ) +{ + uint32_t findByte = 0; + uint32_t findBitInByte = 0; + + if( rowIndex > 0 ) + { + findByte = ( rowIndex * bitsInRow - ( ( rowIndex * ( rowIndex - 1 ) ) >> 1 ) ) >> 3; + findBitInByte = ( rowIndex * bitsInRow - ( ( rowIndex * ( rowIndex - 1 ) ) >> 1 ) ) % 8; + } + if( rowIndex > 0 ) + { + for( uint16_t i = 0; i < rowIndex; i++ ) + { + SetParity( i, bitArray, 0 ); + } + } + for( uint16_t i = rowIndex; i < bitsInRow; i++ ) + { + SetParity( i, + bitArray, + ( FragDecoder.MatrixM2B[findByte] >> ( 7 - findBitInByte ) ) & 0x01 ); + + findBitInByte++; + if( findBitInByte == 8 ) + { + findBitInByte = 0; + findByte++; + } + } +} + +/*! + * \brief Collapses and Pushs a row of a bit array to the matrix + * + * \param [IN] bitArray Pointer to the bit array + * \param [IN] rowIndex Matrix row index + * \param [IN] bitsInRow Number of bits in one row + */ +static void FragPushLineToBinaryMatrix( uint8_t *bitArray, uint16_t rowIndex, uint16_t bitsInRow ) +{ + uint32_t findByte = 0; + uint32_t findBitInByte = 0; + + if ( rowIndex > 0) { + findByte = ( rowIndex * bitsInRow - ( ( rowIndex * ( rowIndex - 1 ) ) >> 1 ) ) >> 3; + findBitInByte = ( rowIndex * bitsInRow - ( ( rowIndex * ( rowIndex - 1 ) ) >> 1 ) ) % 8; + + } + for( uint16_t i = rowIndex; i < bitsInRow; i++ ) + { + if( GetParity( i, bitArray ) == 0 ) + { + FragDecoder.MatrixM2B[findByte] = FragDecoder.MatrixM2B[findByte] & ( 0xFF - ( 1 << ( 7 - findBitInByte ) ) ); + } + findBitInByte++; + if( findBitInByte == 8 ) + { + findBitInByte = 0; + findByte++; + } + } +} diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/FragDecoder.h b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/FragDecoder.h new file mode 100644 index 00000000..d26489e5 --- /dev/null +++ b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/FragDecoder.h @@ -0,0 +1,143 @@ +/*! + * \file FragDecoder.h + * + * \brief Implements the LoRa-Alliance fragmentation decoder + * Specification: https://lora-alliance.org/sites/default/files/2018-09/fragmented_data_block_transport_v1.0.0.pdf + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2018 Semtech + * + * \endcode + * + * \author Fabien Holin ( Semtech ) + * \author Miguel Luis ( Semtech ) + */ +#ifndef __FRAG_DECODER_H__ +#define __FRAG_DECODER_H__ + +#include + +/*! + * If set to 1 the new API defining \ref FragDecoderWrite and + * \ref FragDecoderReadfunction callbacks is used. + */ +#define FRAG_DECODER_FILE_HANDLING_NEW_API 1 + +/*! + * Maximum number of fragment that can be handled. + * + * \remark This parameter has an impact on the memory footprint. + */ +#define FRAG_MAX_NB 21 + +/*! + * Maximum fragment size that can be handled. + * + * \remark This parameter has an impact on the memory footprint. + */ +#define FRAG_MAX_SIZE 50 + +/*! + * Maximum number of extra frames that can be handled. + * + * \remark This parameter has an impact on the memory footprint. + */ +#define FRAG_MAX_REDUNDANCY 5 + +#define FRAG_SESSION_FINISHED ( int32_t )0 +#define FRAG_SESSION_NOT_STARTED ( int32_t )-2 +#define FRAG_SESSION_ONGOING ( int32_t )-1 + +typedef struct sFragDecoderStatus +{ + uint16_t FragNbRx; + uint16_t FragNbLost; + uint16_t FragNbLastRx; + uint8_t MatrixError; +}FragDecoderStatus_t; + +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) +typedef struct sFragDecoderCallbacks +{ + /*! + * Writes `data` buffer of `size` starting at address `addr` + * + * \param [IN] addr Address start index to write to. + * \param [IN] data Data buffer to be written. + * \param [IN] size Size of data buffer to be written. + * + * \retval status Write operation status [0: Success, -1 Fail] + */ + uint8_t ( *FragDecoderWrite )( uint32_t addr, uint8_t *data, uint32_t size ); + /*! + * Reads `data` buffer of `size` starting at address `addr` + * + * \param [IN] addr Address start index to read from. + * \param [IN] data Data buffer to be read. + * \param [IN] size Size of data buffer to be read. + * + * \retval status Read operation status [0: Success, -1 Fail] + */ + uint8_t ( *FragDecoderRead )( uint32_t addr, uint8_t *data, uint32_t size ); +}FragDecoderCallbacks_t; +#endif + +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) +/*! + * \brief Initializes the fragmentation decoder + * + * \param [IN] fragNb Number of expected fragments (without redundancy packets) + * \param [IN] fragSize Size of a fragment + * \param [IN] callbacks Pointer to the Write/Read functions. + */ +void FragDecoderInit( uint16_t fragNb, uint8_t fragSize, FragDecoderCallbacks_t *callbacks ); +#else +/*! + * \brief Initializes the fragmentation decoder + * + * \param [IN] fragNb Number of expected fragments (without redundancy packets) + * \param [IN] fragSize Size of a fragment + * \param [IN] file Pointer to file buffer size + * \param [IN] fileSize File buffer size + */ +void FragDecoderInit( uint16_t fragNb, uint8_t fragSize, uint8_t *file, uint32_t fileSize ); +#endif + +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) +/*! + * \brief Gets the maximum file size that can be received + * + * \retval size FileSize + */ +uint32_t FragDecoderGetMaxFileSize( void ); +#endif + +/*! + * \brief Function to decode and reconstruct the binary file + * Called for each receive frame + * + * \param [IN] fragCounter Fragment counter [1..(FragDecoder.FragNb + FragDecoder.Redundancy)] + * \param [IN] rawData Pointer to the fragment to be processed (length = FragDecoder.FragSize) + * + * \retval status Process status. [FRAG_SESSION_ONGOING, + * FRAG_SESSION_FINISHED or + * FragDecoder.Status.FragNbLost] + */ +int32_t FragDecoderProcess( uint16_t fragCounter, uint8_t *rawData ); + +/*! + * \brief Gets the current fragmentation status + * + * \retval status Fragmentation decoder status + */ +FragDecoderStatus_t FragDecoderGetStatus( void ); + +#endif // __FRAG_DECODER_H__ diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhPackage.h b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhPackage.h new file mode 100644 index 00000000..dcc47da8 --- /dev/null +++ b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhPackage.h @@ -0,0 +1,156 @@ +/*! + * \file LmPackage.h + * + * \brief Defines the packages API + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2018 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + */ +#ifndef __LMH_PACKAGE_H__ +#define __LMH_PACKAGE_H__ + +#include +#include +#include "LmHandlerTypes.h" + +/*! + * Maximum number of packages + */ +#define PKG_MAX_NUMBER 4 + +typedef struct LmhPackage_s +{ + uint8_t Port; + /* + *========================================================================= + * Below callbacks must be initialized in package variable declaration + *========================================================================= + */ + + /*! + * Initializes the package with provided parameters + * + * \param [IN] params Pointer to the package parameters + * \param [IN] dataBuffer Pointer to main application buffer + * \param [IN] dataBufferMaxSize Main application buffer maximum size + */ + void ( *Init )( void *params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize ); + /*! + * Returns the current package initialization status. + * + * \retval status Package initialization status + * [true: Initialized, false: Not initialized] + */ + bool ( *IsInitialized )( void ); + /*! + * Returns the package operation status. + * + * \retval status Package operation status + * [true: Running, false: Not running] + */ + bool ( *IsRunning )( void ); + /*! + * Processes the internal package events. + */ + void ( *Process )( void ); + /*! + * Processes the MCSP Confirm + * + * \param [IN] mcpsConfirm MCPS confirmation primitive data + */ + void ( *OnMcpsConfirmProcess )( McpsConfirm_t *mcpsConfirm ); + /*! + * Processes the MCPS Indication + * + * \param [IN] mcpsIndication MCPS indication primitive data + */ + void ( *OnMcpsIndicationProcess )( McpsIndication_t *mcpsIndication ); + /*! + * Processes the MLME Confirm + * + * \param [IN] mlmeConfirm MLME confirmation primitive data + */ + void ( *OnMlmeConfirmProcess )( MlmeConfirm_t *mlmeConfirm ); + /*! + * Processes the MLME Indication + * + * \param [IN] mlmeIndication MLME indication primitive data + */ + void ( *OnMlmeIndicationProcess )( MlmeIndication_t *mlmeIndication ); + + /* + *========================================================================= + * Below callbacks must be initialized in LmHandler initialization with + * provideded LmHandlerSend and OnMacRequest functions + *========================================================================= + */ + + /*! + * Notifies the upper layer that a MCPS request has been made to the MAC layer + * + * \param [IN] status - Request returned status + * \param [IN] mcpsRequest - Performed MCPS-Request. Refer to \ref McpsReq_t. + * \param [IN] nextTxDelay - Time to wait until another TX is possible. + */ + void ( *OnMacMcpsRequest )( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxDelay ); + /*! + * Notifies the upper layer that a MLME request has been made to the MAC layer + * + * \param [IN] status - Request returned status + * \param [IN] mlmeRequest - Performed MLME-Request. Refer to \ref MlmeReq_t. + * \param [IN] nextTxDelay - Time to wait until another TX is possible. + */ + void ( *OnMacMlmeRequest )( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxDelay ); + /*! + * Join a LoRa Network in classA + * + * \Note if the device is ABP, this is a pass through function + * + * \param [IN] isOtaa Indicates which activation mode must be used + */ + void ( *OnJoinRequest )( bool isOtaa ); + /*! + * Instructs the MAC layer to send a ClassA uplink + * + * \param [IN] appData Data to be sent + * \param [IN] isTxConfirmed Indicates if the uplink requires an acknowledgement + * + * \retval status Returns \ref LORAMAC_HANDLER_SUCCESS if request has been + * processed else \ref LORAMAC_HANDLER_ERROR + */ + LmHandlerErrorStatus_t ( *OnSendRequest )( LmHandlerAppData_t *appData, LmHandlerMsgTypes_t isTxConfirmed ); + /*! + * Requests network server time update + * + * \retval status Returns \ref LORAMAC_HANDLER_SET if joined else \ref LORAMAC_HANDLER_RESET + */ + LmHandlerErrorStatus_t ( *OnDeviceTimeRequest )( void ); +#if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) + /*! + * Notifies the upper layer that the system time has been updated. + * + * \param [in] isSynchronized Indicates if the system time is synchronized in the range +/-1 second + * \param [in] timeCorrection Received time correction value + */ + void ( *OnSysTimeUpdate )( bool isSynchronized, int32_t timeCorrection ); +#else + /*! + * Notifies the upper layer that the system time has been updated. + */ + void ( *OnSysTimeUpdate )( void ); +#endif +}LmhPackage_t; + +#endif // __LMH_PACKAGE_H__ diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpClockSync.c b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpClockSync.c new file mode 100644 index 00000000..0e0b6127 --- /dev/null +++ b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpClockSync.c @@ -0,0 +1,375 @@ +/*! + * \file LmhpClockSync.c + * + * \brief Implements the LoRa-Alliance clock synchronization package + * Specification: https://lora-alliance.org/sites/default/files/2018-09/application_layer_clock_synchronization_v1.0.0.pdf + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2018 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + */ +#include "systime.h" +#include "LmHandler.h" +#include "LmhpClockSync.h" + +/*! + * LoRaWAN Application Layer Clock Synchronization Specification + */ +#define CLOCK_SYNC_PORT 202 + +#define CLOCK_SYNC_ID 1 +#define CLOCK_SYNC_VERSION 1 + +/*! + * Package current context + */ +typedef struct LmhpClockSyncState_s +{ + bool Initialized; + bool IsRunning; + uint8_t DataBufferMaxSize; + uint8_t *DataBuffer; + union + { + uint8_t Value; + struct + { + uint8_t TokenReq: 4; + uint8_t AnsRequired: 1; + uint8_t RFU: 3; + }Fields; + }TimeReqParam; + bool AppTimeReqPending; + bool AdrEnabledPrev; + uint8_t NbTransPrev; + uint8_t DataratePrev; + uint8_t NbTransmissions; +}LmhpClockSyncState_t; + +typedef enum LmhpClockSyncMoteCmd_e +{ + CLOCK_SYNC_PKG_VERSION_ANS = 0x00, + CLOCK_SYNC_APP_TIME_REQ = 0x01, + CLOCK_SYNC_APP_TIME_PERIOD_ANS = 0x02, + CLOCK_SYNC_FORCE_RESYNC_ANS = 0x03, +}LmhpClockSyncMoteCmd_t; + +typedef enum LmhpClockSyncSrvCmd_e +{ + CLOCK_SYNC_PKG_VERSION_REQ = 0x00, + CLOCK_SYNC_APP_TIME_ANS = 0x01, + CLOCK_SYNC_APP_TIME_PERIOD_REQ = 0x02, + CLOCK_SYNC_FORCE_RESYNC_REQ = 0x03, +}LmhpClockSyncSrvCmd_t; + +/*! + * Initializes the package with provided parameters + * + * \param [IN] params Pointer to the package parameters + * \param [IN] dataBuffer Pointer to main application buffer + * \param [IN] dataBufferMaxSize Main application buffer maximum size + */ +static void LmhpClockSyncInit( void *params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize ); + +/*! + * Returns the current package initialization status. + * + * \retval status Package initialization status + * [true: Initialized, false: Not initialized] + */ +static bool LmhpClockSyncIsInitialized( void ); + +/*! + * Returns the package operation status. + * + * \retval status Package operation status + * [true: Running, false: Not running] + */ +static bool LmhpClockSyncIsRunning( void ); + +/*! + * Processes the internal package events. + */ +static void LmhpClockSyncProcess( void ); + +/*! + * Processes the MCSP Confirm + * + * \param [IN] mcpsConfirm MCPS confirmation primitive data + */ +static void LmhpClockSyncOnMcpsConfirm( McpsConfirm_t *mcpsConfirm ); + +/*! + * Processes the MCPS Indication + * + * \param [IN] mcpsIndication MCPS indication primitive data + */ +static void LmhpClockSyncOnMcpsIndication( McpsIndication_t *mcpsIndication ); + +static LmhpClockSyncState_t LmhpClockSyncState = +{ + .Initialized = false, + .IsRunning = false, + .TimeReqParam.Value = 0, + .AppTimeReqPending = false, + .AdrEnabledPrev = false, + .NbTransPrev = 0, + .NbTransmissions = 0, +}; + +static LmhPackage_t LmhpClockSyncPackage = +{ + .Port = CLOCK_SYNC_PORT, + .Init = LmhpClockSyncInit, + .IsInitialized = LmhpClockSyncIsInitialized, + .IsRunning = LmhpClockSyncIsRunning, + .Process = LmhpClockSyncProcess, + .OnMcpsConfirmProcess = LmhpClockSyncOnMcpsConfirm, + .OnMcpsIndicationProcess = LmhpClockSyncOnMcpsIndication, + .OnMlmeConfirmProcess = NULL, // Not used in this package + .OnMlmeIndicationProcess = NULL, // Not used in this package + .OnMacMcpsRequest = NULL, // To be initialized by LmHandler + .OnMacMlmeRequest = NULL, // To be initialized by LmHandler + .OnJoinRequest = NULL, // To be initialized by LmHandler + .OnSendRequest = NULL, // To be initialized by LmHandler + .OnDeviceTimeRequest = NULL, // To be initialized by LmHandler + .OnSysTimeUpdate = NULL, // To be initialized by LmHandler +}; + +LmhPackage_t *LmphClockSyncPackageFactory( void ) +{ + return &LmhpClockSyncPackage; +} + +static void LmhpClockSyncInit( void * params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize ) +{ + if( dataBuffer != NULL ) + { + LmhpClockSyncState.DataBuffer = dataBuffer; + LmhpClockSyncState.DataBufferMaxSize = dataBufferMaxSize; + LmhpClockSyncState.Initialized = true; + LmhpClockSyncState.IsRunning = true; + } + else + { + LmhpClockSyncState.IsRunning = false; + LmhpClockSyncState.Initialized = false; + } +} + +static bool LmhpClockSyncIsInitialized( void ) +{ + return LmhpClockSyncState.Initialized; +} + +static bool LmhpClockSyncIsRunning( void ) +{ + if( LmhpClockSyncState.Initialized == false ) + { + return false; + } + + return LmhpClockSyncState.IsRunning; +} + +static void LmhpClockSyncProcess( void ) +{ + if( LmhpClockSyncState.NbTransmissions > 0 ) + { + if( LmhpClockSyncAppTimeReq( ) == LORAMAC_HANDLER_SUCCESS ) + { + LmhpClockSyncState.NbTransmissions--; + } + } +} + +static void LmhpClockSyncOnMcpsConfirm( McpsConfirm_t *mcpsConfirm ) +{ + MibRequestConfirm_t mibReq; + + if( LmhpClockSyncState.AppTimeReqPending == true ) + { + // Revert ADR setting + mibReq.Type = MIB_ADR; + mibReq.Param.AdrEnable = LmhpClockSyncState.AdrEnabledPrev; + LoRaMacMibSetRequestConfirm( &mibReq ); + + // Revert NbTrans setting + mibReq.Type = MIB_CHANNELS_NB_TRANS; + mibReq.Param.ChannelsNbTrans = LmhpClockSyncState.NbTransPrev; + LoRaMacMibSetRequestConfirm( &mibReq ); + + // Revert data rate setting + mibReq.Type = MIB_CHANNELS_DATARATE; + mibReq.Param.ChannelsDatarate = LmhpClockSyncState.DataratePrev; + LoRaMacMibSetRequestConfirm( &mibReq ); + + LmhpClockSyncState.AppTimeReqPending = false; + } +} + +static void LmhpClockSyncOnMcpsIndication( McpsIndication_t *mcpsIndication ) +{ + uint8_t cmdIndex = 0; + uint8_t dataBufferIndex = 0; + + while( cmdIndex < mcpsIndication->BufferSize ) + { + switch( mcpsIndication->Buffer[cmdIndex++] ) + { + case CLOCK_SYNC_PKG_VERSION_REQ: + { + LmhpClockSyncState.DataBuffer[dataBufferIndex++] = CLOCK_SYNC_PKG_VERSION_ANS; + LmhpClockSyncState.DataBuffer[dataBufferIndex++] = CLOCK_SYNC_ID; + LmhpClockSyncState.DataBuffer[dataBufferIndex++] = CLOCK_SYNC_VERSION; + break; + } + case CLOCK_SYNC_APP_TIME_ANS: + { + LmhpClockSyncState.NbTransmissions = 0; + + // Check if a more precise time correction has been received. + // If yes then don't process and ignore this answer. + if( mcpsIndication->DeviceTimeAnsReceived == true ) + { + cmdIndex += 5; + break; + } + int32_t timeCorrection = 0; + timeCorrection = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF; + timeCorrection += ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00; + timeCorrection += ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000; + timeCorrection += ( mcpsIndication->Buffer[cmdIndex++] << 24 ) & 0xFF000000; + if( ( mcpsIndication->Buffer[cmdIndex++] & 0x0F ) == LmhpClockSyncState.TimeReqParam.Fields.TokenReq ) + { + SysTime_t curTime = { .Seconds = 0, .SubSeconds = 0 }; + curTime = SysTimeGet( ); + curTime.Seconds += timeCorrection; + SysTimeSet( curTime ); + LmhpClockSyncState.TimeReqParam.Fields.TokenReq = ( LmhpClockSyncState.TimeReqParam.Fields.TokenReq + 1 ) & 0x0F; + if( LmhpClockSyncPackage.OnSysTimeUpdate != NULL ) + { +#if( LMH_SYS_TIME_UPDATE_NEW_API == 1 ) + LmhpClockSyncPackage.OnSysTimeUpdate( + ( timeCorrection >= -1 ) && ( timeCorrection <= 1 ), + timeCorrection ); +#else + if( ( timeCorrection >= -1 ) && ( timeCorrection <= 1 ) ) + { + LmhpClockSyncPackage.OnSysTimeUpdate( ); + } +#endif + } + } + break; + } + case CLOCK_SYNC_APP_TIME_PERIOD_REQ: + { + // Increment index + cmdIndex++; + // TODO implement command prosessing and handling + LmhpClockSyncState.DataBuffer[dataBufferIndex++] = CLOCK_SYNC_APP_TIME_PERIOD_ANS; + // Answer status not supported. + LmhpClockSyncState.DataBuffer[dataBufferIndex++] = 0x01; + + SysTime_t curTime = SysTimeGet( ); + // Substract Unix to Gps epcoh offset. The system time is based on Unix time. + curTime.Seconds -= UNIX_GPS_EPOCH_OFFSET; + LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 0 ) & 0xFF; + LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 8 ) & 0xFF; + LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 16 ) & 0xFF; + LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 24 ) & 0xFF; + break; + } + case CLOCK_SYNC_FORCE_RESYNC_REQ: + { + LmhpClockSyncState.NbTransmissions = mcpsIndication->Buffer[cmdIndex++] & 0X07; + break; + } + } + } + + if( dataBufferIndex != 0 ) + { + // Answer commands + LmHandlerAppData_t appData = + { + .Buffer = LmhpClockSyncState.DataBuffer, + .BufferSize = dataBufferIndex, + .Port = CLOCK_SYNC_PORT + }; + LmhpClockSyncPackage.OnSendRequest( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); + } +} + +LmHandlerErrorStatus_t LmhpClockSyncAppTimeReq( void ) +{ + if( LmHandlerIsBusy( ) == true ) + { + return LORAMAC_HANDLER_ERROR; + } + + if( LmhpClockSyncState.AppTimeReqPending == false ) + { + MibRequestConfirm_t mibReq; + + // Disable ADR + mibReq.Type = MIB_ADR; + LoRaMacMibGetRequestConfirm( &mibReq ); + LmhpClockSyncState.AdrEnabledPrev = mibReq.Param.AdrEnable; + mibReq.Param.AdrEnable = false; + LoRaMacMibSetRequestConfirm( &mibReq ); + + // Set NbTrans = 1 + mibReq.Type = MIB_CHANNELS_NB_TRANS; + LoRaMacMibGetRequestConfirm( &mibReq ); + LmhpClockSyncState.NbTransPrev = mibReq.Param.ChannelsNbTrans; + mibReq.Param.ChannelsNbTrans = 1; + LoRaMacMibSetRequestConfirm( &mibReq ); + + // Store data rate + mibReq.Type = MIB_CHANNELS_DATARATE; + LoRaMacMibGetRequestConfirm( &mibReq ); + LmhpClockSyncState.DataratePrev = mibReq.Param.ChannelsDatarate; + + // Add DeviceTimeReq MAC command. + // In case the network server supports this more precise command + // this package will use DeviceTimeAns answer as clock synchronization + // mechanism. + LmhpClockSyncPackage.OnDeviceTimeRequest( ); + } + + SysTime_t curTime = SysTimeGet( ); + uint8_t dataBufferIndex = 0; + + // Substract Unix to Gps epcoh offset. The system time is based on Unix time. + curTime.Seconds -= UNIX_GPS_EPOCH_OFFSET; + + LmhpClockSyncState.DataBuffer[dataBufferIndex++] = CLOCK_SYNC_APP_TIME_REQ; + LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 0 ) & 0xFF; + LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 8 ) & 0xFF; + LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 16 ) & 0xFF; + LmhpClockSyncState.DataBuffer[dataBufferIndex++] = ( curTime.Seconds >> 24 ) & 0xFF; + LmhpClockSyncState.TimeReqParam.Fields.AnsRequired = 0; + LmhpClockSyncState.DataBuffer[dataBufferIndex++] = LmhpClockSyncState.TimeReqParam.Value; + + LmHandlerAppData_t appData = + { + .Buffer = LmhpClockSyncState.DataBuffer, + .BufferSize = dataBufferIndex, + .Port = CLOCK_SYNC_PORT + }; + LmhpClockSyncState.AppTimeReqPending = true; + return LmhpClockSyncPackage.OnSendRequest( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); +} diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpClockSync.h b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpClockSync.h new file mode 100644 index 00000000..c9b207ca --- /dev/null +++ b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpClockSync.h @@ -0,0 +1,49 @@ +/*! + * \file LmhpClockSync.h + * + * \brief Implements the LoRa-Alliance clock synchronization package + * Specification: https://lora-alliance.org/sites/default/files/2018-09/application_layer_clock_synchronization_v1.0.0.pdf + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2018 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + */ +#ifndef __LMHP_CLOCK_SYNC_H__ +#define __LMHP_CLOCK_SYNC_H__ + +#include "LoRaMac.h" +#include "LmHandlerTypes.h" +#include "LmhPackage.h" + +/*! + * Clock sync package identifier. + * + * \remark This value must be unique amongst the packages + */ +#define PACKAGE_ID_CLOCK_SYNC 1 + +/*! + * Clock sync package parameters + * + * This package doesn't require parameters + */ +//typedef struct LmphClockSyncParams_s +//{ +//}LmphClockSyncParams_t; + +LmhPackage_t *LmphClockSyncPackageFactory( void ); + +LmHandlerErrorStatus_t LmhpClockSyncAppTimeReq( void ); + +#endif // __LMHP_CLOCK_SYNC_H__ diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpCompliance.c b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpCompliance.c new file mode 100644 index 00000000..c305b851 --- /dev/null +++ b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpCompliance.c @@ -0,0 +1,491 @@ +/*! + * \file LmhpCompliance.c + * + * \brief Implements the LoRa-Alliance certification protocol handling + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2018 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + */ +#include +#include +#include +#include "utilities.h" +#include "timer.h" +#include "LoRaMac.h" +#include "LoRaMacTest.h" +#include "Region.h" +#include "LmhPackage.h" +#include "LmhpCompliance.h" + +/*! + * LoRaWAN compliance certification protocol port number. + * + * LoRaWAN Specification V1.0.2, chapter 4.3.2 + */ +#define COMPLIANCE_PORT 224 + +/*! + * Defines the compliance mode data transmission duty cycle. + * An uplink will be transmitted ever \ref COMPLIANCE_TX_DUTYCYCLE [ms]. + */ +#define COMPLIANCE_TX_DUTYCYCLE 5000 + +/*! + * LoRaWAN compliance tests support data + */ +typedef struct ComplianceTestState_s +{ + bool Initialized; + bool IsRunning; + uint8_t State; + bool TxPending; + bool IsTxConfirmed; + uint8_t Port; + uint8_t DataBufferMaxSize; + uint8_t DataBufferSize; + uint8_t *DataBuffer; + uint16_t DownLinkCounter; + bool LinkCheck; + uint8_t DemodMargin; + uint8_t NbGateways; +}ComplianceTestState_t; + +/*! + * Timer to handle the application data transmission duty cycle + */ +static TimerEvent_t ComplianceTxNextPacketTimer; + +/*! + * Holds the compliance test current context + */ +static ComplianceTestState_t ComplianceTestState = +{ + .Initialized = false, + .IsRunning = false, + .State = 0, + .TxPending = false, + .IsTxConfirmed = false, + .Port = 0, + .DataBufferMaxSize = 0, + .DataBufferSize = 0, + .DataBuffer = NULL, + .DownLinkCounter = 0, + .LinkCheck = false, + .DemodMargin = 0, + .NbGateways = 0 +}; + +/*! + * LoRaWAN compliance tests protocol handler parameters + */ +static LmhpComplianceParams_t* LmhpComplianceParams; + +/*! + * Initializes the compliance tests with provided parameters + * + * \param [IN] params Structure containing the initial compliance + * tests parameters. + * \param [IN] dataBuffer Pointer to main application buffer + * \param [IN] dataBufferMaxSize Application buffer maximum size + */ +static void LmhpComplianceInit( void *params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize ); + +/*! + * Returns the current compliance certification protocol initialization status. + * + * \retval status Compliance certification protocol initialization status + * [true: Initialized, false: Not initialized] + */ +static bool LmhpComplianceIsInitialized( void ); + +/*! + * Returns the current compliance certification protocol handling status. + * + * \retval status Compliance certification protocol handling status + * [true: Running, false: Not running] + */ +static bool LmhpComplianceIsRunning( void ); + +/*! + * Processes the LoRaMac Compliance events. + */ +static void LmhpComplianceProcess( void ); + +/*! + * Processes the MCPS Indication + * + * \param [IN] mcpsIndication MCPS indication primitive data + */ +static void LmhpComplianceOnMcpsIndication( McpsIndication_t *mcpsIndication ); + +/*! + * Processes the MLME Confirm + * + * \param [IN] mlmeConfirm MLME confirmation primitive data + */ +static void LmhpComplianceOnMlmeConfirm( MlmeConfirm_t *mlmeConfirm ); + +/*! + * Function executed on TxNextPacket Timeout event + */ +static void OnComplianceTxNextPacketTimerEvent( void *context ); + +/*! + * Processes the data to transmit on port \ref COMPLIANCE_PORT + * Handles the compliance certification protocol data transmission + * + * \retval status Returns \ref LORAMAC_HANDLER_SUCCESS if request has been + * processed else \ref LORAMAC_HANDLER_ERROR + */ +static LmHandlerErrorStatus_t LmhpComplianceTxProcess( void ); + +LmhPackage_t LmhpCompliancePackage = +{ + .Port = COMPLIANCE_PORT, + .Init = LmhpComplianceInit, + .IsInitialized = LmhpComplianceIsInitialized, + .IsRunning = LmhpComplianceIsRunning, + .Process = LmhpComplianceProcess, + .OnMcpsConfirmProcess = NULL, // Not used in this package + .OnMcpsIndicationProcess = LmhpComplianceOnMcpsIndication, + .OnMlmeConfirmProcess = LmhpComplianceOnMlmeConfirm, + .OnMlmeIndicationProcess = NULL, // Not used in this package + .OnMacMcpsRequest = NULL, // To be initialized by LmHandler + .OnMacMlmeRequest = NULL, // To be initialized by LmHandler + .OnJoinRequest = NULL, // To be initialized by LmHandler + .OnSendRequest = NULL, // To be initialized by LmHandler + .OnDeviceTimeRequest = NULL, // To be initialized by LmHandler + .OnSysTimeUpdate = NULL, // To be initialized by LmHandler +}; + +LmhPackage_t *LmphCompliancePackageFactory( void ) +{ + return &LmhpCompliancePackage; +} + +static void LmhpComplianceInit( void *params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize ) +{ + if( ( params != NULL ) && ( dataBuffer != NULL ) ) + { + LmhpComplianceParams = ( LmhpComplianceParams_t* )params; + ComplianceTestState.DataBuffer = dataBuffer; + ComplianceTestState.DataBufferMaxSize = dataBufferMaxSize; + ComplianceTestState.Initialized = true; + } + else + { + LmhpComplianceParams = NULL; + ComplianceTestState.Initialized = false; + } +} + +static bool LmhpComplianceIsInitialized( void ) +{ + return ComplianceTestState.Initialized; +} + +static bool LmhpComplianceIsRunning( void ) +{ + if( ComplianceTestState.Initialized == false ) + { + return false; + } + + return ComplianceTestState.IsRunning; +} + +static void LmhpComplianceOnMlmeConfirm( MlmeConfirm_t *mlmeConfirm ) +{ + if( ComplianceTestState.Initialized == false ) + { + return; + } + + if( mlmeConfirm->MlmeRequest == MLME_LINK_CHECK ) + { + ComplianceTestState.LinkCheck = true; + ComplianceTestState.DemodMargin = mlmeConfirm->DemodMargin; + ComplianceTestState.NbGateways = mlmeConfirm->NbGateways; + } +} + +static LmHandlerErrorStatus_t LmhpComplianceTxProcess( void ) +{ + if( ComplianceTestState.Initialized == false ) + { + return LORAMAC_HANDLER_ERROR; + } + + if( ComplianceTestState.LinkCheck == true ) + { + ComplianceTestState.LinkCheck = false; + ComplianceTestState.DataBufferSize = 3; + ComplianceTestState.DataBuffer[0] = 5; + ComplianceTestState.DataBuffer[1] = ComplianceTestState.DemodMargin; + ComplianceTestState.DataBuffer[2] = ComplianceTestState.NbGateways; + ComplianceTestState.State = 1; + } + else + { + switch( ComplianceTestState.State ) + { + case 4: + ComplianceTestState.State = 1; + break; + case 1: + ComplianceTestState.DataBufferSize = 2; + ComplianceTestState.DataBuffer[0] = ComplianceTestState.DownLinkCounter >> 8; + ComplianceTestState.DataBuffer[1] = ComplianceTestState.DownLinkCounter; + break; + } + } + + LmHandlerAppData_t appData = + { + .Buffer = ComplianceTestState.DataBuffer, + .BufferSize = ComplianceTestState.DataBufferSize, + .Port = COMPLIANCE_PORT + }; + + // Schedule next transmission + TimerStart( &ComplianceTxNextPacketTimer ); + + return LmhpCompliancePackage.OnSendRequest( &appData, ( LmHandlerMsgTypes_t )ComplianceTestState.IsTxConfirmed ); +} + +static void LmhpComplianceOnMcpsIndication( McpsIndication_t* mcpsIndication ) +{ + if( ComplianceTestState.Initialized == false ) + { + return; + } + + if( mcpsIndication->RxData == false ) + { + return; + } + + if( mcpsIndication->Port != COMPLIANCE_PORT ) + { + return; + } + + if( ComplianceTestState.IsRunning == false ) + { + // Check compliance test enable command (i) + if( ( mcpsIndication->BufferSize == 4 ) && + ( mcpsIndication->Buffer[0] == 0x01 ) && + ( mcpsIndication->Buffer[1] == 0x01 ) && + ( mcpsIndication->Buffer[2] == 0x01 ) && + ( mcpsIndication->Buffer[3] == 0x01 ) ) + { + MibRequestConfirm_t mibReq; + + // Initialize compliance test mode context + ComplianceTestState.IsTxConfirmed = false; + ComplianceTestState.TxPending = false; + ComplianceTestState.Port = 224; + ComplianceTestState.DataBufferSize = 2; + ComplianceTestState.DownLinkCounter = 0; + ComplianceTestState.LinkCheck = false; + ComplianceTestState.DemodMargin = 0; + ComplianceTestState.NbGateways = 0; + ComplianceTestState.IsRunning = true; + ComplianceTestState.State = 1; + + // Enable ADR while in compliance test mode + mibReq.Type = MIB_ADR; + mibReq.Param.AdrEnable = true; + LoRaMacMibSetRequestConfirm( &mibReq ); + + // Disable duty cycle enforcement while in compliance test mode + LoRaMacTestSetDutyCycleOn( false ); + + // Stop peripherals + if( LmhpComplianceParams->StopPeripherals != NULL ) + { + LmhpComplianceParams->StopPeripherals( ); + } + // Initialize compliance protocol transmission timer + TimerInit( &ComplianceTxNextPacketTimer, OnComplianceTxNextPacketTimerEvent ); + TimerSetValue( &ComplianceTxNextPacketTimer, COMPLIANCE_TX_DUTYCYCLE ); + + // Confirm compliance test protocol activation + CRITICAL_SECTION_BEGIN( ); + ComplianceTestState.TxPending = true; //LmhpComplianceTxProcess( ); + CRITICAL_SECTION_END( ); + } + } + else + { + // Increment the compliance certification protocol downlink counter + ComplianceTestState.DownLinkCounter++; + + // Parse compliance test protocol + ComplianceTestState.State = mcpsIndication->Buffer[0]; + switch( ComplianceTestState.State ) + { + case 0: // Check compliance test disable command (ii) + { + MibRequestConfirm_t mibReq; + + TimerStop( &ComplianceTxNextPacketTimer ); + + // Disable compliance test mode and reset the downlink counter. + ComplianceTestState.DownLinkCounter = 0; + ComplianceTestState.IsRunning = false; + + // Restore previous ADR seeting + mibReq.Type = MIB_ADR; + mibReq.Param.AdrEnable = LmhpComplianceParams->AdrEnabled; + LoRaMacMibSetRequestConfirm( &mibReq ); + + // Enable duty cycle enforcement + LoRaMacTestSetDutyCycleOn( LmhpComplianceParams->DutyCycleEnabled ); + + // Restart peripherals + if( LmhpComplianceParams->StartPeripherals != NULL ) + { + LmhpComplianceParams->StartPeripherals( ); + } + } + break; + case 1: // (iii, iv) + ComplianceTestState.DataBufferSize = 2; + break; + case 2: // Enable confirmed messages (v) + ComplianceTestState.IsTxConfirmed = true; + ComplianceTestState.State = 1; + break; + case 3: // Disable confirmed messages (vi) + ComplianceTestState.IsTxConfirmed = false; + ComplianceTestState.State = 1; + break; + case 4: // (vii) + ComplianceTestState.DataBufferSize = mcpsIndication->BufferSize; + + ComplianceTestState.DataBuffer[0] = 4; + for( uint8_t i = 1; i < MIN( ComplianceTestState.DataBufferSize, ComplianceTestState.DataBufferMaxSize ); i++ ) + { + ComplianceTestState.DataBuffer[i] = mcpsIndication->Buffer[i] + 1; + } + break; + case 5: // (viii) + { + MlmeReq_t mlmeReq; + + mlmeReq.Type = MLME_LINK_CHECK; + + LmhpCompliancePackage.OnMacMlmeRequest( LoRaMacMlmeRequest( &mlmeReq ), &mlmeReq, 0 ); + } + break; + case 6: // (ix) + { + MibRequestConfirm_t mibReq; + + // Disable TestMode and revert back to normal operation + // Disable compliance test mode and reset the downlink counter. + ComplianceTestState.DownLinkCounter = 0; + ComplianceTestState.IsRunning = false; + + // Restore previous ADR seeting + mibReq.Type = MIB_ADR; + mibReq.Param.AdrEnable = LmhpComplianceParams->AdrEnabled; + LoRaMacMibSetRequestConfirm( &mibReq ); + + // Enable duty cycle enforcement + LoRaMacTestSetDutyCycleOn( LmhpComplianceParams->DutyCycleEnabled ); + + // Restart peripherals + if( LmhpComplianceParams->StartPeripherals != NULL ) + { + LmhpComplianceParams->StartPeripherals( ); + } + + LmhpCompliancePackage.OnJoinRequest( true ); + } + break; + case 7: // (x) + { + MlmeReq_t mlmeReq; + if( mcpsIndication->BufferSize == 3 ) + { + mlmeReq.Type = MLME_TXCW; + mlmeReq.Req.TxCw.Timeout = ( uint16_t )( ( mcpsIndication->Buffer[1] << 8 ) | mcpsIndication->Buffer[2] ); + } + else if( mcpsIndication->BufferSize == 7 ) + { + mlmeReq.Type = MLME_TXCW_1; + mlmeReq.Req.TxCw.Timeout = ( uint16_t )( ( mcpsIndication->Buffer[1] << 8 ) | mcpsIndication->Buffer[2] ); + mlmeReq.Req.TxCw.Frequency = ( uint32_t )( ( mcpsIndication->Buffer[3] << 16 ) | ( mcpsIndication->Buffer[4] << 8 ) | mcpsIndication->Buffer[5] ) * 100; + mlmeReq.Req.TxCw.Power = mcpsIndication->Buffer[6]; + } + LmhpCompliancePackage.OnMacMlmeRequest( LoRaMacMlmeRequest( &mlmeReq ), &mlmeReq, 0 ); + ComplianceTestState.State = 1; + } + break; + case 8: // Send DeviceTimeReq + { + MlmeReq_t mlmeReq; + + mlmeReq.Type = MLME_DEVICE_TIME; + + LmhpCompliancePackage.OnMacMlmeRequest( LoRaMacMlmeRequest( &mlmeReq ), &mlmeReq, 0 ); + } + break; + case 9: // Switch end device Class + { + MibRequestConfirm_t mibReq; + + mibReq.Type = MIB_DEVICE_CLASS; + // CLASS_A = 0, CLASS_B = 1, CLASS_C = 2 + mibReq.Param.Class = ( DeviceClass_t )mcpsIndication->Buffer[1];; + LoRaMacMibSetRequestConfirm( &mibReq ); + } + break; + case 10: // Send PingSlotInfoReq + { + MlmeReq_t mlmeReq; + + mlmeReq.Type = MLME_PING_SLOT_INFO; + mlmeReq.Req.PingSlotInfo.PingSlot.Value = mcpsIndication->Buffer[1]; + + LmhpCompliancePackage.OnMacMlmeRequest( LoRaMacMlmeRequest( &mlmeReq ), &mlmeReq, 0 ); + } + break; + default: + break; + } + } +} + +static void LmhpComplianceProcess( void ) +{ + bool isPending; + + CRITICAL_SECTION_BEGIN( ); + isPending = ComplianceTestState.TxPending; + ComplianceTestState.TxPending = false; + CRITICAL_SECTION_END( ); + if( isPending == true ) + { + LmhpComplianceTxProcess( ); + } +} + +static void OnComplianceTxNextPacketTimerEvent( void* context ) +{ + ComplianceTestState.TxPending = true; +} diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpCompliance.h b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpCompliance.h new file mode 100644 index 00000000..75587815 --- /dev/null +++ b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpCompliance.h @@ -0,0 +1,68 @@ +/*! + * \file LmhpCompliance.h + * + * \brief Implements the LoRa-Alliance certification protocol handling + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2018 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + */ +#ifndef __LMHP_COMPLIANCE__ +#define __LMHP_COMPLIANCE__ + +#include "LoRaMac.h" +#include "LmHandlerTypes.h" +#include "LmhPackage.h" + +/*! + * Compliance package identifier. + * + * \remark This value must be unique amongst the packages + */ +#define PACKAGE_ID_COMPLIANCE 0 + +/*! + * Compliance test protocol handler parameters + */ +typedef struct LmhpComplianceParams_s +{ + /*! + * Holds the ADR state + */ + bool AdrEnabled; + /*! + * LoRaWAN ETSI duty cycle control enable/disable + * + * \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes + */ + bool DutyCycleEnabled; + /*! + * Stops unnecessary peripherals. + * + * \remark Use for the compliance tests protocol handling in order to + * reduce the power consumption. + */ + void ( *StopPeripherals )( void ); + /*! + * Starts previously stopped peripherals. + * + * \remark Use for the compliance tests protocol handling in order to + * reduce the power consumption. + */ + void ( *StartPeripherals )( void ); +}LmhpComplianceParams_t; + +LmhPackage_t *LmphCompliancePackageFactory( void ); + +#endif // __LMHP_COMPLIANCE__ diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpFragmentation.c b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpFragmentation.c new file mode 100644 index 00000000..0c8db61d --- /dev/null +++ b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpFragmentation.c @@ -0,0 +1,527 @@ +/*! + * \file LmhpFragmentation.c + * + * \brief Implements the LoRa-Alliance fragmented data block transport package + * Specification: https://lora-alliance.org/sites/default/files/2018-09/fragmented_data_block_transport_v1.0.0.pdf + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2018 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + */ +#include "LmHandler.h" +#include "LmhpFragmentation.h" +#include "FragDecoder.h" + +/*! + * LoRaWAN Application Layer Fragmented Data Block Transport Specification + */ +#define FRAGMENTATION_PORT 201 + +#define FRAGMENTATION_ID 3 +#define FRAGMENTATION_VERSION 1 + +#define FRAGMENTATION_MAX_SESSIONS 4 + +// Fragmentation Tx delay state +typedef enum LmhpFragmentationTxDelayStates_e +{ + // Tx delay in idle state. + FRAGMENTATION_TX_DELAY_STATE_IDLE, + // Tx delay to be started. + FRAGMENTATION_TX_DELAY_STATE_START, + // Tx delay to be stopped. + FRAGMENTATION_TX_DELAY_STATE_STOP, +}LmhpFragmentationTxDelayStates_t; + +/*! + * Package current context + */ +typedef struct LmhpFragmentationState_s +{ + bool Initialized; + bool IsRunning; + LmhpFragmentationTxDelayStates_t TxDelayState; + uint8_t DataBufferMaxSize; + uint8_t *DataBuffer; + uint8_t *file; +}LmhpFragmentationState_t; + +typedef enum LmhpFragmentationMoteCmd_e +{ + FRAGMENTATION_PKG_VERSION_ANS = 0x00, + FRAGMENTATION_FRAG_STATUS_ANS = 0x01, + FRAGMENTATION_FRAG_SESSION_SETUP_ANS = 0x02, + FRAGMENTATION_FRAG_SESSION_DELETE_ANS = 0x03, +}LmhpFragmentationMoteCmd_t; + +typedef enum LmhpFragmentationSrvCmd_e +{ + FRAGMENTATION_PKG_VERSION_REQ = 0x00, + FRAGMENTATION_FRAG_STATUS_REQ = 0x01, + FRAGMENTATION_FRAG_SESSION_SETUP_REQ = 0x02, + FRAGMENTATION_FRAG_SESSION_DELETE_REQ = 0x03, + FRAGMENTATION_DATA_FRAGMENT = 0x08, +}LmhpFragmentationSrvCmd_t; + +/*! + * LoRaWAN fragmented data block transport handler parameters + */ +static LmhpFragmentationParams_t* LmhpFragmentationParams; + +/*! + * Initializes the package with provided parameters + * + * \param [IN] params Pointer to the package parameters + * \param [IN] dataBuffer Pointer to main application buffer + * \param [IN] dataBufferMaxSize Main application buffer maximum size + */ +static void LmhpFragmentationInit( void *params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize ); + +/*! + * Returns the current package initialization status. + * + * \retval status Package initialization status + * [true: Initialized, false: Not initialized] + */ +static bool LmhpFragmentationIsInitialized( void ); + +/*! + * Returns the package operation status. + * + * \retval status Package operation status + * [true: Running, false: Not running] + */ +static bool LmhpFragmentationIsRunning( void ); + +/*! + * Processes the internal package events. + */ +static void LmhpFragmentationProcess( void ); + +/*! + * Processes the MCPS Indication + * + * \param [IN] mcpsIndication MCPS indication primitive data + */ +static void LmhpFragmentationOnMcpsIndication( McpsIndication_t *mcpsIndication ); + +static LmhpFragmentationState_t LmhpFragmentationState = +{ + .Initialized = false, + .IsRunning = false, + .TxDelayState = FRAGMENTATION_TX_DELAY_STATE_IDLE, +}; + +typedef struct FragGroupData_s +{ + bool IsActive; + union + { + uint8_t Value; + struct + { + uint8_t McGroupBitMask: 4; + uint8_t FragIndex: 2; + uint8_t RFU: 2; + }Fields; + }FragSession; + uint16_t FragNb; + uint8_t FragSize; + union + { + uint8_t Value; + struct + { + uint8_t BlockAckDelay: 3; + uint8_t FragAlgo: 3; + uint8_t RFU: 2; + }Fields; + }Control; + uint8_t Padding; + uint32_t Descriptor; +}FragGroupData_t; + +typedef struct FragSessionData_s +{ + FragGroupData_t FragGroupData; + FragDecoderStatus_t FragDecoderStatus; + int32_t FragDecoderPorcessStatus; +}FragSessionData_t; + +FragSessionData_t FragSessionData[FRAGMENTATION_MAX_SESSIONS]; + +// Answer struct for the commands. +LmHandlerAppData_t DelayedReplyAppData; + +static LmhPackage_t LmhpFragmentationPackage = +{ + .Port = FRAGMENTATION_PORT, + .Init = LmhpFragmentationInit, + .IsInitialized = LmhpFragmentationIsInitialized, + .IsRunning = LmhpFragmentationIsRunning, + .Process = LmhpFragmentationProcess, + .OnMcpsConfirmProcess = NULL, // Not used in this package + .OnMcpsIndicationProcess = LmhpFragmentationOnMcpsIndication, + .OnMlmeConfirmProcess = NULL, // Not used in this package + .OnMlmeIndicationProcess = NULL, // Not used in this package + .OnMacMcpsRequest = NULL, // To be initialized by LmHandler + .OnMacMlmeRequest = NULL, // To be initialized by LmHandler + .OnJoinRequest = NULL, // To be initialized by LmHandler + .OnSendRequest = NULL, // To be initialized by LmHandler + .OnDeviceTimeRequest = NULL, // To be initialized by LmHandler + .OnSysTimeUpdate = NULL, // To be initialized by LmHandler +}; + +// Delay value. +static uint32_t TxDelayTime; + +// Fragment Delay Timer struct +static TimerEvent_t FragmentTxDelayTimer; + +/*! + * \brief Callback function for Fragment delay timer. + */ +static void OnFragmentTxDelay( void* context ) +{ + // Stop the timer. + TimerStop( &FragmentTxDelayTimer ); + // Set the state. + LmhpFragmentationState.TxDelayState = FRAGMENTATION_TX_DELAY_STATE_STOP; +} + +LmhPackage_t *LmhpFragmentationPackageFactory( void ) +{ + return &LmhpFragmentationPackage; +} + +static void LmhpFragmentationInit( void *params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize ) +{ + if( ( params != NULL ) && ( dataBuffer != NULL ) ) + { + LmhpFragmentationParams = ( LmhpFragmentationParams_t* )params; + LmhpFragmentationState.DataBuffer = dataBuffer; + LmhpFragmentationState.DataBufferMaxSize = dataBufferMaxSize; + LmhpFragmentationState.Initialized = true; + LmhpFragmentationState.IsRunning = true; + // Initialize Fragmentation delay time. + TxDelayTime = 0; + // Initialize Fragmentation delay timer. + TimerInit( &FragmentTxDelayTimer, OnFragmentTxDelay ); + } + else + { + LmhpFragmentationParams = NULL; + LmhpFragmentationState.IsRunning = false; + LmhpFragmentationState.Initialized = false; + } +} + +static bool LmhpFragmentationIsInitialized( void ) +{ + return LmhpFragmentationState.Initialized; +} + +static bool LmhpFragmentationIsRunning( void ) +{ + if( LmhpFragmentationState.Initialized == false ) + { + return false; + } + + return LmhpFragmentationState.IsRunning; +} + +static void LmhpFragmentationProcess( void ) +{ + LmhpFragmentationTxDelayStates_t delayTimerState; + + CRITICAL_SECTION_BEGIN( ); + delayTimerState = LmhpFragmentationState.TxDelayState; + // Set the state to idle so that the other states are executed only when they are set + // in the appropriate functions. + LmhpFragmentationState.TxDelayState = FRAGMENTATION_TX_DELAY_STATE_IDLE; + CRITICAL_SECTION_END( ); + + switch( delayTimerState ) + { + case FRAGMENTATION_TX_DELAY_STATE_START: + // Set the timer with the initially calculated Delay value. + TimerSetValue( &FragmentTxDelayTimer, TxDelayTime ); + // Start the timer. + TimerStart( &FragmentTxDelayTimer ); + break; + case FRAGMENTATION_TX_DELAY_STATE_STOP: + // Send the reply. + LmHandlerSend( &DelayedReplyAppData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); + break; + case FRAGMENTATION_TX_DELAY_STATE_IDLE: + // Intentional fall through + default: + // Nothing to do. + break; + } +} + +static void LmhpFragmentationOnMcpsIndication( McpsIndication_t *mcpsIndication ) +{ + uint8_t cmdIndex = 0; + uint8_t dataBufferIndex = 0; + bool isAnswerDelayed = false; + // Answer struct for the commands. + LmHandlerAppData_t cmdReplyAppData; + // Co-efficient used to calculate delay. + uint8_t blockAckDelay = 0; + + while( cmdIndex < mcpsIndication->BufferSize ) + { + switch( mcpsIndication->Buffer[cmdIndex++] ) + { + case FRAGMENTATION_PKG_VERSION_REQ: + { + if( mcpsIndication->Multicast == 1 ) + { + // Multicast channel. Don't process command. + break; + } + LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FRAGMENTATION_PKG_VERSION_ANS; + LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FRAGMENTATION_ID; + LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FRAGMENTATION_VERSION; + break; + } + case FRAGMENTATION_FRAG_STATUS_REQ: + { + uint8_t fragIndex = mcpsIndication->Buffer[cmdIndex++]; + uint8_t participants = fragIndex & 0x01; + + fragIndex >>= 1; + FragSessionData[fragIndex].FragDecoderStatus = FragDecoderGetStatus( ); + + if( ( participants == 1 ) || + ( ( participants == 0 ) && ( FragSessionData[fragIndex].FragDecoderStatus.FragNbLost > 0 ) ) ) + { + LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FRAGMENTATION_FRAG_STATUS_ANS; + LmhpFragmentationState.DataBuffer[dataBufferIndex++] = ( fragIndex << 14 ) | + ( ( FragSessionData[fragIndex].FragDecoderStatus.FragNbRx >> 8 ) & 0x3F ); + LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FragSessionData[fragIndex].FragDecoderStatus.FragNbRx & 0xFF; + LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FragSessionData[fragIndex].FragDecoderStatus.FragNbLost; + LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FragSessionData[fragIndex].FragDecoderStatus.MatrixError & 0x01; + + // Fetch the co-efficient value required to calculate delay of that respective session. + blockAckDelay = FragSessionData[fragIndex].FragGroupData.Control.Fields.BlockAckDelay; + isAnswerDelayed = true; + } + break; + } + case FRAGMENTATION_FRAG_SESSION_SETUP_REQ: + { + if( mcpsIndication->Multicast == 1 ) + { + // Multicast channel. Don't process command. + break; + } + FragSessionData_t fragSessionData; + uint8_t status = 0x00; + + fragSessionData.FragGroupData.FragSession.Value = mcpsIndication->Buffer[cmdIndex++]; + + fragSessionData.FragGroupData.FragNb = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x00FF; + fragSessionData.FragGroupData.FragNb |= ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0xFF00; + + fragSessionData.FragGroupData.FragSize = mcpsIndication->Buffer[cmdIndex++]; + + fragSessionData.FragGroupData.Control.Value = mcpsIndication->Buffer[cmdIndex++]; + + fragSessionData.FragGroupData.Padding = mcpsIndication->Buffer[cmdIndex++]; + + fragSessionData.FragGroupData.Descriptor = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF; + fragSessionData.FragGroupData.Descriptor += ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00; + fragSessionData.FragGroupData.Descriptor += ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000; + fragSessionData.FragGroupData.Descriptor += ( mcpsIndication->Buffer[cmdIndex++] << 24 ) & 0xFF000000; + + if( fragSessionData.FragGroupData.Control.Fields.FragAlgo > 0 ) + { + status |= 0x01; // Encoding unsupported + } + +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) + if( ( fragSessionData.FragGroupData.FragNb * fragSessionData.FragGroupData.FragSize ) > FragDecoderGetMaxFileSize( ) ) + { + status |= 0x02; // Not enough Memory + } +#else + if( ( fragSessionData.FragGroupData.FragNb * fragSessionData.FragGroupData.FragSize ) > LmhpFragmentationParams->BufferSize ) + { + status |= 0x02; // Not enough Memory + } +#endif + status |= ( fragSessionData.FragGroupData.FragSession.Fields.FragIndex << 6 ) & 0xC0; + if( fragSessionData.FragGroupData.FragSession.Fields.FragIndex >= FRAGMENTATION_MAX_SESSIONS ) + { + status |= 0x04; // FragSession index not supported + } + + // Descriptor is not really defined in the specification + // Not clear how to handle this. + // Currently the descriptor is always correct + if( fragSessionData.FragGroupData.Descriptor != 0x01020304 ) + { + //status |= 0x08; // Wrong Descriptor + } + + if( ( status & 0x0F ) == 0 ) + { + // The FragSessionSetup is accepted + fragSessionData.FragGroupData.IsActive = true; + fragSessionData.FragDecoderPorcessStatus = FRAG_SESSION_ONGOING; + FragSessionData[fragSessionData.FragGroupData.FragSession.Fields.FragIndex] = fragSessionData; +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) + FragDecoderInit( fragSessionData.FragGroupData.FragNb, + fragSessionData.FragGroupData.FragSize, + &LmhpFragmentationParams->DecoderCallbacks ); +#else + FragDecoderInit( fragSessionData.FragGroupData.FragNb, + fragSessionData.FragGroupData.FragSize, + LmhpFragmentationParams->Buffer, + LmhpFragmentationParams->BufferSize ); +#endif + } + LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FRAGMENTATION_FRAG_SESSION_SETUP_ANS; + LmhpFragmentationState.DataBuffer[dataBufferIndex++] = status; + isAnswerDelayed = false; + break; + } + case FRAGMENTATION_FRAG_SESSION_DELETE_REQ: + { + if( mcpsIndication->Multicast == 1 ) + { + // Multicast channel. Don't process command. + break; + } + uint8_t status = 0x00; + uint8_t id = mcpsIndication->Buffer[cmdIndex++] & 0x03; + + status |= id; + if( ( id >= FRAGMENTATION_MAX_SESSIONS ) || ( FragSessionData[id].FragGroupData.IsActive == false ) ) + { + status |= 0x04; // Session does not exist + } + else + { + // Delete session + FragSessionData[id].FragGroupData.IsActive = false; + } + LmhpFragmentationState.DataBuffer[dataBufferIndex++] = FRAGMENTATION_FRAG_SESSION_DELETE_ANS; + LmhpFragmentationState.DataBuffer[dataBufferIndex++] = status; + isAnswerDelayed = false; + break; + } + case FRAGMENTATION_DATA_FRAGMENT: + { + uint8_t fragIndex = 0; + uint16_t fragCounter = 0; + + fragCounter = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x00FF; + fragCounter |= ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0xFF00; + + fragIndex = ( fragCounter >> 14 ) & 0x03; + fragCounter &= 0x3FFF; + + if( mcpsIndication->Multicast == 1 ) + { + // Message received on a multicast address + // + // TODO: Not working yet + // + // Check McGroupBitMask + //uint8_t groupId = LoRaMacMcChannelGetGroupId( mcpsIndication->DevAddress ); + //if( ( groupId == 0xFF ) || + // ( ( FragSessionData[fragIndex].FragGroupData.FragSession.Fields.McGroupBitMask & ( 1 << groupId ) ) == 0 ) ) + //{ + // // Ignore message + // break; + //} + } + + if( FragSessionData[fragIndex].FragDecoderPorcessStatus == FRAG_SESSION_ONGOING ) + { + FragSessionData[fragIndex].FragDecoderPorcessStatus = FragDecoderProcess( fragCounter, &mcpsIndication->Buffer[cmdIndex] ); + FragSessionData[fragIndex].FragDecoderStatus = FragDecoderGetStatus( ); + if( LmhpFragmentationParams->OnProgress != NULL ) + { + LmhpFragmentationParams->OnProgress( FragSessionData[fragIndex].FragDecoderStatus.FragNbRx, + FragSessionData[fragIndex].FragGroupData.FragNb, + FragSessionData[fragIndex].FragGroupData.FragSize, + FragSessionData[fragIndex].FragDecoderStatus.FragNbLost ); + } + } + else + { + if( FragSessionData[fragIndex].FragDecoderPorcessStatus >= 0 ) + { + // Fragmentation successfully done + FragSessionData[fragIndex].FragDecoderPorcessStatus = FRAG_SESSION_NOT_STARTED; + if( LmhpFragmentationParams->OnDone != NULL ) + { +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) + LmhpFragmentationParams->OnDone( FragSessionData[fragIndex].FragDecoderPorcessStatus, + ( FragSessionData[fragIndex].FragGroupData.FragNb * FragSessionData[fragIndex].FragGroupData.FragSize ) - FragSessionData[fragIndex].FragGroupData.Padding ); +#else + LmhpFragmentationParams->OnDone( FragSessionData[fragIndex].FragDecoderPorcessStatus, + LmhpFragmentationParams->Buffer, + ( FragSessionData[fragIndex].FragGroupData.FragNb * FragSessionData[fragIndex].FragGroupData.FragSize ) - FragSessionData[fragIndex].FragGroupData.Padding ); +#endif + } + } + } + cmdIndex += FragSessionData[fragIndex].FragGroupData.FragSize; + break; + } + default: + { + break; + } + } + } + + // After processing the commands, if the end-node has to reply back then a flag is checked if the + // reply is to be sent immediately or with a delay. + // In some scenarios it is not desired that multiple end-notes send uplinks at the same time to + // the same server. (Example: Fragment status during a multicast FUOTA) + if( dataBufferIndex != 0 ) + { + // Prepare Answer that is to be transmitted + cmdReplyAppData.Buffer = LmhpFragmentationState.DataBuffer; + cmdReplyAppData.BufferSize = dataBufferIndex; + cmdReplyAppData.Port = FRAGMENTATION_PORT; + + if( isAnswerDelayed == true ) + { + // Delay value is calculated using BlockAckDelay which is communicated by server during the FragSessionSetupReq + // Pseudo Random Delay = rand(0:1) * 2^(blockAckDelay + 4) Seconds. + // Delay = Pseudo Random Delay * 1000 milli seconds. + // Eg: blockAckDelay = 7 + // Pseudo Random Delay = rand(0:1) * 2^11 + // rand(0:1) seconds = rand(0:1000) milliseconds + // Delay = rand(0:1000) * 2048 => 2048000ms = 34 minutes + TxDelayTime = randr( 0, 1000 ) * ( 1 << ( blockAckDelay + 4 ) ); + DelayedReplyAppData = cmdReplyAppData; + LmhpFragmentationState.TxDelayState = FRAGMENTATION_TX_DELAY_STATE_START; + } + else + { + // Send the prepared answer + LmhpFragmentationPackage.OnSendRequest( &cmdReplyAppData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); + } + } +} diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpFragmentation.h b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpFragmentation.h new file mode 100644 index 00000000..f5229a6d --- /dev/null +++ b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpFragmentation.h @@ -0,0 +1,92 @@ +/*! + * \file LmhpFragmentation.h + * + * \brief Implements the LoRa-Alliance fragmented data block transport package + * Specification: https://lora-alliance.org/sites/default/files/2018-09/fragmented_data_block_transport_v1.0.0.pdf + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2018 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + */ +#ifndef __LMHP_FRAGMENTATION_H__ +#define __LMHP_FRAGMENTATION_H__ + +#include "LoRaMac.h" +#include "LmHandlerTypes.h" +#include "LmhPackage.h" +#include "FragDecoder.h" + +/*! + * Fragmentation data block transport package identifier. + * + * \remark This value must be unique amongst the packages + */ +#define PACKAGE_ID_FRAGMENTATION 3 + +/*! + * Fragmentation package parameters + */ +typedef struct LmhpFragmentationParams_s +{ +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) + /*! + * FragDecoder Write/Read function callbacks + */ + FragDecoderCallbacks_t DecoderCallbacks; +#else + /*! + * Pointer to the un-fragmented received buffer. + */ + uint8_t *Buffer; + /*! + * Size of the un-fragmented received buffer. + */ + uint32_t BufferSize; +#endif + /*! + * Notifies the progress of the current fragmentation session + * + * \param [IN] fragCounter Fragment counter + * \param [IN] fragNb Number of fragments + * \param [IN] fragSize Size of fragments + * \param [IN] fragNbLost Number of lost fragments + */ + void ( *OnProgress )( uint16_t fragCounter, uint16_t fragNb, uint8_t fragSize, uint16_t fragNbLost ); +#if( FRAG_DECODER_FILE_HANDLING_NEW_API == 1 ) + /*! + * Notifies that the fragmentation session is finished + * + * \param [IN] status Fragmentation session status [FRAG_SESSION_ONGOING, + * FRAG_SESSION_FINISHED or + * FragDecoder.Status.FragNbLost] + * \param [IN] size Received file size + */ + void ( *OnDone )( int32_t status, uint32_t size ); +#else + /*! + * Notifies that the fragmentation session is finished + * + * \param [IN] status Fragmentation session status [FRAG_SESSION_ONGOING, + * FRAG_SESSION_FINISHED or + * FragDecoder.Status.FragNbLost] + * \param [IN] file Pointer to the reception file buffer + * \param [IN] size Received file size + */ + void ( *OnDone )( int32_t status, uint8_t *file, uint32_t size ); +#endif +}LmhpFragmentationParams_t; + +LmhPackage_t *LmhpFragmentationPackageFactory( void ); + +#endif // __LMHP_FRAGMENTATION_H__ diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpRemoteMcastSetup.c b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpRemoteMcastSetup.c new file mode 100644 index 00000000..0205a673 --- /dev/null +++ b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpRemoteMcastSetup.c @@ -0,0 +1,459 @@ +/*! + * \file LmhpRemoteMcastSetup.c + * + * \brief Implements the LoRa-Alliance remote multicast setup package + * Specification: https://lora-alliance.org/sites/default/files/2018-09/remote_multicast_setup_v1.0.0.pdf + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2018 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + */ +#include "LmHandler.h" +#include "LmhpRemoteMcastSetup.h" + +#define DBG_TRACE 1 + +#if DBG_TRACE == 1 + #include + /*! + * Works in the same way as the printf function does. + */ + #define DBG( ... ) \ + do \ + { \ + printf( __VA_ARGS__ ); \ + }while( 0 ) +#else + #define DBG( ... ) +#endif + +/*! + * LoRaWAN Application Layer Remote multicast setup Specification + */ +#define REMOTE_MCAST_SETUP_PORT 200 + +#define REMOTE_MCAST_SETUP_ID 2 +#define REMOTE_MCAST_SETUP_VERSION 1 + +typedef enum LmhpRemoteMcastSetupSessionStates_e +{ + REMOTE_MCAST_SETUP_SESSION_STATE_IDLE, + REMOTE_MCAST_SETUP_SESSION_STATE_START, + REMOTE_MCAST_SETUP_SESSION_STATE_STOP, +}LmhpRemoteMcastSetupSessionStates_t; + +/*! + * Package current context + */ +typedef struct LmhpRemoteMcastSetupState_s +{ + bool Initialized; + bool IsRunning; + LmhpRemoteMcastSetupSessionStates_t SessionState; + uint8_t DataBufferMaxSize; + uint8_t *DataBuffer; +}LmhpRemoteMcastSetupState_t; + +typedef enum LmhpRemoteMcastSetupMoteCmd_e +{ + REMOTE_MCAST_SETUP_PKG_VERSION_ANS = 0x00, + REMOTE_MCAST_SETUP_MC_GROUP_STATUS_ANS = 0x01, + REMOTE_MCAST_SETUP_MC_GROUP_SETUP_ANS = 0x02, + REMOTE_MCAST_SETUP_MC_GROUP_DELETE_ANS = 0x03, + REMOTE_MCAST_SETUP_MC_GROUP_CLASS_C_SESSION_ANS = 0x04, + REMOTE_MCAST_SETUP_MC_GROUP_CLASS_B_SESSION_ANS = 0x05, +}LmhpRemoteMcastSetupMoteCmd_t; + +typedef enum LmhpRemoteMcastSetupSrvCmd_e +{ + REMOTE_MCAST_SETUP_PKG_VERSION_REQ = 0x00, + REMOTE_MCAST_SETUP_MC_GROUP_STATUS_REQ = 0x01, + REMOTE_MCAST_SETUP_MC_GROUP_SETUP_REQ = 0x02, + REMOTE_MCAST_SETUP_MC_GROUP_DELETE_REQ = 0x03, + REMOTE_MCAST_SETUP_MC_GROUP_CLASS_C_SESSION_REQ = 0x04, + REMOTE_MCAST_SETUP_MC_GROUP_CLASS_B_SESSION_REQ = 0x05, +}LmhpRemoteMcastSetupSrvCmd_t; + +/*! + * Initializes the package with provided parameters + * + * \param [IN] params Pointer to the package parameters + * \param [IN] dataBuffer Pointer to main application buffer + * \param [IN] dataBufferMaxSize Main application buffer maximum size + */ +static void LmhpRemoteMcastSetupInit( void *params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize ); + +/*! + * Returns the current package initialization status. + * + * \retval status Package initialization status + * [true: Initialized, false: Not initialized] + */ +static bool LmhpRemoteMcastSetupIsInitialized( void ); + +/*! + * Returns the package operation status. + * + * \retval status Package operation status + * [true: Running, false: Not running] + */ +static bool LmhpRemoteMcastSetupIsRunning( void ); + +/*! + * Processes the internal package events. + */ +static void LmhpRemoteMcastSetupProcess( void ); + +/*! + * Processes the MCPS Indication + * + * \param [IN] mcpsIndication MCPS indication primitive data + */ +static void LmhpRemoteMcastSetupOnMcpsIndication( McpsIndication_t *mcpsIndication ); + +static void OnSessionStartTimer( void *context ); + +static void OnSessionStopTimer( void *context ); + +static LmhpRemoteMcastSetupState_t LmhpRemoteMcastSetupState = +{ + .Initialized = false, + .IsRunning = false, + .SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_IDLE, +}; + +typedef struct McGroupData_s +{ + union + { + uint8_t Value; + struct + { + uint8_t McGroupId: 2; + uint8_t RFU: 6; + }Fields; + }IdHeader; + uint32_t McAddr; + uint8_t McKeyEncrypted[16]; + uint32_t McFCountMin; + uint32_t McFCountMax; +}McGroupData_t; + +typedef enum eSessionState +{ + SESSION_STOPED, + SESSION_STARTED +}SessionState_t; + +typedef struct McSessionData_s +{ + McGroupData_t McGroupData; + SessionState_t SessionState; + uint32_t SessionTime; + uint8_t SessionTimeout; + McRxParams_t RxParams; +}McSessionData_t; + +McSessionData_t McSessionData[LORAMAC_MAX_MC_CTX]; + +/*! + * Session start timer + */ +static TimerEvent_t SessionStartTimer; + +/*! + * Session start timer + */ +static TimerEvent_t SessionStopTimer; + +static LmhPackage_t LmhpRemoteMcastSetupPackage = +{ + .Port = REMOTE_MCAST_SETUP_PORT, + .Init = LmhpRemoteMcastSetupInit, + .IsInitialized = LmhpRemoteMcastSetupIsInitialized, + .IsRunning = LmhpRemoteMcastSetupIsRunning, + .Process = LmhpRemoteMcastSetupProcess, + .OnMcpsConfirmProcess = NULL, // Not used in this package + .OnMcpsIndicationProcess = LmhpRemoteMcastSetupOnMcpsIndication, + .OnMlmeConfirmProcess = NULL, // Not used in this package + .OnMlmeIndicationProcess = NULL, // Not used in this package + .OnMacMcpsRequest = NULL, // To be initialized by LmHandler + .OnMacMlmeRequest = NULL, // To be initialized by LmHandler + .OnJoinRequest = NULL, // To be initialized by LmHandler + .OnSendRequest = NULL, // To be initialized by LmHandler + .OnDeviceTimeRequest = NULL, // To be initialized by LmHandler + .OnSysTimeUpdate = NULL, // To be initialized by LmHandler +}; + +LmhPackage_t *LmhpRemoteMcastSetupPackageFactory( void ) +{ + return &LmhpRemoteMcastSetupPackage; +} + +static void LmhpRemoteMcastSetupInit( void * params, uint8_t *dataBuffer, uint8_t dataBufferMaxSize ) +{ + if( dataBuffer != NULL ) + { + LmhpRemoteMcastSetupState.DataBuffer = dataBuffer; + LmhpRemoteMcastSetupState.DataBufferMaxSize = dataBufferMaxSize; + LmhpRemoteMcastSetupState.Initialized = true; + LmhpRemoteMcastSetupState.IsRunning = true; + TimerInit( &SessionStartTimer, OnSessionStartTimer ); + TimerInit( &SessionStopTimer, OnSessionStopTimer ); + } + else + { + LmhpRemoteMcastSetupState.IsRunning = false; + LmhpRemoteMcastSetupState.Initialized = false; + } +} + +static bool LmhpRemoteMcastSetupIsInitialized( void ) +{ + return LmhpRemoteMcastSetupState.Initialized; +} + +static bool LmhpRemoteMcastSetupIsRunning( void ) +{ + if( LmhpRemoteMcastSetupState.Initialized == false ) + { + return false; + } + + return LmhpRemoteMcastSetupState.IsRunning; +} + +static void LmhpRemoteMcastSetupProcess( void ) +{ + LmhpRemoteMcastSetupSessionStates_t state; + + CRITICAL_SECTION_BEGIN( ); + state = LmhpRemoteMcastSetupState.SessionState; + LmhpRemoteMcastSetupState.SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_IDLE; + CRITICAL_SECTION_END( ); + + switch( state ) + { + case REMOTE_MCAST_SETUP_SESSION_STATE_START: + // Switch to Class C + LmHandlerRequestClass( CLASS_C ); + + TimerSetValue( &SessionStopTimer, ( 1 << McSessionData[0].SessionTimeout ) * 1000 ); + TimerStart( &SessionStopTimer ); + break; + case REMOTE_MCAST_SETUP_SESSION_STATE_STOP: + // Switch back to Class A + LmHandlerRequestClass( CLASS_A ); + break; + case REMOTE_MCAST_SETUP_SESSION_STATE_IDLE: + // Intentional fall through + default: + // Nothing to do. + break; + } +} + +static void LmhpRemoteMcastSetupOnMcpsIndication( McpsIndication_t *mcpsIndication ) +{ + uint8_t cmdIndex = 0; + uint8_t dataBufferIndex = 0; + + while( cmdIndex < mcpsIndication->BufferSize ) + { + switch( mcpsIndication->Buffer[cmdIndex++] ) + { + case REMOTE_MCAST_SETUP_PKG_VERSION_REQ: + { + LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = REMOTE_MCAST_SETUP_PKG_VERSION_ANS; + LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = REMOTE_MCAST_SETUP_ID; + LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = REMOTE_MCAST_SETUP_VERSION; + break; + } + case REMOTE_MCAST_SETUP_MC_GROUP_STATUS_REQ: + { + // TODO implement command prosessing and handling + break; + } + case REMOTE_MCAST_SETUP_MC_GROUP_SETUP_REQ: + { + uint8_t id = mcpsIndication->Buffer[cmdIndex++]; + McSessionData[id].McGroupData.IdHeader.Value = id; + + McSessionData[id].McGroupData.McAddr = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF; + McSessionData[id].McGroupData.McAddr += ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00; + McSessionData[id].McGroupData.McAddr += ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000; + McSessionData[id].McGroupData.McAddr += ( mcpsIndication->Buffer[cmdIndex++] << 24 ) & 0xFF000000; + + for( int8_t i = 0; i < 16; i++ ) + { + McSessionData[id].McGroupData.McKeyEncrypted[i] = mcpsIndication->Buffer[cmdIndex++]; + } + + McSessionData[id].McGroupData.McFCountMin = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF; + McSessionData[id].McGroupData.McFCountMin += ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00; + McSessionData[id].McGroupData.McFCountMin += ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000; + McSessionData[id].McGroupData.McFCountMin += ( mcpsIndication->Buffer[cmdIndex++] << 24 ) & 0xFF000000; + + McSessionData[id].McGroupData.McFCountMax = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF; + McSessionData[id].McGroupData.McFCountMax += ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00; + McSessionData[id].McGroupData.McFCountMax += ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000; + McSessionData[id].McGroupData.McFCountMax += ( mcpsIndication->Buffer[cmdIndex++] << 24 ) & 0xFF000000; + + McChannelParams_t channel = + { + .IsRemotelySetup = true, + .Class = CLASS_C, // Field not used for multicast channel setup. Must be initialized to something + .IsEnabled = true, + .GroupID = ( AddressIdentifier_t )McSessionData[id].McGroupData.IdHeader.Fields.McGroupId, + .Address = McSessionData[id].McGroupData.McAddr, + .McKeys.McKeyE = McSessionData[id].McGroupData.McKeyEncrypted, + .FCountMin = McSessionData[id].McGroupData.McFCountMin, + .FCountMax = McSessionData[id].McGroupData.McFCountMax, + .RxParams.ClassC = // Field not used for multicast channel setup. Must be initialized to something + { + .Frequency = 0, + .Datarate = 0 + } + }; + uint8_t idError = 0x01; // One bit value + if( LoRaMacMcChannelSetup( &channel ) == LORAMAC_STATUS_OK ) + { + idError = 0x00; + } + LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = REMOTE_MCAST_SETUP_MC_GROUP_SETUP_ANS; + LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = ( idError << 2 ) | McSessionData[id].McGroupData.IdHeader.Fields.McGroupId; + break; + } + case REMOTE_MCAST_SETUP_MC_GROUP_DELETE_REQ: + { + uint8_t status = 0x00; + uint8_t id = mcpsIndication->Buffer[cmdIndex++] & 0x03; + + status = id; + + LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = REMOTE_MCAST_SETUP_MC_GROUP_DELETE_ANS; + + if( LoRaMacMcChannelDelete( ( AddressIdentifier_t )id ) != LORAMAC_STATUS_OK ) + { + status |= 0x04; // McGroupUndefined bit set + } + LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = status; + break; + } + case REMOTE_MCAST_SETUP_MC_GROUP_CLASS_C_SESSION_REQ: + { + uint8_t status = 0x00; + uint8_t id = mcpsIndication->Buffer[cmdIndex++] & 0x03; + + McSessionData[id].SessionTime = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF; + McSessionData[id].SessionTime += ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00; + McSessionData[id].SessionTime += ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000; + McSessionData[id].SessionTime += ( mcpsIndication->Buffer[cmdIndex++] << 24 ) & 0xFF000000; + + // Add Unix to Gps epcoh offset. The system time is based on Unix time. + McSessionData[id].SessionTime += UNIX_GPS_EPOCH_OFFSET; + + McSessionData[id].SessionTimeout = mcpsIndication->Buffer[cmdIndex++] & 0x0F; + + McSessionData[id].RxParams.ClassC.Frequency = ( mcpsIndication->Buffer[cmdIndex++] << 0 ) & 0x000000FF; + McSessionData[id].RxParams.ClassC.Frequency |= ( mcpsIndication->Buffer[cmdIndex++] << 8 ) & 0x0000FF00; + McSessionData[id].RxParams.ClassC.Frequency |= ( mcpsIndication->Buffer[cmdIndex++] << 16 ) & 0x00FF0000; + McSessionData[id].RxParams.ClassC.Frequency *= 100; + + McSessionData[id].RxParams.ClassC.Datarate = mcpsIndication->Buffer[cmdIndex++]; + + LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = REMOTE_MCAST_SETUP_MC_GROUP_CLASS_C_SESSION_ANS; + if( LoRaMacMcChannelSetupRxParams( ( AddressIdentifier_t )id, &McSessionData[id].RxParams, &status ) == LORAMAC_STATUS_OK ) + { + SysTime_t curTime = { .Seconds = 0, .SubSeconds = 0 }; + curTime = SysTimeGet( ); + + int32_t timeToSessionStart = McSessionData[id].SessionTime - curTime.Seconds; + if( timeToSessionStart > 0 ) + { + // Start session start timer + TimerSetValue( &SessionStartTimer, timeToSessionStart * 1000 ); + TimerStart( &SessionStartTimer ); + + DBG( "Time2SessionStart: %ld ms\n", timeToSessionStart * 1000 ); + + LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = status; + LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = ( timeToSessionStart >> 0 ) & 0xFF; + LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = ( timeToSessionStart >> 8 ) & 0xFF; + LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = ( timeToSessionStart >> 16 ) & 0xFF; + break; + } + else + { + // Session start time before current device time + status |= 0x10; + } + } + LmhpRemoteMcastSetupState.DataBuffer[dataBufferIndex++] = status; + break; + } + case REMOTE_MCAST_SETUP_MC_GROUP_CLASS_B_SESSION_REQ: + { + // TODO implement command prosessing and handling + break; + } + default: + { + break; + } + } + } + + if( dataBufferIndex != 0 ) + { + // Answer commands + LmHandlerAppData_t appData = + { + .Buffer = LmhpRemoteMcastSetupState.DataBuffer, + .BufferSize = dataBufferIndex, + .Port = REMOTE_MCAST_SETUP_PORT + }; + LmhpRemoteMcastSetupPackage.OnSendRequest( &appData, LORAMAC_HANDLER_UNCONFIRMED_MSG ); + + DBG( "ID : %d\n", McSessionData[0].McGroupData.IdHeader.Fields.McGroupId ); + DBG( "McAddr : %08lX\n", McSessionData[0].McGroupData.McAddr ); + DBG( "McKey : %02X", McSessionData[0].McGroupData.McKeyEncrypted[0] ); + for( int i = 1; i < 16; i++ ) + { + DBG( "-%02X", McSessionData[0].McGroupData.McKeyEncrypted[i] ); + } + DBG( "\n" ); + DBG( "McFCountMin : %lu\n", McSessionData[0].McGroupData.McFCountMin ); + DBG( "McFCountMax : %lu\n", McSessionData[0].McGroupData.McFCountMax ); + DBG( "SessionTime : %lu\n", McSessionData[0].SessionTime ); + DBG( "SessionTimeT: %d\n", McSessionData[0].SessionTimeout ); + DBG( "Rx Freq : %lu\n", McSessionData[0].RxParams.ClassC.Frequency ); + DBG( "Rx DR : DR_%d\n", McSessionData[0].RxParams.ClassC.Datarate ); + + } +} + +static void OnSessionStartTimer( void *context ) +{ + TimerStop( &SessionStartTimer ); + + LmhpRemoteMcastSetupState.SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_START; +} + +static void OnSessionStopTimer( void *context ) +{ + TimerStop( &SessionStopTimer ); + + LmhpRemoteMcastSetupState.SessionState = REMOTE_MCAST_SETUP_SESSION_STATE_STOP; +} diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpRemoteMcastSetup.h b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpRemoteMcastSetup.h new file mode 100644 index 00000000..58286182 --- /dev/null +++ b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandler/packages/LmhpRemoteMcastSetup.h @@ -0,0 +1,47 @@ +/*! + * \file LmhpRemoteMcastSetup.h + * + * \brief Implements the LoRa-Alliance remote multicast setup package + * Specification: https://lora-alliance.org/sites/default/files/2018-09/remote_multicast_setup_v1.0.0.pdf + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2018 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + */ +#ifndef __LMHP_REMOTE_MCAST_SETUP_H__ +#define __LMHP_REMOTE_MCAST_SETUP_H__ + +#include "LoRaMac.h" +#include "LmHandlerTypes.h" +#include "LmhPackage.h" + +/*! + * Remote multicast setup package identifier. + * + * \remark This value must be unique amongst the packages + */ +#define PACKAGE_ID_REMOTE_MCAST_SETUP 2 + +/*! + * Remote multicast setup package parameters + * + * This package doesn't require parameters + */ +//typedef struct LmhpRemoteMcastSetupParams_s +//{ +//}LmhpRemoteMcastSetupParams_t; + +LmhPackage_t *LmhpRemoteMcastSetupPackageFactory( void ); + +#endif // __LMHP_REMOTE_MCAST_SETUP_H__ diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandlerMsgDisplay.c b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandlerMsgDisplay.c new file mode 100644 index 00000000..0cdf61c0 --- /dev/null +++ b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandlerMsgDisplay.c @@ -0,0 +1,434 @@ +/*! + * \file LmHandlerMsgDisplay.h + * + * \brief Common set of functions to display default messages from + * LoRaMacHandler. + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2019 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + */ +#include +#include +#include +#include +#include "utilities.h" +#include "timer.h" + +#include "LmHandlerMsgDisplay.h" + +/*! + * MAC status strings + */ +const char* MacStatusStrings[] = +{ + "OK", // LORAMAC_STATUS_OK + "Busy", // LORAMAC_STATUS_BUSY + "Service unknown", // LORAMAC_STATUS_SERVICE_UNKNOWN + "Parameter invalid", // LORAMAC_STATUS_PARAMETER_INVALID + "Frequency invalid", // LORAMAC_STATUS_FREQUENCY_INVALID + "Datarate invalid", // LORAMAC_STATUS_DATARATE_INVALID + "Frequency or datarate invalid", // LORAMAC_STATUS_FREQ_AND_DR_INVALID + "No network joined", // LORAMAC_STATUS_NO_NETWORK_JOINED + "Length error", // LORAMAC_STATUS_LENGTH_ERROR + "Region not supported", // LORAMAC_STATUS_REGION_NOT_SUPPORTED + "Skipped APP data", // LORAMAC_STATUS_SKIPPED_APP_DATA + "Duty-cycle restricted", // LORAMAC_STATUS_DUTYCYCLE_RESTRICTED + "No channel found", // LORAMAC_STATUS_NO_CHANNEL_FOUND + "No free channel found", // LORAMAC_STATUS_NO_FREE_CHANNEL_FOUND + "Busy beacon reserved time", // LORAMAC_STATUS_BUSY_BEACON_RESERVED_TIME + "Busy ping-slot window time", // LORAMAC_STATUS_BUSY_PING_SLOT_WINDOW_TIME + "Busy uplink collision", // LORAMAC_STATUS_BUSY_UPLINK_COLLISION + "Crypto error", // LORAMAC_STATUS_CRYPTO_ERROR + "FCnt handler error", // LORAMAC_STATUS_FCNT_HANDLER_ERROR + "MAC command error", // LORAMAC_STATUS_MAC_COMMAD_ERROR + "ClassB error", // LORAMAC_STATUS_CLASS_B_ERROR + "Confirm queue error", // LORAMAC_STATUS_CONFIRM_QUEUE_ERROR + "Multicast group undefined", // LORAMAC_STATUS_MC_GROUP_UNDEFINED + "Unknown error", // LORAMAC_STATUS_ERROR +}; + +/*! + * MAC event info status strings. + */ +const char* EventInfoStatusStrings[] = +{ + "OK", // LORAMAC_EVENT_INFO_STATUS_OK + "Error", // LORAMAC_EVENT_INFO_STATUS_ERROR + "Tx timeout", // LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT + "Rx 1 timeout", // LORAMAC_EVENT_INFO_STATUS_RX1_TIMEOUT + "Rx 2 timeout", // LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT + "Rx1 error", // LORAMAC_EVENT_INFO_STATUS_RX1_ERROR + "Rx2 error", // LORAMAC_EVENT_INFO_STATUS_RX2_ERROR + "Join failed", // LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL + "Downlink repeated", // LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED + "Tx DR payload size error", // LORAMAC_EVENT_INFO_STATUS_TX_DR_PAYLOAD_SIZE_ERROR + "Downlink too many frames loss", // LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS + "Address fail", // LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL + "MIC fail", // LORAMAC_EVENT_INFO_STATUS_MIC_FAIL + "Multicast fail", // LORAMAC_EVENT_INFO_STATUS_MULTICAST_FAIL + "Beacon locked", // LORAMAC_EVENT_INFO_STATUS_BEACON_LOCKED + "Beacon lost", // LORAMAC_EVENT_INFO_STATUS_BEACON_LOST + "Beacon not found" // LORAMAC_EVENT_INFO_STATUS_BEACON_NOT_FOUND +}; + +/*! + * Prints the provided buffer in HEX + * + * \param buffer Buffer to be printed + * \param size Buffer size to be printed + */ +void PrintHexBuffer( uint8_t *buffer, uint8_t size ) +{ + uint8_t newline = 0; + + for( uint8_t i = 0; i < size; i++ ) + { + if( newline != 0 ) + { + printf( "\n" ); + newline = 0; + } + + printf( "%02X ", buffer[i] ); + + if( ( ( i + 1 ) % 16 ) == 0 ) + { + newline = 1; + } + } + printf( "\n" ); +} + +void DisplayNvmContextChange( LmHandlerNvmContextStates_t state ) +{ + if( state == LORAMAC_HANDLER_NVM_STORE ) + { + printf( "\n###### ============ CTXS STORED ============ ######\n\n" ); + } + else + { + printf( "\n###### =========== CTXS RESTORED =========== ######\n\n" ); + } +} + +void DisplayNetworkParametersUpdate( CommissioningParams_t *commissioningParams ) +{ + printf( "DevEui : %02X", commissioningParams->DevEui[0] ); + for( int i = 1; i < 8; i++ ) + { + printf( "-%02X", commissioningParams->DevEui[i] ); + } + printf( "\n" ); + printf( "JoinEui : %02X", commissioningParams->JoinEui[0] ); + for( int i = 1; i < 8; i++ ) + { + printf( "-%02X", commissioningParams->JoinEui[i] ); + } + printf( "\n" ); + printf( "Pin : %02X", commissioningParams->SePin[0] ); + for( int i = 1; i < 4; i++ ) + { + printf( "-%02X", commissioningParams->SePin[i] ); + } + printf( "\n\n" ); +} + +void DisplayMacMcpsRequestUpdate( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ) +{ + switch( mcpsReq->Type ) + { + case MCPS_CONFIRMED: + { + printf( "\n###### =========== MCPS-Request ============ ######\n" ); + printf( "###### MCPS_CONFIRMED ######\n"); + printf( "###### ===================================== ######\n"); + break; + } + case MCPS_UNCONFIRMED: + { + printf( "\n###### =========== MCPS-Request ============ ######\n" ); + printf( "###### MCPS_UNCONFIRMED ######\n"); + printf( "###### ===================================== ######\n"); + break; + } + case MCPS_PROPRIETARY: + { + printf( "\n###### =========== MCPS-Request ============ ######\n" ); + printf( "###### MCPS_PROPRIETARY ######\n"); + printf( "###### ===================================== ######\n"); + break; + } + default: + { + printf( "\n###### =========== MCPS-Request ============ ######\n" ); + printf( "###### MCPS_ERROR ######\n"); + printf( "###### ===================================== ######\n"); + break; + } + } + printf( "STATUS : %s\n", MacStatusStrings[status] ); + if( status == LORAMAC_STATUS_DUTYCYCLE_RESTRICTED ) + { + printf( "Next Tx in : %lu [ms]\n", nextTxIn ); + } +} + +void DisplayMacMlmeRequestUpdate( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ) +{ + switch( mlmeReq->Type ) + { + case MLME_JOIN: + { + printf( "\n###### =========== MLME-Request ============ ######\n" ); + printf( "###### MLME_JOIN ######\n"); + printf( "###### ===================================== ######\n"); + break; + } + case MLME_LINK_CHECK: + { + printf( "\n###### =========== MLME-Request ============ ######\n" ); + printf( "###### MLME_LINK_CHECK ######\n"); + printf( "###### ===================================== ######\n"); + break; + } + case MLME_DEVICE_TIME: + { + printf( "\n###### =========== MLME-Request ============ ######\n" ); + printf( "###### MLME_DEVICE_TIME ######\n"); + printf( "###### ===================================== ######\n"); + break; + } + case MLME_TXCW: + { + printf( "\n###### =========== MLME-Request ============ ######\n" ); + printf( "###### MLME_TXCW ######\n"); + printf( "###### ===================================== ######\n"); + break; + } + case MLME_TXCW_1: + { + printf( "\n###### =========== MLME-Request ============ ######\n" ); + printf( "###### MLME_TXCW_1 ######\n"); + printf( "###### ===================================== ######\n"); + break; + } + default: + { + printf( "\n###### =========== MLME-Request ============ ######\n" ); + printf( "###### MLME_UNKNOWN ######\n"); + printf( "###### ===================================== ######\n"); + break; + } + } + printf( "STATUS : %s\n", MacStatusStrings[status] ); + if( status == LORAMAC_STATUS_DUTYCYCLE_RESTRICTED ) + { + printf( "Next Tx in : %lu [ms]\n", nextTxIn ); + } +} + +void DisplayJoinRequestUpdate( LmHandlerJoinParams_t *params ) +{ + if( params->CommissioningParams->IsOtaaActivation == true ) + { + if( params->Status == LORAMAC_HANDLER_SUCCESS ) + { + printf( "###### =========== JOINED ============ ######\n" ); + printf( "\nOTAA\n\n" ); + printf( "DevAddr : %08lX\n", params->CommissioningParams->DevAddr ); + printf( "\n\n" ); + printf( "DATA RATE : DR_%d\n\n", params->Datarate ); + } + } +#if ( OVER_THE_AIR_ACTIVATION == 0 ) + else + { + printf( "###### =========== JOINED ============ ######\n" ); + printf( "\nABP\n\n" ); + printf( "DevAddr : %08lX\n", params->CommissioningParams->DevAddr ); + printf( "\n\n" ); + } +#endif +} + +void DisplayTxUpdate( LmHandlerTxParams_t *params ) +{ + MibRequestConfirm_t mibGet; + + if( params->IsMcpsConfirm == 0 ) + { + printf( "\n###### =========== MLME-Confirm ============ ######\n" ); + printf( "STATUS : %s\n", EventInfoStatusStrings[params->Status] ); + return; + } + + printf( "\n###### =========== MCPS-Confirm ============ ######\n" ); + printf( "STATUS : %s\n", EventInfoStatusStrings[params->Status] ); + + printf( "\n###### ===== UPLINK FRAME %8lu ===== ######\n", params->UplinkCounter ); + printf( "\n" ); + + printf( "CLASS : %c\n", "ABC"[LmHandlerGetCurrentClass( )] ); + printf( "\n" ); + printf( "TX PORT : %d\n", params->AppData.Port ); + + if( params->AppData.BufferSize != 0 ) + { + printf( "TX DATA : " ); + if( params->MsgType == LORAMAC_HANDLER_CONFIRMED_MSG ) + { + printf( "CONFIRMED - %s\n", ( params->AckReceived != 0 ) ? "ACK" : "NACK" ); + } + else + { + printf( "UNCONFIRMED\n" ); + } + PrintHexBuffer( params->AppData.Buffer, params->AppData.BufferSize ); + } + + printf( "\n" ); + printf( "DATA RATE : DR_%d\n", params->Datarate ); + + mibGet.Type = MIB_CHANNELS; + if( LoRaMacMibGetRequestConfirm( &mibGet ) == LORAMAC_STATUS_OK ) + { + printf( "U/L FREQ : %lu\n", mibGet.Param.ChannelList[params->Channel].Frequency ); + } + + printf( "TX POWER : %d\n", params->TxPower ); + + mibGet.Type = MIB_CHANNELS_MASK; + if( LoRaMacMibGetRequestConfirm( &mibGet ) == LORAMAC_STATUS_OK ) + { + printf("CHANNEL MASK: "); + switch( LmHandlerGetActiveRegion( ) ) + { + case LORAMAC_REGION_AS923: + case LORAMAC_REGION_CN779: + case LORAMAC_REGION_EU868: + case LORAMAC_REGION_IN865: + case LORAMAC_REGION_KR920: + case LORAMAC_REGION_EU433: + case LORAMAC_REGION_RU864: + { + printf( "%04X ", mibGet.Param.ChannelsMask[0] ); + break; + } + case LORAMAC_REGION_AU915: + case LORAMAC_REGION_CN470: + case LORAMAC_REGION_US915: + { + for( uint8_t i = 0; i < 5; i++) + { + printf( "%04X ", mibGet.Param.ChannelsMask[i] ); + } + break; + } + default: + { + printf( "\n###### ========= Unknown Region ============ ######" ); + break; + } + } + printf("\n"); + } + + printf( "\n" ); +} + +void DisplayRxUpdate( LmHandlerAppData_t *appData, LmHandlerRxParams_t *params ) +{ + const char *slotStrings[] = { "1", "2", "C", "C Multicast", "B Ping-Slot", "B Multicast Ping-Slot" }; + + if( params->IsMcpsIndication == 0 ) + { + printf( "\n###### ========== MLME-Indication ========== ######\n" ); + printf( "STATUS : %s\n", EventInfoStatusStrings[params->Status] ); + return; + } + + printf( "\n###### ========== MCPS-Indication ========== ######\n" ); + printf( "STATUS : %s\n", EventInfoStatusStrings[params->Status] ); + + printf( "\n###### ===== DOWNLINK FRAME %8lu ===== ######\n", params->DownlinkCounter ); + + printf( "RX WINDOW : %s\n", slotStrings[params->RxSlot] ); + + printf( "RX PORT : %d\n", appData->Port ); + + if( appData->BufferSize != 0 ) + { + printf( "RX DATA : \n" ); + PrintHexBuffer( appData->Buffer, appData->BufferSize ); + } + + printf( "\n" ); + printf( "DATA RATE : DR_%d\n", params->Datarate ); + printf( "RX RSSI : %d\n", params->Rssi ); + printf( "RX SNR : %d\n", params->Snr ); + + printf( "\n" ); +} + +void DisplayBeaconUpdate( LoRaMAcHandlerBeaconParams_t *params ) +{ + switch( params->State ) + { + default: + case LORAMAC_HANDLER_BEACON_ACQUIRING: + { + printf( "\n###### ========= BEACON ACQUIRING ========== ######\n" ); + break; + } + case LORAMAC_HANDLER_BEACON_LOST: + { + printf( "\n###### ============ BEACON LOST ============ ######\n" ); + break; + } + case LORAMAC_HANDLER_BEACON_RX: + { + printf( "\n###### ===== BEACON %8lu ==== ######\n", params->Info.Time.Seconds ); + printf( "GW DESC : %d\n", params->Info.GwSpecific.InfoDesc ); + printf( "GW INFO : " ); + PrintHexBuffer( params->Info.GwSpecific.Info, 6 ); + printf( "\n" ); + printf( "FREQ : %lu\n", params->Info.Frequency ); + printf( "DATA RATE : DR_%d\n", params->Info.Datarate ); + printf( "RX RSSI : %d\n", params->Info.Rssi ); + printf( "RX SNR : %d\n", params->Info.Snr ); + printf( "\n" ); + break; + } + case LORAMAC_HANDLER_BEACON_NRX: + { + printf( "\n###### ======== BEACON NOT RECEIVED ======== ######\n" ); + break; + } + } +} + +void DisplayClassUpdate( DeviceClass_t deviceClass ) +{ + printf( "\n\n###### ===== Switch to Class %c done. ===== ######\n\n", "ABC"[deviceClass] ); +} + +void DisplayAppInfo( const char* appName, const Version_t* appVersion, const Version_t* gitHubVersion ) +{ + printf( "\n###### ===================================== ######\n\n" ); + printf( "Application name : %s\n", appName ); + printf( "Application version: %d.%d.%d\n", appVersion->Fields.Major, appVersion->Fields.Minor, appVersion->Fields.Patch ); + printf( "GitHub base version: %d.%d.%d\n", gitHubVersion->Fields.Major, gitHubVersion->Fields.Minor, gitHubVersion->Fields.Patch ); + printf( "\n###### ===================================== ######\n\n" ); +} diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandlerMsgDisplay.h b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandlerMsgDisplay.h new file mode 100644 index 00000000..4bd73069 --- /dev/null +++ b/board/RHF76_STM32L072CBxx_Lora/apps/common/LmHandlerMsgDisplay.h @@ -0,0 +1,102 @@ +/*! + * \file LmHandlerMsgDisplay.h + * + * \brief Common set of functions to display default messages from + * LoRaMacHandler. + * + * \copyright Revised BSD License, see section \ref LICENSE. + * + * \code + * ______ _ + * / _____) _ | | + * ( (____ _____ ____ _| |_ _____ ____| |__ + * \____ \| ___ | (_ _) ___ |/ ___) _ \ + * _____) ) ____| | | || |_| ____( (___| | | | + * (______/|_____)_|_|_| \__)_____)\____)_| |_| + * (C)2013-2019 Semtech + * + * \endcode + * + * \author Miguel Luis ( Semtech ) + */ +#ifndef __LMHANDLER_MSG_DISPLAY_H__ +#define __LMHANDLER_MSG_DISPLAY_H__ + +#include "utilities.h" +#include "LmHandler.h" + +/*! + * \brief Displays NVM context operation state + * + * \param [IN] state Indicates if we are storing (true) or + * restoring (false) the NVM context + */ +void DisplayNvmContextChange( LmHandlerNvmContextStates_t state ); + +/*! + * \brief Displays updated network parameters + * + * \param [IN] commissioningParams Commissioning provided parameters + */ +void DisplayNetworkParametersUpdate( CommissioningParams_t* commissioningParams ); + +/*! + * \brief Displays updated McpsRequest + * + * \param [IN] status McpsRequest execution status + * \param [IN] mcpsReq McpsRequest command executed + * \param [IN] nextTxIn Time to wait for the next uplink transmission + */ +void DisplayMacMcpsRequestUpdate( LoRaMacStatus_t status, McpsReq_t *mcpsReq, TimerTime_t nextTxIn ); + +/*! + * \brief Displays updated MlmeRequest + * + * \param [IN] status MlmeRequest execution status + * \param [IN] mlmeReq MlmeRequest command executed + * \param [IN] nextTxIn Time to wait for the next uplink transmission + */ +void DisplayMacMlmeRequestUpdate( LoRaMacStatus_t status, MlmeReq_t *mlmeReq, TimerTime_t nextTxIn ); + +/*! + * \brief Displays updated JoinRequest + * + * \param [IN] params Executed JoinRequest parameters + */ +void DisplayJoinRequestUpdate( LmHandlerJoinParams_t* params ); + +/*! + * \brief Displays Tx params + * + * \param [IN] params Tx parameters + */ +void DisplayTxUpdate( LmHandlerTxParams_t* params ); + +/*! + * \brief Displays Rx params + * + * \param [IN] appData Receive data payload and port number + * \param [IN] params Rx parameters + */ +void DisplayRxUpdate( LmHandlerAppData_t* appData, LmHandlerRxParams_t* params ); + +/*! + * \brief Displays beacon status update + * + * \param [IN] params Beacon parameters + */ +void DisplayBeaconUpdate( LoRaMAcHandlerBeaconParams_t* params ); + +/*! + * \brief Displays end-device class update + * + * \param [IN] deviceClass Current end-device class + */ +void DisplayClassUpdate( DeviceClass_t deviceClass ); + +/*! + * \brief Displays application information + */ +void DisplayAppInfo( const char* appName, const Version_t* appVersion, const Version_t* gitHubVersion ); + +#endif // __LMHANDLER_MSG_DISPLAY_H__ diff --git a/board/RHF76_STM32L072CBxx_Lora/apps/common/NvmCtxMgmt.c b/board/RHF76_STM32L072CBxx_Lora/apps/common/NvmCtxMgmt.c index 5123319b..f75350db 100644 --- a/board/RHF76_STM32L072CBxx_Lora/apps/common/NvmCtxMgmt.c +++ b/board/RHF76_STM32L072CBxx_Lora/apps/common/NvmCtxMgmt.c @@ -112,7 +112,6 @@ LoRaMacCtxUpdateStatus_t CtxUpdateStatus = { .Value = 0 }; /* * Nvmm handles */ -static NvmmDataBlock_t FCntHandlerNvmCtxDataBlock; static NvmmDataBlock_t SecureElementNvmCtxDataBlock; static NvmmDataBlock_t CryptoNvmCtxDataBlock; #if ( MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 ) @@ -164,11 +163,6 @@ void NvmCtxMgmtEvent( LoRaMacNvmCtxModule_t module ) CtxUpdateStatus.Elements.ConfirmQueue = 1; break; } - case LORAMAC_NVMCTXMODULE_FCNT_HANDLER: - { - CtxUpdateStatus.Elements.FCntHandlerNvmCtx = 1; - break; - } default: { break; @@ -213,14 +207,6 @@ NvmCtxMgmtStatus_t NvmCtxMgmtStore( void ) } } - if( CtxUpdateStatus.Elements.FCntHandlerNvmCtx == 1 ) - { - if( NvmmWrite( &FCntHandlerNvmCtxDataBlock, MacContexts->FCntHandlerNvmCtx, MacContexts->FCntHandlerNvmCtxSize ) != NVMM_SUCCESS ) - { - return NVMCTXMGMT_STATUS_FAIL; - } - } - #if ( MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 ) if( CtxUpdateStatus.Elements.Mac == 1 ) { @@ -288,7 +274,6 @@ NvmCtxMgmtStatus_t NvmCtxMgmtRestore( void ) uint8_t NvmCryptoCtxRestore[mibReq.Param.Contexts->CryptoNvmCtxSize]; uint8_t NvmSecureElementCtxRestore[mibReq.Param.Contexts->SecureElementNvmCtxSize]; - uint8_t NvmFCntHandlerCtxRestore[mibReq.Param.Contexts->FCntHandlerNvmCtxSize]; #if ( MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 ) uint8_t NvmMacCtxRestore[mibReq.Param.Contexts->MacNvmCtxSize]; uint8_t NvmRegionCtxRestore[mibReq.Param.Contexts->RegionNvmCtxSize]; @@ -319,17 +304,6 @@ NvmCtxMgmtStatus_t NvmCtxMgmtRestore( void ) status = NVMCTXMGMT_STATUS_FAIL; } - if ( NvmmDeclare( &FCntHandlerNvmCtxDataBlock, mibReq.Param.Contexts->FCntHandlerNvmCtxSize ) == NVMM_SUCCESS ) - { - NvmmRead( &FCntHandlerNvmCtxDataBlock, NvmFCntHandlerCtxRestore, mibReq.Param.Contexts->FCntHandlerNvmCtxSize ); - contexts.FCntHandlerNvmCtx = &NvmFCntHandlerCtxRestore; - contexts.FCntHandlerNvmCtxSize = mibReq.Param.Contexts->FCntHandlerNvmCtxSize; - } - else - { - status = NVMCTXMGMT_STATUS_FAIL; - } - #if ( MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 ) if( NvmmDeclare( &MacNvmCtxDataBlock, mibReq.Param.Contexts->MacNvmCtxSize ) == NVMM_SUCCESS ) { diff --git a/components/connectivity/LoraWAN/mac/region/RegionCN470.c b/components/connectivity/LoraWAN/mac/region/RegionCN470.c index b2e7c7d5..5dfc7235 100644 --- a/components/connectivity/LoraWAN/mac/region/RegionCN470.c +++ b/components/connectivity/LoraWAN/mac/region/RegionCN470.c @@ -367,13 +367,21 @@ void RegionCN470InitDefaults( InitDefaultsParams_t* params ) } // Initialize the channels default mask + #if 1 // set your channels NvmCtx.ChannelsDefaultMask[0] = 0xFFFF; NvmCtx.ChannelsDefaultMask[1] = 0xFFFF; NvmCtx.ChannelsDefaultMask[2] = 0xFFFF; NvmCtx.ChannelsDefaultMask[3] = 0xFFFF; NvmCtx.ChannelsDefaultMask[4] = 0xFFFF; NvmCtx.ChannelsDefaultMask[5] = 0xFFFF; - + #else + NvmCtx.ChannelsDefaultMask[0] = 0x0000; + NvmCtx.ChannelsDefaultMask[1] = 0x0000; + NvmCtx.ChannelsDefaultMask[2] = 0x0000; + NvmCtx.ChannelsDefaultMask[3] = 0x0000; + NvmCtx.ChannelsDefaultMask[4] = 0x0000; + NvmCtx.ChannelsDefaultMask[5] = 0x00FF; + #endif // Update the channels mask RegionCommonChanMaskCopy( NvmCtx.ChannelsMask, NvmCtx.ChannelsDefaultMask, 6 ); break; diff --git a/components/connectivity/LoraWAN/peripherals/soft-se/se-identity.h b/components/connectivity/LoraWAN/peripherals/soft-se/se-identity.h index 872167b4..3c2f7a9a 100644 --- a/components/connectivity/LoraWAN/peripherals/soft-se/se-identity.h +++ b/components/connectivity/LoraWAN/peripherals/soft-se/se-identity.h @@ -66,17 +66,17 @@ extern "C" { * When set to 1 DevEui is LORAWAN_DEVICE_EUI * When set to 0 DevEui is automatically set with a value provided by MCU platform */ -#define STATIC_DEVICE_EUI 0 +#define STATIC_DEVICE_EUI 1 /*! * end-device IEEE EUI (big endian) */ -#define LORAWAN_DEVICE_EUI { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define LORAWAN_DEVICE_EUI { 0x8c, 0xf9, 0x57, 0x20, 0x00, 0x00, 0xf7, 0x37} /*! * App/Join server IEEE EUI (big endian) */ -#define LORAWAN_JOIN_EUI { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +#define LORAWAN_JOIN_EUI { 0x8c, 0xf9, 0x57, 0x20, 0x00, 0x00, 0xf7, 0x37} /*! * Secure-element pin @@ -103,8 +103,8 @@ extern "C" { * WARNING: FOR 1.0.x DEVICES IT IS THE \ref LORAWAN_GEN_APP_KEY \ */ \ .KeyID = APP_KEY, \ - .KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \ - 0x3C }, \ + .KeyValue = { 0x8c, 0xf9, 0x57, 0x20, 0x00, 0x00, 0xf7, 0x37, 0x1e, 0x29, 0xaa, 0xaa, 0xad, 0x20, 0x4a, \ + 0x72 }, \ }, \ { \ /*! \ @@ -112,8 +112,8 @@ extern "C" { * WARNING: FOR 1.0.x DEVICES IT IS THE \ref LORAWAN_APP_KEY \ */ \ .KeyID = NWK_KEY, \ - .KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \ - 0x3C }, \ + .KeyValue = { 0x8c, 0xf9, 0x57, 0x20, 0x00, 0x00, 0xf7, 0x37, 0x1e, 0x29, 0xaa, 0xaa, 0xad, 0x20, 0x4a, \ + 0x72 }, \ }, \ { \ /*! \ @@ -139,8 +139,8 @@ extern "C" { * WARNING: NWK_S_KEY FOR 1.0.x DEVICES \ */ \ .KeyID = F_NWK_S_INT_KEY, \ - .KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \ - 0x3C }, \ + .KeyValue = { 0x8c, 0xf9, 0x57, 0x20, 0x00, 0x00, 0xf7, 0x37, 0x1e, 0x29, 0xaa, 0xaa, 0xad, 0x20, 0x4a, \ + 0x72 }, \ }, \ { \ /*! \ @@ -148,8 +148,8 @@ extern "C" { * WARNING: NOT USED FOR 1.0.x DEVICES. MUST BE THE SAME AS \ref LORAWAN_F_NWK_S_INT_KEY \ */ \ .KeyID = S_NWK_S_INT_KEY, \ - .KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \ - 0x3C }, \ + .KeyValue = { 0x8c, 0xf9, 0x57, 0x20, 0x00, 0x00, 0xf7, 0x37, 0x1e, 0x29, 0xaa, 0xaa, 0xad, 0x20, 0x4a, \ + 0x72 }, \ }, \ { \ /*! \ @@ -157,16 +157,16 @@ extern "C" { * WARNING: NOT USED FOR 1.0.x DEVICES. MUST BE THE SAME AS \ref LORAWAN_F_NWK_S_INT_KEY \ */ \ .KeyID = NWK_S_ENC_KEY, \ - .KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \ - 0x3C }, \ + .KeyValue = { 0x8c, 0xf9, 0x57, 0x20, 0x00, 0x00, 0xf7, 0x37, 0x1e, 0x29, 0xaa, 0xaa, 0xad, 0x20, 0x4a, \ + 0x72 }, \ }, \ { \ /*! \ * Application session key \ */ \ .KeyID = APP_S_KEY, \ - .KeyValue = { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, \ - 0x3C }, \ + .KeyValue = { 0x8c, 0xf9, 0x57, 0x20, 0x00, 0x00, 0xf7, 0x37, 0x1e, 0x29, 0xaa, 0xaa, 0xad, 0x20, 0x4a, \ + 0x72 }, \ }, \ { \ /*! \