A very easy to understand LoRaWAN-node code.

Dependencies:   LoRaWAN-lib SX1272Lib X_NUCLEO_IKS01A1 mbed

Important parameters:

• In comissioning.h: DevEUI, AppEUI, AppKEY, DevADR, NwksKEY, AppsKEY, OTAA and public network. Frequency and channel block to use, confirmed or unconfirmed messages, app port, app data size and OTAA and Tx duty cycles.

• In LoRaMac.h: Maximum payload and MAC commands length, receive delays, max FCNT, adr ack limit, timeout and delay, max ack retries, rssi threshold and sync words.

• In LoRaMac.cpp: Maximum payload, MAC commands and FRMpayload length.

• In LoRaMac-board.h: Tx power, data rates and band settings.

NOTE: Please refer to LoRaWAN regional parameters (page 12 for US band) to know which parameters you can modify.

Files at this revision

API Documentation at this revision

Comitter:
dgabino
Date:
Tue Apr 03 17:09:34 2018 +0000
Commit message:
A simpler way to customize your LoRaWAN payload

Changed in this revision

Code/Comissioning.h Show annotated file Show diff for this revision Revisions of this file
Code/Common.h Show annotated file Show diff for this revision Revisions of this file
Code/LoRaDeviceFunctions.h Show annotated file Show diff for this revision Revisions of this file
Code/SerialDisplay.cpp Show annotated file Show diff for this revision Revisions of this file
Code/SerialDisplay.h Show annotated file Show diff for this revision Revisions of this file
Code/board.h Show annotated file Show diff for this revision Revisions of this file
Code/main.cpp Show annotated file Show diff for this revision Revisions of this file
Code/vt100.h Show annotated file Show diff for this revision Revisions of this file
LoRaWAN-lib-v1_0_1.lib Show annotated file Show diff for this revision Revisions of this file
SX1272Lib.lib Show annotated file Show diff for this revision Revisions of this file
X_NUCLEO_IKS01A1.lib Show annotated file Show diff for this revision Revisions of this file
system/crypto/aes.cpp Show annotated file Show diff for this revision Revisions of this file
system/crypto/aes.h Show annotated file Show diff for this revision Revisions of this file
system/crypto/cmac.cpp Show annotated file Show diff for this revision Revisions of this file
system/crypto/cmac.h Show annotated file Show diff for this revision Revisions of this file
system/mbed.bld Show annotated file Show diff for this revision Revisions of this file
system/timer.cpp Show annotated file Show diff for this revision Revisions of this file
system/timer.h Show annotated file Show diff for this revision Revisions of this file
system/utilities.cpp Show annotated file Show diff for this revision Revisions of this file
system/utilities.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 60ff878b27b8 Code/Comissioning.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/Comissioning.h	Tue Apr 03 17:09:34 2018 +0000
@@ -0,0 +1,163 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+    (C)2015 Semtech
+
+Description: End device comissioning and comunication parameters
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+Maintainer: Miguel Luis and Gregory Cristian
+*/
+#include "board.h"
+
+//********************************************************************* COMISSIONING PARAMETERS ************************************************************************
+
+#ifndef __LORA_COMISSIONING_H__
+#define __LORA_COMISSIONING_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
+
+/*!
+ * Indicates if the end-device is to be connected to a private or public network
+ */
+#define LORAWAN_PUBLIC_NETWORK                      true
+
+#if( OVER_THE_AIR_ACTIVATION != 0 )
+
+/*!
+ * Mote device IEEE OUI (big endian)
+ * \remark This is unique to a company or organization
+ */
+#define IEEE_OUI                                    0x4f, 0x72, 0x62
+
+/*!
+ * Mote device IEEE EUI (big endian)
+ *
+ * \remark In this application, if the last 4 bytes are all 0, then the 32 bit address is automatically generated using a pseudo random generator seeded with a value derived from BoardUniqueId value
+ * If provided by user, e.g. {IEEE_OUI, 0x00, 0x00, 0x00, 0xFF, 0x01}, then this value is used by the application. *0x69, 0x00, 0xab, 0xcd, 0xaa 
+ */
+#define LORAWAN_DEVICE_EUI                          { IEEE_OUI, 0x69, 0x00, 0xab, 0xcd, 0xff } 
+
+/*!
+ * Application IEEE EUI (big endian)
+ */
+#define LORAWAN_APPLICATION_EUI                     { 0x70, 0xb3, 0xd5, 0x7e, 0xd0, 0x00, 0x96, 0x4b} //0x70, 0xb3, 0xd5, 0x7e, 0xd0, 0x00, 0x96, 0x4b     for TTN server
+                                                                                                       //0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00     for semtech NA server
+/*!
+ * AES encryption/decryption cipher application key
+ */
+#define LORAWAN_APPLICATION_KEY                     { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }
+
+#else
+
+/*!
+ * Device address on the network (big endian)
+ *
+ * \remark In this application, if the value is 0, then the address is automatically generated using a pseudo random generator seeded with a value derived from BoardUniqueId value
+ * If provided by user, e.g. 0x78563412, then this value is used by the application
+ */
+#define LORAWAN_DEVICE_ADDRESS                      ( uint32_t )0x0
+
+/*!
+ * AES encryption/decryption cipher network session key
+ */
+#define LORAWAN_NWKSKEY                             { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }
+
+/*!
+ * AES encryption/decryption cipher application session key
+ */
+#define LORAWAN_APPSKEY                             { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }
+
+#endif
+
+#endif // __LORA_COMISSIONING_H__
+
+ 
+//********************************************************************* COMUNICATION PARAMETERS ************************************************************************
+
+#ifndef __LORA_CONFIG_H__
+#define __LORA_CONFIG_H__
+
+/*!
+ * Configure End-Device to use 8-channels corresponding to Block A
+ * Comment/Uncomment to disable/enable Hybrid mode
+ */
+#define USE_BAND_915_HYBRID
+
+#ifndef USE_BAND_915_HYBRID
+/*!
+ * Configure End-Device to use 64-channels across to Block A thru Block H
+ */
+#define USE_BAND_915
+
+#else
+
+// define channel block: e.g. USE_BAND_915_HYBRID_BLOCK_A, USE_BAND_915_HYBRID_BLOCK_B ... USE_BAND_915_HYBRID_BLOCK_H etc.
+#define USE_BAND_915_HYBRID_BLOCK_A
+
+#endif
+
+/*!
+ * Join requests trials periodicity(+12s). It is the time between RX1/RX2 and next TX
+ */
+#define OVER_THE_AIR_ACTIVATION_DUTYCYCLE           5000000  // value in us
+
+/*!
+ * Defines the application data transmission periodicity. It is the time between RX1/RX2 and next TX
+ */
+#define APP_TX_DUTYCYCLE                            25000000  // value in us
+
+/*!
+ * Defines the randomness in the dutycycle. 
+ */
+#define APP_TX_DUTYCYCLE_RND                        3000000
+
+/*!
+ * LoRaWAN confirmed messages
+ * \remark 1 : Confirmed messages enabled. Must receive ACK from network server
+           0 : Confirmed messages disabled. 
+ */
+#define LORAWAN_CONFIRMED_MSG_ON                    0
+
+/*!
+ * LoRaWAN Adaptive Data Rate
+ *
+ * \remark Please note that when ADR is enabled the end-device uses default datarate of DR_0
+ */
+#define LORAWAN_ADR_ON                              0
+
+/*!
+ * Default mote datarate
+ * \remark DR_0 : 980 bps; DR_1 : 1760 bps; DR_2 : 3125 bps; DR_3 : 5470 bps; DR_4 : 12500 bps
+ */
+#define LORAWAN_DEFAULT_DATARATE                    DR_0
+
+/*!
+ * LoRaWAN application port
+ */
+#define LORAWAN_APP_PORT                            5
+
+/*!
+ * LoRaWAN User defined Tx Power
+ *
+ * \remark The Tx power level is set as TX_POWER_P_DBM, where 10 <= P <= 30 and P is even value { i.e. P = 10, 12, 14 ... 28 or 30 }
+ */
+#define LORAWAN_TX_POWER                            TX_POWER_10_DBM
+
+
+#define LORAWAN_APP_DATA_SIZE                       11
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define USE_IKS01A1_SENSOR
+
+#endif //  __LORA_CONFIG_H__
+
diff -r 000000000000 -r 60ff878b27b8 Code/Common.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/Common.h	Tue Apr 03 17:09:34 2018 +0000
@@ -0,0 +1,74 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+    (C)2015 Semtech
+
+Description: Extern declaration of parameters defined in main.cpp
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+Maintainer: Uttam Bhat
+*/
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#include "Comissioning.h"
+#include "board.h"
+
+
+/*!
+ * User application data buffer size
+ */
+#define LORAWAN_APP_DATA_MAX_SIZE                           64
+
+/*!
+ * Current network ID
+ */
+#define LORAWAN_NETWORK_ID                          ( uint32_t )0
+
+
+#if( OVER_THE_AIR_ACTIVATION != 0 )
+/*!
+ * Over the Air Activation 
+ */
+
+extern uint8_t DevEui[];
+extern uint8_t AppEui[];
+extern uint8_t AppKey[];
+
+#else
+/*!
+ * Activation by Personalization 
+ */
+
+extern uint8_t NwkSKey[];
+extern uint8_t AppSKey[];
+extern uint32_t DevAddr;
+
+#endif
+
+
+extern uint8_t AppData[LORAWAN_APP_DATA_MAX_SIZE]; //  User application data size
+
+extern uint8_t AppPort; // Application port
+
+extern uint8_t AppDataSize; // Application size
+
+extern uint8_t IsTxConfirmed; // Indicates if the node is sending confirmed or unconfirmed messages
+
+extern bool IsTxIntUpdate; // Indicates if a new transmit interrupt can be set
+
+extern bool NextTx; // Indicates if a new packet can be sent
+
+extern bool IsNetworkJoinedStatusUpdate; // Indicates if the MAC layer network join status has changed.
+
+extern bool IsTxUpdate; // Indicates if the message sent
+
+extern bool IsRxUpdate; // Indicates if the message received in the RX window.
+
+extern TimerEvent_t TxNextPacketTimer; // Timer to handle the application data transmission duty cycle
+
+#endif // __COMMON_H__
\ No newline at end of file
diff -r 000000000000 -r 60ff878b27b8 Code/LoRaDeviceFunctions.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/LoRaDeviceFunctions.h	Tue Apr 03 17:09:34 2018 +0000
@@ -0,0 +1,105 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+    (C)2015 Semtech
+
+Description: Process function calls from various Device states
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+Maintainer: Uttam Bhat
+*/
+#ifndef __LORA_DEVICE_STATE_H__
+#define __LORA_DEVICE_STATE_H__
+
+#include "Common.h"
+#include "board.h"
+#include "LoRaMac.h"
+
+#include "SerialDisplay.h"
+#include "mbed.h"
+#include "LoRaMacLayerService.h"
+
+/*!
+ * Strucure containing the Uplink status
+ */
+struct sLoRaMacUplinkStatus
+{
+    /*!
+     * MCPS-Request type
+     */
+    Mcps_t Type;    
+    uint8_t Acked;
+    int8_t Datarate;
+    uint16_t UplinkCounter;
+    uint8_t Port;
+    uint8_t *Buffer;
+    uint8_t BufferSize;
+    int8_t TxPower;
+};
+
+/*!
+ * Strucure containing the Downlink status
+ */
+struct sLoRaMacDownlinkStatus
+{
+    int16_t Rssi;
+    int8_t Snr;
+    uint16_t DownlinkCounter;
+    bool RxData;
+    uint8_t Port;
+    uint8_t *Buffer;
+    uint8_t BufferSize;
+    uint8_t RxSlot;
+};
+
+/*!
+ * Device states
+ */
+enum eDevicState
+{
+    DEVICE_STATE_INIT,
+    DEVICE_STATE_JOIN,
+    DEVICE_STATE_SEND,
+    DEVICE_STATE_SLEEP
+};
+
+extern sLoRaMacUplinkStatus LoRaMacUplinkStatus;
+
+extern sLoRaMacDownlinkStatus LoRaMacDownlinkStatus;
+
+extern eDevicState DeviceState;
+
+/*!
+ * \brief Initialize Device: Timer, MAC Services, MAC
+ */
+void DeviceInit( void );
+
+/*!
+ * \brief Device Join update
+ */
+void DeviceJoinUpdate( void );
+
+/*!
+ * \brief OTA: if device not joined, send JOIN REQUEST to network
+ *      ABP: Request DevAddr if not already set
+ */
+void DeviceJoin( void );
+
+/*!
+ * \brief   Prepares the payload of the frame to be transmitted
+ *
+ * \param [IN] port application port corresponding to which payload is generated
+ */
+void PrepareTxFrame( uint8_t port );
+
+/*!
+ * \brief   Send the frame
+ *
+ */
+bool SendFrame( void );
+
+#endif // __LORA_DEVICE_STATE_H__
\ No newline at end of file
diff -r 000000000000 -r 60ff878b27b8 Code/SerialDisplay.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/SerialDisplay.cpp	Tue Apr 03 17:09:34 2018 +0000
@@ -0,0 +1,137 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+    (C)2015 Semtech
+
+Description: VT100 serial display management
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+Maintainer: Miguel Luis and Gregory Cristian
+*/
+
+#include "SerialDisplay.h"
+
+VT100 vt( USBTX, USBRX );
+
+void SerialDisplayJoinUpdate( void )
+{
+    printf( "###### ===== JOINING ==== ######\r\n" );
+    
+    DisplayNetworkParam( );
+
+    printf( "\r\n" );
+}
+
+void SerialDisplayTxUpdate(void)
+{
+    printf( "###### ===== UPLINK FRAME %d ==== ######\r\n", LoRaMacUplinkStatus.UplinkCounter );
+
+    DisplayNetworkParam( );
+    
+    printf( "TX PORT: %d\r\n", LoRaMacUplinkStatus.Port );
+
+    if( LoRaMacUplinkStatus.BufferSize != 0 )
+    {
+        printf( "TX DATA: " );
+        if( LoRaMacUplinkStatus.Type == MCPS_CONFIRMED )
+        {
+            printf( "CONFIRMED\r\n" );
+        }
+        else
+        {
+            printf( "UNCONFIRMED\r\n" );
+        }
+        SerialDisplayHex( LoRaMacUplinkStatus.Buffer, LoRaMacUplinkStatus.BufferSize );
+    }
+
+    printf( "DATA RATE: DR%d\r\n", LoRaMacUplinkStatus.Datarate );
+
+    printf( "TX POWER: %d dBm\r\n", 30 - ( LoRaMacUplinkStatus.TxPower << 1 ) );
+
+    printf( "BATTERY: %2.2fV\r\n", BoardGetBatteryLevel( ) );
+
+    printf( "\r\n");
+}
+
+void SerialDisplayRxUpdate( void )
+{
+    printf( "###### ===== DOWNLINK FRAME %d ==== ######\r\n", LoRaMacDownlinkStatus.DownlinkCounter );
+
+    printf( "RX WINDOW: %d\r\n", LoRaMacDownlinkStatus.RxSlot + 1 );
+    
+    printf( "RX PORT: %d\r\n", LoRaMacDownlinkStatus.Port );
+
+    if( LoRaMacDownlinkStatus.BufferSize != 0 )
+    {
+        printf( "RX DATA: \r\n" );
+        SerialDisplayHex( LoRaMacDownlinkStatus.Buffer, LoRaMacDownlinkStatus.BufferSize );
+    }
+
+    printf( "RX RSSI: %d\r\n", LoRaMacDownlinkStatus.Rssi );
+
+    printf( "RX SNR: %d\r\n", LoRaMacDownlinkStatus.Snr );
+
+    printf( "\r\n" );
+}
+
+void SerialDisplayHex( uint8_t *pData, uint8_t len )
+{
+    int i;
+    bool newline = 0;
+
+    for( i = 0; i < len; i++ )
+    {
+        if( newline != 0 )
+        {
+            printf( "\r\n" );
+            newline = 0;
+        }
+
+        printf( "%02X", pData[i] );
+
+        if( ( ( i + 1 ) % 16 ) == 0 )
+        {
+            newline = 1;
+        }
+    }
+    printf( "\r\n" );
+}
+
+
+
+void DisplayNetworkParam( void )
+{
+#if( OVER_THE_AIR_ACTIVATION != 0 )
+
+    printf( "DEVEUI: " );
+    SerialDisplayHex( DevEui, 8 );
+
+    printf( "APPEUI: " );
+    SerialDisplayHex( AppEui, 8 );
+
+    printf( "APPKEY: " );
+    SerialDisplayHex( AppKey, 16 );
+
+#else
+
+    printf( "DEVADDR: " );
+    
+    uint8_t *pData = ( uint8_t* )&DevAddr;
+    for( int32_t i = 3; i >= 0; i-- )
+    {
+        printf( "%02X", pData[i] );
+    }
+    printf( "\r\n" );
+
+    printf( "NWKSKEY: " );
+    SerialDisplayHex( NwkSKey, 16 );
+
+    printf( "APPSKEY: " );
+    SerialDisplayHex( AppSKey, 16 );
+
+#endif
+}
\ No newline at end of file
diff -r 000000000000 -r 60ff878b27b8 Code/SerialDisplay.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/SerialDisplay.h	Tue Apr 03 17:09:34 2018 +0000
@@ -0,0 +1,31 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+    (C)2015 Semtech
+
+Description: Serial display management
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+Maintainer: Uttam Bhat
+*/
+#ifndef __SERIAL_DISPLAY_H__
+#define __SERIAL_DISPLAY_H__
+
+#include "board.h"
+#include "vt100.h"
+#include "Comissioning.h"
+#include "LoRaMac.h"
+#include "Common.h"
+#include "LoRaDeviceFunctions.h"
+
+void SerialDisplayJoinUpdate( void );
+void SerialDisplayTxUpdate( void );
+void SerialDisplayRxUpdate( void );
+void SerialDisplayHex( uint8_t *pData, uint8_t len );
+void DisplayNetworkParam( void );
+
+#endif // __SERIAL_DISPLAY_H__
diff -r 000000000000 -r 60ff878b27b8 Code/board.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/board.h	Tue Apr 03 17:09:34 2018 +0000
@@ -0,0 +1,81 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+    (C)2015 Semtech
+
+Description: Target board general functions implementation
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+Maintainer: Miguel Luis and Gregory Cristian
+*/
+#ifndef __BOARD_H__
+#define __BOARD_H__
+
+#include "Comissioning.h"
+#include "mbed.h"
+#include "system/timer.h"
+#include "debug.h"
+#include "system/utilities.h"
+#include "sx1272-hal.h"
+
+#ifdef USE_IKS01A1_SENSOR
+#include "x_nucleo_iks01a1.h"
+#endif
+/*!
+ * Unique Devices IDs register set ( STM32L1xxx )
+ */
+#define         ID1                                 ( 0x1FF800D0 )
+#define         ID2                                 ( 0x1FF800D4 )
+#define         ID3                                 ( 0x1FF800E4 )
+
+#define LOW_BAT_THRESHOLD   3.45
+#define AIN_VREF            3.3     // STM32 internal refernce
+#define AIN_VBAT_DIV        2       // Resistor divider
+
+extern SX1272MB2xAS Radio;
+
+extern DigitalIn UsrButton;
+
+extern DigitalOut Led;
+
+#ifdef USE_IKS01A1_SENSOR
+extern X_NUCLEO_IKS01A1 *mems_expansion_board;
+extern MotionSensor *accelerometer;
+extern HumiditySensor *humidity_sensor;
+extern PressureSensor *pressure_sensor;
+extern TempSensor *temp_sensor1;
+extern TempSensor *temp_sensor2;
+#endif
+
+/*!
+ * \brief Initializes the target board peripherals.
+ */
+void BoardInit( void );
+
+/*!
+ * \brief Measure the Battery level
+ *
+ * \retval value  battery level ( 0: very low, 254: fully charged )
+ */
+uint8_t BoardGetBatteryLevel( void );
+
+/*!
+ * Returns a pseudo random seed generated using the MCU Unique ID
+ *
+ * \retval seed Generated pseudo random seed
+ */
+uint32_t BoardGetRandomSeed( void );
+
+/*!
+ * \brief Generates Lower 32 bits of DEVEUI using 96 bits unique device ID 
+ *
+ * \param [IN] id Pointer to an array that will contain the Unique ID
+ */
+void BoardGetDevEUI( uint8_t *id );
+
+
+#endif // __BOARD_H__
diff -r 000000000000 -r 60ff878b27b8 Code/main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/main.cpp	Tue Apr 03 17:09:34 2018 +0000
@@ -0,0 +1,411 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+    (C)2015 Semtech
+
+Description: LoRaMac classA device implementation
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+Maintainer: Miguel Luis and Gregory Cristian
+*/
+#include "mbed.h"
+#include "board.h"
+#include "radio.h"
+
+#include "LoRaMac.h"
+#include "Comissioning.h"
+#include "SerialDisplay.h"
+#include "LoRaDeviceFunctions.h"
+#include "LoRaMacLayerService.h"
+
+
+#if( OVER_THE_AIR_ACTIVATION != 0 )         
+
+uint8_t DevEui[] = LORAWAN_DEVICE_EUI;
+uint8_t AppEui[] = LORAWAN_APPLICATION_EUI;
+uint8_t AppKey[] = LORAWAN_APPLICATION_KEY;
+
+#else
+
+uint8_t NwkSKey[] = LORAWAN_NWKSKEY;
+uint8_t AppSKey[] = LORAWAN_APPSKEY;
+uint32_t DevAddr = LORAWAN_DEVICE_ADDRESS;
+
+#endif
+
+
+uint8_t AppPort = LORAWAN_APP_PORT;     //application port
+
+uint8_t AppDataSize = LORAWAN_APP_DATA_SIZE;    //data size
+
+uint8_t AppData[LORAWAN_APP_DATA_MAX_SIZE];     //payload array
+
+uint8_t IsTxConfirmed = LORAWAN_CONFIRMED_MSG_ON;    //Indicates if the node is sending confirmed or unconfirmed messages
+
+TimerEvent_t TxNextPacketTimer;     //Timer to handle the application data transmission duty cycle
+
+bool IsTxIntUpdate = false;     //Indicates if a new transmit interrupt can be set
+
+bool NextTx = true;     //Indicates if a new packet can be sent
+
+bool IsNetworkJoinedStatusUpdate = false;   //Indicates if the MAC layer network join status has changed.
+
+bool IsTxUpdate = false;    //Indicates if the message sent.
+
+bool IsRxUpdate = false;    //Indicates if the message received in the RX window.
+
+float sensor_data;          //Used to store the sensor data
+
+uint32_t TxDutyCycleTime = APP_TX_DUTYCYCLE;
+
+eDevicState DeviceState;
+
+sLoRaMacUplinkStatus LoRaMacUplinkStatus;
+
+sLoRaMacDownlinkStatus LoRaMacDownlinkStatus;
+
+LoRaMacPrimitives_t LoRaPrimitives;
+
+LoRaMacCallback_t LoRaCallbacks;
+
+MibRequestConfirm_t LoRaMibReq;
+
+MlmeReq_t mlmeReq;
+
+uint16_t ChannelMaskTemp[6] = {0};
+
+uint8_t BoardGetBatteryLevel( void ) 
+{
+    return 0xFE;
+}
+DigitalIn I2cInterrupt( D5 );
+I2C I2c(I2C_SDA, I2C_SCL);
+
+DigitalOut Pc7( D9 );
+DigitalIn Pc1( A4 );
+
+//DigitalIn UsrButton( PC_13 );
+DigitalIn UsrButton( D10 );
+
+DigitalOut Led( D6 );
+
+#ifdef USE_IKS01A1_SENSOR
+X_NUCLEO_IKS01A1 *mems_expansion_board = X_NUCLEO_IKS01A1::Instance();
+MotionSensor *accelerometer = mems_expansion_board->GetAccelerometer();
+HumiditySensor *humidity_sensor = mems_expansion_board->ht_sensor;;
+PressureSensor *pressure_sensor = mems_expansion_board->pt_sensor;
+TempSensor *temp_sensor1 = mems_expansion_board->ht_sensor;
+TempSensor *temp_sensor2 = mems_expansion_board->pt_sensor;
+#endif
+
+SX1272MB2xAS Radio( NULL );
+
+
+uint32_t BoardGetRandomSeed( void )
+{
+    return ( ( *( uint32_t* )ID1 ) ^ ( *( uint32_t* )ID2 ) ^ ( *( uint32_t* )ID3 ) );
+}
+
+void BoardGetDevEUI( uint8_t *id )
+{
+    uint32_t *pDevEuiHWord = ( uint32_t* )&id[4];
+
+    if( *pDevEuiHWord == 0 )
+    {        
+        *pDevEuiHWord = BoardGetRandomSeed( );
+    }
+    
+}
+
+static void OnTxNextPacketTimerEvent( void )
+{
+    MibRequestConfirm_t mibReq;
+    LoRaMacStatus_t status;
+
+    TimerStop( &TxNextPacketTimer );
+
+    mibReq.Type = MIB_NETWORK_JOINED;
+    status = LoRaMacMibGetRequestConfirm( &mibReq );
+
+    if( status == LORAMAC_STATUS_OK )
+    {
+        if( mibReq.Param.IsNetworkJoined == true )
+        {
+            DeviceState = DEVICE_STATE_SEND;            
+        }
+        else
+        {
+            DeviceState = DEVICE_STATE_JOIN;
+        }
+        NextTx = true;
+    }
+}
+
+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;
+        
+        LoRaMacUplinkStatus.Acked = false;
+        LoRaMacUplinkStatus.Port = 0;
+        LoRaMacUplinkStatus.Buffer = NULL;
+        LoRaMacUplinkStatus.BufferSize = 0;        
+    }
+    else
+    {
+        LoRaMacUplinkStatus.Acked = false;
+        LoRaMacUplinkStatus.Port = AppPort;
+        LoRaMacUplinkStatus.Buffer = AppData;
+        LoRaMacUplinkStatus.BufferSize = AppDataSize;
+
+        if( ( IsTxConfirmed == false ) || ( LoRaMacUplinkStatus.UplinkCounter == 0 ) )
+        {
+            mcpsReq.Type = MCPS_UNCONFIRMED;
+            mcpsReq.Req.Unconfirmed.fPort = AppPort;
+            mcpsReq.Req.Unconfirmed.fBuffer = AppData;
+            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 = AppData;
+            mcpsReq.Req.Confirmed.fBufferSize = AppDataSize;
+            mcpsReq.Req.Confirmed.NbTrials = 8;
+            mcpsReq.Req.Confirmed.Datarate = LORAWAN_DEFAULT_DATARATE;
+        }
+    }
+
+    LoRaMacUplinkStatus.Type = mcpsReq.Type;
+
+    if( LoRaMacMcpsRequest( &mcpsReq ) == LORAMAC_STATUS_OK )
+    {
+        return false;
+    }
+    return true;
+}
+
+int main( void )
+{
+   
+    TimerTimeCounterInit( );  //initialize timer
+
+    DeviceState = DEVICE_STATE_INIT; // Indicate Device state
+
+    while( 1 )
+    {               
+        if( IsNetworkJoinedStatusUpdate == true )
+        {
+            //Checks if the device has joined the server and updates the joined status
+            IsNetworkJoinedStatusUpdate = false;
+            LoRaMibReq.Type = MIB_NETWORK_JOINED;
+            LoRaMacMibGetRequestConfirm( &LoRaMibReq ); 
+        }
+
+        if( IsTxIntUpdate == true )
+        {
+            // Initialize next Tx Interrupt
+            IsTxIntUpdate = false;
+            TimerSetValue( &TxNextPacketTimer, TxDutyCycleTime );
+            TimerStart( &TxNextPacketTimer );
+          
+        }
+
+        if( IsRxUpdate == true )
+        {
+            // If downlink received then update Serial Terminal Rx parameters
+            IsRxUpdate = false;
+            SerialDisplayRxUpdate( );            
+        }
+        
+        switch( DeviceState )           //realizes different tasks depending on device state
+        {
+            case DEVICE_STATE_INIT:
+            {
+                
+                LoRaPrimitives.MacMcpsConfirm = McpsConfirm;    //Update uplink and event info status
+                LoRaPrimitives.MacMcpsIndication = McpsIndication;      //
+                LoRaPrimitives.MacMlmeConfirm = MlmeConfirm;
+                LoRaCallbacks.GetBatteryLevel = BoardGetBatteryLevel;      //0: external power source, 1-254: battery level, 255: couldnt measure battery level
+                LoRaMacInitialization( &LoRaPrimitives, &LoRaCallbacks );  //Sets radio parameters (channels, frequency, timers, windows)
+            
+                TimerInit( &TxNextPacketTimer, OnTxNextPacketTimerEvent );
+            
+                LoRaMibReq.Type = MIB_ADR;
+                LoRaMibReq.Param.AdrEnable = LORAWAN_ADR_ON;
+                LoRaMacMibSetRequestConfirm( &LoRaMibReq );
+            
+                LoRaMibReq.Type = MIB_PUBLIC_NETWORK;
+                LoRaMibReq.Param.EnablePublicNetwork = LORAWAN_PUBLIC_NETWORK;
+                LoRaMacMibSetRequestConfirm( &LoRaMibReq );
+            
+                LoRaMibReq.Type = MIB_CHANNELS_TX_POWER;
+                LoRaMibReq.Param.ChannelsTxPower = LORAWAN_TX_POWER;
+                LoRaMacMibSetRequestConfirm( &LoRaMibReq );
+                
+                LoRaMibReq.Type = MIB_CHANNELS_MASK;
+                LoRaMibReq.Param.ChannelsMask = ChannelMaskTemp;       
+                //channel mask for USE_BAND_915_HYBRID
+                ChannelMaskTemp[0] = 0x00FF;
+                ChannelMaskTemp[1] = 0x0000;
+                ChannelMaskTemp[2] = 0x0000;
+                ChannelMaskTemp[3] = 0x0000;
+                ChannelMaskTemp[4] = 0x0001;
+                LoRaMacMibSetRequestConfirm( &LoRaMibReq );
+                
+                LoRaMacDownlinkStatus.DownlinkCounter = 0;
+          
+                DeviceState = DEVICE_STATE_JOIN;        // Change Device state
+                break;
+            }
+            case DEVICE_STATE_JOIN:
+            {
+#if( OVER_THE_AIR_ACTIVATION != 0 )                // OTAA 
+                           
+                BoardGetDevEUI( DevEui );        // Generate DevEUI if not defined by User 
+                
+                mlmeReq.Type = MLME_JOIN;       //Changes Mlmereq content to send in join request
+                mlmeReq.Req.Join.DevEui = DevEui;
+                mlmeReq.Req.Join.AppEui = AppEui;
+                mlmeReq.Req.Join.AppKey = AppKey;
+            
+                if( NextTx == true )
+                {
+                    LoRaMacMlmeRequest( &mlmeReq );
+                }          
+          
+                SerialDisplayJoinUpdate( );     // Show on serial terminal                           
+
+                DeviceState = DEVICE_STATE_SLEEP;
+
+#else                                           // ABP
+    
+                 // Choose a random device address if not already defined in Config.h
+                if( DevAddr == 0 )
+                {
+                    // Random seed initialization
+                    srand1( BoardGetRandomSeed( ) );
+                    DevAddr = randr( 0, 0x01FFFFFF );
+                }
+            
+                LoRaMibReq.Type = MIB_NET_ID;
+                LoRaMibReq.Param.NetID = LORAWAN_NETWORK_ID;
+                LoRaMacMibSetRequestConfirm( &LoRaMibReq );
+            
+                LoRaMibReq.Type = MIB_DEV_ADDR;
+                LoRaMibReq.Param.DevAddr = DevAddr;
+                LoRaMacMibSetRequestConfirm( &LoRaMibReq );
+            
+                LoRaMibReq.Type = MIB_NWK_SKEY;
+                LoRaMibReq.Param.NwkSKey = NwkSKey;
+                LoRaMacMibSetRequestConfirm( &LoRaMibReq );
+            
+                LoRaMibReq.Type = MIB_APP_SKEY;
+                LoRaMibReq.Param.AppSKey = AppSKey;
+                LoRaMacMibSetRequestConfirm( &LoRaMibReq );
+            
+                LoRaMibReq.Type = MIB_NETWORK_JOINED;
+                LoRaMibReq.Param.IsNetworkJoined = true;
+                LoRaMacMibSetRequestConfirm( &LoRaMibReq );
+
+                DeviceState = DEVICE_STATE_SEND;
+#endif
+                IsNetworkJoinedStatusUpdate = true;
+                break;
+            }
+            case DEVICE_STATE_SEND:
+            {   
+                            
+                if( NextTx == true )
+                {   
+                    //===============Functions to get X_NUCLEO_IKS01A1 sensor data===============              
+
+                    temp_sensor2->GetTemperature(&sensor_data);
+                    int16_t tmp_data = (int16_t) (sensor_data*10 + 0.5);
+                    AppData[2] = (int8_t) ( ( tmp_data >> 8 ) & 0xFF );
+                    AppData[3] = (int8_t) tmp_data & 0xFF; 
+                                    
+                    pressure_sensor->GetPressure(&sensor_data);
+                    int16_t tmp =  (int16_t) ( sensor_data * 10 );
+                    AppData[6] = ( tmp >> 8 ) & 0xFF;
+                    AppData[7] = ( tmp ) & 0xFF;
+                    
+                    humidity_sensor->GetHumidity(&sensor_data);
+                    AppData[10] = (uint8_t) ( sensor_data * 2 );
+                    
+                    //accelerometer->Get_X_Axes(Accl_Value);
+                    //AppData[BuffPtr++] = ( (int16_t) Accl_Value[0] >> 8 ) & 0xFF;
+                    //AppData[BuffPtr++] = ( (int16_t) Accl_Value[0] ) & 0xFF; 
+                    //AppData[BuffPtr++] = ( (int16_t) Accl_Value[1] >> 8 ) & 0xFF;
+                    //AppData[BuffPtr++] = ( (int16_t) Accl_Value[1] ) & 0xFF; 
+                    //AppData[BuffPtr++] = ( (int16_t) Accl_Value[2] >> 8 ) & 0xFF;
+                    //AppData[BuffPtr++] = ( (int16_t) Accl_Value[2] ) & 0xFF;  
+                    //===========================Custom payload============================
+                    
+                    //In this case the custom payload is the cayene LPP structure for the sensors data
+                    AppData[0]=0x01;
+                    AppData[1]=0x67;
+ 
+                    AppData[4]=0x02;
+                    AppData[5]=0x73;
+
+                    AppData[8]=0x03;
+                    AppData[9]=0x68;
+   
+      
+                    //=========================Cayenne LPP format=======================
+                    /*
+                    STRUCTURE:
+                    
+                    1 Byte      1 Byte      N Bytes     1 Byte       1 Byte  M Bytes ...
+                    
+                    Data1 Ch.   Data1 Type   Data1     Data2 Ch.   Data2 Type  Data2 ...
+                    
+                    COMMON TYP IDENTIFIERS AND RESOLUTIONS:
+                    
+                    TYPE                LPP    HEX   DATA SIZE     RESOLUTION PER BIT
+                    
+                    Temperature         103     67      2           0.1 °C Signed MSB
+                    Humidity            104     68      1           0.5 % Unsigned
+                    Accelerometer       113     71      6           0.001 G Signed MSB per axis
+                    Barometer           115     73      2           0.1 hPa Unsigned MSB
+                      
+                    */                           
+                    // Send payload over the air
+                    NextTx = SendFrame( );             
+                }
+
+                if( NextTx == false )
+                {
+
+                    SerialDisplayTxUpdate( );
+                }
+                
+                DeviceState = DEVICE_STATE_SLEEP;
+                break;
+            }            
+            case DEVICE_STATE_SLEEP:
+            {
+                break;
+            }
+            default:
+            {
+                DeviceState = DEVICE_STATE_INIT;
+                break;
+            }
+        }
+    }
+}
diff -r 000000000000 -r 60ff878b27b8 Code/vt100.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Code/vt100.h	Tue Apr 03 17:09:34 2018 +0000
@@ -0,0 +1,213 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+    (C)2015 Semtech
+
+Description: VT100 terminal support class
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+Maintainer: Miguel Luis and Gregory Cristian
+*/
+#ifndef __VT100_H__
+#define __VT100_H__
+
+#ifndef STRING_STACK_LIMIT
+#define STRING_STACK_LIMIT    120
+#endif
+
+/**
+ * Implements VT100 terminal commands support.
+ * Implments also the same behaviour has RawSerial class. The only difference
+ * is located in putc fucntion where writeable check is made befor sending the character.
+ */
+class VT100 : public SerialBase
+{
+public:
+    enum TextAttributes
+    {
+        ATTR_OFF      = 0,
+        BOLD          = 1,
+        USCORE        = 4,
+        BLINK         = 5,
+        REVERSE       = 7,
+        BOLD_OFF      = 21,
+        USCORE_OFF    = 24,
+        BLINK_OFF     = 25,
+        REVERSE_OFF   = 27,
+    };
+
+    enum Colors
+    {
+        BLACK   = 0,
+        RED     = 1,
+        GREEN   = 2,
+        BROWN   = 3,
+        BLUE    = 4,
+        MAGENTA = 5,
+        CYAN    = 6,
+        WHITE   = 7,
+    };
+
+    VT100( PinName tx, PinName rx ): SerialBase( tx, rx )
+    {
+        this->baud( 115200 );
+        // initializes terminal to "power-on" settings
+        // ESC c
+        this->printf( "\x1B\x63" );
+    }
+    
+    void ClearScreen( uint8_t param )
+    {
+        // ESC [ Ps J
+        // 0    Clear screen from cursor down
+        // 1    Clear screen from cursor up
+        // 2    Clear entire screen 
+        this->printf( "\x1B[%dJ", param );
+    }
+
+    void ClearLine( uint8_t param )
+    {
+        // ESC [ Ps K
+        // 0    Erase from the active position to the end of the line, inclusive (default)
+        // 1    Erase from the start of the screen to the active position, inclusive
+        // 2    Erase all of the line, inclusive
+        this->printf( "\x1B[%dK", param );
+    }
+
+    void SetAttribute( uint8_t attr )
+    {
+        // ESC [ Ps;...;Ps m
+        this->printf( "\x1B[%dm", attr );
+    }
+
+    void SetAttribute( uint8_t attr, uint8_t fgcolor, uint8_t bgcolor )
+    {
+        // ESC [ Ps;...;Ps m
+        this->printf( "\x1B[%d;%d;%dm", attr, fgcolor + 30, bgcolor + 40 );
+    }
+
+    void SetCursorMode( uint8_t visible )
+    {
+        if( visible == true )
+        {
+            // ESC [ ? 25 h
+            this->printf( "\x1B[?25h" );
+        }
+        else
+        {
+            // ESC [ ? 25 l
+            this->printf( "\x1B[?25l" );
+        }
+    }
+
+    void SetCursorPos( uint8_t line, uint8_t col )
+    {
+        // ESC [ Pl ; Pc H
+        this->printf( "\x1B[%d;%dH", line, col );
+    }
+
+    void PutStringAt( uint8_t line, uint8_t col, const char *s )
+    {
+        this->SetCursorPos( line, col );
+        this->printf( "%s", s );
+    }
+
+    void PutCharAt( uint8_t line, uint8_t col, uint8_t c )
+    {
+        this->SetCursorPos( line, col );
+        this->printf( "%c", c );
+    }
+
+    void PutHexAt( uint8_t line, uint8_t col, uint16_t n )
+    {
+        this->SetCursorPos( line, col );
+        this->printf( "%X", n );
+    }
+
+    void PutBoxDrawingChar( uint8_t c )
+    {
+        this->printf( "\x1B(0%c\x1b(B", c );
+    }
+    
+    bool Readable( void )
+    {
+        return this->readable( );
+    }
+    
+    uint8_t GetChar( void )
+    {
+        return this->getc( );
+    }
+
+    /*
+     * RawSerial class implmentation copy.
+     */
+    /** Read a char from the serial port
+     *
+     * @returns The char read from the serial port
+     */
+    int getc( )
+    {
+        return _base_getc();
+    }
+
+    /** Write a char to the serial port
+     *
+     * @param c The char to write
+     *
+     * @returns The written char or -1 if an error occured
+     */
+    int putc( int c )
+    {
+        while( this->writeable( ) != 1 );
+        return _base_putc( c );
+    }
+
+    /** Write a string to the serial port
+     *
+     * @param str The string to write
+     *
+     * @returns 0 if the write succeeds, EOF for error
+     */
+    int puts( const char *str )
+    {
+        while( *str )
+            putc( *str++ );
+        return 0;
+    }
+
+    // Experimental support for printf in RawSerial. No Stream inheritance
+    // means we can't call printf() directly, so we use sprintf() instead.
+    // We only call malloc() for the sprintf() buffer if the buffer
+    // length is above a certain threshold, otherwise we use just the stack.
+    int printf( const char *format, ... )
+    {
+        std::va_list arg;
+        va_start( arg, format );
+        int len = vsnprintf( NULL, 0, format, arg );
+        if( len < STRING_STACK_LIMIT )
+        {
+            char temp[STRING_STACK_LIMIT];
+            vsprintf( temp, format, arg );
+            puts( temp );
+        }
+        else
+        {
+            char *temp = new char[len + 1];
+            vsprintf( temp, format, arg );
+            puts( temp );
+            delete[] temp;
+        }
+        va_end( arg );
+        return len;
+    }
+
+private:
+    
+};
+
+#endif // __VT100_H__
diff -r 000000000000 -r 60ff878b27b8 LoRaWAN-lib-v1_0_1.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LoRaWAN-lib-v1_0_1.lib	Tue Apr 03 17:09:34 2018 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/dgabino/code/LoRaWAN-lib/#54937781831b
diff -r 000000000000 -r 60ff878b27b8 SX1272Lib.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SX1272Lib.lib	Tue Apr 03 17:09:34 2018 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/teams/Semtech/code/SX1272Lib/#69d5976b504d
diff -r 000000000000 -r 60ff878b27b8 X_NUCLEO_IKS01A1.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/X_NUCLEO_IKS01A1.lib	Tue Apr 03 17:09:34 2018 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/teams/ST/code/X_NUCLEO_IKS01A1/#f4fa3dad9ec4
diff -r 000000000000 -r 60ff878b27b8 system/crypto/aes.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/system/crypto/aes.cpp	Tue Apr 03 17:09:34 2018 +0000
@@ -0,0 +1,936 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The redistribution and use of this software (with or without changes)
+ is allowed without the payment of fees or royalties provided that:
+
+  1. source code distributions include the above copyright notice, this
+     list of conditions and the following disclaimer;
+
+  2. binary distributions include the above copyright notice, this list
+     of conditions and the following disclaimer in their documentation;
+
+  3. the name of the copyright holder is not used to endorse products
+     built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue 09/09/2006
+
+ This is an AES implementation that uses only 8-bit byte operations on the
+ cipher state (there are options to use 32-bit types if available).
+
+ The combination of mix columns and byte substitution used here is based on
+ that developed by Karl Malbrain. His contribution is acknowledged.
+ */
+
+/* define if you have a fast memcpy function on your system */
+#if 0
+#  define HAVE_MEMCPY
+#  include <string.h>
+#  if defined( _MSC_VER )
+#    include <intrin.h>
+#    pragma intrinsic( memcpy )
+#  endif
+#endif
+
+
+#include <stdlib.h>
+#include <stdint.h>
+
+/* define if you have fast 32-bit types on your system */
+#if ( __CORTEX_M != 0 ) // if Cortex is different from M0/M0+
+#  define HAVE_UINT_32T
+#endif
+
+/* define if you don't want any tables */
+#if 1
+#  define USE_TABLES
+#endif
+
+/*  On Intel Core 2 duo VERSION_1 is faster */
+
+/* alternative versions (test for performance on your system) */
+#if 1
+#  define VERSION_1
+#endif
+
+#include "aes.h"
+
+//#if defined( HAVE_UINT_32T )
+//  typedef unsigned long uint32_t;
+//#endif
+
+/* functions for finite field multiplication in the AES Galois field    */
+
+#define WPOLY   0x011b
+#define BPOLY     0x1b
+#define DPOLY   0x008d
+
+#define f1(x)   (x)
+#define f2(x)   ((x << 1) ^ (((x >> 7) & 1) * WPOLY))
+#define f4(x)   ((x << 2) ^ (((x >> 6) & 1) * WPOLY) ^ (((x >> 6) & 2) * WPOLY))
+#define f8(x)   ((x << 3) ^ (((x >> 5) & 1) * WPOLY) ^ (((x >> 5) & 2) * WPOLY) \
+                          ^ (((x >> 5) & 4) * WPOLY))
+#define d2(x)   (((x) >> 1) ^ ((x) & 1 ? DPOLY : 0))
+
+#define f3(x)   (f2(x) ^ x)
+#define f9(x)   (f8(x) ^ x)
+#define fb(x)   (f8(x) ^ f2(x) ^ x)
+#define fd(x)   (f8(x) ^ f4(x) ^ x)
+#define fe(x)   (f8(x) ^ f4(x) ^ f2(x))
+
+#if defined( USE_TABLES )
+
+#define sb_data(w) {    /* S Box data values */                            \
+    w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\
+    w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\
+    w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\
+    w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\
+    w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\
+    w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\
+    w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\
+    w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\
+    w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\
+    w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\
+    w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\
+    w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\
+    w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\
+    w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\
+    w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\
+    w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\
+    w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\
+    w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\
+    w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\
+    w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\
+    w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\
+    w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\
+    w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\
+    w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\
+    w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\
+    w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\
+    w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\
+    w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\
+    w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\
+    w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\
+    w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\
+    w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) }
+
+#define isb_data(w) {   /* inverse S Box data values */                    \
+    w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\
+    w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\
+    w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\
+    w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\
+    w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\
+    w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\
+    w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\
+    w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\
+    w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\
+    w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\
+    w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\
+    w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\
+    w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\
+    w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\
+    w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\
+    w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\
+    w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\
+    w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\
+    w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\
+    w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\
+    w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\
+    w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\
+    w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\
+    w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\
+    w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\
+    w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\
+    w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\
+    w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\
+    w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\
+    w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\
+    w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\
+    w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) }
+
+#define mm_data(w) {    /* basic data for forming finite field tables */   \
+    w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\
+    w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\
+    w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\
+    w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\
+    w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\
+    w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\
+    w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\
+    w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\
+    w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\
+    w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\
+    w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\
+    w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\
+    w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\
+    w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\
+    w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\
+    w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\
+    w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\
+    w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\
+    w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\
+    w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\
+    w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\
+    w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\
+    w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\
+    w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\
+    w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\
+    w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\
+    w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\
+    w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\
+    w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\
+    w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\
+    w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\
+    w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) }
+
+static const uint8_t sbox[256]  =  sb_data(f1);
+
+#if defined( AES_DEC_PREKEYED )
+static const uint8_t isbox[256] = isb_data(f1);
+#endif
+
+static const uint8_t gfm2_sbox[256] = sb_data(f2);
+static const uint8_t gfm3_sbox[256] = sb_data(f3);
+
+#if defined( AES_DEC_PREKEYED )
+static const uint8_t gfmul_9[256] = mm_data(f9);
+static const uint8_t gfmul_b[256] = mm_data(fb);
+static const uint8_t gfmul_d[256] = mm_data(fd);
+static const uint8_t gfmul_e[256] = mm_data(fe);
+#endif
+
+#define s_box(x)     sbox[(x)]
+#if defined( AES_DEC_PREKEYED )
+#define is_box(x)    isbox[(x)]
+#endif
+#define gfm2_sb(x)   gfm2_sbox[(x)]
+#define gfm3_sb(x)   gfm3_sbox[(x)]
+#if defined( AES_DEC_PREKEYED )
+#define gfm_9(x)     gfmul_9[(x)]
+#define gfm_b(x)     gfmul_b[(x)]
+#define gfm_d(x)     gfmul_d[(x)]
+#define gfm_e(x)     gfmul_e[(x)]
+#endif
+#else
+
+/* this is the high bit of x right shifted by 1 */
+/* position. Since the starting polynomial has  */
+/* 9 bits (0x11b), this right shift keeps the   */
+/* values of all top bits within a byte         */
+
+static uint8_t hibit(const uint8_t x)
+{   uint8_t r = (uint8_t)((x >> 1) | (x >> 2));
+
+    r |= (r >> 2);
+    r |= (r >> 4);
+    return (r + 1) >> 1;
+}
+
+/* return the inverse of the finite field element x */
+
+static uint8_t gf_inv(const uint8_t x)
+{   uint8_t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0;
+
+    if(x < 2)
+        return x;
+
+    for( ; ; )
+    {
+        if(n1)
+            while(n2 >= n1)             /* divide polynomial p2 by p1    */
+            {
+                n2 /= n1;               /* shift smaller polynomial left */
+                p2 ^= (p1 * n2) & 0xff; /* and remove from larger one    */
+                v2 ^= (v1 * n2);        /* shift accumulated value and   */
+                n2 = hibit(p2);         /* add into result               */
+            }
+        else
+            return v1;
+
+        if(n2)                          /* repeat with values swapped    */
+            while(n1 >= n2)
+            {
+                n1 /= n2;
+                p1 ^= p2 * n1;
+                v1 ^= v2 * n1;
+                n1 = hibit(p1);
+            }
+        else
+            return v2;
+    }
+}
+
+/* The forward and inverse affine transformations used in the S-box */
+uint8_t fwd_affine(const uint8_t x)
+{
+#if defined( HAVE_UINT_32T )
+    uint32_t w = x;
+    w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4);
+    return 0x63 ^ ((w ^ (w >> 8)) & 0xff);
+#else
+    return 0x63 ^ x ^ (x << 1) ^ (x << 2) ^ (x << 3) ^ (x << 4)
+                    ^ (x >> 7) ^ (x >> 6) ^ (x >> 5) ^ (x >> 4);
+#endif
+}
+
+uint8_t inv_affine(const uint8_t x)
+{
+#if defined( HAVE_UINT_32T )
+    uint32_t w = x;
+    w = (w << 1) ^ (w << 3) ^ (w << 6);
+    return 0x05 ^ ((w ^ (w >> 8)) & 0xff);
+#else
+    return 0x05 ^ (x << 1) ^ (x << 3) ^ (x << 6)
+                ^ (x >> 7) ^ (x >> 5) ^ (x >> 2);
+#endif
+}
+
+#define s_box(x)   fwd_affine(gf_inv(x))
+#define is_box(x)  gf_inv(inv_affine(x))
+#define gfm2_sb(x) f2(s_box(x))
+#define gfm3_sb(x) f3(s_box(x))
+#define gfm_9(x)   f9(x)
+#define gfm_b(x)   fb(x)
+#define gfm_d(x)   fd(x)
+#define gfm_e(x)   fe(x)
+
+#endif
+
+#if defined( HAVE_MEMCPY )
+#  define block_copy_nn(d, s, l)    memcpy(d, s, l)
+#  define block_copy(d, s)          memcpy(d, s, N_BLOCK)
+#else
+#  define block_copy_nn(d, s, l)    copy_block_nn(d, s, l)
+#  define block_copy(d, s)          copy_block(d, s)
+#endif
+
+static void copy_block( void *d, const void *s )
+{
+#if defined( HAVE_UINT_32T )
+    ((uint32_t*)d)[ 0] = ((uint32_t*)s)[ 0];
+    ((uint32_t*)d)[ 1] = ((uint32_t*)s)[ 1];
+    ((uint32_t*)d)[ 2] = ((uint32_t*)s)[ 2];
+    ((uint32_t*)d)[ 3] = ((uint32_t*)s)[ 3];
+#else
+    ((uint8_t*)d)[ 0] = ((uint8_t*)s)[ 0];
+    ((uint8_t*)d)[ 1] = ((uint8_t*)s)[ 1];
+    ((uint8_t*)d)[ 2] = ((uint8_t*)s)[ 2];
+    ((uint8_t*)d)[ 3] = ((uint8_t*)s)[ 3];
+    ((uint8_t*)d)[ 4] = ((uint8_t*)s)[ 4];
+    ((uint8_t*)d)[ 5] = ((uint8_t*)s)[ 5];
+    ((uint8_t*)d)[ 6] = ((uint8_t*)s)[ 6];
+    ((uint8_t*)d)[ 7] = ((uint8_t*)s)[ 7];
+    ((uint8_t*)d)[ 8] = ((uint8_t*)s)[ 8];
+    ((uint8_t*)d)[ 9] = ((uint8_t*)s)[ 9];
+    ((uint8_t*)d)[10] = ((uint8_t*)s)[10];
+    ((uint8_t*)d)[11] = ((uint8_t*)s)[11];
+    ((uint8_t*)d)[12] = ((uint8_t*)s)[12];
+    ((uint8_t*)d)[13] = ((uint8_t*)s)[13];
+    ((uint8_t*)d)[14] = ((uint8_t*)s)[14];
+    ((uint8_t*)d)[15] = ((uint8_t*)s)[15];
+#endif
+}
+
+static void copy_block_nn( uint8_t * d, const uint8_t *s, uint8_t nn )
+{
+    while( nn-- )
+        //*((uint8_t*)d)++ = *((uint8_t*)s)++;
+        *d++ = *s++;
+}
+
+static void xor_block( void *d, const void *s )
+{
+#if defined( HAVE_UINT_32T )
+    ((uint32_t*)d)[ 0] ^= ((uint32_t*)s)[ 0];
+    ((uint32_t*)d)[ 1] ^= ((uint32_t*)s)[ 1];
+    ((uint32_t*)d)[ 2] ^= ((uint32_t*)s)[ 2];
+    ((uint32_t*)d)[ 3] ^= ((uint32_t*)s)[ 3];
+#else
+    ((uint8_t*)d)[ 0] ^= ((uint8_t*)s)[ 0];
+    ((uint8_t*)d)[ 1] ^= ((uint8_t*)s)[ 1];
+    ((uint8_t*)d)[ 2] ^= ((uint8_t*)s)[ 2];
+    ((uint8_t*)d)[ 3] ^= ((uint8_t*)s)[ 3];
+    ((uint8_t*)d)[ 4] ^= ((uint8_t*)s)[ 4];
+    ((uint8_t*)d)[ 5] ^= ((uint8_t*)s)[ 5];
+    ((uint8_t*)d)[ 6] ^= ((uint8_t*)s)[ 6];
+    ((uint8_t*)d)[ 7] ^= ((uint8_t*)s)[ 7];
+    ((uint8_t*)d)[ 8] ^= ((uint8_t*)s)[ 8];
+    ((uint8_t*)d)[ 9] ^= ((uint8_t*)s)[ 9];
+    ((uint8_t*)d)[10] ^= ((uint8_t*)s)[10];
+    ((uint8_t*)d)[11] ^= ((uint8_t*)s)[11];
+    ((uint8_t*)d)[12] ^= ((uint8_t*)s)[12];
+    ((uint8_t*)d)[13] ^= ((uint8_t*)s)[13];
+    ((uint8_t*)d)[14] ^= ((uint8_t*)s)[14];
+    ((uint8_t*)d)[15] ^= ((uint8_t*)s)[15];
+#endif
+}
+
+static void copy_and_key( void *d, const void *s, const void *k )
+{
+#if defined( HAVE_UINT_32T )
+    ((uint32_t*)d)[ 0] = ((uint32_t*)s)[ 0] ^ ((uint32_t*)k)[ 0];
+    ((uint32_t*)d)[ 1] = ((uint32_t*)s)[ 1] ^ ((uint32_t*)k)[ 1];
+    ((uint32_t*)d)[ 2] = ((uint32_t*)s)[ 2] ^ ((uint32_t*)k)[ 2];
+    ((uint32_t*)d)[ 3] = ((uint32_t*)s)[ 3] ^ ((uint32_t*)k)[ 3];
+#elif 1
+    ((uint8_t*)d)[ 0] = ((uint8_t*)s)[ 0] ^ ((uint8_t*)k)[ 0];
+    ((uint8_t*)d)[ 1] = ((uint8_t*)s)[ 1] ^ ((uint8_t*)k)[ 1];
+    ((uint8_t*)d)[ 2] = ((uint8_t*)s)[ 2] ^ ((uint8_t*)k)[ 2];
+    ((uint8_t*)d)[ 3] = ((uint8_t*)s)[ 3] ^ ((uint8_t*)k)[ 3];
+    ((uint8_t*)d)[ 4] = ((uint8_t*)s)[ 4] ^ ((uint8_t*)k)[ 4];
+    ((uint8_t*)d)[ 5] = ((uint8_t*)s)[ 5] ^ ((uint8_t*)k)[ 5];
+    ((uint8_t*)d)[ 6] = ((uint8_t*)s)[ 6] ^ ((uint8_t*)k)[ 6];
+    ((uint8_t*)d)[ 7] = ((uint8_t*)s)[ 7] ^ ((uint8_t*)k)[ 7];
+    ((uint8_t*)d)[ 8] = ((uint8_t*)s)[ 8] ^ ((uint8_t*)k)[ 8];
+    ((uint8_t*)d)[ 9] = ((uint8_t*)s)[ 9] ^ ((uint8_t*)k)[ 9];
+    ((uint8_t*)d)[10] = ((uint8_t*)s)[10] ^ ((uint8_t*)k)[10];
+    ((uint8_t*)d)[11] = ((uint8_t*)s)[11] ^ ((uint8_t*)k)[11];
+    ((uint8_t*)d)[12] = ((uint8_t*)s)[12] ^ ((uint8_t*)k)[12];
+    ((uint8_t*)d)[13] = ((uint8_t*)s)[13] ^ ((uint8_t*)k)[13];
+    ((uint8_t*)d)[14] = ((uint8_t*)s)[14] ^ ((uint8_t*)k)[14];
+    ((uint8_t*)d)[15] = ((uint8_t*)s)[15] ^ ((uint8_t*)k)[15];
+#else
+    block_copy(d, s);
+    xor_block(d, k);
+#endif
+}
+
+static void add_round_key( uint8_t d[N_BLOCK], const uint8_t k[N_BLOCK] )
+{
+    xor_block(d, k);
+}
+
+static void shift_sub_rows( uint8_t st[N_BLOCK] )
+{   uint8_t tt;
+
+    st[ 0] = s_box(st[ 0]); st[ 4] = s_box(st[ 4]);
+    st[ 8] = s_box(st[ 8]); st[12] = s_box(st[12]);
+
+    tt = st[1]; st[ 1] = s_box(st[ 5]); st[ 5] = s_box(st[ 9]);
+    st[ 9] = s_box(st[13]); st[13] = s_box( tt );
+
+    tt = st[2]; st[ 2] = s_box(st[10]); st[10] = s_box( tt );
+    tt = st[6]; st[ 6] = s_box(st[14]); st[14] = s_box( tt );
+
+    tt = st[15]; st[15] = s_box(st[11]); st[11] = s_box(st[ 7]);
+    st[ 7] = s_box(st[ 3]); st[ 3] = s_box( tt );
+}
+
+#if defined( AES_DEC_PREKEYED )
+
+static void inv_shift_sub_rows( uint8_t st[N_BLOCK] )
+{   uint8_t tt;
+
+    st[ 0] = is_box(st[ 0]); st[ 4] = is_box(st[ 4]);
+    st[ 8] = is_box(st[ 8]); st[12] = is_box(st[12]);
+
+    tt = st[13]; st[13] = is_box(st[9]); st[ 9] = is_box(st[5]);
+    st[ 5] = is_box(st[1]); st[ 1] = is_box( tt );
+
+    tt = st[2]; st[ 2] = is_box(st[10]); st[10] = is_box( tt );
+    tt = st[6]; st[ 6] = is_box(st[14]); st[14] = is_box( tt );
+
+    tt = st[3]; st[ 3] = is_box(st[ 7]); st[ 7] = is_box(st[11]);
+    st[11] = is_box(st[15]); st[15] = is_box( tt );
+}
+
+#endif
+
+#if defined( VERSION_1 )
+  static void mix_sub_columns( uint8_t dt[N_BLOCK] )
+  { uint8_t st[N_BLOCK];
+    block_copy(st, dt);
+#else
+  static void mix_sub_columns( uint8_t dt[N_BLOCK], uint8_t st[N_BLOCK] )
+  {
+#endif
+    dt[ 0] = gfm2_sb(st[0]) ^ gfm3_sb(st[5]) ^ s_box(st[10]) ^ s_box(st[15]);
+    dt[ 1] = s_box(st[0]) ^ gfm2_sb(st[5]) ^ gfm3_sb(st[10]) ^ s_box(st[15]);
+    dt[ 2] = s_box(st[0]) ^ s_box(st[5]) ^ gfm2_sb(st[10]) ^ gfm3_sb(st[15]);
+    dt[ 3] = gfm3_sb(st[0]) ^ s_box(st[5]) ^ s_box(st[10]) ^ gfm2_sb(st[15]);
+
+    dt[ 4] = gfm2_sb(st[4]) ^ gfm3_sb(st[9]) ^ s_box(st[14]) ^ s_box(st[3]);
+    dt[ 5] = s_box(st[4]) ^ gfm2_sb(st[9]) ^ gfm3_sb(st[14]) ^ s_box(st[3]);
+    dt[ 6] = s_box(st[4]) ^ s_box(st[9]) ^ gfm2_sb(st[14]) ^ gfm3_sb(st[3]);
+    dt[ 7] = gfm3_sb(st[4]) ^ s_box(st[9]) ^ s_box(st[14]) ^ gfm2_sb(st[3]);
+
+    dt[ 8] = gfm2_sb(st[8]) ^ gfm3_sb(st[13]) ^ s_box(st[2]) ^ s_box(st[7]);
+    dt[ 9] = s_box(st[8]) ^ gfm2_sb(st[13]) ^ gfm3_sb(st[2]) ^ s_box(st[7]);
+    dt[10] = s_box(st[8]) ^ s_box(st[13]) ^ gfm2_sb(st[2]) ^ gfm3_sb(st[7]);
+    dt[11] = gfm3_sb(st[8]) ^ s_box(st[13]) ^ s_box(st[2]) ^ gfm2_sb(st[7]);
+
+    dt[12] = gfm2_sb(st[12]) ^ gfm3_sb(st[1]) ^ s_box(st[6]) ^ s_box(st[11]);
+    dt[13] = s_box(st[12]) ^ gfm2_sb(st[1]) ^ gfm3_sb(st[6]) ^ s_box(st[11]);
+    dt[14] = s_box(st[12]) ^ s_box(st[1]) ^ gfm2_sb(st[6]) ^ gfm3_sb(st[11]);
+    dt[15] = gfm3_sb(st[12]) ^ s_box(st[1]) ^ s_box(st[6]) ^ gfm2_sb(st[11]);
+  }
+
+#if defined( AES_DEC_PREKEYED )
+
+#if defined( VERSION_1 )
+  static void inv_mix_sub_columns( uint8_t dt[N_BLOCK] )
+  { uint8_t st[N_BLOCK];
+    block_copy(st, dt);
+#else
+  static void inv_mix_sub_columns( uint8_t dt[N_BLOCK], uint8_t st[N_BLOCK] )
+  {
+#endif
+    dt[ 0] = is_box(gfm_e(st[ 0]) ^ gfm_b(st[ 1]) ^ gfm_d(st[ 2]) ^ gfm_9(st[ 3]));
+    dt[ 5] = is_box(gfm_9(st[ 0]) ^ gfm_e(st[ 1]) ^ gfm_b(st[ 2]) ^ gfm_d(st[ 3]));
+    dt[10] = is_box(gfm_d(st[ 0]) ^ gfm_9(st[ 1]) ^ gfm_e(st[ 2]) ^ gfm_b(st[ 3]));
+    dt[15] = is_box(gfm_b(st[ 0]) ^ gfm_d(st[ 1]) ^ gfm_9(st[ 2]) ^ gfm_e(st[ 3]));
+
+    dt[ 4] = is_box(gfm_e(st[ 4]) ^ gfm_b(st[ 5]) ^ gfm_d(st[ 6]) ^ gfm_9(st[ 7]));
+    dt[ 9] = is_box(gfm_9(st[ 4]) ^ gfm_e(st[ 5]) ^ gfm_b(st[ 6]) ^ gfm_d(st[ 7]));
+    dt[14] = is_box(gfm_d(st[ 4]) ^ gfm_9(st[ 5]) ^ gfm_e(st[ 6]) ^ gfm_b(st[ 7]));
+    dt[ 3] = is_box(gfm_b(st[ 4]) ^ gfm_d(st[ 5]) ^ gfm_9(st[ 6]) ^ gfm_e(st[ 7]));
+
+    dt[ 8] = is_box(gfm_e(st[ 8]) ^ gfm_b(st[ 9]) ^ gfm_d(st[10]) ^ gfm_9(st[11]));
+    dt[13] = is_box(gfm_9(st[ 8]) ^ gfm_e(st[ 9]) ^ gfm_b(st[10]) ^ gfm_d(st[11]));
+    dt[ 2] = is_box(gfm_d(st[ 8]) ^ gfm_9(st[ 9]) ^ gfm_e(st[10]) ^ gfm_b(st[11]));
+    dt[ 7] = is_box(gfm_b(st[ 8]) ^ gfm_d(st[ 9]) ^ gfm_9(st[10]) ^ gfm_e(st[11]));
+
+    dt[12] = is_box(gfm_e(st[12]) ^ gfm_b(st[13]) ^ gfm_d(st[14]) ^ gfm_9(st[15]));
+    dt[ 1] = is_box(gfm_9(st[12]) ^ gfm_e(st[13]) ^ gfm_b(st[14]) ^ gfm_d(st[15]));
+    dt[ 6] = is_box(gfm_d(st[12]) ^ gfm_9(st[13]) ^ gfm_e(st[14]) ^ gfm_b(st[15]));
+    dt[11] = is_box(gfm_b(st[12]) ^ gfm_d(st[13]) ^ gfm_9(st[14]) ^ gfm_e(st[15]));
+  }
+
+#endif
+
+#if defined( AES_ENC_PREKEYED ) || defined( AES_DEC_PREKEYED )
+
+/*  Set the cipher key for the pre-keyed version */
+
+return_type aes_set_key( const uint8_t key[], length_type keylen, aes_context ctx[1] )
+{
+    uint8_t cc, rc, hi;
+
+    switch( keylen )
+    {
+    case 16:
+    case 24:
+    case 32:
+        break;
+    default:
+        ctx->rnd = 0;
+        return ( uint8_t )-1;
+    }
+    block_copy_nn(ctx->ksch, key, keylen);
+    hi = (keylen + 28) << 2;
+    ctx->rnd = (hi >> 4) - 1;
+    for( cc = keylen, rc = 1; cc < hi; cc += 4 )
+    {   uint8_t tt, t0, t1, t2, t3;
+
+        t0 = ctx->ksch[cc - 4];
+        t1 = ctx->ksch[cc - 3];
+        t2 = ctx->ksch[cc - 2];
+        t3 = ctx->ksch[cc - 1];
+        if( cc % keylen == 0 )
+        {
+            tt = t0;
+            t0 = s_box(t1) ^ rc;
+            t1 = s_box(t2);
+            t2 = s_box(t3);
+            t3 = s_box(tt);
+            rc = f2(rc);
+        }
+        else if( keylen > 24 && cc % keylen == 16 )
+        {
+            t0 = s_box(t0);
+            t1 = s_box(t1);
+            t2 = s_box(t2);
+            t3 = s_box(t3);
+        }
+        tt = cc - keylen;
+        ctx->ksch[cc + 0] = ctx->ksch[tt + 0] ^ t0;
+        ctx->ksch[cc + 1] = ctx->ksch[tt + 1] ^ t1;
+        ctx->ksch[cc + 2] = ctx->ksch[tt + 2] ^ t2;
+        ctx->ksch[cc + 3] = ctx->ksch[tt + 3] ^ t3;
+    }
+    return 0;
+}
+
+#endif
+
+#if defined( AES_ENC_PREKEYED )
+
+/*  Encrypt a single block of 16 bytes */
+
+return_type aes_encrypt( const uint8_t in[N_BLOCK], uint8_t  out[N_BLOCK], const aes_context ctx[1] )
+{
+    if( ctx->rnd )
+    {
+        uint8_t s1[N_BLOCK], r;
+        copy_and_key( s1, in, ctx->ksch );
+
+        for( r = 1 ; r < ctx->rnd ; ++r )
+#if defined( VERSION_1 )
+        {
+            mix_sub_columns( s1 );
+            add_round_key( s1, ctx->ksch + r * N_BLOCK);
+        }
+#else
+        {   uint8_t s2[N_BLOCK];
+            mix_sub_columns( s2, s1 );
+            copy_and_key( s1, s2, ctx->ksch + r * N_BLOCK);
+        }
+#endif
+        shift_sub_rows( s1 );
+        copy_and_key( out, s1, ctx->ksch + r * N_BLOCK );
+    }
+    else
+        return ( uint8_t )-1;
+    return 0;
+}
+
+/* CBC encrypt a number of blocks (input and return an IV) */
+
+return_type aes_cbc_encrypt( const uint8_t *in, uint8_t *out,
+                         int32_t n_block, uint8_t iv[N_BLOCK], const aes_context ctx[1] )
+{
+
+    while(n_block--)
+    {
+        xor_block(iv, in);
+        if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS)
+            return EXIT_FAILURE;
+        //memcpy(out, iv, N_BLOCK);
+        block_copy(out, iv);
+        in += N_BLOCK;
+        out += N_BLOCK;
+    }
+    return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined( AES_DEC_PREKEYED )
+
+/*  Decrypt a single block of 16 bytes */
+
+return_type aes_decrypt( const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK], const aes_context ctx[1] )
+{
+    if( ctx->rnd )
+    {
+        uint8_t s1[N_BLOCK], r;
+        copy_and_key( s1, in, ctx->ksch + ctx->rnd * N_BLOCK );
+        inv_shift_sub_rows( s1 );
+
+        for( r = ctx->rnd ; --r ; )
+#if defined( VERSION_1 )
+        {
+            add_round_key( s1, ctx->ksch + r * N_BLOCK );
+            inv_mix_sub_columns( s1 );
+        }
+#else
+        {   uint8_t s2[N_BLOCK];
+            copy_and_key( s2, s1, ctx->ksch + r * N_BLOCK );
+            inv_mix_sub_columns( s1, s2 );
+        }
+#endif
+        copy_and_key( out, s1, ctx->ksch );
+    }
+    else
+        return -1;
+    return 0;
+}
+
+/* CBC decrypt a number of blocks (input and return an IV) */
+
+return_type aes_cbc_decrypt( const uint8_t *in, uint8_t *out,
+                         int32_t n_block, uint8_t iv[N_BLOCK], const aes_context ctx[1] )
+{
+    while(n_block--)
+    {   uint8_t tmp[N_BLOCK];
+
+        //memcpy(tmp, in, N_BLOCK);
+        block_copy(tmp, in);
+        if(aes_decrypt(in, out, ctx) != EXIT_SUCCESS)
+            return EXIT_FAILURE;
+        xor_block(out, iv);
+        //memcpy(iv, tmp, N_BLOCK);
+        block_copy(iv, tmp);
+        in += N_BLOCK;
+        out += N_BLOCK;
+    }
+    return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined( AES_ENC_128_OTFK )
+
+/*  The 'on the fly' encryption key update for for 128 bit keys */
+
+static void update_encrypt_key_128( uint8_t k[N_BLOCK], uint8_t *rc )
+{   uint8_t cc;
+
+    k[0] ^= s_box(k[13]) ^ *rc;
+    k[1] ^= s_box(k[14]);
+    k[2] ^= s_box(k[15]);
+    k[3] ^= s_box(k[12]);
+    *rc = f2( *rc );
+
+    for(cc = 4; cc < 16; cc += 4 )
+    {
+        k[cc + 0] ^= k[cc - 4];
+        k[cc + 1] ^= k[cc - 3];
+        k[cc + 2] ^= k[cc - 2];
+        k[cc + 3] ^= k[cc - 1];
+    }
+}
+
+/*  Encrypt a single block of 16 bytes with 'on the fly' 128 bit keying */
+
+void aes_encrypt_128( const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK],
+                     const uint8_t key[N_BLOCK], uint8_t o_key[N_BLOCK] )
+{   uint8_t s1[N_BLOCK], r, rc = 1;
+
+    if(o_key != key)
+        block_copy( o_key, key );
+    copy_and_key( s1, in, o_key );
+
+    for( r = 1 ; r < 10 ; ++r )
+#if defined( VERSION_1 )
+    {
+        mix_sub_columns( s1 );
+        update_encrypt_key_128( o_key, &rc );
+        add_round_key( s1, o_key );
+    }
+#else
+    {   uint8_t s2[N_BLOCK];
+        mix_sub_columns( s2, s1 );
+        update_encrypt_key_128( o_key, &rc );
+        copy_and_key( s1, s2, o_key );
+    }
+#endif
+
+    shift_sub_rows( s1 );
+    update_encrypt_key_128( o_key, &rc );
+    copy_and_key( out, s1, o_key );
+}
+
+#endif
+
+#if defined( AES_DEC_128_OTFK )
+
+/*  The 'on the fly' decryption key update for for 128 bit keys */
+
+static void update_decrypt_key_128( uint8_t k[N_BLOCK], uint8_t *rc )
+{   uint8_t cc;
+
+    for( cc = 12; cc > 0; cc -= 4 )
+    {
+        k[cc + 0] ^= k[cc - 4];
+        k[cc + 1] ^= k[cc - 3];
+        k[cc + 2] ^= k[cc - 2];
+        k[cc + 3] ^= k[cc - 1];
+    }
+    *rc = d2(*rc);
+    k[0] ^= s_box(k[13]) ^ *rc;
+    k[1] ^= s_box(k[14]);
+    k[2] ^= s_box(k[15]);
+    k[3] ^= s_box(k[12]);
+}
+
+/*  Decrypt a single block of 16 bytes with 'on the fly' 128 bit keying */
+
+void aes_decrypt_128( const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK],
+                      const uint8_t key[N_BLOCK], uint8_t o_key[N_BLOCK] )
+{
+    uint8_t s1[N_BLOCK], r, rc = 0x6c;
+    if(o_key != key)
+        block_copy( o_key, key );
+
+    copy_and_key( s1, in, o_key );
+    inv_shift_sub_rows( s1 );
+
+    for( r = 10 ; --r ; )
+#if defined( VERSION_1 )
+    {
+        update_decrypt_key_128( o_key, &rc );
+        add_round_key( s1, o_key );
+        inv_mix_sub_columns( s1 );
+    }
+#else
+    {   uint8_t s2[N_BLOCK];
+        update_decrypt_key_128( o_key, &rc );
+        copy_and_key( s2, s1, o_key );
+        inv_mix_sub_columns( s1, s2 );
+    }
+#endif
+    update_decrypt_key_128( o_key, &rc );
+    copy_and_key( out, s1, o_key );
+}
+
+#endif
+
+#if defined( AES_ENC_256_OTFK )
+
+/*  The 'on the fly' encryption key update for for 256 bit keys */
+
+static void update_encrypt_key_256( uint8_t k[2 * N_BLOCK], uint8_t *rc )
+{   uint8_t cc;
+
+    k[0] ^= s_box(k[29]) ^ *rc;
+    k[1] ^= s_box(k[30]);
+    k[2] ^= s_box(k[31]);
+    k[3] ^= s_box(k[28]);
+    *rc = f2( *rc );
+
+    for(cc = 4; cc < 16; cc += 4)
+    {
+        k[cc + 0] ^= k[cc - 4];
+        k[cc + 1] ^= k[cc - 3];
+        k[cc + 2] ^= k[cc - 2];
+        k[cc + 3] ^= k[cc - 1];
+    }
+
+    k[16] ^= s_box(k[12]);
+    k[17] ^= s_box(k[13]);
+    k[18] ^= s_box(k[14]);
+    k[19] ^= s_box(k[15]);
+
+    for( cc = 20; cc < 32; cc += 4 )
+    {
+        k[cc + 0] ^= k[cc - 4];
+        k[cc + 1] ^= k[cc - 3];
+        k[cc + 2] ^= k[cc - 2];
+        k[cc + 3] ^= k[cc - 1];
+    }
+}
+
+/*  Encrypt a single block of 16 bytes with 'on the fly' 256 bit keying */
+
+void aes_encrypt_256( const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK],
+                      const uint8_t key[2 * N_BLOCK], uint8_t o_key[2 * N_BLOCK] )
+{
+    uint8_t s1[N_BLOCK], r, rc = 1;
+    if(o_key != key)
+    {
+        block_copy( o_key, key );
+        block_copy( o_key + 16, key + 16 );
+    }
+    copy_and_key( s1, in, o_key );
+
+    for( r = 1 ; r < 14 ; ++r )
+#if defined( VERSION_1 )
+    {
+        mix_sub_columns(s1);
+        if( r & 1 )
+            add_round_key( s1, o_key + 16 );
+        else
+        {
+            update_encrypt_key_256( o_key, &rc );
+            add_round_key( s1, o_key );
+        }
+    }
+#else
+    {   uint8_t s2[N_BLOCK];
+        mix_sub_columns( s2, s1 );
+        if( r & 1 )
+            copy_and_key( s1, s2, o_key + 16 );
+        else
+        {
+            update_encrypt_key_256( o_key, &rc );
+            copy_and_key( s1, s2, o_key );
+        }
+    }
+#endif
+
+    shift_sub_rows( s1 );
+    update_encrypt_key_256( o_key, &rc );
+    copy_and_key( out, s1, o_key );
+}
+
+#endif
+
+#if defined( AES_DEC_256_OTFK )
+
+/*  The 'on the fly' encryption key update for for 256 bit keys */
+
+static void update_decrypt_key_256( uint8_t k[2 * N_BLOCK], uint8_t *rc )
+{   uint8_t cc;
+
+    for(cc = 28; cc > 16; cc -= 4)
+    {
+        k[cc + 0] ^= k[cc - 4];
+        k[cc + 1] ^= k[cc - 3];
+        k[cc + 2] ^= k[cc - 2];
+        k[cc + 3] ^= k[cc - 1];
+    }
+
+    k[16] ^= s_box(k[12]);
+    k[17] ^= s_box(k[13]);
+    k[18] ^= s_box(k[14]);
+    k[19] ^= s_box(k[15]);
+
+    for(cc = 12; cc > 0; cc -= 4)
+    {
+        k[cc + 0] ^= k[cc - 4];
+        k[cc + 1] ^= k[cc - 3];
+        k[cc + 2] ^= k[cc - 2];
+        k[cc + 3] ^= k[cc - 1];
+    }
+
+    *rc = d2(*rc);
+    k[0] ^= s_box(k[29]) ^ *rc;
+    k[1] ^= s_box(k[30]);
+    k[2] ^= s_box(k[31]);
+    k[3] ^= s_box(k[28]);
+}
+
+/*  Decrypt a single block of 16 bytes with 'on the fly'
+    256 bit keying
+*/
+void aes_decrypt_256( const uint8_t in[N_BLOCK], uint8_t out[N_BLOCK],
+                      const uint8_t key[2 * N_BLOCK], uint8_t o_key[2 * N_BLOCK] )
+{
+    uint8_t s1[N_BLOCK], r, rc = 0x80;
+
+    if(o_key != key)
+    {
+        block_copy( o_key, key );
+        block_copy( o_key + 16, key + 16 );
+    }
+
+    copy_and_key( s1, in, o_key );
+    inv_shift_sub_rows( s1 );
+
+    for( r = 14 ; --r ; )
+#if defined( VERSION_1 )
+    {
+        if( ( r & 1 ) )
+        {
+            update_decrypt_key_256( o_key, &rc );
+            add_round_key( s1, o_key + 16 );
+        }
+        else
+            add_round_key( s1, o_key );
+        inv_mix_sub_columns( s1 );
+    }
+#else
+    {   uint8_t s2[N_BLOCK];
+        if( ( r & 1 ) )
+        {
+            update_decrypt_key_256( o_key, &rc );
+            copy_and_key( s2, s1, o_key + 16 );
+        }
+        else
+            copy_and_key( s2, s1, o_key );
+        inv_mix_sub_columns( s1, s2 );
+    }
+#endif
+    copy_and_key( out, s1, o_key );
+}
+
+#endif
diff -r 000000000000 -r 60ff878b27b8 system/crypto/aes.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/system/crypto/aes.h	Tue Apr 03 17:09:34 2018 +0000
@@ -0,0 +1,160 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The redistribution and use of this software (with or without changes)
+ is allowed without the payment of fees or royalties provided that:
+
+  1. source code distributions include the above copyright notice, this
+     list of conditions and the following disclaimer;
+
+  2. binary distributions include the above copyright notice, this list
+     of conditions and the following disclaimer in their documentation;
+
+  3. the name of the copyright holder is not used to endorse products
+     built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue 09/09/2006
+
+ This is an AES implementation that uses only 8-bit byte operations on the
+ cipher state.
+ */
+
+#ifndef AES_H
+#define AES_H
+
+#if 1
+#  define AES_ENC_PREKEYED  /* AES encryption with a precomputed key schedule  */
+#endif
+#if 0
+#  define AES_DEC_PREKEYED  /* AES decryption with a precomputed key schedule  */
+#endif
+#if 0
+#  define AES_ENC_128_OTFK  /* AES encryption with 'on the fly' 128 bit keying */
+#endif
+#if 0
+#  define AES_DEC_128_OTFK  /* AES decryption with 'on the fly' 128 bit keying */
+#endif
+#if 0
+#  define AES_ENC_256_OTFK  /* AES encryption with 'on the fly' 256 bit keying */
+#endif
+#if 0
+#  define AES_DEC_256_OTFK  /* AES decryption with 'on the fly' 256 bit keying */
+#endif
+
+#define N_ROW                   4
+#define N_COL                   4
+#define N_BLOCK   (N_ROW * N_COL)
+#define N_MAX_ROUNDS           14
+
+typedef uint8_t return_type;
+
+/*  Warning: The key length for 256 bit keys overflows a byte
+    (see comment below)
+*/
+
+typedef uint8_t length_type;
+
+typedef struct
+{   uint8_t ksch[(N_MAX_ROUNDS + 1) * N_BLOCK];
+    uint8_t rnd;
+} aes_context;
+
+/*  The following calls are for a precomputed key schedule
+
+    NOTE: If the length_type used for the key length is an
+    unsigned 8-bit character, a key length of 256 bits must
+    be entered as a length in bytes (valid inputs are hence
+    128, 192, 16, 24 and 32).
+*/
+
+#if defined( AES_ENC_PREKEYED ) || defined( AES_DEC_PREKEYED )
+
+return_type aes_set_key( const uint8_t key[],
+                         length_type keylen,
+                         aes_context ctx[1] );
+#endif
+
+#if defined( AES_ENC_PREKEYED )
+
+return_type aes_encrypt( const uint8_t in[N_BLOCK],
+                         uint8_t out[N_BLOCK],
+                         const aes_context ctx[1] );
+
+return_type aes_cbc_encrypt( const uint8_t *in,
+                         uint8_t *out,
+                         int32_t n_block,
+                         uint8_t iv[N_BLOCK],
+                         const aes_context ctx[1] );
+#endif
+
+#if defined( AES_DEC_PREKEYED )
+
+return_type aes_decrypt( const uint8_t in[N_BLOCK],
+                         uint8_t out[N_BLOCK],
+                         const aes_context ctx[1] );
+
+return_type aes_cbc_decrypt( const uint8_t *in,
+                         uint8_t *out,
+                         int32_t n_block,
+                         uint8_t iv[N_BLOCK],
+                         const aes_context ctx[1] );
+#endif
+
+/*  The following calls are for 'on the fly' keying.  In this case the
+    encryption and decryption keys are different.
+
+    The encryption subroutines take a key in an array of bytes in
+    key[L] where L is 16, 24 or 32 bytes for key lengths of 128,
+    192, and 256 bits respectively.  They then encrypts the input
+    data, in[] with this key and put the reult in the output array
+    out[].  In addition, the second key array, o_key[L], is used
+    to output the key that is needed by the decryption subroutine
+    to reverse the encryption operation.  The two key arrays can
+    be the same array but in this case the original key will be
+    overwritten.
+
+    In the same way, the decryption subroutines output keys that
+    can be used to reverse their effect when used for encryption.
+
+    Only 128 and 256 bit keys are supported in these 'on the fly'
+    modes.
+*/
+
+#if defined( AES_ENC_128_OTFK )
+void aes_encrypt_128( const uint8_t in[N_BLOCK],
+                      uint8_t out[N_BLOCK],
+                      const uint8_t key[N_BLOCK],
+                      uint8_t o_key[N_BLOCK] );
+#endif
+
+#if defined( AES_DEC_128_OTFK )
+void aes_decrypt_128( const uint8_t in[N_BLOCK],
+                      uint8_t out[N_BLOCK],
+                      const uint8_t key[N_BLOCK],
+                      uint8_t o_key[N_BLOCK] );
+#endif
+
+#if defined( AES_ENC_256_OTFK )
+void aes_encrypt_256( const uint8_t in[N_BLOCK],
+                      uint8_t out[N_BLOCK],
+                      const uint8_t key[2 * N_BLOCK],
+                      uint8_t o_key[2 * N_BLOCK] );
+#endif
+
+#if defined( AES_DEC_256_OTFK )
+void aes_decrypt_256( const uint8_t in[N_BLOCK],
+                      uint8_t out[N_BLOCK],
+                      const uint8_t key[2 * N_BLOCK],
+                      uint8_t o_key[2 * N_BLOCK] );
+#endif
+
+#endif
diff -r 000000000000 -r 60ff878b27b8 system/crypto/cmac.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/system/crypto/cmac.cpp	Tue Apr 03 17:09:34 2018 +0000
@@ -0,0 +1,153 @@
+/**************************************************************************
+Copyright (C) 2009 Lander Casado, Philippas Tsigas
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files 
+(the "Software"), to deal with the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish, 
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions: 
+
+Redistributions of source code must retain the above copyright notice, 
+this list of conditions and the following disclaimers. Redistributions in
+binary form must reproduce the above copyright notice, this list of
+conditions and the following disclaimers in the documentation and/or 
+other materials provided with the distribution.
+
+In no event shall the authors or copyright holders be liable for any special,
+incidental, indirect or consequential damages of any kind, or any damages 
+whatsoever resulting from loss of use, data or profits, whether or not 
+advised of the possibility of damage, and on any theory of liability, 
+arising out of or in connection with the use or performance of this software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+DEALINGS WITH THE SOFTWARE
+
+*****************************************************************************/
+//#include <sys/param.h>
+//#include <sys/systm.h> 
+#include <stdint.h>
+#include "aes.h"
+#include "cmac.h"
+#include "utilities.h"
+
+#define LSHIFT(v, r) do {                                       \
+  int32_t i;                                                  \
+           for (i = 0; i < 15; i++)                                \
+                    (r)[i] = (v)[i] << 1 | (v)[i + 1] >> 7;         \
+            (r)[15] = (v)[15] << 1;                                 \
+    } while (0)
+    
+#define XOR(v, r) do {                                          \
+            int32_t i;                                                  \
+            for (i = 0; i < 16; i++)     \
+        {   \
+                    (r)[i] = (r)[i] ^ (v)[i]; \
+        }                          \
+    } while (0) \
+
+
+void AES_CMAC_Init(AES_CMAC_CTX *ctx)
+{
+            memset1(ctx->X, 0, sizeof ctx->X);
+            ctx->M_n = 0;
+        memset1(ctx->rijndael.ksch, '\0', 240);
+}
+    
+void AES_CMAC_SetKey(AES_CMAC_CTX *ctx, const uint8_t key[AES_CMAC_KEY_LENGTH])
+{
+           //rijndael_set_key_enc_only(&ctx->rijndael, key, 128);
+       aes_set_key( key, AES_CMAC_KEY_LENGTH, &ctx->rijndael);
+}
+    
+void AES_CMAC_Update(AES_CMAC_CTX *ctx, const uint8_t *data, uint32_t len)
+{
+            uint32_t mlen;
+        uint8_t in[16];
+    
+            if (ctx->M_n > 0) {
+                  mlen = MIN(16 - ctx->M_n, len);
+                    memcpy1(ctx->M_last + ctx->M_n, data, mlen);
+                    ctx->M_n += mlen;
+                    if (ctx->M_n < 16 || len == mlen)
+                            return;
+                   XOR(ctx->M_last, ctx->X);
+                    //rijndael_encrypt(&ctx->rijndael, ctx->X, ctx->X);
+            aes_encrypt( ctx->X, ctx->X, &ctx->rijndael);
+                    data += mlen;
+                    len -= mlen;
+            }
+            while (len > 16) {      /* not last block */
+
+                    XOR(data, ctx->X);
+                    //rijndael_encrypt(&ctx->rijndael, ctx->X, ctx->X);
+
+                    memcpy1(in, &ctx->X[0], 16); //Bestela ez du ondo iten
+            aes_encrypt( in, in, &ctx->rijndael);
+                    memcpy1(&ctx->X[0], in, 16);
+
+                    data += 16;
+                    len -= 16;
+            }
+            /* potential last block, save it */
+            memcpy1(ctx->M_last, data, len);
+            ctx->M_n = len;
+}
+   
+void AES_CMAC_Final(uint8_t digest[AES_CMAC_DIGEST_LENGTH], AES_CMAC_CTX *ctx)
+{
+            uint8_t K[16];
+        uint8_t in[16];
+            /* generate subkey K1 */
+            memset1(K, '\0', 16);
+
+            //rijndael_encrypt(&ctx->rijndael, K, K);
+
+            aes_encrypt( K, K, &ctx->rijndael);
+
+            if (K[0] & 0x80) {
+                    LSHIFT(K, K);
+                   K[15] ^= 0x87;
+            } else
+                    LSHIFT(K, K);
+
+
+            if (ctx->M_n == 16) {
+                    /* last block was a complete block */
+                    XOR(K, ctx->M_last);
+
+           } else {
+                   /* generate subkey K2 */
+                  if (K[0] & 0x80) {
+                          LSHIFT(K, K);
+                          K[15] ^= 0x87;
+                  } else
+                           LSHIFT(K, K);
+
+                   /* padding(M_last) */
+                   ctx->M_last[ctx->M_n] = 0x80;
+                   while (++ctx->M_n < 16)
+                         ctx->M_last[ctx->M_n] = 0;
+   
+                  XOR(K, ctx->M_last);
+
+
+           }
+           XOR(ctx->M_last, ctx->X);
+
+           //rijndael_encrypt(&ctx->rijndael, ctx->X, digest);
+
+       memcpy1(in, &ctx->X[0], 16); //Bestela ez du ondo iten
+       aes_encrypt(in, digest, &ctx->rijndael);
+           memset1(K, 0, sizeof K);
+
+}
+
diff -r 000000000000 -r 60ff878b27b8 system/crypto/cmac.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/system/crypto/cmac.h	Tue Apr 03 17:09:34 2018 +0000
@@ -0,0 +1,63 @@
+/**************************************************************************
+Copyright (C) 2009 Lander Casado, Philippas Tsigas
+
+All rights reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files 
+(the "Software"), to deal with the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish, 
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions: 
+
+Redistributions of source code must retain the above copyright notice, 
+this list of conditions and the following disclaimers. Redistributions in
+binary form must reproduce the above copyright notice, this list of
+conditions and the following disclaimers in the documentation and/or 
+other materials provided with the distribution.
+
+In no event shall the authors or copyright holders be liable for any special,
+incidental, indirect or consequential damages of any kind, or any damages 
+whatsoever resulting from loss of use, data or profits, whether or not 
+advised of the possibility of damage, and on any theory of liability, 
+arising out of or in connection with the use or performance of this software.
+ 
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
+DEALINGS WITH THE SOFTWARE
+
+*****************************************************************************/
+
+#ifndef _CMAC_H_
+#define _CMAC_H_
+
+#include "aes.h" 
+  
+#define AES_CMAC_KEY_LENGTH     16
+#define AES_CMAC_DIGEST_LENGTH  16
+ 
+typedef struct _AES_CMAC_CTX {
+            aes_context    rijndael;
+            uint8_t        X[16];
+            uint8_t        M_last[16];
+            uint32_t       M_n;
+    } AES_CMAC_CTX;
+   
+//#include <sys/cdefs.h>
+    
+//__BEGIN_DECLS
+void     AES_CMAC_Init(AES_CMAC_CTX * ctx);
+void     AES_CMAC_SetKey(AES_CMAC_CTX * ctx, const uint8_t key[AES_CMAC_KEY_LENGTH]);
+void     AES_CMAC_Update(AES_CMAC_CTX * ctx, const uint8_t * data, uint32_t len);
+          //          __attribute__((__bounded__(__string__,2,3)));
+void     AES_CMAC_Final(uint8_t digest[AES_CMAC_DIGEST_LENGTH], AES_CMAC_CTX  * ctx);
+            //     __attribute__((__bounded__(__minbytes__,1,AES_CMAC_DIGEST_LENGTH)));
+//__END_DECLS
+
+#endif /* _CMAC_H_ */
+
diff -r 000000000000 -r 60ff878b27b8 system/mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/system/mbed.bld	Tue Apr 03 17:09:34 2018 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/7c328cabac7e
\ No newline at end of file
diff -r 000000000000 -r 60ff878b27b8 system/timer.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/system/timer.cpp	Tue Apr 03 17:09:34 2018 +0000
@@ -0,0 +1,78 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+    (C)2013 Semtech
+
+Description: Timer objects and scheduling management
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+Maintainer: Miguel Luis and Gregory Cristian
+*/
+#include "board.h"
+
+Timer TimeCounter;
+Ticker LoadTimeCounter;
+
+volatile uint32_t CurrentTime = 0;
+
+void TimerResetTimeCounter( void )
+{
+    CurrentTime = CurrentTime + TimeCounter.read_us( );
+    TimeCounter.reset( );
+    TimeCounter.start( );
+}
+
+void TimerTimeCounterInit( void )
+{
+    TimeCounter.start( );
+    LoadTimeCounter.attach( &TimerResetTimeCounter, 10 );
+}
+
+TimerTime_t TimerGetCurrentTime( void )
+{
+    CurrentTime += TimeCounter.read_us( );
+    TimeCounter.reset( );
+    TimeCounter.start( );
+    return ( ( TimerTime_t )CurrentTime );
+}
+
+TimerTime_t TimerGetElapsedTime( TimerTime_t savedTime )
+{
+    CurrentTime += TimeCounter.read_us( );
+    TimeCounter.reset( );
+    TimeCounter.start( );
+    return ( TimerTime_t )( CurrentTime - savedTime );
+}
+
+TimerTime_t TimerGetFutureTime( TimerTime_t eventInFuture )
+{
+    CurrentTime += TimeCounter.read_us( );
+    TimeCounter.reset( );
+    TimeCounter.start( );
+    return ( TimerTime_t )( CurrentTime + eventInFuture );
+}
+
+void TimerInit( TimerEvent_t *obj, void ( *callback )( void ) )
+{
+    obj->value = 0;
+    obj->Callback = callback;
+}
+
+void TimerStart( TimerEvent_t *obj )
+{
+    obj->Timer.attach_us( obj->Callback, obj->value );
+}
+
+void TimerStop( TimerEvent_t *obj )
+{
+    obj->Timer.detach( );
+}
+
+void TimerSetValue( TimerEvent_t *obj, uint32_t value )
+{
+    obj->value = value;
+}
diff -r 000000000000 -r 60ff878b27b8 system/timer.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/system/timer.h	Tue Apr 03 17:09:34 2018 +0000
@@ -0,0 +1,107 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+    (C)2013 Semtech
+
+Description: Timer objects and scheduling management
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+Maintainer: Miguel Luis and Gregory Cristian
+*/
+#ifndef __TIMER_H__
+#define __TIMER_H__
+
+#include "mbed.h"
+
+/*!
+ * \brief Timer object description
+ */
+typedef struct TimerEvent_s
+{
+    uint32_t value;
+    void ( *Callback )( void );
+    Ticker Timer;
+}TimerEvent_t;
+
+/*!
+ * \brief Timer time variable definition
+ */
+#ifndef TimerTime_t
+typedef uint32_t TimerTime_t;
+#endif
+
+/*!
+ * \brief Inializes the timer used to get current time.
+ *
+ * \remark Current time corresponds to the time since system startup
+ */
+void TimerTimeCounterInit( void );
+
+/*!
+ * \brief Initializes the timer object
+ *
+ * \remark TimerSetValue function must be called before starting the timer.
+ *         this function initializes timestamp and reload value at 0.
+ *
+ * \param [IN] obj          Structure containing the timer object parameters
+ * \param [IN] callback     Function callback called at the end of the timeout
+ */
+void TimerInit( TimerEvent_t *obj, void ( *callback )( void ) );
+
+/*!
+ * \brief Starts and adds the timer object to the list of timer events
+ *
+ * \param [IN] obj Structure containing the timer object parameters
+ */
+void TimerStart( TimerEvent_t *obj );
+
+/*!
+ * \brief Stops and removes the timer object from the list of timer events
+ *
+ * \param [IN] obj Structure containing the timer object parameters
+ */
+void TimerStop( TimerEvent_t *obj );
+
+/*!
+ * \brief Resets the timer object
+ *
+ * \param [IN] obj Structure containing the timer object parameters
+ */
+void TimerReset( TimerEvent_t *obj );
+
+/*!
+ * \brief Set timer new timeout value
+ *
+ * \param [IN] obj   Structure containing the timer object parameters
+ * \param [IN] value New timer timeout value
+ */
+void TimerSetValue( TimerEvent_t *obj, uint32_t value );
+
+/*!
+ * \brief Read the current time
+ *
+ * \retval time returns current time
+ */
+TimerTime_t TimerGetCurrentTime( void );
+
+/*!
+ * \brief Return the Time elapsed since a fix moment in Time
+ *
+ * \param [IN] savedTime    fix moment in Time
+ * \retval time             returns elapsed time
+ */
+TimerTime_t TimerGetElapsedTime( TimerTime_t savedTime );
+
+/*!
+ * \brief Return the Time elapsed since a fix moment in Time
+ *
+ * \param [IN] eventInFuture    fix moment in the future
+ * \retval time             returns difference between now and future event
+ */
+TimerTime_t TimerGetFutureTime( TimerTime_t eventInFuture );
+
+#endif // __TIMER_H__
diff -r 000000000000 -r 60ff878b27b8 system/utilities.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/system/utilities.cpp	Tue Apr 03 17:09:34 2018 +0000
@@ -0,0 +1,85 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+    (C)2013 Semtech
+
+Description: Helper functions implementation
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+Maintainer: Miguel Luis and Gregory Cristian
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include "board.h"
+#include "utilities.h"
+
+/*!
+ * Redefinition of rand() and srand() standard C functions.
+ * These functions are redefined in order to get the same behavior across
+ * different compiler toolchains implementations.
+ */
+// Standard random functions redefinition start
+#define RAND_LOCAL_MAX 2147483647L
+
+static uint32_t next = 1;
+
+int32_t rand1( void )
+{
+    return ( ( next = next * 1103515245L + 12345L ) % RAND_LOCAL_MAX );
+}
+
+void srand1( uint32_t seed )
+{
+    next = seed;
+}
+// Standard random functions redefinition end
+
+int32_t randr( int32_t min, int32_t max )
+{
+    return ( int32_t )rand1( ) % ( max - min + 1 ) + min;
+}
+
+void memcpy1( uint8_t *dst, const uint8_t *src, uint16_t size )
+{
+    while( size-- )
+    {
+        *dst++ = *src++;
+    }
+}
+
+void memcpyr( uint8_t *dst, const uint8_t *src, uint16_t size )
+{
+    dst = dst + ( size - 1 );
+    while( size-- )
+    {
+        *dst-- = *src++;
+    }
+}
+
+void memset1( uint8_t *dst, uint8_t value, uint16_t size )
+{
+    while( size-- )
+    {
+        *dst++ = value;
+    }
+}
+
+int8_t Nibble2HexChar( uint8_t a )
+{
+    if( a < 10 )
+    {
+        return '0' + a;
+    }
+    else if( a < 16 )
+    {
+        return 'A' + ( a - 10 );
+    }
+    else
+    {
+        return '?';
+    }
+}
diff -r 000000000000 -r 60ff878b27b8 system/utilities.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/system/utilities.h	Tue Apr 03 17:09:34 2018 +0000
@@ -0,0 +1,99 @@
+/*
+ / _____)             _              | |
+( (____  _____ ____ _| |_ _____  ____| |__
+ \____ \| ___ |    (_   _) ___ |/ ___)  _ \
+ _____) ) ____| | | || |_| ____( (___| | | |
+(______/|_____)_|_|_| \__)_____)\____)_| |_|
+    (C)2013 Semtech
+
+Description: Helper functions implementation
+
+License: Revised BSD License, see LICENSE.TXT file include in the project
+
+Maintainer: Miguel Luis and Gregory Cristian
+*/
+#ifndef __UTILITIES_H__
+#define __UTILITIES_H__
+
+/*!
+ * \brief Returns the minimum value betwen a and b
+ *
+ * \param [IN] a 1st value
+ * \param [IN] b 2nd value
+ * \retval minValue Minimum value
+ */
+#define MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) )
+
+/*!
+ * \brief Returns the maximum value betwen a and b
+ *
+ * \param [IN] a 1st value
+ * \param [IN] b 2nd value
+ * \retval maxValue Maximum value
+ */
+#define MAX( a, b ) ( ( ( a ) > ( b ) ) ? ( a ) : ( b ) )
+
+/*!
+ * \brief Returns 2 raised to the power of n
+ *
+ * \param [IN] n power value
+ * \retval result of raising 2 to the power n
+ */
+#define POW2( n ) ( 1 << n )
+
+/*!
+ * \brief Initializes the pseudo ramdom generator initial value
+ *
+ * \param [IN] seed Pseudo ramdom generator initial value
+ */
+void srand1( uint32_t seed );
+
+/*!
+ * \brief Computes a random number between min and max
+ *
+ * \param [IN] min range minimum value
+ * \param [IN] max range maximum value
+ * \retval random random value in range min..max
+ */
+int32_t randr( int32_t min, int32_t max );
+
+/*!
+ * \brief Copies size elements of src array to dst array
+ * 
+ * \remark STM32 Standard memcpy function only works on pointers that are aligned
+ *
+ * \param [OUT] dst  Destination array
+ * \param [IN]  src  Source array
+ * \param [IN]  size Number of bytes to be copied
+ */
+void memcpy1( uint8_t *dst, const uint8_t *src, uint16_t size );
+
+/*!
+ * \brief Copies size elements of src array to dst array reversing the byte order
+ *
+ * \param [OUT] dst  Destination array
+ * \param [IN]  src  Source array
+ * \param [IN]  size Number of bytes to be copied
+ */
+void memcpyr( uint8_t *dst, const uint8_t *src, uint16_t size );
+
+/*!
+ * \brief Set size elements of dst array with value 
+ * 
+ * \remark STM32 Standard memset function only works on pointers that are aligned
+ *
+ * \param [OUT] dst   Destination array
+ * \param [IN]  value Default value
+ * \param [IN]  size  Number of bytes to be copied
+ */
+void memset1( uint8_t *dst, uint8_t value, uint16_t size );
+
+/*!
+ * \brief Converts a nibble to an hexadecimal character
+ * 
+ * \param [IN] a   Nibble to be converted
+ * \retval hexChar Converted hexadecimal character
+ */
+int8_t Nibble2HexChar( uint8_t a );
+
+#endif // __UTILITIES_H__