end node on synchronous star LoRa network.

Dependencies:   SX127x sx12xx_hal TSL2561

radio chip selection

Radio chip driver is not included, allowing choice of radio device.
If you're using SX1272 or SX1276, then import sx127x driver into your program.
if you're using SX1261 or SX1262, then import sx126x driver into your program.
if you're using SX1280, then import sx1280 driver into your program.
If you're using NAmote72 or Murata discovery, then you must import only sx127x driver.

This project for use with LoRaWAN_singlechannel_gateway project.

Alternately gateway running on raspberry pi can be used as gateway.

LoRaWAN on single radio channel

Network description is at gateway project page. Synchronous star network.

Hardware Support

This project supports SX1276 and SX1272, sx126x kit, sx126x shield, and sx128x 2.4GHz. The ST board B-L072Z-LRWAN1 is also supported (TypeABZ module). When B-L072Z-LRWAN1 target is selected, TARGET_DISCO_L072CZ_LRWAN1 is defined by tools, allowing correct radio driver configuration for this platform. Alternately, any mbed board that can use LoRa radio shield board should work, but NUCLEO boards are tested.

End-node Unique ID

DevEUI is created from CPU serial number. AppEUI and AppKey are declared as software constants.

End-node Configuration

Data rate definition LORAMAC_DEFAULT_DATARATE configured in LoRaMac-definitions.h. See gateway project page for configuration of gateway.
LoRaWAN addressing is configured in Comissioning.h; only OTA mode is functional.
Header file board/lora_config.h, selects application layer options (i.e. sensors) to be compiled in.

Serial Interface

Serial port operates at 115200bps.
Application layer single_us915_main.cpp User button triggers uplink (i.e. blue button on nucleo board), or jumper enables continuously sends repeated uplink packets. The MAC layer holds each uplink request until the allocated timeslot.

commandargumentsdescription
?-print available commands
. (period)-print status (DevEUI, DevAddr, etc)
ullength integerset payload length of test uplink packets

sensor demo

Selected grove sensors may be plugged into SX1272 shield.
To enable, edit lora_config.h to define SENSORS.

Sensor connections on SX1272MB2xAS:

D8 D9: buttonRX TX: (unused)A3 A4: Rotary Angle Sensor
D6 D7: RGB LEDSCL SDA: digital light sensorA1 A2: Rotary Angle Sensor

Digital input pin, state reported via uplink: PC8
Digital output pin, controlled via downlink: PC6
PWM out: PB_10

Jumper enables auto-repeated transmit: PC10 and PC12 on NUCLEO board, located on end of morpho headers nearby JP4.

Committer:
Wayne Roberts
Date:
Fri Dec 07 17:57:41 2018 -0800
Revision:
29:ad409c68c0a6
Parent:
0:8f0d0ae0a077
Child:
34:9c8966cd66a2
update to latest radio HAL

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dudmuck 0:8f0d0ae0a077 1 /*
dudmuck 0:8f0d0ae0a077 2 / _____) _ | |
dudmuck 0:8f0d0ae0a077 3 ( (____ _____ ____ _| |_ _____ ____| |__
dudmuck 0:8f0d0ae0a077 4 \____ \| ___ | (_ _) ___ |/ ___) _ \
dudmuck 0:8f0d0ae0a077 5 _____) ) ____| | | || |_| ____( (___| | | |
dudmuck 0:8f0d0ae0a077 6 (______/|_____)_|_|_| \__)_____)\____)_| |_|
dudmuck 0:8f0d0ae0a077 7 (C)2013 Semtech
dudmuck 0:8f0d0ae0a077 8 ___ _____ _ ___ _ _____ ___ ___ ___ ___
dudmuck 0:8f0d0ae0a077 9 / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
dudmuck 0:8f0d0ae0a077 10 \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
dudmuck 0:8f0d0ae0a077 11 |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
dudmuck 0:8f0d0ae0a077 12 embedded.connectivity.solutions===============
dudmuck 0:8f0d0ae0a077 13
dudmuck 0:8f0d0ae0a077 14 Description: LoRa MAC layer implementation
dudmuck 0:8f0d0ae0a077 15
dudmuck 0:8f0d0ae0a077 16 License: Revised BSD License, see LICENSE.TXT file include in the project
dudmuck 0:8f0d0ae0a077 17
dudmuck 0:8f0d0ae0a077 18 Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jäckle ( STACKFORCE )
dudmuck 0:8f0d0ae0a077 19 */
dudmuck 0:8f0d0ae0a077 20 #include <stdlib.h>
dudmuck 0:8f0d0ae0a077 21 #include <stdint.h>
dudmuck 0:8f0d0ae0a077 22 #include <stdio.h> // dbg remove me
dudmuck 0:8f0d0ae0a077 23 #include "utilities.h"
dudmuck 0:8f0d0ae0a077 24
dudmuck 0:8f0d0ae0a077 25 // TODO: use mbed-os/features/mbedtls/inc/mbedtls/(aes|cmac).h
dudmuck 0:8f0d0ae0a077 26 #include "gladman_aes.h"
dudmuck 0:8f0d0ae0a077 27 #include "gladman_cmac.h"
dudmuck 0:8f0d0ae0a077 28
dudmuck 0:8f0d0ae0a077 29 #include "LoRaMacCrypto.h"
dudmuck 0:8f0d0ae0a077 30
dudmuck 0:8f0d0ae0a077 31 /*!
dudmuck 0:8f0d0ae0a077 32 * CMAC/AES Message Integrity Code (MIC) Block B0 size
dudmuck 0:8f0d0ae0a077 33 */
dudmuck 0:8f0d0ae0a077 34 #define LORAMAC_MIC_BLOCK_B0_SIZE 16
dudmuck 0:8f0d0ae0a077 35
dudmuck 0:8f0d0ae0a077 36 /*!
dudmuck 0:8f0d0ae0a077 37 * MIC field computation initial data
dudmuck 0:8f0d0ae0a077 38 */
dudmuck 0:8f0d0ae0a077 39 static uint8_t MicBlockB0[] = { 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
dudmuck 0:8f0d0ae0a077 40 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
dudmuck 0:8f0d0ae0a077 41 };
dudmuck 0:8f0d0ae0a077 42
dudmuck 0:8f0d0ae0a077 43 /*!
dudmuck 0:8f0d0ae0a077 44 * Contains the computed MIC field.
dudmuck 0:8f0d0ae0a077 45 *
dudmuck 0:8f0d0ae0a077 46 * \remark Only the 4 first bytes are used
dudmuck 0:8f0d0ae0a077 47 */
dudmuck 0:8f0d0ae0a077 48 static uint8_t Mic[16];
dudmuck 0:8f0d0ae0a077 49
dudmuck 0:8f0d0ae0a077 50 /*!
dudmuck 0:8f0d0ae0a077 51 * Encryption aBlock and sBlock
dudmuck 0:8f0d0ae0a077 52 */
dudmuck 0:8f0d0ae0a077 53 static uint8_t aBlock[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
dudmuck 0:8f0d0ae0a077 54 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
dudmuck 0:8f0d0ae0a077 55 };
dudmuck 0:8f0d0ae0a077 56 static uint8_t sBlock[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
dudmuck 0:8f0d0ae0a077 57 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
dudmuck 0:8f0d0ae0a077 58 };
dudmuck 0:8f0d0ae0a077 59
dudmuck 0:8f0d0ae0a077 60 /*!
dudmuck 0:8f0d0ae0a077 61 * AES computation context variable
dudmuck 0:8f0d0ae0a077 62 */
dudmuck 0:8f0d0ae0a077 63 static aes_context AesContext;
dudmuck 0:8f0d0ae0a077 64
dudmuck 0:8f0d0ae0a077 65 /*!
dudmuck 0:8f0d0ae0a077 66 * CMAC computation context variable
dudmuck 0:8f0d0ae0a077 67 */
dudmuck 0:8f0d0ae0a077 68 static AES_CMAC_CTX AesCmacCtx[1];
dudmuck 0:8f0d0ae0a077 69
dudmuck 0:8f0d0ae0a077 70 /*!
dudmuck 0:8f0d0ae0a077 71 * \brief Computes the LoRaMAC frame MIC field
dudmuck 0:8f0d0ae0a077 72 *
dudmuck 0:8f0d0ae0a077 73 * \param [IN] buffer Data buffer
dudmuck 0:8f0d0ae0a077 74 * \param [IN] size Data buffer size
dudmuck 0:8f0d0ae0a077 75 * \param [IN] key AES key to be used
dudmuck 0:8f0d0ae0a077 76 * \param [IN] address Frame address
dudmuck 0:8f0d0ae0a077 77 * \param [IN] dir Frame direction [0: uplink, 1: downlink]
dudmuck 0:8f0d0ae0a077 78 * \param [IN] sequenceCounter Frame sequence counter
dudmuck 0:8f0d0ae0a077 79 * \param [OUT] mic Computed MIC field
dudmuck 0:8f0d0ae0a077 80 */
dudmuck 0:8f0d0ae0a077 81 void LoRaMacComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint32_t *mic )
dudmuck 0:8f0d0ae0a077 82 {
dudmuck 0:8f0d0ae0a077 83 MicBlockB0[5] = dir;
dudmuck 0:8f0d0ae0a077 84
dudmuck 0:8f0d0ae0a077 85 MicBlockB0[6] = ( address ) & 0xFF;
dudmuck 0:8f0d0ae0a077 86 MicBlockB0[7] = ( address >> 8 ) & 0xFF;
dudmuck 0:8f0d0ae0a077 87 MicBlockB0[8] = ( address >> 16 ) & 0xFF;
dudmuck 0:8f0d0ae0a077 88 MicBlockB0[9] = ( address >> 24 ) & 0xFF;
dudmuck 0:8f0d0ae0a077 89
dudmuck 0:8f0d0ae0a077 90 MicBlockB0[10] = ( sequenceCounter ) & 0xFF;
dudmuck 0:8f0d0ae0a077 91 MicBlockB0[11] = ( sequenceCounter >> 8 ) & 0xFF;
dudmuck 0:8f0d0ae0a077 92 MicBlockB0[12] = ( sequenceCounter >> 16 ) & 0xFF;
dudmuck 0:8f0d0ae0a077 93 MicBlockB0[13] = ( sequenceCounter >> 24 ) & 0xFF;
dudmuck 0:8f0d0ae0a077 94
dudmuck 0:8f0d0ae0a077 95 MicBlockB0[15] = size & 0xFF;
dudmuck 0:8f0d0ae0a077 96
dudmuck 0:8f0d0ae0a077 97 AES_CMAC_Init( AesCmacCtx );
dudmuck 0:8f0d0ae0a077 98
dudmuck 0:8f0d0ae0a077 99 AES_CMAC_SetKey( AesCmacCtx, key );
dudmuck 0:8f0d0ae0a077 100
dudmuck 0:8f0d0ae0a077 101 AES_CMAC_Update( AesCmacCtx, MicBlockB0, LORAMAC_MIC_BLOCK_B0_SIZE );
dudmuck 0:8f0d0ae0a077 102
dudmuck 0:8f0d0ae0a077 103 AES_CMAC_Update( AesCmacCtx, buffer, size & 0xFF );
dudmuck 0:8f0d0ae0a077 104
dudmuck 0:8f0d0ae0a077 105 AES_CMAC_Final( Mic, AesCmacCtx );
dudmuck 0:8f0d0ae0a077 106
dudmuck 0:8f0d0ae0a077 107 *mic = ( uint32_t )( ( uint32_t )Mic[3] << 24 | ( uint32_t )Mic[2] << 16 | ( uint32_t )Mic[1] << 8 | ( uint32_t )Mic[0] );
dudmuck 0:8f0d0ae0a077 108 }
dudmuck 0:8f0d0ae0a077 109
dudmuck 0:8f0d0ae0a077 110 void LoRaMacPayloadEncrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *encBuffer )
dudmuck 0:8f0d0ae0a077 111 {
dudmuck 0:8f0d0ae0a077 112 uint16_t i;
dudmuck 0:8f0d0ae0a077 113 uint8_t bufferIndex = 0;
dudmuck 0:8f0d0ae0a077 114 uint16_t ctr = 1;
dudmuck 0:8f0d0ae0a077 115
dudmuck 0:8f0d0ae0a077 116 memset1( AesContext.ksch, '\0', 240 );
dudmuck 0:8f0d0ae0a077 117 aes_set_key( key, 16, &AesContext );
dudmuck 0:8f0d0ae0a077 118
dudmuck 0:8f0d0ae0a077 119 aBlock[5] = dir;
dudmuck 0:8f0d0ae0a077 120
dudmuck 0:8f0d0ae0a077 121 aBlock[6] = ( address ) & 0xFF;
dudmuck 0:8f0d0ae0a077 122 aBlock[7] = ( address >> 8 ) & 0xFF;
dudmuck 0:8f0d0ae0a077 123 aBlock[8] = ( address >> 16 ) & 0xFF;
dudmuck 0:8f0d0ae0a077 124 aBlock[9] = ( address >> 24 ) & 0xFF;
dudmuck 0:8f0d0ae0a077 125
dudmuck 0:8f0d0ae0a077 126 aBlock[10] = ( sequenceCounter ) & 0xFF;
dudmuck 0:8f0d0ae0a077 127 aBlock[11] = ( sequenceCounter >> 8 ) & 0xFF;
dudmuck 0:8f0d0ae0a077 128 aBlock[12] = ( sequenceCounter >> 16 ) & 0xFF;
dudmuck 0:8f0d0ae0a077 129 aBlock[13] = ( sequenceCounter >> 24 ) & 0xFF;
dudmuck 0:8f0d0ae0a077 130
dudmuck 0:8f0d0ae0a077 131 while( size >= 16 )
dudmuck 0:8f0d0ae0a077 132 {
dudmuck 0:8f0d0ae0a077 133 aBlock[15] = ( ( ctr ) & 0xFF );
dudmuck 0:8f0d0ae0a077 134 ctr++;
dudmuck 0:8f0d0ae0a077 135 aes_encrypt( aBlock, sBlock, &AesContext );
dudmuck 0:8f0d0ae0a077 136 for( i = 0; i < 16; i++ )
dudmuck 0:8f0d0ae0a077 137 {
dudmuck 0:8f0d0ae0a077 138 encBuffer[bufferIndex + i] = buffer[bufferIndex + i] ^ sBlock[i];
dudmuck 0:8f0d0ae0a077 139 }
dudmuck 0:8f0d0ae0a077 140 size -= 16;
dudmuck 0:8f0d0ae0a077 141 bufferIndex += 16;
dudmuck 0:8f0d0ae0a077 142 }
dudmuck 0:8f0d0ae0a077 143
dudmuck 0:8f0d0ae0a077 144 if( size > 0 )
dudmuck 0:8f0d0ae0a077 145 {
dudmuck 0:8f0d0ae0a077 146 aBlock[15] = ( ( ctr ) & 0xFF );
dudmuck 0:8f0d0ae0a077 147 aes_encrypt( aBlock, sBlock, &AesContext );
dudmuck 0:8f0d0ae0a077 148 for( i = 0; i < size; i++ )
dudmuck 0:8f0d0ae0a077 149 {
dudmuck 0:8f0d0ae0a077 150 encBuffer[bufferIndex + i] = buffer[bufferIndex + i] ^ sBlock[i];
dudmuck 0:8f0d0ae0a077 151 }
dudmuck 0:8f0d0ae0a077 152 }
dudmuck 0:8f0d0ae0a077 153 }
dudmuck 0:8f0d0ae0a077 154
dudmuck 0:8f0d0ae0a077 155 void LoRaMacPayloadDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *decBuffer )
dudmuck 0:8f0d0ae0a077 156 {
dudmuck 0:8f0d0ae0a077 157 LoRaMacPayloadEncrypt( buffer, size, key, address, dir, sequenceCounter, decBuffer );
dudmuck 0:8f0d0ae0a077 158 }
dudmuck 0:8f0d0ae0a077 159
dudmuck 0:8f0d0ae0a077 160 void LoRaMacJoinComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t *mic )
dudmuck 0:8f0d0ae0a077 161 {
dudmuck 0:8f0d0ae0a077 162 AES_CMAC_Init( AesCmacCtx );
dudmuck 0:8f0d0ae0a077 163
dudmuck 0:8f0d0ae0a077 164 AES_CMAC_SetKey( AesCmacCtx, key );
dudmuck 0:8f0d0ae0a077 165
dudmuck 0:8f0d0ae0a077 166 AES_CMAC_Update( AesCmacCtx, buffer, size & 0xFF );
dudmuck 0:8f0d0ae0a077 167
dudmuck 0:8f0d0ae0a077 168 AES_CMAC_Final( Mic, AesCmacCtx );
dudmuck 0:8f0d0ae0a077 169
dudmuck 0:8f0d0ae0a077 170 *mic = ( uint32_t )( ( uint32_t )Mic[3] << 24 | ( uint32_t )Mic[2] << 16 | ( uint32_t )Mic[1] << 8 | ( uint32_t )Mic[0] );
dudmuck 0:8f0d0ae0a077 171 }
dudmuck 0:8f0d0ae0a077 172
dudmuck 0:8f0d0ae0a077 173 void LoRaMacJoinDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint8_t *decBuffer )
dudmuck 0:8f0d0ae0a077 174 {
dudmuck 0:8f0d0ae0a077 175 /*int i;
Wayne Roberts 29:ad409c68c0a6 176 pc.printf("LoRaMacJoinDecrypt%u: ", size);
dudmuck 0:8f0d0ae0a077 177 for (i = 0; i < size; i++)
Wayne Roberts 29:ad409c68c0a6 178 pc.printf("%02x ", buffer[i]);*/
dudmuck 0:8f0d0ae0a077 179
dudmuck 0:8f0d0ae0a077 180 memset1( AesContext.ksch, '\0', 240 );
dudmuck 0:8f0d0ae0a077 181 aes_set_key( key, 16, &AesContext );
dudmuck 0:8f0d0ae0a077 182 aes_encrypt( buffer, decBuffer, &AesContext );
dudmuck 0:8f0d0ae0a077 183 // Check if optional CFList is included
Wayne Roberts 29:ad409c68c0a6 184 /*pc.printf("\r\ndecr:");
dudmuck 0:8f0d0ae0a077 185 for (i = 0; i < 16; i++)
Wayne Roberts 29:ad409c68c0a6 186 pc.printf("%02x ", decBuffer[i]);*/
dudmuck 0:8f0d0ae0a077 187 if( size >= 16 )
dudmuck 0:8f0d0ae0a077 188 {
dudmuck 0:8f0d0ae0a077 189 aes_encrypt( buffer + 16, decBuffer + 16, &AesContext );
Wayne Roberts 29:ad409c68c0a6 190 /*pc.printf("\r\ndecr:");
dudmuck 0:8f0d0ae0a077 191 for (i = 0; i < 16; i++)
Wayne Roberts 29:ad409c68c0a6 192 pc.printf("%02x ", decBuffer[i+16]);
Wayne Roberts 29:ad409c68c0a6 193 pc.printf("\r\n");*/
dudmuck 0:8f0d0ae0a077 194 }
dudmuck 0:8f0d0ae0a077 195 }
dudmuck 0:8f0d0ae0a077 196
dudmuck 0:8f0d0ae0a077 197 void LoRaMacJoinComputeSKeys( const uint8_t *key, const uint8_t *appNonce, uint16_t devNonce, uint8_t *nwkSKey, uint8_t *appSKey )
dudmuck 0:8f0d0ae0a077 198 {
dudmuck 0:8f0d0ae0a077 199 uint8_t nonce[16];
dudmuck 0:8f0d0ae0a077 200 uint8_t *pDevNonce = ( uint8_t * )&devNonce;
dudmuck 0:8f0d0ae0a077 201
dudmuck 0:8f0d0ae0a077 202 memset1( AesContext.ksch, '\0', 240 );
dudmuck 0:8f0d0ae0a077 203 aes_set_key( key, 16, &AesContext );
dudmuck 0:8f0d0ae0a077 204
dudmuck 0:8f0d0ae0a077 205 memset1( nonce, 0, sizeof( nonce ) );
dudmuck 0:8f0d0ae0a077 206 nonce[0] = 0x01;
dudmuck 0:8f0d0ae0a077 207 memcpy1( nonce + 1, appNonce, 6 );
dudmuck 0:8f0d0ae0a077 208 memcpy1( nonce + 7, pDevNonce, 2 );
dudmuck 0:8f0d0ae0a077 209 aes_encrypt( nonce, nwkSKey, &AesContext );
dudmuck 0:8f0d0ae0a077 210
dudmuck 0:8f0d0ae0a077 211 memset1( nonce, 0, sizeof( nonce ) );
dudmuck 0:8f0d0ae0a077 212 nonce[0] = 0x02;
dudmuck 0:8f0d0ae0a077 213 memcpy1( nonce + 1, appNonce, 6 );
dudmuck 0:8f0d0ae0a077 214 memcpy1( nonce + 7, pDevNonce, 2 );
dudmuck 0:8f0d0ae0a077 215 aes_encrypt( nonce, appSKey, &AesContext );
dudmuck 0:8f0d0ae0a077 216 }