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 }, \
}, \
{ \
/*! \