Synchronous wireless star LoRa network, central device.

Dependencies:   SX127x sx12xx_hal

radio chip selection

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


Alternate to this project gateway running on raspberry pi can be used as gateway.

LoRaWAN on single radio channel

Synchronous Star Network

This project acts as central node for LoRaWAN-like network operating on single radio channel. Intended for use where network infrastructure would never exist due to cost and/or complexity of standard network. This project uses the class-B method of beacon generation to synchronize the end nodes with the gateway. OTA mode must be used. End-node will be allocated an uplink time slot upon joining. End node may transmit uplink at this assigned timeslot, if it desires to do so. This time slot is always referenced to the beacon sent by gateway.

LoRaWAN server is not necessary. All network control is implemented by this project. User can observe network activity on the mbed serial port. Downlinks can be scheduled using command on serial port.

This implementation must not be used on radio channels requiring duty-cycle transmit limiting.

alterations from LoRaWAN specification

This mode of operation uses a single datarate on single radio channel. ADR is not implemented, because datarate cannot be changed. OTA mode must be used. When join-accept is sent by gateway, it will have appended (instead of CFlist) the beacon timing answer to inform of when next beacon occurs, and two timing values: the time slot allocated to this end-node and the periodicity of the network. Periodicity means how often the end-node may again transmit. /media/uploads/dudmuck/class-b-single.png Beacon is sent for purpose of providing timing reference to end-nodes. The beacon payload may contain a broadcast command to end nodes. Time value is not sent in beacon payload. The time at which beacon is sent provides timing reference: every 128 seconds as standard.

Rx2 receive window is not implemented. Only Rx1 is used because a single radio channel is used. Rx1 delay is reduced to 100 milliseconds. Original LoRaWAN has 1000 millisecond Rx1 delay to accommodate internet latency.

LoRaWAN standard class-B beacon requires GPS timing reference. This implementation does not use GPS, instead a hardware timer peripheral generates interrupts to send beacons. Absolute accuracy is not required, only relative crystal drift between gateway and end-nodes is considered.

Timing values are always specified as 30ms per step as in LoRaWAN standard. Each beacon period has 4096 30ms steps per beacon period.

join OTA procedure

The join procedure has changed the join-accept delay to 100 milliseconds (standard is 5 seconds). This allows end-node to hunt for gateway on several channels during joining. When gateway starts, it will scan available channels for the optimal choice based on ambient noise on the channels. End node will retry join request until it finds the gateway. Gateway might change channel during operation if it deems current channel too busy.

configuration of network

End nodes must be provisioned by editing file Comissioning.h. The array motes lists every end node permitted on network. It contains appEui, devEUI and appKey just as specified in standard LoRaWAN. All provisioning is hard-coded; changing provisioning requires reprogramming gateway. When changing number of motes, N_MOTES definition must be changed in lorawan.h.

lorawan.h

#define N_MOTES     8
extern ota_mote_t motes[N_MOTES];   /* from Comissioning.h */

configuring number of end-nodes vs transmit rate

Trade-off can be selected between number of end-nodes on network vs. how often each end-node can transmit.
In this example, where DR_13 is SF7 at 500KHz:

lorawan.cpp

    #elif (LORAMAC_DEFAULT_DATARATE == DR_13)
        #define TX_SLOT_STEPPING        8  //approx 0.25 seconds
        #define PERIODICITY_SLOTS       (TX_SLOT_STEPPING * 6)
    #endif

Here, each end-node is given time of 240ms = 8 * 30ms; accommodating maximum payload length for both uplink and downlink.
6 in this code is the maximum count of end nodes using this gateway. Each end-node can transmit every 1.44 seconds, in this example.
If you wanted to change 6 to 20 end-nodes, each would be able to use network every 4.8 seconds.
Another example: If you wanted to use DR_12 = SF8, you would have approx 2.5 to 3dB more gain compared to SF7, but each end-node must be given double time, resulting in 20 nodes able to use network every 9.6 seconds at DR_12.

network capacity limitation

The number of end-nodes which can be supported is determined by number of SLOT_STEPPING's which can occur during BEACON_PERIOD. Beacon guard is implemented same as standard LoRaWAN, which is 3 seconds prior to beacon start and 2.12 seconds after beacon start, which gives 122.88 seconds for network traffic for each beacon period.

gateway configuration

spreading factor is declared at #define LORAMAC_DEFAULT_DATARATE in lorawan.h, valid rates are DR_8 to DR_13 (sf12 to sf7). In the end-node, the same definition must be configured in LoRaMac-definitions.h. This network operates at this constant datarate for all packets.
Band plan can be selected by defining USE_BAND_* in lorawan.h. 434MHz can be used on SX1276 shield. TypeABZ module and sx1272 only support 800/900MHz channels band.

end-node provisioning

Security permits only matching DevEUI / AppEui to join the network, due to unique AES root key for each end device; in this case the DevEUI must be programmed in advance into gateway. However, if the same AES root key could be used for each end device , then any number of end devices could be added at a later time, without checking DevEUI on the gateway when an end device joins the network. On the gateway, the end device join acceptance is performed in file lorawan.cpp LoRaWan::parse_receive() where MType == MTYPE_JOIN_REQ. A memcmp() is performed on both DevEUI and AppEUI.

If you wish to allow any DevEUI to join, define ANY_DEVEUI at top of lorawan.cpp . In this configuration, all end devices must use same AppEUI and AES key. N_MOTES must be defined to the maximum number of end devices expected. Test end device by commenting BoardGetUniqueId() in end node, and replace DevEui[] with 8 arbitrary bytes to verify gateway permits any DevEUI to join.

RAM usage

For gateway CPU, recommend to consider larger RAM size depending on number of end devices required. ota_motes_t has size of 123 bytes. Each end device has one of these, however if less RAM usage is required for more end-devices, the MAC command queue size may be reduced.

hardware support

The radio driver supports both SX1272 and SX1276, sx126x kit, sx126x radio-only shield, and sx128x 2.4GHz.. The selection of radio chip type is made by your choice of importing radio driver library.



Beacon generation requires low power ticker to be clocked from crystal, not internal RC oscillator.

Gateway Serial Interface

Gateway serial port operates at 115200bps.

commandargumentdescription
list-list joined end nodes
?-list available commands
dl<mote-hex-dev-addr> <hex-payload>send downlink, sent after uplink received
gpo<mote-hex-dev-addr> <0 or 1>set output PC6 pin level on end device
b32bit hex valueset beacon payload to be sent at next beacon
. (period)-print current status
opdBmconfigure TX power of gateway
sbcountskip sending beacons, for testing end node
fhex devAddrprinter filtering, show only single end node
hm-print filtering, hide MAC layer printing
hp-print filtering, hide APP layer printing
sa-print filtering, show all, undo hm and hp

Any received uplink will be printed with DevAddr and decrypted payload.

Files at this revision

API Documentation at this revision

Comitter:
Wayne Roberts
Date:
Tue Jul 14 11:08:24 2020 -0700
Parent:
22:dd3023aac3b1
Commit message:
update to mbed-6

Changed in this revision

Commissioning.h Show annotated file Show diff for this revision Revisions of this file
SX127x.lib Show annotated file Show diff for this revision Revisions of this file
TimeoutAbs.lib Show diff for this revision Revisions of this file
gladman_aes.cpp Show diff for this revision Revisions of this file
gladman_aes.h Show diff for this revision Revisions of this file
gladman_cmac.cpp Show diff for this revision Revisions of this file
gladman_cmac.h Show diff for this revision Revisions of this file
lorawan.cpp Show annotated file Show diff for this revision Revisions of this file
lorawan.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-os.lib Show annotated file Show diff for this revision Revisions of this file
sx12xx_hal.lib Show annotated file Show diff for this revision Revisions of this file
diff -r dd3023aac3b1 -r 801d4bd6dccc Commissioning.h
--- a/Commissioning.h	Thu Dec 13 16:53:37 2018 -0800
+++ b/Commissioning.h	Tue Jul 14 11:08:24 2020 -0700
@@ -9,7 +9,7 @@
     }
     */
     { 
-        { 0x05, 0x50, 0x34, 0x48, 0x91, 0x32, 0x7e, 0x20 },
+        { 0x31, 0x34, 0x30, 0x36, 0x5e, 0x33, 0x71, 0x0c },
         { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
         { 0x3e, 0xfc, 0xf2, 0x81, 0x44, 0x0d, 0x8a, 0x8c, 0x3f, 0xd4, 0x88, 0x24, 0xab, 0xd3, 0x22, 0x52 },
     },
diff -r dd3023aac3b1 -r 801d4bd6dccc SX127x.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SX127x.lib	Tue Jul 14 11:08:24 2020 -0700
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/dudmuck/code/SX127x/#cd54c52c6003
diff -r dd3023aac3b1 -r 801d4bd6dccc TimeoutAbs.lib
--- a/TimeoutAbs.lib	Thu Dec 13 16:53:37 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-https://os.mbed.com/users/dudmuck/code/TimeoutAbs/#ae6b29794806
diff -r dd3023aac3b1 -r 801d4bd6dccc gladman_aes.cpp
--- a/gladman_aes.cpp	Thu Dec 13 16:53:37 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,936 +0,0 @@
-/*
- ---------------------------------------------------------------------------
- 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 "gladman_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 dd3023aac3b1 -r 801d4bd6dccc gladman_aes.h
--- a/gladman_aes.h	Thu Dec 13 16:53:37 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,160 +0,0 @@
-/*
- ---------------------------------------------------------------------------
- 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 1
-#  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 dd3023aac3b1 -r 801d4bd6dccc gladman_cmac.cpp
--- a/gladman_cmac.cpp	Thu Dec 13 16:53:37 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,159 +0,0 @@
-/**************************************************************************
-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 "gladman_aes.h"
-#include "gladman_cmac.h"
-//#include "utilities.h"
-#include <string.h>
-
-#define memset1 memset
-#define memcpy1 memcpy
-#define MIN(n,m) (((n) < (m)) ? (n) : (m))
-
-
-#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 dd3023aac3b1 -r 801d4bd6dccc gladman_cmac.h
--- a/gladman_cmac.h	Thu Dec 13 16:53:37 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,63 +0,0 @@
-/**************************************************************************
-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 dd3023aac3b1 -r 801d4bd6dccc lorawan.cpp
--- a/lorawan.cpp	Thu Dec 13 16:53:37 2018 -0800
+++ b/lorawan.cpp	Tue Jul 14 11:08:24 2020 -0700
@@ -3,12 +3,13 @@
 #include "lorawan.h"
 #include "Commissioning.h"
 
-#include "gladman_aes.h"
-#include "gladman_cmac.h"
+#include "cmac.h"
 
 //#define ANY_DEVEUI
 
-#define RECEIVE_DELAY_ms        100
+const microseconds RECEIVE_DELAY_us(100000);
+
+Timeout timeout;
 
 #define LORA_FRAMEMICBYTES              4
 #define LORA_ENCRYPTIONBLOCKBYTES       16
@@ -30,7 +31,7 @@
 uint8_t LoRaWan::user_downlink[128];
 volatile uint16_t LoRaWan::rx_slot;
 volatile uint32_t LoRaWan::beaconDur;
-volatile uint32_t LoRaWan::rx_ms;    // captured timer milliseconds at RxDone
+HighResClock::time_point LoRaWan::rx_at;
 volatile flags_t LoRaWan::flags;
 uint32_t LoRaWan::dev_addr_filter;
 uint8_t LoRaWan::_tmp_payload_length;
@@ -271,25 +272,37 @@
     SRV_MAC_BEACON_FREQ_REQ          = 0x13,
 }LoRaMacSrvCmd_t;
 
+mtype_e user_dowlink_mtype = MTYPE_UNCONF_DN;
 
-mtype_e user_dowlink_mtype = MTYPE_UNCONF_DN;
+static mbedtls_cipher_context_t ctx;
+
+void pc_printf(const char *fmt, ...)
+{
+    char n, str[64];
+    va_list arg_ptr;
+
+    va_start(arg_ptr, fmt);
+    n = vsnprintf(str, sizeof(str), fmt, arg_ptr);
+    va_end(arg_ptr);
+    pc.write(str, n);
+}
 
 void print_octets(char const* label, uint8_t const* buf, uint8_t buf_len)
 {
     int i;
-    pc.printf("%s:", label);
+    pc_printf("%s:", label);
     for (i = 0; i < buf_len; i++)
-        pc.printf(" %02x", buf[i]);
-//    pc.printf("\n");
+        pc_printf(" %02x", buf[i]);
+//    pc_printf("\n");
 }
 
 void LoRaWan::print_octets_rev(char const* label, uint8_t const* buf, uint8_t buf_len)
 {
     int i;
-    pc.printf("%s:", label);
+    pc_printf("%s:", label);
     for (i = buf_len-1; i >= 0; i--)
-        pc.printf(" %02x", buf[i]);
-//    pc.printf("\n");
+        pc_printf(" %02x", buf[i]);
+//    pc_printf("\n");
 }
 
 void LoRaWan::filtered_printf(uint32_t dev_addr, layer_e l, const char* format, ...)
@@ -368,64 +381,70 @@
     return ptr;
 }
 
-void LoRa_GenerateJoinFrameIntegrityCode(const uint8_t key[], uint8_t const input[], uint16_t dataLength, uint8_t* output)
+int LoRa_GenerateJoinFrameIntegrityCode(const uint8_t key[], uint8_t const input[], uint16_t dataLength, uint8_t* output)
 {
-    AES_CMAC_CTX cmacctx;
-    AES_CMAC_Init(&cmacctx);
-    AES_CMAC_SetKey(&cmacctx, key);
+    uint8_t temp[LORA_AUTHENTICATIONBLOCKBYTES];
 
-    AES_CMAC_Update(&cmacctx, input, dataLength);
-    uint8_t temp[LORA_AUTHENTICATIONBLOCKBYTES];
-    AES_CMAC_Final(temp, &cmacctx);
-    memcpy(output, temp, LORA_FRAMEMICBYTES);
-#if 0
-    TODO https://tls.mbed.org/kb/compiling-and-building/how-do-i-configure-mbedtls
     int ret;
-    mbedtls_cipher_context_t m_ctx;
-    const mbedtls_cipher_info_t *cipher_info = mbedtls_cipher_info_from_type( MBEDTLS_CIPHER_AES_128_CBC );
-    mbedtls_cipher_init(&m_ctx);
-    ret = mbedtls_cipher_setup( &m_ctx, cipher_info );
-    pc.printf("%d = mbedtls_cipher_setup()\r\n", ret);
-    ret = mbedtls_cipher_cmac_starts(&m_ctx, key, LORA_CYPHERKEYBYTES * 8);
-    pc.printf("%d = mbedtls_cipher_cmac_starts()\r\n", ret);
+    ret = mbedtls_cipher_cmac_starts(&ctx, key, 128);
+    if (ret < 0)
+        return ret;
+    ret = mbedtls_cipher_cmac_update(&ctx, input, dataLength & 0xff);
+    if (ret < 0)
+        return ret;
+    ret = mbedtls_cipher_cmac_finish(&ctx, temp);
+    if (ret < 0)
+        return ret;
 
-    ret= mbedtls_cipher_cmac_update(&m_ctx, input, dataLength);
-    pc.printf("%d = mbedtls_cipher_cmac_update returned\r\n",ret);
+    memcpy(output, temp, LORA_FRAMEMICBYTES);
 
-    ret=mbedtls_cipher_cmac_finish(&m_ctx, output);
-    pc.printf("%d = mbedtls_cipher_cmac_starts returned\r\n",ret);
-#endif
+    return 0;
 }
 
-void GenerateSessionKey(bool generateNetworkKey, const uint8_t* applicationKey, uint32_t networkId, uint32_t applicationNonce, uint16_t deviceNonce, uint8_t* output)
+int GenerateSessionKey(bool generateNetworkKey, const uint8_t* applicationKey, uint32_t networkId, uint32_t applicationNonce, uint16_t deviceNonce, uint8_t* output)
 {
     uint8_t input[LORA_ENCRYPTIONBLOCKBYTES];
 
-    input[0] = generateNetworkKey ? 0x01 : 0x02;
-    uint8_t* ptr = &input[1];
+    {
+        mbedtls_aes_context actx;
+        mbedtls_aes_init(&actx);
+        if (mbedtls_aes_setkey_enc(&actx, applicationKey, 128) < 0)
+            return -1;
+
+        input[0] = generateNetworkKey ? 0x01 : 0x02;
+        uint8_t* ptr = &input[1];
 
-    ptr = Write3ByteValue(ptr, applicationNonce);
-    ptr = Write3ByteValue(ptr, networkId);
-    ptr = Write2ByteValue(ptr, deviceNonce);
-    memset(ptr, 0, LORA_ENCRYPTIONBLOCKBYTES - (ptr - input));
+        ptr = Write3ByteValue(ptr, applicationNonce);
+        ptr = Write3ByteValue(ptr, networkId);
+        ptr = Write2ByteValue(ptr, deviceNonce);
+        memset(ptr, 0, LORA_ENCRYPTIONBLOCKBYTES - (ptr - input));
 
-    aes_context aesContext;
-    aes_set_key(applicationKey, LORA_CYPHERKEYBYTES, &aesContext);
+        mbedtls_aes_encrypt(&actx, input, output);
 
-    aes_encrypt(input, output, &aesContext);
+        mbedtls_aes_free(&actx);
+    }
+
+    return 0;
 }
 
-void CryptJoinServer(uint8_t const* key, uint8_t const* input, uint16_t length, uint8_t* output)
+int CryptJoinServer(uint8_t const* key, uint8_t const* input, uint16_t length, uint8_t* output)
 {
-    aes_context aesContext;
-    memset(aesContext.ksch, '\0', 240);
-    aes_set_key(key, LORA_CYPHERKEYBYTES, &aesContext);
+    int ret;
+    mbedtls_aes_context actx;
 
-    aes_decrypt(input, output, &aesContext);
+    mbedtls_aes_init(&actx);
+    ret = mbedtls_aes_setkey_dec(&actx, key, 128);
+    if (ret < 0)
+        return -1;
+
+    mbedtls_aes_decrypt(&actx, input, output);
+
     if (length >= 16) {
-        aes_decrypt(input + 16, output + 16, &aesContext);
+        mbedtls_aes_decrypt(&actx, input + 16, output + 16);
     }
 
+    mbedtls_aes_free(&actx);
+    return 0;
 }
 
 void LoRaWan::SendJoinComplete(uint16_t deviceNonce, uint8_t firstReceiveWindowDataRateoffset, ota_mote_t* mote)
@@ -437,7 +456,7 @@
     uint32_t applicationNonce = rand() & 0xffffff;  // 24bit
 
     if (flags.do_downlink) {
-        pc.printf("SendJoinComplete(): tx busy\r\n");
+        pc_printf("\e[41mSendJoinComplete(): tx busy\e[0m\r\n");
         return;
     }
 
@@ -445,22 +464,23 @@
 
     memcpy(mote->network_session_key, networkSessionKey, LORA_CYPHERKEYBYTES);
     
-    pc.printf("SendJoinComplete() ");
+    pc_printf("SendJoinComplete() ");
     if (mote->dev_addr == DEVADDR_NONE) {
         // new mote joining
-        pc.printf("new-mote ");
+        pc_printf("new-mote ");
         if ( mote->tx_slot_offset >= PERIODICITY_SLOTS) {
-            pc.printf("max motes reached\r\n");
+            pc_printf("max motes reached\r\n");
             return;
         }
         mote->dev_addr = ++networkAddress | (network_id << LORA_NETWORKADDRESSBITS);
         mote->tx_slot_offset = next_available_tx_slot;
         next_available_tx_slot += TX_SLOT_STEPPING;
     } else
-        pc.printf("rejoin ");
+        pc_printf("rejoin ");
 
-    pc.printf(" mote->dev_addr:%lx ", mote->dev_addr);
-    pc.printf("networkAddress:%lu\r\n", networkAddress);
+    pc_printf(" mote->dev_addr:%lx ", mote->dev_addr);
+    pc_printf("networkAddress:%lu\r\n", networkAddress);
+    memset(current, 0 , LORA_MAXDATABYTES);
     *(current++) = MTYPE_JOIN_ACC << 5; // MHDR     0
     current = Write3ByteValue(current, applicationNonce);// 1 2 3
     current = Write3ByteValue(current, network_id);// 4 5 6
@@ -470,7 +490,7 @@
     current = Write1ByteValue(current, 0); // 12
 
     /* put beacon timing answer */
-    pc.printf("slots:%u\r\n", rx_slot);
+    pc_printf("slots:%u\r\n", rx_slot);
     current = Write2ByteValue(current, rx_slot); // 13, 14
     current = Write2ByteValue(current, mote->tx_slot_offset); // 15, 16
     current = Write2ByteValue(current, PERIODICITY_SLOTS); // 17, 18
@@ -489,16 +509,16 @@
 
     /**** RF TX ********/
     _tmp_payload_length = current - uncyphered;
-    uint32_t now_ms = timer.read_ms();
-    queue.call_in(rx_ms + 100 - now_ms, send_downlink);
+    timeout.attach_absolute(send_downlink, rx_at + RECEIVE_DELAY_us);
     flags.do_downlink = true;
     mote->FCntDown = 0;
 
     GenerateSessionKey(false, mote->app_key, network_id, applicationNonce, deviceNonce, mote->app_session_key);
 }
 
-void LoRa_GenerateDataFrameIntegrityCode(const uint8_t key[], uint8_t const input[], uint16_t dataLength, uint32_t address, bool up, uint32_t sequenceNumber, uint8_t* output)
+int LoRa_GenerateDataFrameIntegrityCode(const uint8_t key[], uint8_t const input[], uint16_t dataLength, uint32_t address, bool up, uint32_t sequenceNumber, uint8_t* output)
 {
+    uint8_t temp[LORA_AUTHENTICATIONBLOCKBYTES];
     /*
     Generate artificial B[0] block
     Encrypt B[0] to give X[1]
@@ -518,17 +538,16 @@
 
     b0[15] = (uint8_t)dataLength;
 
-    AES_CMAC_CTX cmacctx;
-    AES_CMAC_Init(&cmacctx);
-    AES_CMAC_SetKey(&cmacctx, key);
-
-    AES_CMAC_Update(&cmacctx, b0, LORA_AUTHENTICATIONBLOCKBYTES);
-    AES_CMAC_Update(&cmacctx, input, dataLength);
-
-    uint8_t temp[LORA_AUTHENTICATIONBLOCKBYTES];
-    AES_CMAC_Final(temp, &cmacctx);
-
+    if (mbedtls_cipher_cmac_starts(&ctx, key, 128))
+        return -1;
+ 
+    mbedtls_cipher_cmac_update(&ctx, b0, LORA_AUTHENTICATIONBLOCKBYTES);
+ 
+    mbedtls_cipher_cmac_update(&ctx, input, dataLength);
+ 
+    mbedtls_cipher_cmac_finish(&ctx, temp);
     memcpy(output, temp, LORA_FRAMEMICBYTES);
+    return 0;
 }
 
 static uint16_t FindBlockOverhang(uint16_t inputDataLength)
@@ -559,10 +578,13 @@
 
 void LoRa_EncryptPayload(const uint8_t key[], const uint8_t* in, uint16_t inputDataLength, uint32_t address, bool up, uint32_t sequenceNumber, uint8_t out[])
 {
+    uint8_t A[LORA_ENCRYPTIONBLOCKBYTES];
+    mbedtls_aes_context actx;
     if (inputDataLength == 0)
         return;
 
-    uint8_t A[LORA_ENCRYPTIONBLOCKBYTES];
+    mbedtls_aes_init(&actx);
+    mbedtls_aes_setkey_enc(&actx, key, 128);
 
     memset(A, 0, LORA_ENCRYPTIONBLOCKBYTES);
 
@@ -581,11 +603,9 @@
     {
         A[15] = (uint8_t)i;
 
-        aes_context aesContext;
-        aes_set_key(key, LORA_CYPHERKEYBYTES, &aesContext);
+        uint8_t S[LORA_CYPHERKEYBYTES];
 
-        uint8_t S[LORA_CYPHERKEYBYTES];
-        aes_encrypt(A, S, &aesContext);
+        mbedtls_aes_encrypt(&actx, A, S);
 
         uint16_t bytesToExOr;
         if ((i < blocks) || (overHangBytes == 0))
@@ -595,6 +615,8 @@
 
         BlockExOr(S, blockInput, blockOutput, bytesToExOr);
     }
+
+    mbedtls_aes_free(&actx);
 }
 
 void put_queue_mac_cmds(ota_mote_t* mote, uint8_t cmd_len, uint8_t* cmd_buf)
@@ -603,18 +625,18 @@
     uint8_t* this_cmd_buf = mote->macCmd_queue[mote->macCmd_queue_in_idx];
     this_cmd_buf[0] = cmd_len;
 
-    pc.printf("put_queue_mac_cmds %u: ", cmd_len);
+    pc_printf("put_queue_mac_cmds %u: ", cmd_len);
     for (i = 0; i < cmd_len; i++) {
         this_cmd_buf[i+1] = cmd_buf[i];
-        pc.printf("%02x ", cmd_buf[i]);
+        pc_printf("%02x ", cmd_buf[i]);
     }
-    pc.printf("\r\n");
+    pc_printf("\r\n");
 
     if (++mote->macCmd_queue_in_idx == MAC_CMD_QUEUE_SIZE)
         mote->macCmd_queue_in_idx = 0;
 
     if (mote->macCmd_queue_in_idx == mote->macCmd_queue_out_idx) {
-        pc.printf("macCmd_queue full\r\n");
+        pc_printf("macCmd_queue full\r\n");
     }
 }
 
@@ -624,10 +646,10 @@
     uint8_t cmd_buf[MAC_CMD_SIZE];
     uint8_t rx_cmd_buf_idx = 0;
     int i;
-    pc.printf("rx_mac_command(s):");
+    pc_printf("rx_mac_command(s):");
     for (i = 0; i < rx_cmd_buf_len; i++)
-        pc.printf("%02x ", rx_cmd_buf[i]);
-    pc.printf("\n");
+        pc_printf("%02x ", rx_cmd_buf[i]);
+    pc_printf("\n");
 
     while (rx_cmd_buf_idx < rx_cmd_buf_len) {
 
@@ -635,7 +657,7 @@
             //float diff;
             uint16_t i_diff;
             case MOTE_MAC_LINK_CHECK_REQ:   // 0x02
-                pc.printf("MOTE_MAC_LINK_CHECK_REQ\n");
+                pc_printf("MOTE_MAC_LINK_CHECK_REQ\n");
                 /* no payload in request */
                 cmd_buf[0] = SRV_MAC_LINK_CHECK_ANS;
                 cmd_buf[1] = 20;  // db margin above noise floor
@@ -649,33 +671,33 @@
                 /*diff = (float)(tick_at_next_beacon - tick_at_RxDone) / 30.0;
                 i_diff = (int)floor(diff);*/
                 i_diff = rx_slot;
-                //pc.printf("MOTE_MAC_BEACON_TIMING_REQ slots:%.1f=%.1fms (int:%u,%u)", diff, diff*30.0, i_diff, i_diff*30);
-                pc.printf("MOTE_MAC_BEACON_TIMING_REQ slots:%u", i_diff);
+                //pc_printf("MOTE_MAC_BEACON_TIMING_REQ slots:%.1f=%.1fms (int:%u,%u)", diff, diff*30.0, i_diff, i_diff*30);
+                pc_printf("MOTE_MAC_BEACON_TIMING_REQ slots:%u", i_diff);
                 cmd_buf[0] = SRV_MAC_BEACON_TIMING_ANS;   // 0x12
                 cmd_buf[1] = i_diff & 0xff; //lsbyte first byte
                 cmd_buf[2] = (i_diff >> 8) & 0xff;
                 cmd_buf[3] = 0;   // beacon channel index
                 put_queue_mac_cmds(mote, 4, cmd_buf);
-                pc.printf("%02x %02x %02x\n", cmd_buf[1], cmd_buf[2], cmd_buf[3]);
+                pc_printf("%02x %02x %02x\n", cmd_buf[1], cmd_buf[2], cmd_buf[3]);
                 break;
             case MOTE_MAC_PING_SLOT_FREQ_ANS:
                 i = rx_cmd_buf[rx_cmd_buf_idx++];
-                pc.printf("PING_SLOT_FREQ_ANS status:0x%02x\n", i);
+                pc_printf("PING_SLOT_FREQ_ANS status:0x%02x\n", i);
                 break;
             case MOTE_MAC_BEACON_FREQ_ANS:
                 i = rx_cmd_buf[rx_cmd_buf_idx++];
-                pc.printf("BEACON_FREQ_ANS status:0x%02x\n", i);
+                pc_printf("BEACON_FREQ_ANS status:0x%02x\n", i);
                 break;
             case MOTE_MAC_RX_PARAM_SETUP_ANS:
                 i = rx_cmd_buf[rx_cmd_buf_idx++];
-                pc.printf("RX_PARAM_SETUP_ANS status:0x%02x\n", i);
+                pc_printf("RX_PARAM_SETUP_ANS status:0x%02x\n", i);
                 break;
             case MOTE_MAC_NEW_CHANNEL_ANS:
                 i = rx_cmd_buf[rx_cmd_buf_idx++];
-                pc.printf("NEW_CHANNEL_ANS status:0x%02x\n", i);
+                pc_printf("NEW_CHANNEL_ANS status:0x%02x\n", i);
                 break;
             default:
-                pc.printf("TODO mac cmd %02x\n", rx_cmd_buf[rx_cmd_buf_idx-1]);
+                pc_printf("TODO mac cmd %02x\n", rx_cmd_buf[rx_cmd_buf_idx-1]);
                 return;
         } // ..switch (<mac_command>)
     } // .. while have mac comannds
@@ -695,8 +717,7 @@
     LoRa_GenerateDataFrameIntegrityCode(mote->network_session_key, Radio::radio.tx_buf, _tmp_payload_length, fhdr->DevAddr, false, fhdr->FCnt, mic_ptr);
     _tmp_payload_length += LORA_FRAMEMICBYTES;
 
-
-    queue.call_in(rx_ms + RECEIVE_DELAY_ms - timer.read_ms(), send_downlink);
+    timeout.attach_absolute(send_downlink, rx_at + RECEIVE_DELAY_us);
     flags.do_downlink = true;
 }
 
@@ -779,7 +800,7 @@
 
             _tmp_payload_length = tx_fhdr->FCtrl.dlBits.FOptsLen + mote->user_downlink_length + 1; // +1 for fport
             Radio::radio.tx_buf[0] = user_dowlink_mtype << 5; // MHDR
-            pc.printf(", DL-send %d", mote->user_downlink_length);
+            pc_printf(", DL-send %d", mote->user_downlink_length);
         } else {
             /* downlink not triggered by user_downlink */
             /* downlink triggered by FOpotsLen > 0 or conf_uplink */
@@ -813,7 +834,7 @@
     rx_mic += Radio::radio.rx_buf[rx_size-3] << 8;
     rx_mic += Radio::radio.rx_buf[rx_size-4];
     if (calculated_mic != rx_mic) {
-        pc.printf("join_req mic fail: %08lx, %08lx\r\n", calculated_mic, rx_mic);
+        pc_printf("join_req mic fail: %08lx, %08lx\r\n", calculated_mic, rx_mic);
         return;
     }
 
@@ -844,12 +865,21 @@
     }
 }
 
-void LoRaWan::init()
+int LoRaWan::init()
 {
-    int i;
+    const mbedtls_cipher_info_t *cipher_info;
+    int i, ret;
     for (i = 0; i < N_MOTES; i++) {
         motes[i].dev_addr = DEVADDR_NONE;
     }
+
+    mbedtls_cipher_init(&ctx);
+    cipher_info = mbedtls_cipher_info_from_type( MBEDTLS_CIPHER_AES_128_ECB );
+    if (cipher_info == NULL) {
+        return -1;
+    }
+    ret = mbedtls_cipher_setup(&ctx, cipher_info);
+    return ret;
 }
 
 #ifdef ANY_DEVEUI 
@@ -863,23 +893,23 @@
     mhdr_t *mhdr = (mhdr_t*)Radio::radio.rx_buf;
 
     if (rx_size <= (sizeof(fhdr_t) + LORA_FRAMEMICBYTES)) {
-        pc.printf("too small %d, snr:%.1f %ddBm\r\n", rx_size, snr, rssi);
+        pc_printf("too small %d, snr:%.1f %ddBm\r\n", rx_size, snr, rssi);
         return 1;
     }
     if (mhdr->bits.major != 0) {
-        pc.printf("unsupported major:%u\r\n", mhdr->bits.major);
+        pc_printf("unsupported major:%u\r\n", mhdr->bits.major);
         return 0;
     }
 
     if (mhdr->bits.MType == MTYPE_JOIN_REQ) {
         join_req_t* join_req = (join_req_t*)&Radio::radio.rx_buf[0];
-        pc.printf("MTYPE_JOIN_REQ, ");
+        pc_printf("MTYPE_JOIN_REQ, ");
 
 #ifdef ANY_DEVEUI
         if (num_motes_joined < N_MOTES && 
             (memcmp_rev(join_req->AppEUI, motes[num_motes_joined].app_eui, LORA_EUI_LENGTH) == 0))
         {
-            pc.printf("assigning to mote %u\r\n", num_motes_joined);
+            pc_printf("assigning to mote %u\r\n", num_motes_joined);
             i = num_motes_joined++;
             mote = &motes[i];
             memcpy_rev(mote->dev_eui, join_req->DevEUI, LORA_EUI_LENGTH);
@@ -889,20 +919,20 @@
             if ((memcmp_rev(join_req->AppEUI, motes[i].app_eui, LORA_EUI_LENGTH) == 0) &&
                 (memcmp_rev(join_req->DevEUI, motes[i].dev_eui, LORA_EUI_LENGTH) == 0))
             {
-                pc.printf("found mote\r\n");
+                pc_printf("found mote\r\n");
                 mote = &motes[i];
             }
         }
 #endif /* !ANY_DEVEUI */
 
         if (mote != NULL) {
-            pc.printf("Join-Found\r\n");
+            pc_printf("Join-Found\r\n");
             parse_join_req(mote, rx_size);
         } else {
-            pc.printf("join-not-found:\r\n");
+            pc_printf("join-not-found:\r\n");
             print_octets_rev("app_eui", join_req->AppEUI, LORA_EUI_LENGTH);
             print_octets_rev("\r\ndev_eui", join_req->DevEUI, LORA_EUI_LENGTH);
-            pc.printf("\r\n");
+            pc_printf("\r\n");
         }
     } else if (mhdr->bits.MType == MTYPE_UNCONF_UP || mhdr->bits.MType == MTYPE_CONF_UP) {
         fhdr_t *fhdr = (fhdr_t*)&Radio::radio.rx_buf[1];
@@ -932,11 +962,11 @@
             parse_uplink(mote, rx_size);
             filtered_printf(mote->dev_addr, MAC, "\r\n");
         } else {
-            pc.printf("mote-not-found %08lx\r\n", fhdr->DevAddr);
+            pc_printf("mote-not-found %08lx\r\n", fhdr->DevAddr);
         }
 
     } else
-        pc.printf(" %02x mtype:%d\r\n", Radio::radio.rx_buf[0], mhdr->bits.MType);
+        pc_printf(" %02x mtype:%d\r\n", Radio::radio.rx_buf[0], mhdr->bits.MType);
 
 
     return 0;
diff -r dd3023aac3b1 -r 801d4bd6dccc lorawan.h
--- a/lorawan.h	Thu Dec 13 16:53:37 2018 -0800
+++ b/lorawan.h	Tue Jul 14 11:08:24 2020 -0700
@@ -71,9 +71,13 @@
 #define LORA_EUI_LENGTH                 8
 #define LORA_CYPHERKEYBYTES             16
 
-extern Timer timer;
-extern EventQueue queue;
-extern RawSerial pc;
+using namespace std::chrono;
+
+//extern Timer timer;
+//extern EventQueue queue;
+
+extern UnbufferedSerial pc;
+void pc_printf(const char *fmt, ...);
 
 #define MAC_CMD_QUEUE_SIZE      6
 #define MAC_CMD_SIZE            8
@@ -123,14 +127,14 @@
 
     public:
         static int parse_receive(uint8_t rxSize, float rssi, float snr);
-        static void init(void);
+        static int init(void);
         static void print_octets_rev(char const* label, uint8_t const* buf, uint8_t buf_len);
 
         static volatile uint16_t rx_slot;
         static volatile uint32_t beaconDur;
         static uint8_t user_downlink[];
         static const uint8_t Datarates[];
-        static volatile uint32_t rx_ms;
+        static HighResClock::time_point rx_at;  //static volatile uint32_t rx_ms;
         static uint32_t dev_addr_filter;
         static void filtered_printf(uint32_t dev_addr, layer_e, const char* format, ...);
 
diff -r dd3023aac3b1 -r 801d4bd6dccc main.cpp
--- a/main.cpp	Thu Dec 13 16:53:37 2018 -0800
+++ b/main.cpp	Tue Jul 14 11:08:24 2020 -0700
@@ -1,20 +1,17 @@
 #include "lorawan.h"
 #include "commands.h"
-#include "TimeoutAbs.h"
 #include "SPIu.h"
 #define __STDC_FORMAT_MACROS
 #include <inttypes.h>
 
 #define PREAMBLE_SYMBS          8
 
-#define BEACON_PRELOAD_us               500000
-#define BEACON_INTERVAL_SECONDS_us      /*16000000*/     128000000     /*8000000*/
-volatile us_timestamp_t beaconAt;
-TimeoutAbs load_beaconTimer;
-TimeoutAbs send_beaconTimer;
+const microseconds BEACON_PRELOAD_us(500000);
+const seconds BEACON_INTERVAL_s(128);
+HighResClock::time_point beaconAt;
+Timeout beacon_timeout; /* beacon generator */
 
-RawSerial pc(USBTX, USBRX);
-Timer timer;
+UnbufferedSerial pc( USBTX, USBRX );
 
 char pcbuf[64];
 int pcbuf_len;
@@ -33,7 +30,7 @@
     int acc[LORA_MAX_NB_CHANNELS];
 
     Radio::Standby( );
-    wait(0.02);
+    ThisThread::sleep_for(20ms);
     
     for (ch = 0; ch < LORA_MAX_NB_CHANNELS; ch++) {
         int i;
@@ -43,12 +40,12 @@
         for (i = 0; i < N_SAMPLES; i++) {
             int rssi = Radio::GetRssiInst();
             acc[ch] += rssi;
-            wait(0.01);
+            ThisThread::sleep_for(10ms);
         }
         Radio::Standby( );
-        pc.printf("ch%u: %f\r\n", ch, acc[ch] / (float)N_SAMPLES);
+        pc_printf("ch%u: %d\r\n", ch, (int)(acc[ch] / (float)N_SAMPLES));
         hz += LORAMAC_STEPWIDTH_CHANNEL;
-        wait(0.02);
+        ThisThread::sleep_for(20ms);
         Radio::SetChannel(hz);
     }
 
@@ -61,7 +58,7 @@
         }
     }
     hz = LORAMAC_FIRST_CHANNEL + (min_ch * LORAMAC_STEPWIDTH_CHANNEL);
-    pc.printf("using ch%u, %luhz\r\n", min_ch, hz);
+    pc_printf("using ch%u, %luhz\r\n", min_ch, hz);
     Radio::SetChannel(hz);
     usingChHz = hz;
     
@@ -78,11 +75,12 @@
     for (i = 0; i < N_SAMPLES; i++) {
         int rssi = Radio::GetRssiInst();
         acc += rssi;
-        wait(0.01);
+        ThisThread::sleep_for(10ms);
     }
     bg_rssi = acc / (float)N_SAMPLES;
     diff = bg_rssi - starting_bg_rssi;
-    pc.printf("bg_rssi:%.1fdBm vs %1.fdBm, diff:%.1f, %d\r\n", bg_rssi, starting_bg_rssi, diff, cnt);
+    //pc_printf("bg_rssi:%.1fdBm vs %1.fdBm, diff:%.1f, %d\r\n", bg_rssi, starting_bg_rssi, diff, cnt);
+    pc_printf("bg_rssi:%ddBm vs %1ddBm, diff:%d, %d\r\n", (int)bg_rssi, (int)starting_bg_rssi, (int)diff, cnt);
     if (diff > 10) {
         if (++cnt > 3) {
             /* find better channel */
@@ -110,7 +108,7 @@
 #endif
 
     Radio::LoRaModemConfig(BANDWIDTH_KHZ, LoRaWan::Datarates[LORAMAC_DEFAULT_DATARATE], 1);
-    pc.printf("using sf%u\r\n", LoRaWan::Datarates[LORAMAC_DEFAULT_DATARATE]);
+    pc_printf("using sf%u\r\n", LoRaWan::Datarates[LORAMAC_DEFAULT_DATARATE]);
     Radio::SetPublicNetwork(true);
 
     channel_scan();
@@ -121,26 +119,26 @@
 #if defined SX127x_H
 void printLoraIrqs(bool clear)
 {
-    pc.printf("\r\nIrqFlags:");
+    pc_printf("\r\nIrqFlags:");
     if (Radio::lora.RegIrqFlags.bits.CadDetected)
-        pc.printf("CadDetected ");
+        pc_printf("CadDetected ");
     if (Radio::lora.RegIrqFlags.bits.FhssChangeChannel) {
-        pc.printf("FhssChangeChannel:%d ", Radio::lora.RegHopChannel.bits.FhssPresentChannel);
+        pc_printf("FhssChangeChannel:%d ", Radio::lora.RegHopChannel.bits.FhssPresentChannel);
     }
     if (Radio::lora.RegIrqFlags.bits.CadDone)
-        pc.printf("CadDone ");
+        pc_printf("CadDone ");
     if (Radio::lora.RegIrqFlags.bits.TxDone)
-        pc.printf("TxDone-dio0:%d ", Radio::radio.dio0.read());
+        pc_printf("TxDone-dio0:%d ", Radio::radio.dio0.read());
     if (Radio::lora.RegIrqFlags.bits.ValidHeader)
-        pc.printf("ValidHeader ");
+        pc_printf("ValidHeader ");
     if (Radio::lora.RegIrqFlags.bits.PayloadCrcError)
-        pc.printf("PayloadCrcError ");
+        pc_printf("PayloadCrcError ");
     if (Radio::lora.RegIrqFlags.bits.RxDone)
-        pc.printf("RxDone ");  
+        pc_printf("RxDone ");  
     if (Radio::lora.RegIrqFlags.bits.RxTimeout)
-        pc.printf("RxTimeout ");
+        pc_printf("RxTimeout ");
 
-    pc.printf("\r\n");
+    pc_printf("\r\n");
 
     if (clear)
         Radio::radio.write_reg(REG_LR_IRQFLAGS, Radio::lora.RegIrqFlags.octet);
@@ -150,23 +148,23 @@
 {
     Radio::radio.RegOpMode.octet = Radio::radio.read_reg(REG_OPMODE);
     switch (Radio::radio.RegOpMode.bits.Mode) {
-        case RF_OPMODE_SLEEP: pc.printf("sleep"); break;
-        case RF_OPMODE_STANDBY: pc.printf("stby"); break;
-        case RF_OPMODE_SYNTHESIZER_TX: pc.printf("fstx"); break;
-        case RF_OPMODE_TRANSMITTER: pc.printf("tx"); break;
-        case RF_OPMODE_SYNTHESIZER_RX: pc.printf("fsrx"); break;
-        case RF_OPMODE_RECEIVER: pc.printf("rx"); break;
+        case RF_OPMODE_SLEEP: pc_printf("sleep"); break;
+        case RF_OPMODE_STANDBY: pc_printf("stby"); break;
+        case RF_OPMODE_SYNTHESIZER_TX: pc_printf("fstx"); break;
+        case RF_OPMODE_TRANSMITTER: pc_printf("tx"); break;
+        case RF_OPMODE_SYNTHESIZER_RX: pc_printf("fsrx"); break;
+        case RF_OPMODE_RECEIVER: pc_printf("rx"); break;
         case 6:
             if (Radio::radio.RegOpMode.bits.LongRangeMode)
-                pc.printf("rxs");
+                pc_printf("rxs");
             else
-                pc.printf("-6-");
+                pc_printf("-6-");
             break;  // todo: different lora/fsk
         case 7:
             if (Radio::radio.RegOpMode.bits.LongRangeMode)
-                pc.printf("cad");
+                pc_printf("cad");
             else
-                pc.printf("-7-");
+                pc_printf("-7-");
             break;  // todo: different lora/fsk
     }
 }
@@ -211,20 +209,19 @@
     }
 }
 
-EventQueue queue;
-
+//EventQueue queue;
 
 void send_downlink()
 {
     if (!LoRaWan::flags.do_downlink) {
-        pc.printf("\e[31mno downlink to send\e[0m\r\n");
+        pc_printf("\e[41mno downlink to send\e[0m\r\n");
         return;
     }
 
     LoRaWan::flags.do_downlink = false;
 
     if (LoRaWan::flags.beacon_guard) {
-        pc.printf("\e[33mdownlink during beacon_guard\e[0m\r\n");
+        pc_printf("\e[33mdownlink during beacon_guard\e[0m\r\n");
         return;
     }
 
@@ -238,14 +235,14 @@
 
 uint16_t tim_get_current_slot()
 {
-    us_timestamp_t us_until = beaconAt - send_beaconTimer.read_us();
+    int us_until = beaconAt.time_since_epoch().count() - HighResClock::now().time_since_epoch().count();
     return us_until / 30000;
 }
 
 static void OnRadioRxDone(uint8_t size, float rssi, float snr)
 {
     LoRaWan::rx_slot = tim_get_current_slot();
-    LoRaWan::rx_ms = timer.read_ms();
+    LoRaWan::rx_at = HighResClock::now();
 
     LoRaWan::parse_receive(size, rssi, snr);
 
@@ -255,18 +252,9 @@
     }
 }
 
-
-volatile float prev_beacon_send_at;
-volatile float beacon_send_at;
-
-volatile us_timestamp_t sbAt;
 void
 send_beacon()
 {
-    prev_beacon_send_at = beacon_send_at;
-    beacon_send_at = timer.read();
-    sbAt = send_beaconTimer.read_us();
-
     if (!LoRaWan::flags.beacon_loaded)
         return;
 
@@ -305,6 +293,17 @@
     uint16_t crc;
     Radio::Standby( );
 
+#if defined SX127x_H
+    while(Radio::radio.dio0) {
+        pc_printf("\e[41mmissed-interrupt\e[0m\r\n");
+        Radio::service();
+    }
+#elif defined(SX128x_H)
+    #error todo handle missed interrupt sx1280
+#elif defined(SX126x_H)
+    #error todo handle missed interrupt sx126x
+#endif /* SX127x_H */
+
     if (skip_beacon_cnt > 0) {
         inv_iq = true;
         skip_beacon_cnt--;
@@ -326,31 +325,33 @@
     Radio::radio.tx_buf[5] = crc >> 8;
 
     LoRaWan::flags.beacon_loaded = true;
+
+    beacon_timeout.attach_absolute(send_beacon, beaconAt);
 }
 
 void load_beacon()
 {
     LoRaWan::flags.beacon_guard = true;
-    queue.call_in(200, _load_beacon);
+    beacon_timeout.attach(_load_beacon, 200ms);
 }
 
 void get_time_till_beacon()
 {
     uint16_t slots = tim_get_current_slot();
-    pc.printf("slots:%u\r\n", slots);
+    pc_printf("slots:%u\r\n", slots);
 }
 
 void rx_isr()
 {
     static uint8_t pcbuf_idx = 0;
     static uint8_t prev_len = 0;;
-    char c = pc.getc();
+    char c;
+    pc.read(&c, 1);
 
     if (c == 8) {
         if (pcbuf_idx > 0) {
-            pc.putc(8);
-            pc.putc(' ');
-            pc.putc(8);
+            uint8_t buf[3] = {8, ' ', 8};
+            pc.write(buf, 3);
             pcbuf_idx--;
         }
     } else if (c == 3) {    // ctrl-C
@@ -366,7 +367,7 @@
         }
     } else if (pcbuf_idx < sizeof(pcbuf)) {
         pcbuf[pcbuf_idx++] = c;
-        pc.putc(c);
+        pc.write(&c, 1);
     }
 }
 
@@ -375,7 +376,7 @@
     if (pcbuf[idx] >= '0' && pcbuf[idx] <= '9') {
         sscanf(pcbuf+idx, "%u", &skip_beacon_cnt);
     }
-    pc.printf("skip_beacon_cnt:%u\r\n", skip_beacon_cnt);
+    pc_printf("skip_beacon_cnt:%u\r\n", skip_beacon_cnt);
 }
 
 void cmd_list_motes(uint8_t idx)
@@ -384,7 +385,7 @@
     for (i = 0; i < N_MOTES; i++) {
         if (motes[i].dev_addr != DEVADDR_NONE) {
             LoRaWan::print_octets_rev("", motes[i].dev_eui, LORA_EUI_LENGTH);
-            pc.printf("    %" PRIx32 "\r\n", motes[i].dev_addr);
+            pc_printf("    %" PRIx32 "\r\n", motes[i].dev_addr);
         }
     }
 }
@@ -395,7 +396,7 @@
     uint32_t i;
     uint32_t* ptr;
     sscanf(pcbuf+idx, "%" PRIx32, &i);
-    pc.printf("beacon_payload:%08" PRIx32 "\r\n", i);
+    pc_printf("beacon_payload:%08" PRIx32 "\r\n", i);
     ptr = (uint32_t*)beacon_payload;
     *ptr = i;
 }
@@ -413,14 +414,14 @@
         }
     }
     if (i == N_MOTES) {
-        pc.printf("mote %x not found\r\n", dev_addr);
+        pc_printf("mote %x not found\r\n", dev_addr);
         return;
     }
     mote = &motes[i];
 
     while (pcbuf[idx] != ' ') {
         if (pcbuf[++idx] == 0) {
-            pc.printf("hit end\r\n");
+            pc_printf("hit end\r\n");
             return;
         }
     }
@@ -434,19 +435,19 @@
         idx += 2;
     }
 
-    pc.printf("%u bytes scheduled for %" PRIx32 "\r\n", mote->user_downlink_length, mote->dev_addr);
+    pc_printf("%u bytes scheduled for %" PRIx32 "\r\n", mote->user_downlink_length, mote->dev_addr);
 }
 
 #if 0
 void cmd_rx_restart(uint8_t idx)
 {
     /*radio.set_opmode(RF_OPMODE_STANDBY);
-    pc.printf("standby\r\n");*/
+    pc_printf("standby\r\n");*/
     radio.set_opmode(RF_OPMODE_SLEEP);
-    pc.printf("sleep\r\n");
+    pc_printf("sleep\r\n");
     wait(0.05);
     radio.set_opmode(RF_OPMODE_RECEIVER);
-    pc.printf("receive\r\n");
+    pc_printf("receive\r\n");
 }
 #endif /* if 0 */
 
@@ -456,7 +457,7 @@
     sscanf(pcbuf+idx, "%d", &gpo);
     beacon_payload[0] = CMD_GPIO_OUT;
     beacon_payload[1] = gpo;   
-    pc.printf("beacon gpo: %d\r\n", gpo);
+    pc_printf("beacon gpo: %d\r\n", gpo);
 }
 
 void cmd_beacon_rgb(uint8_t idx)
@@ -467,7 +468,7 @@
     beacon_payload[1] = r;
     beacon_payload[2] = g;
     beacon_payload[3] = b;
-    pc.printf("beacon rgb: %d %d %d\r\n", r, g, b);
+    pc_printf("beacon rgb: %d %d %d\r\n", r, g, b);
 }
 
 void cmd_downlink_rgb(uint8_t idx)
@@ -482,7 +483,7 @@
         }
     }
     if (i == N_MOTES) {
-        pc.printf("mote %x not found\r\n", dev_addr);
+        pc_printf("mote %x not found\r\n", dev_addr);
         return;
     }
     mote = &motes[i];
@@ -493,7 +494,7 @@
     LoRaWan::user_downlink[mote->user_downlink_length++] = g;
     LoRaWan::user_downlink[mote->user_downlink_length++] = b;
     
-    pc.printf("rgb %d %d %d to mote %" PRIx32 "\r\n", r, g, b, mote->dev_addr);
+    pc_printf("rgb %d %d %d to mote %" PRIx32 "\r\n", r, g, b, mote->dev_addr);
 }
 
 void cmd_downlink_gpo(uint8_t idx)
@@ -508,7 +509,7 @@
         }
     }
     if (i == N_MOTES) {
-        pc.printf("mote %x not found\r\n", dev_addr);
+        pc_printf("mote %x not found\r\n", dev_addr);
         return;
     }
     mote = &motes[i];
@@ -517,81 +518,81 @@
     LoRaWan::user_downlink[mote->user_downlink_length++] = CMD_GPIO_OUT;
     LoRaWan::user_downlink[mote->user_downlink_length++] = gpo;
     
-    pc.printf("gpo %d to mote %" PRIx32 "\r\n", gpo, mote->dev_addr);    
+    pc_printf("gpo %d to mote %" PRIx32 "\r\n", gpo, mote->dev_addr);    
 }
 
 void cmd_status(uint8_t idx)
 {
-    pc.printf(" %uHz do_downlink:%u, ", usingChHz, LoRaWan::flags.do_downlink);
-    pc.printf("rssi:%f\r\n", Radio::GetRssiInst());
-    pc.printf("\r\nskip_beacon_cnt:%u, curSlot:%u\r\n", skip_beacon_cnt, tim_get_current_slot());
+    pc_printf(" %uHz do_downlink:%u, ", usingChHz, LoRaWan::flags.do_downlink);
+    pc_printf("rssi:%f\r\n", Radio::GetRssiInst());
+    pc_printf("\r\nskip_beacon_cnt:%u, curSlot:%u\r\n", skip_beacon_cnt, tim_get_current_slot());
 #ifdef SX128x_H
     status_t status;
     Radio::radio.xfer(OPCODE_GET_STATUS, 0, 1, &status.octet);
     switch (status.bits.cmdStatus) {
-        case 1: pc.printf("success"); break;
-        case 2: pc.printf("dataAvail"); break;
-        case 3: pc.printf("cmdTimeout"); break;
-        case 4: pc.printf("cmdErr"); break;
-        case 5: pc.printf("exeFail"); break;
-        case 6: pc.printf("txdone"); break;
-        default: pc.printf("cmdStatus:<%u>", status.bits.cmdStatus); break;
+        case 1: pc_printf("success"); break;
+        case 2: pc_printf("dataAvail"); break;
+        case 3: pc_printf("cmdTimeout"); break;
+        case 4: pc_printf("cmdErr"); break;
+        case 5: pc_printf("exeFail"); break;
+        case 6: pc_printf("txdone"); break;
+        default: pc_printf("cmdStatus:<%u>", status.bits.cmdStatus); break;
     }
-    pc.printf(" ");
+    pc_printf(" ");
     switch (status.bits.chipMode) {
-        case 2: pc.printf("stdby_rc"); break;
-        case 3: pc.printf("stdby_xosc"); break;
-        case 4: pc.printf("fs"); break;
-        case 5: pc.printf("\e[32mrx\e[0m"); break;
-        case 6: pc.printf("\e[31mtx\e[0m"); break;
-        default: pc.printf("chipMode:<%u>", status.bits.chipMode); break;
+        case 2: pc_printf("stdby_rc"); break;
+        case 3: pc_printf("stdby_xosc"); break;
+        case 4: pc_printf("fs"); break;
+        case 5: pc_printf("\e[32mrx\e[0m"); break;
+        case 6: pc_printf("\e[31mtx\e[0m"); break;
+        default: pc_printf("chipMode:<%u>", status.bits.chipMode); break;
     }
     LoRaPktPar0_t LoRaPktPar0; 
     LoRaPktPar0.octet = Radio::radio.readReg(REG_ADDR_LORA_PKTPAR0, 1);
-    pc.printf(" bw:%u sf%u ", LoRaPktPar0.bits.modem_bw, LoRaPktPar0.bits.modem_sf);
-    pc.printf("loraSync:%04x\r\n", Radio::radio.readReg(REG_ADDR_LORA_SYNC, 2));
+    pc_printf(" bw:%u sf%u ", LoRaPktPar0.bits.modem_bw, LoRaPktPar0.bits.modem_sf);
+    pc_printf("loraSync:%04x\r\n", Radio::radio.readReg(REG_ADDR_LORA_SYNC, 2));
 #elif defined SX126x_H
     status_t status;
     Radio::radio.xfer(OPCODE_GET_STATUS, 0, 1, &status.octet);
     switch (status.bits.chipMode) {
-        case 2: pc.printf("STBY_RC"); break;
-        case 3: pc.printf("STBY_XOSC"); break;
-        case 4: pc.printf("FS"); break;
-        case 5: pc.printf("\e[32mRX\e[0m"); break;
-        case 6: pc.printf("\e[31mTX\e[0m"); break;
-        default: pc.printf("%u", status.bits.chipMode); break;
+        case 2: pc_printf("STBY_RC"); break;
+        case 3: pc_printf("STBY_XOSC"); break;
+        case 4: pc_printf("FS"); break;
+        case 5: pc_printf("\e[32mRX\e[0m"); break;
+        case 6: pc_printf("\e[31mTX\e[0m"); break;
+        default: pc_printf("%u", status.bits.chipMode); break;
     }
-    pc.printf(" ");
+    pc_printf(" ");
     switch (status.bits.cmdStatus) {
-        case 1: pc.printf("rfu"); break;
-        case 2: pc.printf("dataAvail"); break;
-        case 3: pc.printf("timeout"); break;
-        case 4: pc.printf("err"); break;
-        case 5: pc.printf("fail"); break;
-        case 6: pc.printf("txdone"); break;
-        default: pc.printf("%u", status.bits.cmdStatus); break;
+        case 1: pc_printf("rfu"); break;
+        case 2: pc_printf("dataAvail"); break;
+        case 3: pc_printf("timeout"); break;
+        case 4: pc_printf("err"); break;
+        case 5: pc_printf("fail"); break;
+        case 6: pc_printf("txdone"); break;
+        default: pc_printf("%u", status.bits.cmdStatus); break;
     }
     loraConfig0_t conf0;
     conf0.octet = Radio::radio.readReg(REG_ADDR_LORA_CONFIG0, 1);
     // bw7=125 bw8=250 b9=500
-    pc.printf(" bw:%u sf%u\r\n", conf0.bits.modem_bw, conf0.bits.modem_sf);
+    pc_printf(" bw:%u sf%u\r\n", conf0.bits.modem_bw, conf0.bits.modem_sf);
     loraConfig1_t conf1;
     conf1.octet = Radio::radio.readReg(REG_ADDR_LORA_CONFIG1, 1);
-    pc.printf("inviq:%u cr%u\r\n", conf1.bits.rx_invert_iq, conf1.bits.tx_coding_rate);
-    pc.printf("loraSync:%04x\r\n", Radio::radio.readReg(REG_ADDR_LORA_SYNC, 2));
+    pc_printf("inviq:%u cr%u\r\n", conf1.bits.rx_invert_iq, conf1.bits.tx_coding_rate);
+    pc_printf("loraSync:%04x\r\n", Radio::radio.readReg(REG_ADDR_LORA_SYNC, 2));
 #elif defined SX127x_H
     Radio::radio.RegPaConfig.octet = Radio::radio.read_reg(REG_PACONFIG);
     if (Radio::radio.RegPaConfig.bits.PaSelect)
-        pc.printf("PA_BOOST ");
+        pc_printf("PA_BOOST ");
     else
-        pc.printf("RFO ");
+        pc_printf("RFO ");
 
     Radio::radio.RegOpMode.octet = Radio::radio.read_reg(REG_OPMODE);
-    pc.printf("%.3fMHz sf%ubw%u ", Radio::radio.get_frf_MHz(), Radio::lora.getSf(), Radio::lora.getBw());
-    pc.printf("dio0pin:%u ", Radio::radio.dio0.read());
+    pc_printf("%.3fMHz sf%ubw%u ", Radio::radio.get_frf_MHz(), Radio::lora.getSf(), Radio::lora.getBw());
+    pc_printf("dio0pin:%u ", Radio::radio.dio0.read());
     printOpMode();
     if (!Radio::radio.RegOpMode.bits.LongRangeMode) {
-        pc.printf("FSK\r\n");
+        pc_printf("FSK\r\n");
         return;
     }
 
@@ -600,10 +601,10 @@
 
     Radio::lora.RegTest33.octet = Radio::radio.read_reg(REG_LR_TEST33);     // invert_i_q
     Radio::lora.RegDriftInvert.octet = Radio::radio.read_reg(REG_LR_DRIFT_INVERT);
-    pc.printf("modemstat:%02x, rxinv:%x,%x\r\n", Radio::radio.read_reg(REG_LR_MODEMSTAT), Radio::lora.RegTest33.octet, Radio::lora.RegDriftInvert.octet);
+    pc_printf("modemstat:%02x, rxinv:%x,%x\r\n", Radio::radio.read_reg(REG_LR_MODEMSTAT), Radio::lora.RegTest33.octet, Radio::lora.RegDriftInvert.octet);
     Radio::radio.RegDioMapping1.octet = Radio::radio.read_reg(REG_DIOMAPPING1);
-    pc.printf("\r\nskip_beacon_cnt:%u, currently:%u dio0map:%u\r\n", skip_beacon_cnt, tim_get_current_slot(), Radio::radio.RegDioMapping1.bits.Dio0Mapping);
-    pc.printf("FIfoAddrPtr:%02x RxBase:%02x\r\n", Radio::radio.read_reg(REG_LR_FIFOADDRPTR), Radio::radio.read_reg(REG_LR_FIFORXBASEADDR));
+    pc_printf("\r\nskip_beacon_cnt:%u, currently:%u dio0map:%u\r\n", skip_beacon_cnt, tim_get_current_slot(), Radio::radio.RegDioMapping1.bits.Dio0Mapping);
+    pc_printf("FIfoAddrPtr:%02x RxBase:%02x\r\n", Radio::radio.read_reg(REG_LR_FIFOADDRPTR), Radio::radio.read_reg(REG_LR_FIFORXBASEADDR));
 #endif
 }
 
@@ -611,9 +612,9 @@
 {
     if (sscanf(pcbuf+idx, "%lx", &LoRaWan::dev_addr_filter) != 1) {
         LoRaWan::dev_addr_filter = 0;
-        pc.printf("filter off\r\n");
+        pc_printf("filter off\r\n");
     } else
-        pc.printf("filtering %lx\r\n", LoRaWan::dev_addr_filter);
+        pc_printf("filtering %lx\r\n", LoRaWan::dev_addr_filter);
 }
 
 void cmd_op(uint8_t idx)
@@ -621,7 +622,7 @@
     int dbm;
     if (sscanf(pcbuf+idx, "%d", &dbm) == 1) {
         Radio::set_tx_dbm(dbm);
-        pc.printf("OutputPower:%ddBm\r\n", dbm);
+        pc_printf("OutputPower:%ddBm\r\n", dbm);
     }
 }
 
@@ -631,16 +632,16 @@
     radio.RegPaConfig.bits.PaSelect ^= 1;
     radio.write_reg(REG_PACONFIG, radio.RegPaConfig.octet);
     if (radio.RegPaConfig.bits.PaSelect)
-        pc.printf("PA_BOOST\r\n");
+        pc_printf("PA_BOOST\r\n");
     else
-        pc.printf("RFO\r\n");
+        pc_printf("RFO\r\n");
 }
 #endif /* TYPE_ABZ */
 
 void cmd_set_time(uint8_t idx)
 {
     set_time(0);
-    pc.printf("time:%" PRIu32 "\r\n", time(NULL));
+    pc_printf("time:%" PRIu32 "\r\n", time(NULL));
 }
 
 
@@ -651,7 +652,7 @@
     unsigned dev_addr, p, d;
 
     if (sscanf(pcbuf+idx, "%x %u %u", &dev_addr, &p, &d) != 3) {
-        pc.printf("parse fail\r\n");
+        pc_printf("parse fail\r\n");
         return;
     }
     for (i = 0; i < N_MOTES; i++) {
@@ -660,7 +661,7 @@
         }
     }
     if (i == N_MOTES) {
-        pc.printf("mote %x not found\r\n", dev_addr);
+        pc_printf("mote %x not found\r\n", dev_addr);
         return;
     }
 
@@ -671,14 +672,14 @@
     LoRaWan::user_downlink[mote->user_downlink_length++] = p;
     LoRaWan::user_downlink[mote->user_downlink_length++] = d;
     
-    pc.printf("period:%u duty:%u to mote %" PRIx32 "\r\n", p, d, mote->dev_addr);
+    pc_printf("period:%u duty:%u to mote %" PRIx32 "\r\n", p, d, mote->dev_addr);
 }
 
 void cmd_beacon_pwm(uint8_t idx)
 {
     unsigned p, d;
     if (sscanf(pcbuf+idx, "%u %u", &p, &d) != 2) {
-        pc.printf("parse fail\r\n");
+        pc_printf("parse fail\r\n");
         return;
     }
 
@@ -686,7 +687,7 @@
     beacon_payload[1] = p;
     beacon_payload[2] = d;
     
-    pc.printf("period:%u duty:%u\r\n", p, d);
+    pc_printf("period:%u duty:%u\r\n", p, d);
 }
 
 void cmd_endnode_txp(uint8_t idx)
@@ -696,7 +697,7 @@
     unsigned dev_addr, txi;
 
     if (sscanf(pcbuf+idx, "%x %u", &dev_addr, &txi) != 2) {
-        pc.printf("parse fail\r\n");
+        pc_printf("parse fail\r\n");
         return;
     }
     for (i = 0; i < N_MOTES; i++) {
@@ -705,7 +706,7 @@
         }
     }
     if (i == N_MOTES) {
-        pc.printf("mote %x not found\r\n", dev_addr);
+        pc_printf("mote %x not found\r\n", dev_addr);
         return;
     }
 
@@ -715,40 +716,40 @@
     LoRaWan::user_downlink[mote->user_downlink_length++] = CMD_TX_POWER;
     LoRaWan::user_downlink[mote->user_downlink_length++] = txi;
     
-    pc.printf("txp index %u to mote %" PRIx32 "\r\n", txi, mote->dev_addr);
+    pc_printf("txp index %u to mote %" PRIx32 "\r\n", txi, mote->dev_addr);
 }
 
 void cmd_hide_mac(uint8_t idx)
 {
     LoRaWan::flags.show_mac = 0;
-    pc.printf("!show_mac\r\n");
+    pc_printf("!show_mac\r\n");
 }
 
 void cmd_hide_payload(uint8_t idx)
 {
     LoRaWan::flags.show_app = 0;
-    pc.printf("!show_app\r\n");
+    pc_printf("!show_app\r\n");
 }
 
 void cmd_show_all(uint8_t idx)
 {
     LoRaWan::flags.show_mac = 1;
     LoRaWan::flags.show_app = 1;
-    pc.printf("show-all\r\n");
+    pc_printf("show-all\r\n");
 }
 
 void cmd_beacon_endnode_txp(uint8_t idx)
 {
     unsigned txi;
     if (sscanf(pcbuf+idx, "%u", &txi) != 1) {
-        pc.printf("parse fail\r\n");
+        pc_printf("parse fail\r\n");
         return;
     }
 
     beacon_payload[0] = CMD_TX_POWER;
     beacon_payload[1] = txi;
     
-    pc.printf("txp index:%u\r\n", txi);
+    pc_printf("txp index:%u\r\n", txi);
 }
 
 void cmd_help(uint8_t);
@@ -794,7 +795,7 @@
     int i;
     
     for (i = 0; menu_items[i].cmd != NULL ; i++) {
-        pc.printf("%s%s\t%s\r\n", menu_items[i].cmd, menu_items[i].arg_descr, menu_items[i].description);
+        pc_printf("%s%s\t%s\r\n", menu_items[i].cmd, menu_items[i].arg_descr, menu_items[i].description);
     }
     
 }
@@ -806,13 +807,13 @@
     uint8_t user_cmd_len;
     
     if (pcbuf_len < 0) {    // ctrl-C
-        //pc.printf("abort\r\n");
+        //pc_printf("abort\r\n");
         return;
     }
     if (pcbuf_len == 0)
         return;
         
-    pc.printf("\r\n");
+    pc_printf("\r\n");
         
     /* get end of user-entered command */
     user_cmd_len = 1;   // first character can be any character
@@ -835,7 +836,7 @@
     }
    
     pcbuf_len = 0;
-    pc.printf("> ");
+    pc_printf("> ");
     fflush(stdout); 
 }
 
@@ -855,17 +856,15 @@
         measure_ambient();
         LoRaWan::flags.beacon_guard = false;
 
-        beaconAt += BEACON_INTERVAL_SECONDS_us;
-        load_beaconTimer.attach_us(load_beacon, beaconAt - BEACON_PRELOAD_us);
-        send_beaconTimer.attach_us(send_beacon, beaconAt);
+        beaconAt += BEACON_INTERVAL_s;
+        beacon_timeout.attach_absolute(load_beacon, beaconAt - BEACON_PRELOAD_us);
     }
 }
 
 void tim_init()
 {
-    beaconAt = send_beaconTimer.read_us() + BEACON_INTERVAL_SECONDS_us;
-    load_beaconTimer.attach_us(load_beacon, beaconAt - BEACON_PRELOAD_us);
-    send_beaconTimer.attach_us(send_beacon, beaconAt);
+    beaconAt = HighResClock::now() + BEACON_INTERVAL_s;
+    beacon_timeout.attach_absolute(load_beacon, beaconAt - BEACON_PRELOAD_us);
 }
 
 
@@ -885,7 +884,7 @@
 {
     Thread eventThread;
     pc.baud(115200);
-    pc.printf("\r\nreset\r\n");
+    pc_printf("\r\nreset\r\n");
     set_time(0);
 
     Radio::Init(&rev);
@@ -893,26 +892,24 @@
     init_radio();
 
     {
-        us_timestamp_t txStartAt;
+        long txStartAt;
         _load_beacon();
         send_beacon();
-        txStartAt = Radio::lpt.read_us();
+        txStartAt = HighResClock::now().time_since_epoch().count();
         LoRaWan::flags.beacon_test = 1;
         while (LoRaWan::flags.beacon_test)
             Radio::service();
 
-        LoRaWan::beaconDur = Radio::irqAt - txStartAt;
-        pc.printf("beaconDur:%u, 0x%x\r\n", LoRaWan::beaconDur, LoRaWan::beaconDur);
+        LoRaWan::beaconDur = HighResClock::now().time_since_epoch().count() - txStartAt;
+        pc_printf("beaconDur:%u, 0x%x\r\n", LoRaWan::beaconDur, LoRaWan::beaconDur);
     }
 
            //    preambleLen, fixLen, crcOn, invIQ
     Radio::LoRaPacketConfig(PREAMBLE_SYMBS, false, true, false);
     Radio::Rx(0);
 
-    eventThread.start(callback(&queue, &EventQueue::dispatch_forever));
     LoRaWan::init();
 
-    timer.start();
     tim_init();
     
     pc.attach(&rx_isr);
diff -r dd3023aac3b1 -r 801d4bd6dccc mbed-os.lib
--- a/mbed-os.lib	Thu Dec 13 16:53:37 2018 -0800
+++ b/mbed-os.lib	Tue Jul 14 11:08:24 2020 -0700
@@ -1,1 +1,1 @@
-https://github.com/ARMmbed/mbed-os/#2fd0c5cfbd83fce62da6308f9d64c0ab64e1f0d6
+https://github.com/ARMmbed/mbed-os/#4a0aaf1ce7b940bfa813a748fb2ef3d9f461607e
diff -r dd3023aac3b1 -r 801d4bd6dccc sx12xx_hal.lib
--- a/sx12xx_hal.lib	Thu Dec 13 16:53:37 2018 -0800
+++ b/sx12xx_hal.lib	Tue Jul 14 11:08:24 2020 -0700
@@ -1,1 +1,1 @@
-https://os.mbed.com/users/dudmuck/code/sx12xx_hal/#0518c6e68b79
+https://os.mbed.com/users/dudmuck/code/sx12xx_hal/#75635d50262e