From 1fe8bf692c8ae1169977267d2f7316ba5c4f979c Mon Sep 17 00:00:00 2001 From: Manuel Bleichenbacher Date: Tue, 2 Oct 2018 23:08:38 +0200 Subject: [PATCH] Use mcci-catena/arduino-lmic as the base library --- esp_idf_lmic_config.h | 61 ++ src/TheThingsNetwork.cpp | 5 +- src/aes/{aes.c => lmic_aes.c} | 336 +++---- src/hal/hal_esp32.c | 7 +- src/hal/hal_esp32.h | 1 + src/lmic/config.h | 210 +++-- src/lmic/hal.h | 30 +- src/lmic/lmic.c | 1215 +++++++++----------------- src/lmic/lmic.h | 144 ++- src/lmic/lmic_as923.c | 364 ++++++++ src/lmic/lmic_au921.c | 216 +++++ src/lmic/lmic_bandplan.h | 175 ++++ src/lmic/lmic_bandplan_as923.h | 115 +++ src/lmic/lmic_bandplan_au921.h | 63 ++ src/lmic/lmic_bandplan_eu868.h | 92 ++ src/lmic/lmic_bandplan_in866.h | 85 ++ src/lmic/lmic_bandplan_us915.h | 62 ++ src/lmic/lmic_config_preconditions.h | 181 ++++ src/lmic/lmic_eu868.c | 233 +++++ src/lmic/lmic_eu_like.c | 159 ++++ src/lmic/lmic_eu_like.h | 98 +++ src/lmic/lmic_in866.c | 205 +++++ src/lmic/lmic_us915.c | 209 +++++ src/lmic/lmic_us_like.c | 257 ++++++ src/lmic/lmic_us_like.h | 100 +++ src/lmic/lmic_util.c | 335 +++++++ src/lmic/lmic_util.h | 34 + src/lmic/lorabase.h | 474 +++++++--- src/lmic/lorabase_as923.h | 96 ++ src/lmic/lorabase_au921.h | 84 ++ src/lmic/lorabase_eu868.h | 92 ++ src/lmic/lorabase_in866.h | 78 ++ src/lmic/lorabase_us915.h | 84 ++ src/lmic/oslmic.c | 64 +- src/lmic/oslmic.h | 102 ++- src/lmic/radio.c | 330 +++++-- 36 files changed, 5095 insertions(+), 1301 deletions(-) create mode 100755 esp_idf_lmic_config.h rename src/aes/{aes.c => lmic_aes.c} (72%) mode change 100644 => 100755 src/lmic/config.h create mode 100755 src/lmic/lmic_as923.c create mode 100755 src/lmic/lmic_au921.c create mode 100755 src/lmic/lmic_bandplan.h create mode 100755 src/lmic/lmic_bandplan_as923.h create mode 100755 src/lmic/lmic_bandplan_au921.h create mode 100755 src/lmic/lmic_bandplan_eu868.h create mode 100755 src/lmic/lmic_bandplan_in866.h create mode 100755 src/lmic/lmic_bandplan_us915.h create mode 100755 src/lmic/lmic_config_preconditions.h create mode 100755 src/lmic/lmic_eu868.c create mode 100755 src/lmic/lmic_eu_like.c create mode 100755 src/lmic/lmic_eu_like.h create mode 100755 src/lmic/lmic_in866.c create mode 100755 src/lmic/lmic_us915.c create mode 100755 src/lmic/lmic_us_like.c create mode 100755 src/lmic/lmic_us_like.h create mode 100755 src/lmic/lmic_util.c create mode 100755 src/lmic/lmic_util.h create mode 100755 src/lmic/lorabase_as923.h create mode 100755 src/lmic/lorabase_au921.h create mode 100755 src/lmic/lorabase_eu868.h create mode 100755 src/lmic/lorabase_in866.h create mode 100755 src/lmic/lorabase_us915.h diff --git a/esp_idf_lmic_config.h b/esp_idf_lmic_config.h new file mode 100755 index 0000000..ccb5510 --- /dev/null +++ b/esp_idf_lmic_config.h @@ -0,0 +1,61 @@ +/******************************************************************************* + * + * ttn-esp32 - The Things Network device library for ESP-IDF / SX127x + * + * Copyright (c) 2018 Manuel Bleichenbacher + * + * Licensed under MIT License + * https://opensource.org/licenses/MIT + * + * Convert SDK configuration (make menuconfig) into LMIC configuration. + *******************************************************************************/ + +#include "sdkconfig.h" + +#if defined(CONFIG_TTN_LORA_FREQ_EU_868) +#define CFG_eu868 1 +#elif defined(CONFIG_TTN_LORA_FREQ_US_915) +#define CFG_us915 1 +#else +#define TTN_IS_DISABLED 1 +#define CFG_eu868 1 +#endif + +#if defined(CONFIG_TTN_RADIO_SX1272_73) +#define CFG_sx1272_radio 1 +#elif defined(CONFIG_TTN_RADIO_SX1276_77_78_79) +#define CFG_sx1276_radio 1 +#else +#error TTN LoRa radio chip must be configured using 'make menuconfig' +#endif + +#if defined(CONFIG_TTN_TIMER_0_GROUP_0) +#define TTN_TIMER TIMER_0 +#define TTN_TIMER_GROUP TIMER_GROUP_0 +#define TTN_CLEAR_TIMER_ALARM TIMERG0.int_clr_timers.t0 = 1 +#elif defined(CONFIG_TTN_TIMER_1_GROUP_0) +#define TTN_TIMER TIMER_1 +#define TTN_TIMER_GROUP TIMER_GROUP_0 +#define TTN_CLEAR_TIMER_ALARM TIMERG0.int_clr_timers.t1 = 1 +#elif defined(CONFIG_TTN_TIMER_0_GROUP_1) +#define TTN_TIMER TIMER_0 +#define TTN_TIMER_GROUP TIMER_GROUP_1 +#define TTN_CLEAR_TIMER_ALARM TIMERG1.int_clr_timers.t0 = 1 +#elif defined(CONFIG_TTN_TIMER_1_GROUP_1) +#define TTN_TIMER TIMER_1 +#define TTN_TIMER_GROUP TIMER_GROUP_1 +#define TTN_CLEAR_TIMER_ALARM TIMERG1.int_clr_timers.t1 = 1 +#else +#error TTN timer must be configured using 'make menuconfig' +#endif + +// 16 μs per tick +// LMIC requires ticks to be 15.5μs - 100 μs long +#define US_PER_OSTICK 16 +#define OSTICKS_PER_SEC (1000000 / US_PER_OSTICK) + +#define USE_ORIGINAL_AES + +#if LMIC_DEBUG_LEVEL > 0 || LMIC_X_DEBUG_LEVEL > 0 +#include +#endif \ No newline at end of file diff --git a/src/TheThingsNetwork.cpp b/src/TheThingsNetwork.cpp index b42fa37..f7cfe8c 100644 --- a/src/TheThingsNetwork.cpp +++ b/src/TheThingsNetwork.cpp @@ -14,8 +14,6 @@ #include "esp_event.h" #include "esp_log.h" #include "TheThingsNetwork.h" -#include "lmic/config.h" -#include "lmic/hal.h" #include "hal/hal_esp32.h" #include "lmic/lmic.h" #include "provisioning.h" @@ -218,7 +216,8 @@ static const char *eventNames[] = { "EV_BEACON_MISSED", "EV_BEACON_TRACKED", "EV_JOINING", "EV_JOINED", "EV_RFU1", "EV_JOIN_FAILED", "EV_REJOIN_FAILED", "EV_TXCOMPLETE", "EV_LOST_TSYNC", "EV_RESET", - "EV_RXCOMPLETE", "EV_LINK_DEAD", "EV_LINK_ALIVE" + "EV_RXCOMPLETE", "EV_LINK_DEAD", "EV_LINK_ALIVE", "EV_SCAN_FOUND", + "EV_TXSTART" }; #endif diff --git a/src/aes/aes.c b/src/aes/lmic_aes.c similarity index 72% rename from src/aes/aes.c rename to src/aes/lmic_aes.c index 2d19af6..40eb516 100755 --- a/src/aes/aes.c +++ b/src/aes/lmic_aes.c @@ -27,170 +27,172 @@ #include "../lmic/oslmic.h" +#if defined(USE_ORIGINAL_AES) + #define AES_MICSUB 0x30 // internal use only -static const u4_t AES_RCON[10] = { - 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, +static CONST_TABLE(u4_t, AES_RCON)[10] = { + 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000 }; -static const u1_t AES_S[256] = { - 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, - 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, - 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, - 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, - 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, - 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, - 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, - 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, - 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, - 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, - 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, - 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, - 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, - 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, - 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, +static CONST_TABLE(u1_t, AES_S)[256] = { + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16, }; -static const u4_t AES_E1[256] = { - 0xC66363A5, 0xF87C7C84, 0xEE777799, 0xF67B7B8D, 0xFFF2F20D, 0xD66B6BBD, 0xDE6F6FB1, 0x91C5C554, - 0x60303050, 0x02010103, 0xCE6767A9, 0x562B2B7D, 0xE7FEFE19, 0xB5D7D762, 0x4DABABE6, 0xEC76769A, - 0x8FCACA45, 0x1F82829D, 0x89C9C940, 0xFA7D7D87, 0xEFFAFA15, 0xB25959EB, 0x8E4747C9, 0xFBF0F00B, - 0x41ADADEC, 0xB3D4D467, 0x5FA2A2FD, 0x45AFAFEA, 0x239C9CBF, 0x53A4A4F7, 0xE4727296, 0x9BC0C05B, - 0x75B7B7C2, 0xE1FDFD1C, 0x3D9393AE, 0x4C26266A, 0x6C36365A, 0x7E3F3F41, 0xF5F7F702, 0x83CCCC4F, - 0x6834345C, 0x51A5A5F4, 0xD1E5E534, 0xF9F1F108, 0xE2717193, 0xABD8D873, 0x62313153, 0x2A15153F, - 0x0804040C, 0x95C7C752, 0x46232365, 0x9DC3C35E, 0x30181828, 0x379696A1, 0x0A05050F, 0x2F9A9AB5, - 0x0E070709, 0x24121236, 0x1B80809B, 0xDFE2E23D, 0xCDEBEB26, 0x4E272769, 0x7FB2B2CD, 0xEA75759F, - 0x1209091B, 0x1D83839E, 0x582C2C74, 0x341A1A2E, 0x361B1B2D, 0xDC6E6EB2, 0xB45A5AEE, 0x5BA0A0FB, - 0xA45252F6, 0x763B3B4D, 0xB7D6D661, 0x7DB3B3CE, 0x5229297B, 0xDDE3E33E, 0x5E2F2F71, 0x13848497, - 0xA65353F5, 0xB9D1D168, 0x00000000, 0xC1EDED2C, 0x40202060, 0xE3FCFC1F, 0x79B1B1C8, 0xB65B5BED, - 0xD46A6ABE, 0x8DCBCB46, 0x67BEBED9, 0x7239394B, 0x944A4ADE, 0x984C4CD4, 0xB05858E8, 0x85CFCF4A, - 0xBBD0D06B, 0xC5EFEF2A, 0x4FAAAAE5, 0xEDFBFB16, 0x864343C5, 0x9A4D4DD7, 0x66333355, 0x11858594, - 0x8A4545CF, 0xE9F9F910, 0x04020206, 0xFE7F7F81, 0xA05050F0, 0x783C3C44, 0x259F9FBA, 0x4BA8A8E3, - 0xA25151F3, 0x5DA3A3FE, 0x804040C0, 0x058F8F8A, 0x3F9292AD, 0x219D9DBC, 0x70383848, 0xF1F5F504, - 0x63BCBCDF, 0x77B6B6C1, 0xAFDADA75, 0x42212163, 0x20101030, 0xE5FFFF1A, 0xFDF3F30E, 0xBFD2D26D, - 0x81CDCD4C, 0x180C0C14, 0x26131335, 0xC3ECEC2F, 0xBE5F5FE1, 0x359797A2, 0x884444CC, 0x2E171739, - 0x93C4C457, 0x55A7A7F2, 0xFC7E7E82, 0x7A3D3D47, 0xC86464AC, 0xBA5D5DE7, 0x3219192B, 0xE6737395, - 0xC06060A0, 0x19818198, 0x9E4F4FD1, 0xA3DCDC7F, 0x44222266, 0x542A2A7E, 0x3B9090AB, 0x0B888883, - 0x8C4646CA, 0xC7EEEE29, 0x6BB8B8D3, 0x2814143C, 0xA7DEDE79, 0xBC5E5EE2, 0x160B0B1D, 0xADDBDB76, - 0xDBE0E03B, 0x64323256, 0x743A3A4E, 0x140A0A1E, 0x924949DB, 0x0C06060A, 0x4824246C, 0xB85C5CE4, - 0x9FC2C25D, 0xBDD3D36E, 0x43ACACEF, 0xC46262A6, 0x399191A8, 0x319595A4, 0xD3E4E437, 0xF279798B, - 0xD5E7E732, 0x8BC8C843, 0x6E373759, 0xDA6D6DB7, 0x018D8D8C, 0xB1D5D564, 0x9C4E4ED2, 0x49A9A9E0, - 0xD86C6CB4, 0xAC5656FA, 0xF3F4F407, 0xCFEAEA25, 0xCA6565AF, 0xF47A7A8E, 0x47AEAEE9, 0x10080818, - 0x6FBABAD5, 0xF0787888, 0x4A25256F, 0x5C2E2E72, 0x381C1C24, 0x57A6A6F1, 0x73B4B4C7, 0x97C6C651, - 0xCBE8E823, 0xA1DDDD7C, 0xE874749C, 0x3E1F1F21, 0x964B4BDD, 0x61BDBDDC, 0x0D8B8B86, 0x0F8A8A85, - 0xE0707090, 0x7C3E3E42, 0x71B5B5C4, 0xCC6666AA, 0x904848D8, 0x06030305, 0xF7F6F601, 0x1C0E0E12, - 0xC26161A3, 0x6A35355F, 0xAE5757F9, 0x69B9B9D0, 0x17868691, 0x99C1C158, 0x3A1D1D27, 0x279E9EB9, - 0xD9E1E138, 0xEBF8F813, 0x2B9898B3, 0x22111133, 0xD26969BB, 0xA9D9D970, 0x078E8E89, 0x339494A7, - 0x2D9B9BB6, 0x3C1E1E22, 0x15878792, 0xC9E9E920, 0x87CECE49, 0xAA5555FF, 0x50282878, 0xA5DFDF7A, - 0x038C8C8F, 0x59A1A1F8, 0x09898980, 0x1A0D0D17, 0x65BFBFDA, 0xD7E6E631, 0x844242C6, 0xD06868B8, - 0x824141C3, 0x299999B0, 0x5A2D2D77, 0x1E0F0F11, 0x7BB0B0CB, 0xA85454FC, 0x6DBBBBD6, 0x2C16163A, +static CONST_TABLE(u4_t, AES_E1)[256] = { + 0xC66363A5, 0xF87C7C84, 0xEE777799, 0xF67B7B8D, 0xFFF2F20D, 0xD66B6BBD, 0xDE6F6FB1, 0x91C5C554, + 0x60303050, 0x02010103, 0xCE6767A9, 0x562B2B7D, 0xE7FEFE19, 0xB5D7D762, 0x4DABABE6, 0xEC76769A, + 0x8FCACA45, 0x1F82829D, 0x89C9C940, 0xFA7D7D87, 0xEFFAFA15, 0xB25959EB, 0x8E4747C9, 0xFBF0F00B, + 0x41ADADEC, 0xB3D4D467, 0x5FA2A2FD, 0x45AFAFEA, 0x239C9CBF, 0x53A4A4F7, 0xE4727296, 0x9BC0C05B, + 0x75B7B7C2, 0xE1FDFD1C, 0x3D9393AE, 0x4C26266A, 0x6C36365A, 0x7E3F3F41, 0xF5F7F702, 0x83CCCC4F, + 0x6834345C, 0x51A5A5F4, 0xD1E5E534, 0xF9F1F108, 0xE2717193, 0xABD8D873, 0x62313153, 0x2A15153F, + 0x0804040C, 0x95C7C752, 0x46232365, 0x9DC3C35E, 0x30181828, 0x379696A1, 0x0A05050F, 0x2F9A9AB5, + 0x0E070709, 0x24121236, 0x1B80809B, 0xDFE2E23D, 0xCDEBEB26, 0x4E272769, 0x7FB2B2CD, 0xEA75759F, + 0x1209091B, 0x1D83839E, 0x582C2C74, 0x341A1A2E, 0x361B1B2D, 0xDC6E6EB2, 0xB45A5AEE, 0x5BA0A0FB, + 0xA45252F6, 0x763B3B4D, 0xB7D6D661, 0x7DB3B3CE, 0x5229297B, 0xDDE3E33E, 0x5E2F2F71, 0x13848497, + 0xA65353F5, 0xB9D1D168, 0x00000000, 0xC1EDED2C, 0x40202060, 0xE3FCFC1F, 0x79B1B1C8, 0xB65B5BED, + 0xD46A6ABE, 0x8DCBCB46, 0x67BEBED9, 0x7239394B, 0x944A4ADE, 0x984C4CD4, 0xB05858E8, 0x85CFCF4A, + 0xBBD0D06B, 0xC5EFEF2A, 0x4FAAAAE5, 0xEDFBFB16, 0x864343C5, 0x9A4D4DD7, 0x66333355, 0x11858594, + 0x8A4545CF, 0xE9F9F910, 0x04020206, 0xFE7F7F81, 0xA05050F0, 0x783C3C44, 0x259F9FBA, 0x4BA8A8E3, + 0xA25151F3, 0x5DA3A3FE, 0x804040C0, 0x058F8F8A, 0x3F9292AD, 0x219D9DBC, 0x70383848, 0xF1F5F504, + 0x63BCBCDF, 0x77B6B6C1, 0xAFDADA75, 0x42212163, 0x20101030, 0xE5FFFF1A, 0xFDF3F30E, 0xBFD2D26D, + 0x81CDCD4C, 0x180C0C14, 0x26131335, 0xC3ECEC2F, 0xBE5F5FE1, 0x359797A2, 0x884444CC, 0x2E171739, + 0x93C4C457, 0x55A7A7F2, 0xFC7E7E82, 0x7A3D3D47, 0xC86464AC, 0xBA5D5DE7, 0x3219192B, 0xE6737395, + 0xC06060A0, 0x19818198, 0x9E4F4FD1, 0xA3DCDC7F, 0x44222266, 0x542A2A7E, 0x3B9090AB, 0x0B888883, + 0x8C4646CA, 0xC7EEEE29, 0x6BB8B8D3, 0x2814143C, 0xA7DEDE79, 0xBC5E5EE2, 0x160B0B1D, 0xADDBDB76, + 0xDBE0E03B, 0x64323256, 0x743A3A4E, 0x140A0A1E, 0x924949DB, 0x0C06060A, 0x4824246C, 0xB85C5CE4, + 0x9FC2C25D, 0xBDD3D36E, 0x43ACACEF, 0xC46262A6, 0x399191A8, 0x319595A4, 0xD3E4E437, 0xF279798B, + 0xD5E7E732, 0x8BC8C843, 0x6E373759, 0xDA6D6DB7, 0x018D8D8C, 0xB1D5D564, 0x9C4E4ED2, 0x49A9A9E0, + 0xD86C6CB4, 0xAC5656FA, 0xF3F4F407, 0xCFEAEA25, 0xCA6565AF, 0xF47A7A8E, 0x47AEAEE9, 0x10080818, + 0x6FBABAD5, 0xF0787888, 0x4A25256F, 0x5C2E2E72, 0x381C1C24, 0x57A6A6F1, 0x73B4B4C7, 0x97C6C651, + 0xCBE8E823, 0xA1DDDD7C, 0xE874749C, 0x3E1F1F21, 0x964B4BDD, 0x61BDBDDC, 0x0D8B8B86, 0x0F8A8A85, + 0xE0707090, 0x7C3E3E42, 0x71B5B5C4, 0xCC6666AA, 0x904848D8, 0x06030305, 0xF7F6F601, 0x1C0E0E12, + 0xC26161A3, 0x6A35355F, 0xAE5757F9, 0x69B9B9D0, 0x17868691, 0x99C1C158, 0x3A1D1D27, 0x279E9EB9, + 0xD9E1E138, 0xEBF8F813, 0x2B9898B3, 0x22111133, 0xD26969BB, 0xA9D9D970, 0x078E8E89, 0x339494A7, + 0x2D9B9BB6, 0x3C1E1E22, 0x15878792, 0xC9E9E920, 0x87CECE49, 0xAA5555FF, 0x50282878, 0xA5DFDF7A, + 0x038C8C8F, 0x59A1A1F8, 0x09898980, 0x1A0D0D17, 0x65BFBFDA, 0xD7E6E631, 0x844242C6, 0xD06868B8, + 0x824141C3, 0x299999B0, 0x5A2D2D77, 0x1E0F0F11, 0x7BB0B0CB, 0xA85454FC, 0x6DBBBBD6, 0x2C16163A, }; -static const u4_t AES_E2[256] = { - 0xA5C66363, 0x84F87C7C, 0x99EE7777, 0x8DF67B7B, 0x0DFFF2F2, 0xBDD66B6B, 0xB1DE6F6F, 0x5491C5C5, - 0x50603030, 0x03020101, 0xA9CE6767, 0x7D562B2B, 0x19E7FEFE, 0x62B5D7D7, 0xE64DABAB, 0x9AEC7676, - 0x458FCACA, 0x9D1F8282, 0x4089C9C9, 0x87FA7D7D, 0x15EFFAFA, 0xEBB25959, 0xC98E4747, 0x0BFBF0F0, - 0xEC41ADAD, 0x67B3D4D4, 0xFD5FA2A2, 0xEA45AFAF, 0xBF239C9C, 0xF753A4A4, 0x96E47272, 0x5B9BC0C0, - 0xC275B7B7, 0x1CE1FDFD, 0xAE3D9393, 0x6A4C2626, 0x5A6C3636, 0x417E3F3F, 0x02F5F7F7, 0x4F83CCCC, - 0x5C683434, 0xF451A5A5, 0x34D1E5E5, 0x08F9F1F1, 0x93E27171, 0x73ABD8D8, 0x53623131, 0x3F2A1515, - 0x0C080404, 0x5295C7C7, 0x65462323, 0x5E9DC3C3, 0x28301818, 0xA1379696, 0x0F0A0505, 0xB52F9A9A, - 0x090E0707, 0x36241212, 0x9B1B8080, 0x3DDFE2E2, 0x26CDEBEB, 0x694E2727, 0xCD7FB2B2, 0x9FEA7575, - 0x1B120909, 0x9E1D8383, 0x74582C2C, 0x2E341A1A, 0x2D361B1B, 0xB2DC6E6E, 0xEEB45A5A, 0xFB5BA0A0, - 0xF6A45252, 0x4D763B3B, 0x61B7D6D6, 0xCE7DB3B3, 0x7B522929, 0x3EDDE3E3, 0x715E2F2F, 0x97138484, - 0xF5A65353, 0x68B9D1D1, 0x00000000, 0x2CC1EDED, 0x60402020, 0x1FE3FCFC, 0xC879B1B1, 0xEDB65B5B, - 0xBED46A6A, 0x468DCBCB, 0xD967BEBE, 0x4B723939, 0xDE944A4A, 0xD4984C4C, 0xE8B05858, 0x4A85CFCF, - 0x6BBBD0D0, 0x2AC5EFEF, 0xE54FAAAA, 0x16EDFBFB, 0xC5864343, 0xD79A4D4D, 0x55663333, 0x94118585, - 0xCF8A4545, 0x10E9F9F9, 0x06040202, 0x81FE7F7F, 0xF0A05050, 0x44783C3C, 0xBA259F9F, 0xE34BA8A8, - 0xF3A25151, 0xFE5DA3A3, 0xC0804040, 0x8A058F8F, 0xAD3F9292, 0xBC219D9D, 0x48703838, 0x04F1F5F5, - 0xDF63BCBC, 0xC177B6B6, 0x75AFDADA, 0x63422121, 0x30201010, 0x1AE5FFFF, 0x0EFDF3F3, 0x6DBFD2D2, - 0x4C81CDCD, 0x14180C0C, 0x35261313, 0x2FC3ECEC, 0xE1BE5F5F, 0xA2359797, 0xCC884444, 0x392E1717, - 0x5793C4C4, 0xF255A7A7, 0x82FC7E7E, 0x477A3D3D, 0xACC86464, 0xE7BA5D5D, 0x2B321919, 0x95E67373, - 0xA0C06060, 0x98198181, 0xD19E4F4F, 0x7FA3DCDC, 0x66442222, 0x7E542A2A, 0xAB3B9090, 0x830B8888, - 0xCA8C4646, 0x29C7EEEE, 0xD36BB8B8, 0x3C281414, 0x79A7DEDE, 0xE2BC5E5E, 0x1D160B0B, 0x76ADDBDB, - 0x3BDBE0E0, 0x56643232, 0x4E743A3A, 0x1E140A0A, 0xDB924949, 0x0A0C0606, 0x6C482424, 0xE4B85C5C, - 0x5D9FC2C2, 0x6EBDD3D3, 0xEF43ACAC, 0xA6C46262, 0xA8399191, 0xA4319595, 0x37D3E4E4, 0x8BF27979, - 0x32D5E7E7, 0x438BC8C8, 0x596E3737, 0xB7DA6D6D, 0x8C018D8D, 0x64B1D5D5, 0xD29C4E4E, 0xE049A9A9, - 0xB4D86C6C, 0xFAAC5656, 0x07F3F4F4, 0x25CFEAEA, 0xAFCA6565, 0x8EF47A7A, 0xE947AEAE, 0x18100808, - 0xD56FBABA, 0x88F07878, 0x6F4A2525, 0x725C2E2E, 0x24381C1C, 0xF157A6A6, 0xC773B4B4, 0x5197C6C6, - 0x23CBE8E8, 0x7CA1DDDD, 0x9CE87474, 0x213E1F1F, 0xDD964B4B, 0xDC61BDBD, 0x860D8B8B, 0x850F8A8A, - 0x90E07070, 0x427C3E3E, 0xC471B5B5, 0xAACC6666, 0xD8904848, 0x05060303, 0x01F7F6F6, 0x121C0E0E, - 0xA3C26161, 0x5F6A3535, 0xF9AE5757, 0xD069B9B9, 0x91178686, 0x5899C1C1, 0x273A1D1D, 0xB9279E9E, - 0x38D9E1E1, 0x13EBF8F8, 0xB32B9898, 0x33221111, 0xBBD26969, 0x70A9D9D9, 0x89078E8E, 0xA7339494, - 0xB62D9B9B, 0x223C1E1E, 0x92158787, 0x20C9E9E9, 0x4987CECE, 0xFFAA5555, 0x78502828, 0x7AA5DFDF, - 0x8F038C8C, 0xF859A1A1, 0x80098989, 0x171A0D0D, 0xDA65BFBF, 0x31D7E6E6, 0xC6844242, 0xB8D06868, - 0xC3824141, 0xB0299999, 0x775A2D2D, 0x111E0F0F, 0xCB7BB0B0, 0xFCA85454, 0xD66DBBBB, 0x3A2C1616, +static CONST_TABLE(u4_t, AES_E2)[256] = { + 0xA5C66363, 0x84F87C7C, 0x99EE7777, 0x8DF67B7B, 0x0DFFF2F2, 0xBDD66B6B, 0xB1DE6F6F, 0x5491C5C5, + 0x50603030, 0x03020101, 0xA9CE6767, 0x7D562B2B, 0x19E7FEFE, 0x62B5D7D7, 0xE64DABAB, 0x9AEC7676, + 0x458FCACA, 0x9D1F8282, 0x4089C9C9, 0x87FA7D7D, 0x15EFFAFA, 0xEBB25959, 0xC98E4747, 0x0BFBF0F0, + 0xEC41ADAD, 0x67B3D4D4, 0xFD5FA2A2, 0xEA45AFAF, 0xBF239C9C, 0xF753A4A4, 0x96E47272, 0x5B9BC0C0, + 0xC275B7B7, 0x1CE1FDFD, 0xAE3D9393, 0x6A4C2626, 0x5A6C3636, 0x417E3F3F, 0x02F5F7F7, 0x4F83CCCC, + 0x5C683434, 0xF451A5A5, 0x34D1E5E5, 0x08F9F1F1, 0x93E27171, 0x73ABD8D8, 0x53623131, 0x3F2A1515, + 0x0C080404, 0x5295C7C7, 0x65462323, 0x5E9DC3C3, 0x28301818, 0xA1379696, 0x0F0A0505, 0xB52F9A9A, + 0x090E0707, 0x36241212, 0x9B1B8080, 0x3DDFE2E2, 0x26CDEBEB, 0x694E2727, 0xCD7FB2B2, 0x9FEA7575, + 0x1B120909, 0x9E1D8383, 0x74582C2C, 0x2E341A1A, 0x2D361B1B, 0xB2DC6E6E, 0xEEB45A5A, 0xFB5BA0A0, + 0xF6A45252, 0x4D763B3B, 0x61B7D6D6, 0xCE7DB3B3, 0x7B522929, 0x3EDDE3E3, 0x715E2F2F, 0x97138484, + 0xF5A65353, 0x68B9D1D1, 0x00000000, 0x2CC1EDED, 0x60402020, 0x1FE3FCFC, 0xC879B1B1, 0xEDB65B5B, + 0xBED46A6A, 0x468DCBCB, 0xD967BEBE, 0x4B723939, 0xDE944A4A, 0xD4984C4C, 0xE8B05858, 0x4A85CFCF, + 0x6BBBD0D0, 0x2AC5EFEF, 0xE54FAAAA, 0x16EDFBFB, 0xC5864343, 0xD79A4D4D, 0x55663333, 0x94118585, + 0xCF8A4545, 0x10E9F9F9, 0x06040202, 0x81FE7F7F, 0xF0A05050, 0x44783C3C, 0xBA259F9F, 0xE34BA8A8, + 0xF3A25151, 0xFE5DA3A3, 0xC0804040, 0x8A058F8F, 0xAD3F9292, 0xBC219D9D, 0x48703838, 0x04F1F5F5, + 0xDF63BCBC, 0xC177B6B6, 0x75AFDADA, 0x63422121, 0x30201010, 0x1AE5FFFF, 0x0EFDF3F3, 0x6DBFD2D2, + 0x4C81CDCD, 0x14180C0C, 0x35261313, 0x2FC3ECEC, 0xE1BE5F5F, 0xA2359797, 0xCC884444, 0x392E1717, + 0x5793C4C4, 0xF255A7A7, 0x82FC7E7E, 0x477A3D3D, 0xACC86464, 0xE7BA5D5D, 0x2B321919, 0x95E67373, + 0xA0C06060, 0x98198181, 0xD19E4F4F, 0x7FA3DCDC, 0x66442222, 0x7E542A2A, 0xAB3B9090, 0x830B8888, + 0xCA8C4646, 0x29C7EEEE, 0xD36BB8B8, 0x3C281414, 0x79A7DEDE, 0xE2BC5E5E, 0x1D160B0B, 0x76ADDBDB, + 0x3BDBE0E0, 0x56643232, 0x4E743A3A, 0x1E140A0A, 0xDB924949, 0x0A0C0606, 0x6C482424, 0xE4B85C5C, + 0x5D9FC2C2, 0x6EBDD3D3, 0xEF43ACAC, 0xA6C46262, 0xA8399191, 0xA4319595, 0x37D3E4E4, 0x8BF27979, + 0x32D5E7E7, 0x438BC8C8, 0x596E3737, 0xB7DA6D6D, 0x8C018D8D, 0x64B1D5D5, 0xD29C4E4E, 0xE049A9A9, + 0xB4D86C6C, 0xFAAC5656, 0x07F3F4F4, 0x25CFEAEA, 0xAFCA6565, 0x8EF47A7A, 0xE947AEAE, 0x18100808, + 0xD56FBABA, 0x88F07878, 0x6F4A2525, 0x725C2E2E, 0x24381C1C, 0xF157A6A6, 0xC773B4B4, 0x5197C6C6, + 0x23CBE8E8, 0x7CA1DDDD, 0x9CE87474, 0x213E1F1F, 0xDD964B4B, 0xDC61BDBD, 0x860D8B8B, 0x850F8A8A, + 0x90E07070, 0x427C3E3E, 0xC471B5B5, 0xAACC6666, 0xD8904848, 0x05060303, 0x01F7F6F6, 0x121C0E0E, + 0xA3C26161, 0x5F6A3535, 0xF9AE5757, 0xD069B9B9, 0x91178686, 0x5899C1C1, 0x273A1D1D, 0xB9279E9E, + 0x38D9E1E1, 0x13EBF8F8, 0xB32B9898, 0x33221111, 0xBBD26969, 0x70A9D9D9, 0x89078E8E, 0xA7339494, + 0xB62D9B9B, 0x223C1E1E, 0x92158787, 0x20C9E9E9, 0x4987CECE, 0xFFAA5555, 0x78502828, 0x7AA5DFDF, + 0x8F038C8C, 0xF859A1A1, 0x80098989, 0x171A0D0D, 0xDA65BFBF, 0x31D7E6E6, 0xC6844242, 0xB8D06868, + 0xC3824141, 0xB0299999, 0x775A2D2D, 0x111E0F0F, 0xCB7BB0B0, 0xFCA85454, 0xD66DBBBB, 0x3A2C1616, }; -static const u4_t AES_E3[256] = { - 0x63A5C663, 0x7C84F87C, 0x7799EE77, 0x7B8DF67B, 0xF20DFFF2, 0x6BBDD66B, 0x6FB1DE6F, 0xC55491C5, - 0x30506030, 0x01030201, 0x67A9CE67, 0x2B7D562B, 0xFE19E7FE, 0xD762B5D7, 0xABE64DAB, 0x769AEC76, - 0xCA458FCA, 0x829D1F82, 0xC94089C9, 0x7D87FA7D, 0xFA15EFFA, 0x59EBB259, 0x47C98E47, 0xF00BFBF0, - 0xADEC41AD, 0xD467B3D4, 0xA2FD5FA2, 0xAFEA45AF, 0x9CBF239C, 0xA4F753A4, 0x7296E472, 0xC05B9BC0, - 0xB7C275B7, 0xFD1CE1FD, 0x93AE3D93, 0x266A4C26, 0x365A6C36, 0x3F417E3F, 0xF702F5F7, 0xCC4F83CC, - 0x345C6834, 0xA5F451A5, 0xE534D1E5, 0xF108F9F1, 0x7193E271, 0xD873ABD8, 0x31536231, 0x153F2A15, - 0x040C0804, 0xC75295C7, 0x23654623, 0xC35E9DC3, 0x18283018, 0x96A13796, 0x050F0A05, 0x9AB52F9A, - 0x07090E07, 0x12362412, 0x809B1B80, 0xE23DDFE2, 0xEB26CDEB, 0x27694E27, 0xB2CD7FB2, 0x759FEA75, - 0x091B1209, 0x839E1D83, 0x2C74582C, 0x1A2E341A, 0x1B2D361B, 0x6EB2DC6E, 0x5AEEB45A, 0xA0FB5BA0, - 0x52F6A452, 0x3B4D763B, 0xD661B7D6, 0xB3CE7DB3, 0x297B5229, 0xE33EDDE3, 0x2F715E2F, 0x84971384, - 0x53F5A653, 0xD168B9D1, 0x00000000, 0xED2CC1ED, 0x20604020, 0xFC1FE3FC, 0xB1C879B1, 0x5BEDB65B, - 0x6ABED46A, 0xCB468DCB, 0xBED967BE, 0x394B7239, 0x4ADE944A, 0x4CD4984C, 0x58E8B058, 0xCF4A85CF, - 0xD06BBBD0, 0xEF2AC5EF, 0xAAE54FAA, 0xFB16EDFB, 0x43C58643, 0x4DD79A4D, 0x33556633, 0x85941185, - 0x45CF8A45, 0xF910E9F9, 0x02060402, 0x7F81FE7F, 0x50F0A050, 0x3C44783C, 0x9FBA259F, 0xA8E34BA8, - 0x51F3A251, 0xA3FE5DA3, 0x40C08040, 0x8F8A058F, 0x92AD3F92, 0x9DBC219D, 0x38487038, 0xF504F1F5, - 0xBCDF63BC, 0xB6C177B6, 0xDA75AFDA, 0x21634221, 0x10302010, 0xFF1AE5FF, 0xF30EFDF3, 0xD26DBFD2, - 0xCD4C81CD, 0x0C14180C, 0x13352613, 0xEC2FC3EC, 0x5FE1BE5F, 0x97A23597, 0x44CC8844, 0x17392E17, - 0xC45793C4, 0xA7F255A7, 0x7E82FC7E, 0x3D477A3D, 0x64ACC864, 0x5DE7BA5D, 0x192B3219, 0x7395E673, - 0x60A0C060, 0x81981981, 0x4FD19E4F, 0xDC7FA3DC, 0x22664422, 0x2A7E542A, 0x90AB3B90, 0x88830B88, - 0x46CA8C46, 0xEE29C7EE, 0xB8D36BB8, 0x143C2814, 0xDE79A7DE, 0x5EE2BC5E, 0x0B1D160B, 0xDB76ADDB, - 0xE03BDBE0, 0x32566432, 0x3A4E743A, 0x0A1E140A, 0x49DB9249, 0x060A0C06, 0x246C4824, 0x5CE4B85C, - 0xC25D9FC2, 0xD36EBDD3, 0xACEF43AC, 0x62A6C462, 0x91A83991, 0x95A43195, 0xE437D3E4, 0x798BF279, - 0xE732D5E7, 0xC8438BC8, 0x37596E37, 0x6DB7DA6D, 0x8D8C018D, 0xD564B1D5, 0x4ED29C4E, 0xA9E049A9, - 0x6CB4D86C, 0x56FAAC56, 0xF407F3F4, 0xEA25CFEA, 0x65AFCA65, 0x7A8EF47A, 0xAEE947AE, 0x08181008, - 0xBAD56FBA, 0x7888F078, 0x256F4A25, 0x2E725C2E, 0x1C24381C, 0xA6F157A6, 0xB4C773B4, 0xC65197C6, - 0xE823CBE8, 0xDD7CA1DD, 0x749CE874, 0x1F213E1F, 0x4BDD964B, 0xBDDC61BD, 0x8B860D8B, 0x8A850F8A, - 0x7090E070, 0x3E427C3E, 0xB5C471B5, 0x66AACC66, 0x48D89048, 0x03050603, 0xF601F7F6, 0x0E121C0E, - 0x61A3C261, 0x355F6A35, 0x57F9AE57, 0xB9D069B9, 0x86911786, 0xC15899C1, 0x1D273A1D, 0x9EB9279E, - 0xE138D9E1, 0xF813EBF8, 0x98B32B98, 0x11332211, 0x69BBD269, 0xD970A9D9, 0x8E89078E, 0x94A73394, - 0x9BB62D9B, 0x1E223C1E, 0x87921587, 0xE920C9E9, 0xCE4987CE, 0x55FFAA55, 0x28785028, 0xDF7AA5DF, - 0x8C8F038C, 0xA1F859A1, 0x89800989, 0x0D171A0D, 0xBFDA65BF, 0xE631D7E6, 0x42C68442, 0x68B8D068, - 0x41C38241, 0x99B02999, 0x2D775A2D, 0x0F111E0F, 0xB0CB7BB0, 0x54FCA854, 0xBBD66DBB, 0x163A2C16, +static CONST_TABLE(u4_t, AES_E3)[256] = { + 0x63A5C663, 0x7C84F87C, 0x7799EE77, 0x7B8DF67B, 0xF20DFFF2, 0x6BBDD66B, 0x6FB1DE6F, 0xC55491C5, + 0x30506030, 0x01030201, 0x67A9CE67, 0x2B7D562B, 0xFE19E7FE, 0xD762B5D7, 0xABE64DAB, 0x769AEC76, + 0xCA458FCA, 0x829D1F82, 0xC94089C9, 0x7D87FA7D, 0xFA15EFFA, 0x59EBB259, 0x47C98E47, 0xF00BFBF0, + 0xADEC41AD, 0xD467B3D4, 0xA2FD5FA2, 0xAFEA45AF, 0x9CBF239C, 0xA4F753A4, 0x7296E472, 0xC05B9BC0, + 0xB7C275B7, 0xFD1CE1FD, 0x93AE3D93, 0x266A4C26, 0x365A6C36, 0x3F417E3F, 0xF702F5F7, 0xCC4F83CC, + 0x345C6834, 0xA5F451A5, 0xE534D1E5, 0xF108F9F1, 0x7193E271, 0xD873ABD8, 0x31536231, 0x153F2A15, + 0x040C0804, 0xC75295C7, 0x23654623, 0xC35E9DC3, 0x18283018, 0x96A13796, 0x050F0A05, 0x9AB52F9A, + 0x07090E07, 0x12362412, 0x809B1B80, 0xE23DDFE2, 0xEB26CDEB, 0x27694E27, 0xB2CD7FB2, 0x759FEA75, + 0x091B1209, 0x839E1D83, 0x2C74582C, 0x1A2E341A, 0x1B2D361B, 0x6EB2DC6E, 0x5AEEB45A, 0xA0FB5BA0, + 0x52F6A452, 0x3B4D763B, 0xD661B7D6, 0xB3CE7DB3, 0x297B5229, 0xE33EDDE3, 0x2F715E2F, 0x84971384, + 0x53F5A653, 0xD168B9D1, 0x00000000, 0xED2CC1ED, 0x20604020, 0xFC1FE3FC, 0xB1C879B1, 0x5BEDB65B, + 0x6ABED46A, 0xCB468DCB, 0xBED967BE, 0x394B7239, 0x4ADE944A, 0x4CD4984C, 0x58E8B058, 0xCF4A85CF, + 0xD06BBBD0, 0xEF2AC5EF, 0xAAE54FAA, 0xFB16EDFB, 0x43C58643, 0x4DD79A4D, 0x33556633, 0x85941185, + 0x45CF8A45, 0xF910E9F9, 0x02060402, 0x7F81FE7F, 0x50F0A050, 0x3C44783C, 0x9FBA259F, 0xA8E34BA8, + 0x51F3A251, 0xA3FE5DA3, 0x40C08040, 0x8F8A058F, 0x92AD3F92, 0x9DBC219D, 0x38487038, 0xF504F1F5, + 0xBCDF63BC, 0xB6C177B6, 0xDA75AFDA, 0x21634221, 0x10302010, 0xFF1AE5FF, 0xF30EFDF3, 0xD26DBFD2, + 0xCD4C81CD, 0x0C14180C, 0x13352613, 0xEC2FC3EC, 0x5FE1BE5F, 0x97A23597, 0x44CC8844, 0x17392E17, + 0xC45793C4, 0xA7F255A7, 0x7E82FC7E, 0x3D477A3D, 0x64ACC864, 0x5DE7BA5D, 0x192B3219, 0x7395E673, + 0x60A0C060, 0x81981981, 0x4FD19E4F, 0xDC7FA3DC, 0x22664422, 0x2A7E542A, 0x90AB3B90, 0x88830B88, + 0x46CA8C46, 0xEE29C7EE, 0xB8D36BB8, 0x143C2814, 0xDE79A7DE, 0x5EE2BC5E, 0x0B1D160B, 0xDB76ADDB, + 0xE03BDBE0, 0x32566432, 0x3A4E743A, 0x0A1E140A, 0x49DB9249, 0x060A0C06, 0x246C4824, 0x5CE4B85C, + 0xC25D9FC2, 0xD36EBDD3, 0xACEF43AC, 0x62A6C462, 0x91A83991, 0x95A43195, 0xE437D3E4, 0x798BF279, + 0xE732D5E7, 0xC8438BC8, 0x37596E37, 0x6DB7DA6D, 0x8D8C018D, 0xD564B1D5, 0x4ED29C4E, 0xA9E049A9, + 0x6CB4D86C, 0x56FAAC56, 0xF407F3F4, 0xEA25CFEA, 0x65AFCA65, 0x7A8EF47A, 0xAEE947AE, 0x08181008, + 0xBAD56FBA, 0x7888F078, 0x256F4A25, 0x2E725C2E, 0x1C24381C, 0xA6F157A6, 0xB4C773B4, 0xC65197C6, + 0xE823CBE8, 0xDD7CA1DD, 0x749CE874, 0x1F213E1F, 0x4BDD964B, 0xBDDC61BD, 0x8B860D8B, 0x8A850F8A, + 0x7090E070, 0x3E427C3E, 0xB5C471B5, 0x66AACC66, 0x48D89048, 0x03050603, 0xF601F7F6, 0x0E121C0E, + 0x61A3C261, 0x355F6A35, 0x57F9AE57, 0xB9D069B9, 0x86911786, 0xC15899C1, 0x1D273A1D, 0x9EB9279E, + 0xE138D9E1, 0xF813EBF8, 0x98B32B98, 0x11332211, 0x69BBD269, 0xD970A9D9, 0x8E89078E, 0x94A73394, + 0x9BB62D9B, 0x1E223C1E, 0x87921587, 0xE920C9E9, 0xCE4987CE, 0x55FFAA55, 0x28785028, 0xDF7AA5DF, + 0x8C8F038C, 0xA1F859A1, 0x89800989, 0x0D171A0D, 0xBFDA65BF, 0xE631D7E6, 0x42C68442, 0x68B8D068, + 0x41C38241, 0x99B02999, 0x2D775A2D, 0x0F111E0F, 0xB0CB7BB0, 0x54FCA854, 0xBBD66DBB, 0x163A2C16, }; -static const u4_t AES_E4[256] = { - 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, - 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, - 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, - 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B, - 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, - 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A, - 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F, - 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, - 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B, - 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713, - 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, - 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85, - 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411, - 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, - 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, - 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF, - 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, - 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, - 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B, - 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, - 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8, - 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2, - 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, - 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810, - 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197, - 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, - 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C, - 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927, - 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, - 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, - 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0, - 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C, +static CONST_TABLE(u4_t, AES_E4)[256] = { + 0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491, + 0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC, + 0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB, + 0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B, + 0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83, + 0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A, + 0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F, + 0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA, + 0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B, + 0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713, + 0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6, + 0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85, + 0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411, + 0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B, + 0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1, + 0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF, + 0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E, + 0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6, + 0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B, + 0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD, + 0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8, + 0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2, + 0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049, + 0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810, + 0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197, + 0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F, + 0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C, + 0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927, + 0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733, + 0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5, + 0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0, + 0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C, }; #define msbf4_read(p) ((p)[0]<<24 | (p)[1]<<16 | (p)[2]<<8 | (p)[3]) @@ -204,16 +206,16 @@ static const u4_t AES_E4[256] = { r3 = ki[i+3]; \ r0 = ki[i] -#define AES_expr4(r1,r2,r3,r0,i) r1 ^= AES_E4[u1(i)]; \ - r2 ^= AES_E3[u1(i>>8)]; \ - r3 ^= AES_E2[u1(i>>16)]; \ - r0 ^= AES_E1[ (i>>24)] +#define AES_expr4(r1,r2,r3,r0,i) r1 ^= TABLE_GET_U4(AES_E4, u1(i)); \ + r2 ^= TABLE_GET_U4(AES_E3, u1(i>>8)); \ + r3 ^= TABLE_GET_U4(AES_E2, u1(i>>16)); \ + r0 ^= TABLE_GET_U4(AES_E1, (i>>24)) #define AES_expr(a,r0,r1,r2,r3,i) a = ki[i]; \ - a ^= (AES_S[ r0>>24 ]<<24); \ - a ^= (AES_S[u1(r1>>16)]<<16); \ - a ^= (AES_S[u1(r2>> 8)]<< 8); \ - a ^= AES_S[u1(r3) ] + a ^= ((u4_t)TABLE_GET_U1(AES_S, r0>>24 )<<24); \ + a ^= ((u4_t)TABLE_GET_U1(AES_S, u1(r1>>16))<<16); \ + a ^= ((u4_t)TABLE_GET_U1(AES_S, u1(r2>> 8))<< 8); \ + a ^= (u4_t)TABLE_GET_U1(AES_S, u1(r3) ) // global area for passing parameters (aux, key) and for storing round keys u4_t AESAUX[16/sizeof(u4_t)]; @@ -228,23 +230,23 @@ static void aesroundkeys () { for( i=0; i<4; i++) { AESKEY[i] = swapmsbf(AESKEY[i]); } - + b = AESKEY[3]; for( ; i<44; i++ ) { if( i%4==0 ) { // b = SubWord(RotWord(b)) xor Rcon[i/4] - b = (AES_S[u1(b >> 16)] << 24) ^ - (AES_S[u1(b >> 8)] << 16) ^ - (AES_S[u1(b) ] << 8) ^ - (AES_S[ b >> 24 ] ) ^ - AES_RCON[(i-4)/4]; + b = ((u4_t)TABLE_GET_U1(AES_S, u1(b >> 16)) << 24) ^ + ((u4_t)TABLE_GET_U1(AES_S, u1(b >> 8)) << 16) ^ + ((u4_t)TABLE_GET_U1(AES_S, u1(b) ) << 8) ^ + ((u4_t)TABLE_GET_U1(AES_S, b >> 24 ) ) ^ + TABLE_GET_U4(AES_RCON, (i-4)/4); } AESKEY[i] = b ^= AESKEY[i-4]; } } u4_t os_aes (u1_t mode, xref2u1_t buf, u2_t len) { - + aesroundkeys(); if( mode & AES_MICNOAUX ) { @@ -260,6 +262,7 @@ u4_t os_aes (u1_t mode, xref2u1_t buf, u2_t len) { u4_t a0, a1, a2, a3; u4_t t0, t1, t2, t3; u4_t *ki, *ke; + // ttn-esp32 change: prevent error 'x' may be used uninitialized in this function a0 = a1 = a2 = a3 = 0; t0 = t1 = 0; @@ -283,7 +286,7 @@ u4_t os_aes (u1_t mode, xref2u1_t buf, u2_t len) { a2 = a3; a3 = t1; } - } + } if( mode & AES_MIC ) { a0 ^= AESAUX[0]; a1 ^= AESAUX[1]; @@ -383,3 +386,4 @@ u4_t os_aes (u1_t mode, xref2u1_t buf, u2_t len) { return AESAUX[0]; } +#endif diff --git a/src/hal/hal_esp32.c b/src/hal/hal_esp32.c index d6c6ee9..28c337c 100755 --- a/src/hal/hal_esp32.c +++ b/src/hal/hal_esp32.c @@ -125,6 +125,11 @@ void hal_pin_rst(u1_t val) } } +s1_t hal_getRssiCal (void) { + return lmic_pins.rssi_cal; +} + + // ----------------------------------------------------------------------------- // SPI @@ -444,7 +449,7 @@ static void hal_bgTask(void* pvParameter) { os_runloop(); } -void hal_init() +void hal_init_ex(const void *pContext) { // configure radio I/O and interrupt handler hal_io_init(); diff --git a/src/hal/hal_esp32.h b/src/hal/hal_esp32.h index 0a7ec5f..9de1332 100644 --- a/src/hal/hal_esp32.h +++ b/src/hal/hal_esp32.h @@ -27,6 +27,7 @@ typedef struct lmic_pinmap { uint8_t rst; uint8_t dio0; uint8_t dio1; + int8_t rssi_cal; // cal in dB -- added to RSSI measured prior to decision. Must include noise guardband! } lmic_pinmap; extern lmic_pinmap lmic_pins; diff --git a/src/lmic/config.h b/src/lmic/config.h old mode 100644 new mode 100755 index 416d13b..1750907 --- a/src/lmic/config.h +++ b/src/lmic/config.h @@ -1,68 +1,174 @@ -/******************************************************************************* - * - * ttn-esp32 - The Things Network device library for ESP-IDF / SX127x - * - * Copyright (c) 2018 Manuel Bleichenbacher - * - * Licensed under MIT License - * https://opensource.org/licenses/MIT - * - * This the hardware abstraction layer to run LMIC in on ESP32 using ESP-iDF. - *******************************************************************************/ - #ifndef _lmic_config_h_ #define _lmic_config_h_ -#include "sdkconfig.h" +// In the original LMIC code, these config values were defined on the +// gcc commandline. Since Arduino does not allow easily modifying the +// compiler commandline unless you modify the BSP, you have two choices: +// +// - edit {libraries}/arduino-lmic/project_config/lmic_project_config.h; +// - use a BSP like the MCCI Arduino BSPs, which get the configuration +// from the boards.txt file through a menu option. +// +// You definitely should not edit this file. -#ifdef __cplusplus -extern "C" { +// set up preconditions, and load configuration if needed. +#ifndef _LMIC_CONFIG_PRECONDITIONS_H_ +# include "lmic_config_preconditions.h" #endif -#if defined(CONFIG_TTN_LORA_FREQ_EU_868) -#define CFG_eu868 1 -#elif defined(CONFIG_TTN_LORA_FREQ_US_915) -#define CFG_us915 1 -#else -#define TTN_IS_DISABLED 1 -#define CFG_eu868 1 +// check post-conditions. + +// make sure that we have exactly one target region defined. +#if CFG_LMIC_REGION_MASK == 0 +# define CFG_eu868 1 +#elif (CFG_LMIC_REGION_MASK & (-CFG_LMIC_REGION_MASK)) != CFG_LMIC_REGION_MASK +# error You can define at most one of CFG_... variables +#elif (CFG_LMIC_REGION_MASK & LMIC_REGIONS_SUPPORTED) == 0 +# error The selected CFG_... region is not supported yet. #endif -#if defined(CONFIG_TTN_RADIO_SX1272_73) -#define CFG_sx1272_radio 1 -#elif defined(CONFIG_TTN_RADIO_SX1276_77_78_79) +// make sure that LMIC_COUNTRY_CODE is defined. +#ifndef LMIC_COUNTRY_CODE +# define LMIC_COUNTRY_CODE LMIC_COUNTRY_CODE_NONE +#endif + +// if the country code is Japan, then the region must be AS923 +#if LMIC_COUNTRY_CODE == LMIC_COUNTRY_CODE_JP && CFG_region != LMIC_REGION_as923 +# error "If country code is JP, then region must be AS923" +#endif + +// check for internal consistency +#if !(CFG_LMIC_EU_like || CFG_LMIC_US_like) +# error "Internal error: Neither EU-like nor US-like!" +#endif + +// This is the SX1272/SX1273 radio, which is also used on the HopeRF +// RFM92 boards. +//#define CFG_sx1272_radio 1 +// This is the SX1276/SX1277/SX1278/SX1279 radio, which is also used on +// the HopeRF RFM95 boards. +//#define CFG_sx1276_radio 1 + +// ensure that a radio is defined. +#if ! (defined(CFG_sx1272_radio) || defined(CFG_sx1276_radio)) +# warning Target radio not defined, assuming CFG_sx1276_radio #define CFG_sx1276_radio 1 -#else -#error TTN LoRa radio chip must be configured using 'make menuconfig' +#elif defined(CFG_sx1272_radio) && defined(CFG_sx1276_radio) +# error You can define at most one of CFG_sx1272_radio and CF_sx1276_radio #endif -#if defined(CONFIG_TTN_TIMER_0_GROUP_0) -#define TTN_TIMER TIMER_0 -#define TTN_TIMER_GROUP TIMER_GROUP_0 -#define TTN_CLEAR_TIMER_ALARM TIMERG0.int_clr_timers.t0 = 1 -#elif defined(CONFIG_TTN_TIMER_1_GROUP_0) -#define TTN_TIMER TIMER_1 -#define TTN_TIMER_GROUP TIMER_GROUP_0 -#define TTN_CLEAR_TIMER_ALARM TIMERG0.int_clr_timers.t1 = 1 -#elif defined(CONFIG_TTN_TIMER_0_GROUP_1) -#define TTN_TIMER TIMER_0 -#define TTN_TIMER_GROUP TIMER_GROUP_1 -#define TTN_CLEAR_TIMER_ALARM TIMERG1.int_clr_timers.t0 = 1 -#elif defined(CONFIG_TTN_TIMER_1_GROUP_1) -#define TTN_TIMER TIMER_1 -#define TTN_TIMER_GROUP TIMER_GROUP_1 -#define TTN_CLEAR_TIMER_ALARM TIMERG1.int_clr_timers.t1 = 1 -#else -#error TTN timer must be configured using 'make menuconfig' -#endif - -// 16 μs per tick // LMIC requires ticks to be 15.5μs - 100 μs long -#define US_PER_OSTICK 16 -#define OSTICKS_PER_SEC (1000000 / US_PER_OSTICK) +#ifndef OSTICKS_PER_SEC +// 16 μs per tick +# ifndef US_PER_OSTICK_EXPONENT +# define US_PER_OSTICK_EXPONENT 4 +# endif +# define US_PER_OSTICK (1 << US_PER_OSTICK_EXPONENT) +# define OSTICKS_PER_SEC (1000000 / US_PER_OSTICK) +#endif /* OSTICKS_PER_SEC */ -#ifdef __cplusplus -} +#if ! (10000 <= OSTICKS_PER_SEC && OSTICKS_PER_SEC < 64516) +# error LMIC requires ticks to be 15.5 us to 100 us long #endif +// Change the SPI clock speed if you encounter errors +// communicating with the radio. +// The standard range is 125kHz-8MHz, but some boards can go faster. +#ifndef LMIC_SPI_FREQ +#define LMIC_SPI_FREQ 1E6 +#endif + +// Set this to 1 to enable some basic debug output (using printf) about +// RF settings used during transmission and reception. Set to 2 to +// enable more verbose output. Make sure that printf is actually +// configured (e.g. on AVR it is not by default), otherwise using it can +// cause crashing. +#ifndef LMIC_DEBUG_LEVEL +#define LMIC_DEBUG_LEVEL 0 +#endif + +// Enable this to allow using printf() to print to the given serial port +// (or any other Print object). This can be easy for debugging. The +// current implementation only works on AVR, though. +//#define LMIC_PRINTF_TO Serial + +// Enable this to use interrupt handler routines listening for RISING signals. +// Otherwise, the library polls digital input lines for changes. +//#define LMIC_USE_INTERRUPTS + +// If DISABLE_LMIC_FAILURE_TO is defined, runtime assertion failures +// silently halt execution. Otherwise, LMIC_FAILURE_TO should be defined +// as the name of an object derived from Print, which will be used for +// displaying runtime assertion failures. If you say nothing in your +// lmic_project_config.h, runtime assertion failures are displayed +// using the Serial object. +#if ! defined(DISABLE_LMIC_FAILURE_TO) && ! defined(LMIC_FAILURE_TO) +#define LMIC_FAILURE_TO Serial +#endif + +// define this in lmic_project_config.h to disable all code related to joining +//#define DISABLE_JOIN +// define this in lmic_project_config.h to disable all code related to ping +//#define DISABLE_PING +// define this in lmic_project_config.h to disable all code related to beacon tracking. +// Requires ping to be disabled too +//#define DISABLE_BEACONS + +// define these in lmic_project_config.h to disable the corresponding MAC commands. +// Class A +//#define DISABLE_MCMD_DCAP_REQ // duty cycle cap +//#define DISABLE_MCMD_DN2P_SET // 2nd DN window param +//#define DISABLE_MCMD_SNCH_REQ // set new channel +// Class B +//#define DISABLE_MCMD_PING_SET // set ping freq, automatically disabled by DISABLE_PING +//#define DISABLE_MCMD_BCNI_ANS // next beacon start, automatically disabled by DISABLE_BEACON + +// In LoRaWAN, a gateway applies I/Q inversion on TX, and nodes do the +// same on RX. This ensures that gateways can talk to nodes and vice +// versa, but gateways will not hear other gateways and nodes will not +// hear other nodes. By defining this macro in lmic_project_config.h, +// this inversion is disabled and this node can hear other nodes. If +// two nodes both have this macro set, they can talk to each other +// (but they can no longer hear gateways). This should probably only +// be used when debugging and/or when talking to the radio directly +// (e.g. like in the "raw" example). +//#define DISABLE_INVERT_IQ_ON_RX + +// This allows choosing between multiple included AES implementations. +// Make sure exactly one of these is uncommented. +// +// This selects the original AES implementation included LMIC. This +// implementation is optimized for speed on 32-bit processors using +// fairly big lookup tables, but it takes up big amounts of flash on the +// AVR architecture. +// #define USE_ORIGINAL_AES +// +// This selects the AES implementation written by Ideetroon for their +// own LoRaWAN library. It also uses lookup tables, but smaller +// byte-oriented ones, making it use a lot less flash space (but it is +// also about twice as slow as the original). +// #define USE_IDEETRON_AES + +#if ! (defined(USE_ORIGINAL_AES) || defined(USE_IDEETRON_AES)) +# define USE_IDEETRON_AES +#endif + +#if defined(USE_ORIGINAL_AES) && defined(USE_IDEETRON_AES) +# error "You may define at most one of USE_ORIGINAL_AES and USE_IDEETRON_AES" +#endif + +// LMIC_DISABLE_DR_LEGACY +// turn off legacy DR_* symbols that vary by bandplan. +// Older code uses these for configuration. EU868_DR_*, US915_DR_* +// etc symbols are prefered, but breaking older code is inconvenient for +// everybody. We don't want to use DR_* in the LMIC itself, so we provide +// this #define to allow them to be removed. +#if !defined(LMIC_DR_LEGACY) +# if !defined(LMIC_DISABLE_DR_LEGACY) +# define LMIC_DR_LEGACY 1 +# else // defined(LMIC_DISABLE_DR_LEGACY) +# define LMIC_DR_LEGACY 0 +# endif // defined(LMIC_DISABLE_DR_LEGACY) +#endif // LMIC_DR_LEGACY + #endif // _lmic_config_h_ diff --git a/src/lmic/hal.h b/src/lmic/hal.h index a1d34c6..c5beb62 100755 --- a/src/lmic/hal.h +++ b/src/lmic/hal.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2014-2016 IBM Corporation. + * Copyright (c) 2016, 2018 MCCI Corporation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,11 +29,8 @@ #ifndef _hal_hpp_ #define _hal_hpp_ -#include "oslmic.h" - - #ifdef __cplusplus -extern "C" { +extern "C"{ #endif /* @@ -40,6 +38,11 @@ extern "C" { */ void hal_init (void); +/* + * initialize hardware, passing in platform-specific context + */ +void hal_init_ex (const void *pContext); + /* * drive radio NSS pin (0=low, 1=high). */ @@ -55,6 +58,8 @@ void hal_pin_rxtx (u1_t val); */ void hal_pin_rst (u1_t val); +// BEGIN ttn-esp32 change +// use higher level SPI functions /* * perform SPI write transaction with radio * - write the command byte 'cmd' @@ -69,9 +74,17 @@ void hal_spi_write(u1_t cmd, const u1_t* buf, int len); */ void hal_spi_read(u1_t cmd, u1_t* buf, int len); +/* + * perform 8-bit SPI transaction with radio. + * - write given byte 'outval' + * - read byte and return value + */ +//u1_t hal_spi (u1_t outval); +// END ttn-esp32 change + /* * disable all CPU interrupts. - * - might be invoked nested + * - might be invoked nested * - will be followed by matching call to hal_enableIRQs() */ void hal_disableIRQs (void); @@ -110,10 +123,13 @@ u1_t hal_checkTimer (u4_t targettime); */ void hal_failed (const char *file, u2_t line); +/* + * get the calibration value for radio_rssi + */ +s1_t hal_getRssiCal (void); #ifdef __cplusplus -} +} // extern "C" #endif - #endif // _hal_hpp_ diff --git a/src/lmic/lmic.c b/src/lmic/lmic.c index 9ed15dc..85970e6 100755 --- a/src/lmic/lmic.c +++ b/src/lmic/lmic.c @@ -2,6 +2,9 @@ * Copyright (c) 2014-2016 IBM Corporation. * All rights reserved. * + * Copyright (c) 2016-2018 MCCI Corporation. + * All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright @@ -26,46 +29,35 @@ */ //! \file -#include "lmic.h" +#define LMIC_DR_LEGACY 0 +#include "lmic_bandplan.h" #if defined(DISABLE_BEACONS) && !defined(DISABLE_PING) #error Ping needs beacon tracking #endif -#if !defined(MINRX_SYMS) -#define MINRX_SYMS 5 -#endif // !defined(MINRX_SYMS) -#define PAMBL_SYMS 8 -#define PAMBL_FSK 5 -#define PRERX_FSK 1 -#define RXLEN_FSK (1+5+2) - -#define BCN_INTV_osticks sec2osticks(BCN_INTV_sec) -#define TXRX_GUARD_osticks ms2osticks(TXRX_GUARD_ms) -#define JOIN_GUARD_osticks ms2osticks(JOIN_GUARD_ms) -#define DELAY_JACC1_osticks sec2osticks(DELAY_JACC1) -#define DELAY_JACC2_osticks sec2osticks(DELAY_JACC2) -#define DELAY_EXTDNW2_osticks sec2osticks(DELAY_EXTDNW2) -#define BCN_RESERVE_osticks ms2osticks(BCN_RESERVE_ms) -#define BCN_GUARD_osticks ms2osticks(BCN_GUARD_ms) -#define BCN_WINDOW_osticks ms2osticks(BCN_WINDOW_ms) -#define AIRTIME_BCN_osticks us2osticks(AIRTIME_BCN) -#if defined(CFG_eu868) -#define DNW2_SAFETY_ZONE ms2osticks(3000) -#endif -#if defined(CFG_us915) -#define DNW2_SAFETY_ZONE ms2osticks(750) -#endif - -// Special APIs - for development or testing -#define isTESTMODE() 0 - DEFINE_LMIC; // Fwd decls. static void engineUpdate(void); + +#if !defined(DISABLE_BEACONS) static void startScan (void); +#endif + +static inline void initTxrxFlags(const char *func, u1_t mask) { +#if LMIC_DEBUG_LEVEL > 1 +// ttn-esp32 change: fix printf for for ostime_t + LMIC_DEBUG_PRINTF("%u: %s txrxFlags %#02x --> %02x\n", (unsigned)os_getTime(), func, LMIC.txrxFlags, mask); +#endif + LMIC.txrxFlags = mask; +} + +static inline void orTxrxFlags(const char *func, u1_t mask) { + initTxrxFlags(func, LMIC.txrxFlags | mask); +} + // ================================================================================ @@ -126,7 +118,7 @@ u1_t os_getBattLevel (void) { #if !defined(os_crc16) // New CRC-16 CCITT(XMODEM) checksum for beacons: -u2_t os_crc16 (xref2u1_t data, uint len) { +u2_t os_crc16 (xref2cu1_t data, uint len) { u2_t remainder = 0; u2_t polynomial = 0x1021; for( uint i = 0; i < len; i++ ) { @@ -134,7 +126,7 @@ u2_t os_crc16 (xref2u1_t data, uint len) { for( u1_t bit = 8; bit > 0; bit--) { if( (remainder & 0x8000) ) remainder = (remainder << 1) ^ polynomial; - else + else remainder <<= 1; } } @@ -227,58 +219,7 @@ static void aes_sessKeys (u2_t devnonce, xref2cu1_t artnonce, xref2u1_t nwkkey, // ================================================================================ // BEG LORA -#if defined(CFG_eu868) // ======================================== - -#define maxFrameLen(dr) ((dr)<=DR_SF9 ? maxFrameLens[(dr)] : 0xFF) -const u1_t maxFrameLens [] = { 64,64,64,123 }; - -const u1_t _DR2RPS_CRC[] = { - ILLEGAL_RPS, - (u1_t)MAKERPS(SF12, BW125, CR_4_5, 0, 0), - (u1_t)MAKERPS(SF11, BW125, CR_4_5, 0, 0), - (u1_t)MAKERPS(SF10, BW125, CR_4_5, 0, 0), - (u1_t)MAKERPS(SF9, BW125, CR_4_5, 0, 0), - (u1_t)MAKERPS(SF8, BW125, CR_4_5, 0, 0), - (u1_t)MAKERPS(SF7, BW125, CR_4_5, 0, 0), - (u1_t)MAKERPS(SF7, BW250, CR_4_5, 0, 0), - (u1_t)MAKERPS(FSK, BW125, CR_4_5, 0, 0), - ILLEGAL_RPS -}; - -static const s1_t TXPOWLEVELS[] = { - 20, 14, 11, 8, 5, 2, 0,0, 0,0,0,0, 0,0,0,0 -}; -#define pow2dBm(mcmd_ladr_p1) (TXPOWLEVELS[(mcmd_ladr_p1&MCMD_LADR_POW_MASK)>>MCMD_LADR_POW_SHIFT]) - -#elif defined(CFG_us915) // ======================================== - -#define maxFrameLen(dr) ((dr)<=DR_SF11CR ? maxFrameLens[(dr)] : 0xFF) -const u1_t maxFrameLens [] = { 24,66,142,255,255,255,255,255, 66,142 }; - -const u1_t _DR2RPS_CRC[] = { - ILLEGAL_RPS, - MAKERPS(SF10, BW125, CR_4_5, 0, 0), - MAKERPS(SF9 , BW125, CR_4_5, 0, 0), - MAKERPS(SF8 , BW125, CR_4_5, 0, 0), - MAKERPS(SF7 , BW125, CR_4_5, 0, 0), - MAKERPS(SF8 , BW500, CR_4_5, 0, 0), - ILLEGAL_RPS , - ILLEGAL_RPS , - ILLEGAL_RPS , - MAKERPS(SF12, BW500, CR_4_5, 0, 0), - MAKERPS(SF11, BW500, CR_4_5, 0, 0), - MAKERPS(SF10, BW500, CR_4_5, 0, 0), - MAKERPS(SF9 , BW500, CR_4_5, 0, 0), - MAKERPS(SF8 , BW500, CR_4_5, 0, 0), - MAKERPS(SF7 , BW500, CR_4_5, 0, 0), - ILLEGAL_RPS -}; - -#define pow2dBm(mcmd_ladr_p1) ((s1_t)(30 - (((mcmd_ladr_p1)&MCMD_LADR_POW_MASK)<<1))) - -#endif // ================================================ - -static const u1_t SENSITIVITY[7][3] = { +static CONST_TABLE(u1_t, SENSITIVITY)[7][3] = { // ------------bw---------- // 125kHz 250kHz 500kHz { 141-109, 141-109, 141-109 }, // FSK @@ -291,7 +232,7 @@ static const u1_t SENSITIVITY[7][3] = { }; int getSensitivity (rps_t rps) { - return -141 + SENSITIVITY[getSf(rps)][getBw(rps)]; + return -141 + TABLE_GET_U1_TWODIM(SENSITIVITY, getSf(rps), getBw(rps)); } ostime_t calcAirTime (rps_t rps, u1_t plen) { @@ -338,7 +279,8 @@ extern inline int isFasterDR (dr_t dr1, dr_t dr2); extern inline int isSlowerDR (dr_t dr1, dr_t dr2); extern inline dr_t incDR (dr_t dr); extern inline dr_t decDR (dr_t dr); -extern inline dr_t assertDR (dr_t dr); +// ttn-esp32 change: remove unused function creating warning +//extern inline dr_t assertDR (dr_t dr); extern inline dr_t validDR (dr_t dr); extern inline dr_t lowerDR (dr_t dr, u1_t n); @@ -362,7 +304,7 @@ extern inline int sameSfBw (rps_t r1, rps_t r2); // Adjust DR for TX retries // - indexed by retry count // - return steps to lower DR -static const u1_t DRADJUST[2+TXCONF_ATTEMPTS] = { +static CONST_TABLE(u1_t, DRADJUST)[2+TXCONF_ATTEMPTS] = { // normal frames - 1st try / no retry 0, // confirmed frames @@ -372,37 +314,13 @@ static const u1_t DRADJUST[2+TXCONF_ATTEMPTS] = { // Table below defines the size of one symbol as // symtime = 256us * 2^T(sf,bw) -// 256us is called one symunit. -// SF: +// 256us is called one symunit. +// SF: // BW: |__7___8___9__10__11__12 // 125kHz | 2 3 4 5 6 7 // 250kHz | 1 2 3 4 5 6 // 500kHz | 0 1 2 3 4 5 -// -// Times for half symbol per DR -// Per DR table to minimize rounding errors -static const ostime_t DR2HSYM_osticks[] = { -#if defined(CFG_eu868) -#define dr2hsym(dr) (DR2HSYM_osticks[(dr)]) - us2osticksRound(128<<7), // DR_SF12 - us2osticksRound(128<<6), // DR_SF11 - us2osticksRound(128<<5), // DR_SF10 - us2osticksRound(128<<4), // DR_SF9 - us2osticksRound(128<<3), // DR_SF8 - us2osticksRound(128<<2), // DR_SF7 - us2osticksRound(128<<1), // DR_SF7B - us2osticksRound(80) // FSK -- not used (time for 1/2 byte) -#elif defined(CFG_us915) -#define dr2hsym(dr) (DR2HSYM_osticks[(dr)&7]) // map DR_SFnCR -> 0-6 - us2osticksRound(128<<5), // DR_SF10 DR_SF12CR - us2osticksRound(128<<4), // DR_SF9 DR_SF11CR - us2osticksRound(128<<3), // DR_SF8 DR_SF10CR - us2osticksRound(128<<2), // DR_SF7 DR_SF9CR - us2osticksRound(128<<1), // DR_SF8C DR_SF8CR - us2osticksRound(128<<0) // ------ DR_SF7CR -#endif -}; - +// #if !defined(DISABLE_BEACONS) static ostime_t calcRxWindow (u1_t secs, dr_t dr) { @@ -477,7 +395,7 @@ static bit_t rxschedNext (xref2rxsched_t rxsched, ostime_t cando) { #endif // !DISABLE_PING) -static ostime_t rndDelay (u1_t secSpan) { +ostime_t LMICcore_rndDelay (u1_t secSpan) { u2_t r = os_getRndU2(); ostime_t delay = r; if( delay > OSTICKS_PER_SEC ) @@ -489,7 +407,7 @@ static ostime_t rndDelay (u1_t secSpan) { static void txDelay (ostime_t reftime, u1_t secSpan) { - reftime += rndDelay(secSpan); + reftime += LMICcore_rndDelay(secSpan); if( LMIC.globalDutyRate == 0 || (reftime - LMIC.globalDutyAvail) > 0 ) { LMIC.globalDutyAvail = reftime; LMIC.opmode |= OP_RNDTX; @@ -497,7 +415,7 @@ static void txDelay (ostime_t reftime, u1_t secSpan) { } -static void setDrJoin (u1_t reason, u1_t dr) { +void LMICcore_setDrJoin (u1_t reason, u1_t dr) { EV(drChange, INFO, (e_.reason = reason, e_.deveui = MAIN::CDEV->getEui(), e_.dr = dr|DR_PAGE, @@ -516,7 +434,7 @@ static void setDrTxpow (u1_t reason, u1_t dr, s1_t pow) { e_.txpow = pow, e_.prevdr = LMIC.datarate|DR_PAGE, e_.prevtxpow = LMIC.adrTxPow)); - + if( pow != KEEP_TXPOW ) LMIC.adrTxPow = pow; if( LMIC.datarate != dr ) { @@ -545,412 +463,6 @@ void LMIC_setPingable (u1_t intvExp) { #endif // !DISABLE_PING -#if defined(CFG_eu868) -// ================================================================================ -// -// BEG: EU868 related stuff -// -enum { NUM_DEFAULT_CHANNELS=3 }; -static const u4_t iniChannelFreq[6] = { - // Join frequencies and duty cycle limit (0.1%) - EU868_F1|BAND_MILLI, EU868_F2|BAND_MILLI, EU868_F3|BAND_MILLI, - // Default operational frequencies - EU868_F1|BAND_CENTI, EU868_F2|BAND_CENTI, EU868_F3|BAND_CENTI, -}; - -static void initDefaultChannels (bit_t join) { - os_clearMem(&LMIC.channelFreq, sizeof(LMIC.channelFreq)); - os_clearMem(&LMIC.channelDrMap, sizeof(LMIC.channelDrMap)); - os_clearMem(&LMIC.bands, sizeof(LMIC.bands)); - - LMIC.channelMap = 0x07; - u1_t su = join ? 0 : 3; - for( u1_t fu=0; fu<3; fu++,su++ ) { - LMIC.channelFreq[fu] = iniChannelFreq[su]; - LMIC.channelDrMap[fu] = DR_RANGE_MAP(DR_SF12,DR_SF7); - } - - LMIC.bands[BAND_MILLI].txcap = 1000; // 0.1% - LMIC.bands[BAND_MILLI].txpow = 14; - LMIC.bands[BAND_MILLI].lastchnl = os_getRndU1() % MAX_CHANNELS; - LMIC.bands[BAND_CENTI].txcap = 100; // 1% - LMIC.bands[BAND_CENTI].txpow = 14; - LMIC.bands[BAND_CENTI].lastchnl = os_getRndU1() % MAX_CHANNELS; - LMIC.bands[BAND_DECI ].txcap = 10; // 10% - LMIC.bands[BAND_DECI ].txpow = 27; - LMIC.bands[BAND_DECI ].lastchnl = os_getRndU1() % MAX_CHANNELS; - LMIC.bands[BAND_MILLI].avail = - LMIC.bands[BAND_CENTI].avail = - LMIC.bands[BAND_DECI ].avail = os_getTime(); -} - -bit_t LMIC_setupBand (u1_t bandidx, s1_t txpow, u2_t txcap) { - if( bandidx > BAND_AUX ) return 0; - band_t* b = &LMIC.bands[bandidx]; - b->txpow = txpow; - b->txcap = txcap; - b->avail = os_getTime(); - b->lastchnl = os_getRndU1() % MAX_CHANNELS; - return 1; -} - -bit_t LMIC_setupChannel (u1_t chidx, u4_t freq, u2_t drmap, s1_t band) { - if( chidx >= MAX_CHANNELS ) - return 0; - if( band == -1 ) { - if( freq >= 869400000 && freq <= 869650000 ) - freq |= BAND_DECI; // 10% 27dBm - else if( (freq >= 868000000 && freq <= 868600000) || - (freq >= 869700000 && freq <= 870000000) ) - freq |= BAND_CENTI; // 1% 14dBm - else - freq |= BAND_MILLI; // 0.1% 14dBm - } else { - if( band > BAND_AUX ) return 0; - freq = (freq&~3) | band; - } - LMIC.channelFreq [chidx] = freq; - LMIC.channelDrMap[chidx] = drmap==0 ? DR_RANGE_MAP(DR_SF12,DR_SF7) : drmap; - LMIC.channelMap |= 1<> 8) * 100; - if( freq < EU868_FREQ_MIN || freq > EU868_FREQ_MAX ) - freq = 0; - return freq; -} - -static u1_t mapChannels (u1_t chpage, u2_t chmap) { - // Bad page, disable all channel, enable non-existent - if( chpage != 0 || chmap==0 || (chmap & ~LMIC.channelMap) != 0 ) - return 0; // illegal input - for( u1_t chnl=0; chnltxpow; - band->avail = txbeg + airtime * band->txcap; - if( LMIC.globalDutyRate != 0 ) - LMIC.globalDutyAvail = txbeg + (airtime< 1 - lmic_printf("%lu: Updating info for TX at %lu, airtime will be %lu. Setting available time for band %ld to %lu\n", os_getTime(), txbeg, airtime, freq & 0x3, band->avail); - if( LMIC.globalDutyRate != 0 ) - lmic_printf("%lu: Updating global duty avail to %lu\n", os_getTime(), LMIC.globalDutyAvail); - #endif -} - -static ostime_t nextTx (ostime_t now) { - u1_t bmap=0xF; - do { - ostime_t mintime = now + /*8h*/sec2osticks(28800); - u1_t band=0; - for( u1_t bi=0; bi<4; bi++ ) { - if( (bmap & (1< 0 ) { - #if LMIC_DEBUG_LEVEL > 1 - lmic_printf("%lu: Considering band %d, which is available at %lu\n", os_getTime(), bi, LMIC.bands[bi].avail); - #endif - mintime = LMIC.bands[band = bi].avail; - } - } - // Find next channel in given band - u1_t chnl = LMIC.bands[band].lastchnl; - for( u1_t ci=0; ci= MAX_CHANNELS ) - chnl -= MAX_CHANNELS; - if( (LMIC.channelMap & (1< 1 - lmic_printf("%lu: No channel found in band %d\n", os_getTime(), band); - #endif - if( (bmap &= ~(1<>LMIC.datarate)); - #if LMIC_DEBUG_LEVEL > 1 - if (failed) - lmic_printf("%lu: Join failed\n", os_getTime()); - else - lmic_printf("%lu: Scheduling next join at %lu\n", os_getTime(), LMIC.txend); - #endif - // 1 - triggers EV_JOIN_FAILED event - return failed; -} -#endif // !DISABLE_JOIN - -// -// END: EU868 related stuff -// -// ================================================================================ -#elif defined(CFG_us915) -// ================================================================================ -// -// BEG: US915 related stuff -// - - -static void initDefaultChannels (void) { - for( u1_t i=0; i<4; i++ ) - LMIC.channelMap[i] = 0xFFFF; - LMIC.channelMap[4] = 0x00FF; -} - -static u4_t convFreq (xref2u1_t ptr) { - u4_t freq = (os_rlsbf4(ptr-1) >> 8) * 100; - if( freq < US915_FREQ_MIN || freq > US915_FREQ_MAX ) - freq = 0; - return freq; -} - -bit_t LMIC_setupChannel (u1_t chidx, u4_t freq, u2_t drmap, s1_t band) { - if( chidx < 72 || chidx >= 72+MAX_XCHANNELS ) - return 0; // channels 0..71 are hardwired - chidx -= 72; - LMIC.xchFreq[chidx] = freq; - LMIC.xchDrMap[chidx] = drmap==0 ? DR_RANGE_MAP(DR_SF10,DR_SF8C) : drmap; - LMIC.channelMap[chidx>>4] |= (1<<(chidx&0xF)); - return 1; -} - -void LMIC_disableChannel (u1_t channel) { - if( channel < 72+MAX_XCHANNELS ) - LMIC.channelMap[channel>>4] &= ~(1<<(channel&0xF)); -} - -void LMIC_enableChannel (u1_t channel) { - if( channel < 72+MAX_XCHANNELS ) - LMIC.channelMap[channel>>4] |= (1<<(channel&0xF)); -} - -void LMIC_enableSubBand (u1_t band) { - ASSERT(band < 8); - u1_t start = band * 8; - u1_t end = start + 8; - for (int channel=start; channel < end; ++channel ) - LMIC_enableChannel(channel); -} -void LMIC_disableSubBand (u1_t band) { - ASSERT(band < 8); - u1_t start = band * 8; - u1_t end = start + 8; - for (int channel=start; channel < end; ++channel ) - LMIC_disableChannel(channel); -} -void LMIC_selectSubBand (u1_t band) { - ASSERT(band < 8); - for (int b=0; b<8; ++b) { - if (band==b) - LMIC_enableSubBand(b); - else - LMIC_disableSubBand(b); - } -} - -static u1_t mapChannels (u1_t chpage, u2_t chmap) { - if( chpage == MCMD_LADR_CHP_125ON || chpage == MCMD_LADR_CHP_125OFF ) { - u2_t en125 = chpage == MCMD_LADR_CHP_125ON ? 0xFFFF : 0x0000; - for( u1_t u=0; u<4; u++ ) - LMIC.channelMap[u] = en125; - LMIC.channelMap[64/16] = chmap; - } else { - if( chpage >= (72+MAX_XCHANNELS+15)/16 ) - return 0; - LMIC.channelMap[chpage] = chmap; - } - return 1; -} - -static void updateTx (ostime_t txbeg) { - u1_t chnl = LMIC.txChnl; - if( chnl < 64 ) { - LMIC.freq = US915_125kHz_UPFBASE + chnl*US915_125kHz_UPFSTEP; - LMIC.txpow = 30; - return; - } - LMIC.txpow = 26; - if( chnl < 64+8 ) { - LMIC.freq = US915_500kHz_UPFBASE + (chnl-64)*US915_500kHz_UPFSTEP; - } else { - ASSERT(chnl < 64+8+MAX_XCHANNELS); - LMIC.freq = LMIC.xchFreq[chnl-72]; - } - - // Update global duty cycle stats - if( LMIC.globalDutyRate != 0 ) { - ostime_t airtime = calcAirTime(LMIC.rps, LMIC.dataLen); - LMIC.globalDutyAvail = txbeg + (airtime<= DR_SF8C ) { // 500kHz - u1_t map = LMIC.channelMap[64/16]&0xFF; - for( u1_t i=0; i<8; i++ ) { - if( (map & (1<<(++LMIC.chRnd & 7))) != 0 ) { - LMIC.txChnl = 64 + (LMIC.chRnd & 7); - return; - } - } - } else { // 125kHz - for( u1_t i=0; i<64; i++ ) { - u1_t chnl = ++LMIC.chRnd & 0x3F; - if( (LMIC.channelMap[(chnl >> 4)] & (1<<(chnl & 0xF))) != 0 ) { - LMIC.txChnl = chnl; - return; - } - } - } - // No feasible channel found! Keep old one. -} - -#if !defined(DISABLE_BEACONS) -static void setBcnRxParams (void) { - LMIC.dataLen = 0; - LMIC.freq = US915_500kHz_DNFBASE + LMIC.bcnChnl * US915_500kHz_DNFSTEP; - LMIC.rps = setIh(setNocrc(dndr2rps((dr_t)DR_BCN),1),LEN_BCN); -} -#endif // !DISABLE_BEACONS - -#define setRx1Params() { \ - LMIC.freq = US915_500kHz_DNFBASE + (LMIC.txChnl & 0x7) * US915_500kHz_DNFSTEP; \ - if( /* TX datarate */LMIC.dndr < DR_SF8C ) \ - LMIC.dndr += DR_SF10CR - DR_SF10; \ - else if( LMIC.dndr == DR_SF8C ) \ - LMIC.dndr = DR_SF7CR; \ - LMIC.rps = dndr2rps(LMIC.dndr); \ -} - -#if !defined(DISABLE_JOIN) -static void initJoinLoop (void) { - LMIC.chRnd = 0; - LMIC.txChnl = 0; - LMIC.adrTxPow = 20; - ASSERT((LMIC.opmode & OP_NEXTCHNL)==0); - LMIC.txend = os_getTime(); - setDrJoin(DRCHG_SET, DR_SF7); -} - -static ostime_t nextJoinState (void) { - // Try the following: - // SF7/8/9/10 on a random channel 0..63 - // SF8C on a random channel 64..71 - // - u1_t failed = 0; - if( LMIC.datarate != DR_SF8C ) { - LMIC.txChnl = 64+(LMIC.txChnl&7); - setDrJoin(DRCHG_SET, DR_SF8C); - } else { - LMIC.txChnl = os_getRndU1() & 0x3F; - s1_t dr = DR_SF7 - ++LMIC.txCnt; - if( dr < DR_SF10 ) { - dr = DR_SF10; - failed = 1; // All DR exhausted - signal failed - } - setDrJoin(DRCHG_SET, dr); - } - LMIC.opmode &= ~OP_NEXTCHNL; - LMIC.txend = os_getTime() + - (isTESTMODE() - // Avoid collision with JOIN ACCEPT being sent by GW (but we missed it - GW is still busy) - ? DNW2_SAFETY_ZONE - // Otherwise: randomize join (street lamp case): - // SF10:16, SF9=8,..SF8C:1secs - : rndDelay(16>>LMIC.datarate)); - // 1 - triggers EV_JOIN_FAILED event - return failed; -} -#endif // !DISABLE_JOIN - -// -// END: US915 related stuff -// -// ================================================================================ -#else -#error Unsupported frequency band! -#endif - - static void runEngineUpdate (xref2osjob_t osjob) { engineUpdate(); } @@ -1014,13 +526,7 @@ static void stateJustJoined (void) { static int decodeBeacon (void) { ASSERT(LMIC.dataLen == LEN_BCN); // implicit header RX guarantees this xref2u1_t d = LMIC.frame; - if( -#if CFG_eu868 - d[OFF_BCN_CRC1] != (u1_t)os_crc16(d,OFF_BCN_CRC1) -#elif CFG_us915 - os_rlsbf2(&d[OFF_BCN_CRC1]) != os_crc16(d,OFF_BCN_CRC1) -#endif - ) + if(! LMICbandplan_isValidBeacon1(d)) return 0; // first (common) part fails CRC check // First set of fields is ok u4_t bcnnetid = os_rlsbf4(&d[OFF_BCN_NETID]) & 0xFFFFFF; @@ -1047,6 +553,193 @@ static int decodeBeacon (void) { } #endif // !DISABLE_BEACONS +// scan mac commands starting at opts[] for olen, return count of bytes consumed. +static int +scan_mac_cmds( + const uint8_t *opts, + int olen + ) { + int oidx = 0; + while( oidx < olen ) { + switch( opts[oidx] ) { + case MCMD_LCHK_ANS: { + //int gwmargin = opts[oidx+1]; + //int ngws = opts[oidx+2]; + oidx += 3; + continue; + } + case MCMD_LADR_REQ: { + u1_t p1 = opts[oidx+1]; // txpow + DR + u2_t chmap = os_rlsbf2(&opts[oidx+2]);// list of enabled channels + u1_t chpage = opts[oidx+4] & MCMD_LADR_CHPAGE_MASK; // channel page + u1_t uprpt = opts[oidx+4] & MCMD_LADR_REPEAT_MASK; // up repeat count + oidx += 5; + + // TODO(tmm@mcci.com): LoRaWAN 1.1 requires us to process multiple + // LADR requests, and only update if all pass. So this should check + // ladrAns == 0, and only initialize if so. Need to repeat ACKs, so + // we need to count the number we see. + LMIC.ladrAns = 0x80 | // Include an answer into next frame up + MCMD_LADR_ANS_POWACK | MCMD_LADR_ANS_CHACK | MCMD_LADR_ANS_DRACK; + if( !LMICbandplan_mapChannels(chpage, chmap) ) + LMIC.ladrAns &= ~MCMD_LADR_ANS_CHACK; + dr_t dr = (dr_t)(p1>>MCMD_LADR_DR_SHIFT); + if( !validDR(dr) ) { + LMIC.ladrAns &= ~MCMD_LADR_ANS_DRACK; + EV(specCond, ERR, (e_.reason = EV::specCond_t::BAD_MAC_CMD, + e_.eui = MAIN::CDEV->getEui(), + e_.info = Base::lsbf4(&d[pend]), + e_.info2 = Base::msbf4(&opts[oidx-4]))); + } + // TODO(tmm@mcci.com): see above; this needs to move outside the + // txloop. And we need to have "consistent" answers for the block + // of contiguous commands (whatever that means), and ignore the + // data rate, NbTrans (uprpt) and txPow until the last one. +#if LMIC_DEBUG_LEVEL > 0 +// ttn-esp32 change: fix printf for for ostime_t + LMIC_DEBUG_PRINTF("%u: LinkAdrReq: p1:%02x chmap:%04x chpage:%02x uprt:%02x ans:%02x\n", + (unsigned)os_getTime(), p1, chmap, chpage, uprpt, LMIC.ladrAns + ); +#endif /* LMIC_DEBUG_LEVEL */ + + if( (LMIC.ladrAns & 0x7F) == (MCMD_LADR_ANS_POWACK | MCMD_LADR_ANS_CHACK | MCMD_LADR_ANS_DRACK) ) { + // Nothing went wrong - use settings + LMIC.upRepeat = uprpt; + setDrTxpow(DRCHG_NWKCMD, dr, pow2dBm(p1)); + } + LMIC.adrChanged = 1; // Trigger an ACK to NWK + continue; + } + case MCMD_DEVS_REQ: { + LMIC.devsAns = 1; + // LMIC.snr is SNR time 4, convert to real SNR; rounding towards zero. + const int snr = (LMIC.snr + 2) / 4; + // per [1.02] 5.5. the margin is the SNR. + LMIC.devAnsMargin = (u1_t)(0b00111111 & (snr <= -32 ? -32 : snr >= 31 ? 31 : snr)); + oidx += 1; + continue; + } + case MCMD_DN2P_SET: { +#if !defined(DISABLE_MCMD_DN2P_SET) + dr_t dr = (dr_t)(opts[oidx+1] & 0x0F); + u1_t rx1DrOffset = (u1_t)((opts[oidx+1] & 0x70) >> 4); + u4_t freq = LMICbandplan_convFreq(&opts[oidx+2]); + LMIC.dn2Ans = 0x80; // answer pending + if( validDR(dr) ) + LMIC.dn2Ans |= MCMD_DN2P_ANS_DRACK; + if( freq != 0 ) + LMIC.dn2Ans |= MCMD_DN2P_ANS_CHACK; + if (rx1DrOffset <= 3) + LMIC.dn2Ans |= MCMD_DN2P_ANS_RX1DrOffsetAck; + + if( LMIC.dn2Ans == (0x80|MCMD_DN2P_ANS_DRACK|MCMD_DN2P_ANS_CHACK| MCMD_DN2P_ANS_RX1DrOffsetAck) ) { + LMIC.dn2Dr = dr; + LMIC.dn2Freq = freq; + LMIC.rx1DrOffset = rx1DrOffset; + DO_DEVDB(LMIC.dn2Dr,dn2Dr); + DO_DEVDB(LMIC.dn2Freq,dn2Freq); + } +#endif // !DISABLE_MCMD_DN2P_SET + oidx += 5; + continue; + } + case MCMD_DCAP_REQ: { +#if !defined(DISABLE_MCMD_DCAP_REQ) + u1_t cap = opts[oidx+1]; + // A value cap=0xFF means device is OFF unless enabled again manually. + if( cap==0xFF ) + LMIC.opmode |= OP_SHUTDOWN; // stop any sending + LMIC.globalDutyRate = cap & 0xF; + LMIC.globalDutyAvail = os_getTime(); + DO_DEVDB(cap,dutyCap); + LMIC.dutyCapAns = 1; + oidx += 2; +#endif // !DISABLE_MCMD_DCAP_REQ + continue; + } + case MCMD_SNCH_REQ: { +#if !defined(DISABLE_MCMD_SNCH_REQ) + u1_t chidx = opts[oidx+1]; // channel + u4_t freq = LMICbandplan_convFreq(&opts[oidx+2]); // freq + u1_t drs = opts[oidx+5]; // datarate span + LMIC.snchAns = 0x80; + if( freq != 0 && LMIC_setupChannel(chidx, freq, DR_RANGE_MAP(drs&0xF,drs>>4), -1) ) + LMIC.snchAns |= MCMD_SNCH_ANS_DRACK|MCMD_SNCH_ANS_FQACK; +#endif // !DISABLE_MCMD_SNCH_REQ + oidx += 6; + continue; + } + case MCMD_PING_SET: { +#if !defined(DISABLE_MCMD_PING_SET) && !defined(DISABLE_PING) + u4_t freq = LMICbandplan_convFreq(&opts[oidx+1]); + u1_t flags = 0x80; + if( freq != 0 ) { + flags |= MCMD_PING_ANS_FQACK; + LMIC.ping.freq = freq; + DO_DEVDB(LMIC.ping.intvExp, pingIntvExp); + DO_DEVDB(LMIC.ping.freq, pingFreq); + DO_DEVDB(LMIC.ping.dr, pingDr); + } + LMIC.pingSetAns = flags; +#endif // !DISABLE_MCMD_PING_SET && !DISABLE_PING + oidx += 4; + continue; + } + case MCMD_BCNI_ANS: { +#if !defined(DISABLE_MCMD_BCNI_ANS) && !defined(DISABLE_BEACONS) + // Ignore if tracking already enabled + if( (LMIC.opmode & OP_TRACK) == 0 ) { + LMIC.bcnChnl = opts[oidx+3]; + // Enable tracking - bcninfoTries + LMIC.opmode |= OP_TRACK; + // Cleared later in txComplete handling - triggers EV_BEACON_FOUND + ASSERT(LMIC.bcninfoTries!=0); + // Setup RX parameters + LMIC.bcninfo.txtime = (LMIC.rxtime + + ms2osticks(os_rlsbf2(&opts[oidx+1]) * MCMD_BCNI_TUNIT) + + ms2osticksCeil(MCMD_BCNI_TUNIT/2) + - BCN_INTV_osticks); + LMIC.bcninfo.flags = 0; // txtime above cannot be used as reference (BCN_PARTIAL|BCN_FULL cleared) + calcBcnRxWindowFromMillis(MCMD_BCNI_TUNIT,1); // error of +/-N ms + + EV(lostFrame, INFO, (e_.reason = EV::lostFrame_t::MCMD_BCNI_ANS, + e_.eui = MAIN::CDEV->getEui(), + e_.lostmic = Base::lsbf4(&d[pend]), + e_.info = (LMIC.missedBcns | + (osticks2us(LMIC.bcninfo.txtime + BCN_INTV_osticks + - LMIC.bcnRxtime) << 8)), + e_.time = MAIN::CDEV->ostime2ustime(LMIC.bcninfo.txtime + BCN_INTV_osticks))); + } +#endif // !DISABLE_MCMD_BCNI_ANS && !DISABLE_BEACONS + oidx += 4; + continue; + } /* end case */ + case MCMD_TxParamSetupReq: { +#if LMIC_ENABLE_TxParamSetupReq + uint8_t txParam; + txParam = opts[oidx+1]; + + // we don't allow unrecognized bits to come through + txParam &= (MCMD_TxParam_RxDWELL_MASK| + MCMD_TxParam_TxDWELL_MASK| + MCMD_TxParam_MaxEIRP_MASK); + LMIC.txParam = txParam; + LMIC.txParamSetupAns = 1; +#endif // LMIC_ENABLE_TxParamSetupReq + oidx += 2; + continue; + } /* end case */ + } /* end switch */ + /* unrecognized mac commands fall out of switch to here */ + EV(specCond, ERR, (e_.reason = EV::specCond_t::BAD_MAC_CMD, + e_.eui = MAIN::CDEV->getEui(), + e_.info = Base::lsbf4(&d[pend]), + e_.info2 = Base::msbf4(&opts[oidx]))); + /* stop processing options */ + break; + } /* end while */ + return oidx; +} static bit_t decodeFrame (void) { xref2u1_t d = LMIC.frame; @@ -1056,6 +749,7 @@ static bit_t decodeFrame (void) { #if LMIC_DEBUG_LEVEL > 0 const char *window = (LMIC.txrxFlags & TXRX_DNW1) ? "RX1" : ((LMIC.txrxFlags & TXRX_DNW2) ? "RX2" : "Other"); #endif + if( dlen < OFF_DAT_OPTS+4 || (hdr & HDR_MAJOR) != HDR_MAJOR_V1 || (ftype != HDR_FTYPE_DADN && ftype != HDR_FTYPE_DCDN) ) { @@ -1066,7 +760,8 @@ static bit_t decodeFrame (void) { e_.info2 = hdr + (dlen<<8))); norx: #if LMIC_DEBUG_LEVEL > 0 - lmic_printf("%lu: Invalid downlink, window=%s\n", os_getTime(), window); +// ttn-esp32 change: fix printf for for ostime_t + LMIC_DEBUG_PRINTF("%u: Invalid downlink, window=%s\n", (unsigned)os_getTime(), window); #endif LMIC.dataLen = 0; return 0; @@ -1115,14 +810,14 @@ static bit_t decodeFrame (void) { if( (s4_t)seqno > (s4_t)LMIC.seqnoDn ) { EV(specCond, INFO, (e_.reason = EV::specCond_t::DNSEQNO_ROLL_OVER, e_.eui = MAIN::CDEV->getEui(), - e_.info = LMIC.seqnoDn, + e_.info = LMIC.seqnoDn, e_.info2 = seqno)); goto norx; } if( seqno != LMIC.seqnoDn-1 || !LMIC.dnConf || ftype != HDR_FTYPE_DCDN ) { EV(specCond, INFO, (e_.reason = EV::specCond_t::DNSEQNO_OBSOLETE, e_.eui = MAIN::CDEV->getEui(), - e_.info = LMIC.seqnoDn, + e_.info = LMIC.seqnoDn, e_.info2 = seqno)); goto norx; } @@ -1134,7 +829,7 @@ static bit_t decodeFrame (void) { if( seqno > LMIC.seqnoDn ) { EV(specCond, INFO, (e_.reason = EV::specCond_t::DNSEQNO_SKIP, e_.eui = MAIN::CDEV->getEui(), - e_.info = LMIC.seqnoDn, + e_.info = LMIC.seqnoDn, e_.info2 = seqno)); } LMIC.seqnoDn = seqno+1; // next number to be expected @@ -1151,149 +846,19 @@ static bit_t decodeFrame (void) { if( LMIC.adrAckReq != LINK_CHECK_OFF ) LMIC.adrAckReq = LINK_CHECK_INIT; - // Process OPTS int m = LMIC.rssi - RSSI_OFF - getSensitivity(LMIC.rps); + // for legacy reasons, LMIC.margin is set to the unsigned sensitivity. It can never be negative. + // it's only computed for legacy clients LMIC.margin = m < 0 ? 0 : m > 254 ? 254 : m; +#if LMIC_DEBUG_LEVEL > 0 + // Process OPTS +// ttn-esp32 change: fix printf for for ostime_t + LMIC_DEBUG_PRINTF("%u: process options (olen=%#x)\n", (unsigned)os_getTime(), olen); +#endif + xref2u1_t opts = &d[OFF_DAT_OPTS]; - int oidx = 0; - while( oidx < olen ) { - switch( opts[oidx] ) { - case MCMD_LCHK_ANS: { - //int gwmargin = opts[oidx+1]; - //int ngws = opts[oidx+2]; - oidx += 3; - continue; - } - case MCMD_LADR_REQ: { - u1_t p1 = opts[oidx+1]; // txpow + DR - u2_t chmap = os_rlsbf2(&opts[oidx+2]);// list of enabled channels - u1_t chpage = opts[oidx+4] & MCMD_LADR_CHPAGE_MASK; // channel page - u1_t uprpt = opts[oidx+4] & MCMD_LADR_REPEAT_MASK; // up repeat count - oidx += 5; - - LMIC.ladrAns = 0x80 | // Include an answer into next frame up - MCMD_LADR_ANS_POWACK | MCMD_LADR_ANS_CHACK | MCMD_LADR_ANS_DRACK; - if( !mapChannels(chpage, chmap) ) - LMIC.ladrAns &= ~MCMD_LADR_ANS_CHACK; - dr_t dr = (dr_t)(p1>>MCMD_LADR_DR_SHIFT); - if( !validDR(dr) ) { - LMIC.ladrAns &= ~MCMD_LADR_ANS_DRACK; - EV(specCond, ERR, (e_.reason = EV::specCond_t::BAD_MAC_CMD, - e_.eui = MAIN::CDEV->getEui(), - e_.info = Base::lsbf4(&d[pend]), - e_.info2 = Base::msbf4(&opts[oidx-4]))); - } - if( (LMIC.ladrAns & 0x7F) == (MCMD_LADR_ANS_POWACK | MCMD_LADR_ANS_CHACK | MCMD_LADR_ANS_DRACK) ) { - // Nothing went wrong - use settings - LMIC.upRepeat = uprpt; - setDrTxpow(DRCHG_NWKCMD, dr, pow2dBm(p1)); - } - LMIC.adrChanged = 1; // Trigger an ACK to NWK - continue; - } - case MCMD_DEVS_REQ: { - LMIC.devsAns = 1; - oidx += 1; - continue; - } - case MCMD_DN2P_SET: { -#if !defined(DISABLE_MCMD_DN2P_SET) - dr_t dr = (dr_t)(opts[oidx+1] & 0x0F); - u4_t freq = convFreq(&opts[oidx+2]); - LMIC.dn2Ans = 0x80; // answer pending - if( validDR(dr) ) - LMIC.dn2Ans |= MCMD_DN2P_ANS_DRACK; - if( freq != 0 ) - LMIC.dn2Ans |= MCMD_DN2P_ANS_CHACK; - if( LMIC.dn2Ans == (0x80|MCMD_DN2P_ANS_DRACK|MCMD_DN2P_ANS_CHACK) ) { - LMIC.dn2Dr = dr; - LMIC.dn2Freq = freq; - DO_DEVDB(LMIC.dn2Dr,dn2Dr); - DO_DEVDB(LMIC.dn2Freq,dn2Freq); - } -#endif // !DISABLE_MCMD_DN2P_SET - oidx += 5; - continue; - } - case MCMD_DCAP_REQ: { -#if !defined(DISABLE_MCMD_DCAP_REQ) - u1_t cap = opts[oidx+1]; - // A value cap=0xFF means device is OFF unless enabled again manually. - if( cap==0xFF ) - LMIC.opmode |= OP_SHUTDOWN; // stop any sending - LMIC.globalDutyRate = cap & 0xF; - LMIC.globalDutyAvail = os_getTime(); - DO_DEVDB(cap,dutyCap); - LMIC.dutyCapAns = 1; - oidx += 2; -#endif // !DISABLE_MCMD_DCAP_REQ - continue; - } - case MCMD_SNCH_REQ: { -#if !defined(DISABLE_MCMD_SNCH_REQ) - u1_t chidx = opts[oidx+1]; // channel - u4_t freq = convFreq(&opts[oidx+2]); // freq - u1_t drs = opts[oidx+5]; // datarate span - LMIC.snchAns = 0x80; - if( freq != 0 && LMIC_setupChannel(chidx, freq, DR_RANGE_MAP(drs&0xF,drs>>4), -1) ) - LMIC.snchAns |= MCMD_SNCH_ANS_DRACK|MCMD_SNCH_ANS_FQACK; -#endif // !DISABLE_MCMD_SNCH_REQ - oidx += 6; - continue; - } - case MCMD_PING_SET: { -#if !defined(DISABLE_MCMD_PING_SET) && !defined(DISABLE_PING) - u4_t freq = convFreq(&opts[oidx+1]); - u1_t flags = 0x80; - if( freq != 0 ) { - flags |= MCMD_PING_ANS_FQACK; - LMIC.ping.freq = freq; - DO_DEVDB(LMIC.ping.intvExp, pingIntvExp); - DO_DEVDB(LMIC.ping.freq, pingFreq); - DO_DEVDB(LMIC.ping.dr, pingDr); - } - LMIC.pingSetAns = flags; -#endif // !DISABLE_MCMD_PING_SET && !DISABLE_PING - oidx += 4; - continue; - } - case MCMD_BCNI_ANS: { -#if !defined(DISABLE_MCMD_BCNI_ANS) && !defined(DISABLE_BEACONS) - // Ignore if tracking already enabled - if( (LMIC.opmode & OP_TRACK) == 0 ) { - LMIC.bcnChnl = opts[oidx+3]; - // Enable tracking - bcninfoTries - LMIC.opmode |= OP_TRACK; - // Cleared later in txComplete handling - triggers EV_BEACON_FOUND - ASSERT(LMIC.bcninfoTries!=0); - // Setup RX parameters - LMIC.bcninfo.txtime = (LMIC.rxtime - + ms2osticks(os_rlsbf2(&opts[oidx+1]) * MCMD_BCNI_TUNIT) - + ms2osticksCeil(MCMD_BCNI_TUNIT/2) - - BCN_INTV_osticks); - LMIC.bcninfo.flags = 0; // txtime above cannot be used as reference (BCN_PARTIAL|BCN_FULL cleared) - calcBcnRxWindowFromMillis(MCMD_BCNI_TUNIT,1); // error of +/-N ms - - EV(lostFrame, INFO, (e_.reason = EV::lostFrame_t::MCMD_BCNI_ANS, - e_.eui = MAIN::CDEV->getEui(), - e_.lostmic = Base::lsbf4(&d[pend]), - e_.info = (LMIC.missedBcns | - (osticks2us(LMIC.bcninfo.txtime + BCN_INTV_osticks - - LMIC.bcnRxtime) << 8)), - e_.time = MAIN::CDEV->ostime2ustime(LMIC.bcninfo.txtime + BCN_INTV_osticks))); - } -#endif // !DISABLE_MCMD_BCNI_ANS && !DISABLE_BEACONS - oidx += 4; - continue; - } - } - EV(specCond, ERR, (e_.reason = EV::specCond_t::BAD_MAC_CMD, - e_.eui = MAIN::CDEV->getEui(), - e_.info = Base::lsbf4(&d[pend]), - e_.info2 = Base::msbf4(&opts[oidx]))); - break; - } + int oidx = scan_mac_cmds(opts, olen); if( oidx != olen ) { EV(specCond, ERR, (e_.reason = EV::specCond_t::CORRUPTED_FRAME, e_.eui = MAIN::CDEV->getEui(), @@ -1303,9 +868,27 @@ static bit_t decodeFrame (void) { if( !replayConf ) { // Handle payload only if not a replay // Decrypt payload - if any - if( port >= 0 && pend-poff > 0 ) + if( port >= 0 && pend-poff > 0 ) { aes_cipher(port <= 0 ? LMIC.nwkKey : LMIC.artKey, LMIC.devaddr, seqno, /*dn*/1, d+poff, pend-poff); - + if (port == 0) { + // this is a mac command. scan the options. +#if LMIC_DEBUG_LEVEL > 0 +// ttn-esp32 change: fix printf for for ostime_t + LMIC_DEBUG_PRINTF("%u: process mac commands for port 0 (olen=%#x)\n", (unsigned)os_getTime(), pend-poff); +#endif + int optendindex = scan_mac_cmds(d+poff, pend-poff); + if (optendindex != pend-poff) { +#if LMIC_DEBUG_LEVEL > 0 +// ttn-esp32 change: fix printf for for ostime_t + LMIC_DEBUG_PRINTF( + "%u: error processing mac commands for port 0 " + "(len=%#x, optendindex=%#x)\n", + (unsigned)os_getTime(), pend-poff, optendindex + ); +#endif + } + } + } // end decrypt payload EV(dfinfo, DEBUG, (e_.deveui = MAIN::CDEV->getEui(), e_.devaddr = LMIC.devaddr, e_.seqno = seqno, @@ -1334,22 +917,27 @@ static bit_t decodeFrame (void) { e_.eui = MAIN::CDEV->getEui(), e_.info = seqno, e_.info2 = ackup)); +#if LMIC_DEBUG_LEVEL > 1 +// ttn-esp32 change: fix printf for for ostime_t + LMIC_DEBUG_PRINTF("%u: ??ack error ack=%d txCnt=%d\n", (unsigned)os_getTime(), ackup, LMIC.txCnt); +#endif } if( LMIC.txCnt != 0 ) // we requested an ACK - LMIC.txrxFlags |= ackup ? TXRX_ACK : TXRX_NACK; + orTxrxFlags(__func__, ackup ? TXRX_ACK : TXRX_NACK); - if( port < 0 ) { - LMIC.txrxFlags |= TXRX_NOPORT; + if( port <= 0 ) { + orTxrxFlags(__func__, TXRX_NOPORT); LMIC.dataBeg = poff; LMIC.dataLen = 0; } else { - LMIC.txrxFlags |= TXRX_PORT; + orTxrxFlags(__func__, TXRX_PORT); LMIC.dataBeg = poff; LMIC.dataLen = pend-poff; } #if LMIC_DEBUG_LEVEL > 0 - lmic_printf("%lu: Received downlink, window=%s, port=%d, ack=%d\n", os_getTime(), window, port, ackup); +// ttn-esp32 change: fix printf for for ostime_t + LMIC_DEBUG_PRINTF("%u: Received downlink, window=%s, port=%d, ack=%d, txrxFlags=%#x\n", (unsigned)os_getTime(), window, port, ackup, LMIC.txrxFlags); #endif return 1; } @@ -1360,7 +948,7 @@ static bit_t decodeFrame (void) { static void setupRx2 (void) { - LMIC.txrxFlags = TXRX_DNW2; + initTxrxFlags(__func__, TXRX_DNW2); LMIC.rps = dndr2rps(LMIC.dn2Dr); LMIC.freq = LMIC.dn2Freq; LMIC.dataLen = 0; @@ -1398,11 +986,12 @@ static void schedRx12 (ostime_t delay, osjobcb_t func, u1_t dr) { // (again note that hsym is half a sumbol time, so no /2 needed) LMIC.rxtime = LMIC.txend + delay + PAMBL_SYMS * hsym - LMIC.rxsyms * hsym; + LMIC_X_DEBUG_PRINTF("%lu: sched Rx12 %lu\n", os_getTime(), LMIC.rxtime - RX_RAMPUP); os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, func); } static void setupRx1 (osjobcb_t func) { - LMIC.txrxFlags = TXRX_DNW1; + initTxrxFlags(__func__, TXRX_DNW1); // Turn LMIC.rps from TX over to RX LMIC.rps = setNocrc(LMIC.rps,1); LMIC.dataLen = 0; @@ -1421,18 +1010,14 @@ static void txDone (ostime_t delay, osjobcb_t func) { #endif // !DISABLE_PING // Change RX frequency / rps (US only) before we increment txChnl - setRx1Params(); + LMICbandplan_setRx1Params(); // LMIC.rxsyms carries the TX datarate (can be != LMIC.datarate [confirm retries etc.]) // Setup receive - LMIC.rxtime is preloaded with 1.5 symbols offset to tune // into the middle of the 8 symbols preamble. -#if defined(CFG_eu868) - if( /* TX datarate */LMIC.rxsyms == DR_FSK ) { - LMIC.rxtime = LMIC.txend + delay - PRERX_FSK*us2osticksRound(160); - LMIC.rxsyms = RXLEN_FSK; - os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, func); + if( LMICbandplan_isFSK() ) { + LMICbandplan_txDoneFSK(delay, func); } else -#endif { schedRx12(delay, func, LMIC.dndr); } @@ -1466,23 +1051,38 @@ static bit_t processJoinAccept (void) { return 1; } LMIC.opmode &= ~OP_TXRXPEND; - ostime_t delay = nextJoinState(); + int failed = LMICbandplan_nextJoinState(); EV(devCond, DEBUG, (e_.reason = EV::devCond_t::NO_JACC, e_.eui = MAIN::CDEV->getEui(), e_.info = LMIC.datarate|DR_PAGE, - e_.info2 = osticks2ms(delay))); + e_.info2 = failed)); // Build next JOIN REQUEST with next engineUpdate call // Optionally, report join failed. - // Both after a random/chosen amount of ticks. - os_setTimedCallback(&LMIC.osjob, os_getTime()+delay, - (delay&1) != 0 + // Both after a random/chosen amount of ticks. That time + // is in LMIC.txend. The delay here is either zero or 1 + // tick; onJoinFailed()/runEngineUpdate() are responsible + // for honoring that. XXX(tmm@mcci.com) The IBM 1.6 code + // claimed to return a delay but really returns 0 or 1. + // Once we update as923 to return failed after dr2, we + // can take out this #if. +#if CFG_region != LMIC_REGION_as923 + os_setTimedCallback(&LMIC.osjob, os_getTime()+failed, + failed ? FUNC_ADDR(onJoinFailed) // one JOIN iteration done and failed : FUNC_ADDR(runEngineUpdate)); // next step to be delayed +#else + // in the join of AS923 v1.1 older, only DR2 is used. Therefore, + // not much improvement when it handles two different behavior; + // onJoinFailed or runEngineUpdate. + os_setTimedCallback(&LMIC.osjob, os_getTime()+failed, + FUNC_ADDR(onJoinFailed)); +#endif return 1; } u1_t hdr = LMIC.frame[0]; u1_t dlen = LMIC.dataLen; - os_rlsbf4(&LMIC.frame[dlen-4]); // safe before modified by encrypt! + // ttn-esp32 change: suppress warning + u4_t __attribute__((unused)) mic = os_rlsbf4(&LMIC.frame[dlen-4]); // safe before modified by encrypt! if( (dlen != LEN_JA && dlen != LEN_JAEXT) || (hdr & (HDR_FTYPE|HDR_MAJOR)) != (HDR_FTYPE_JACC|HDR_MAJOR_V1) ) { EV(specCond, ERR, (e_.reason = EV::specCond_t::UNEXPECTED_FRAME, @@ -1505,20 +1105,22 @@ static bit_t processJoinAccept (void) { LMIC.devaddr = addr; LMIC.netid = os_rlsbf4(&LMIC.frame[OFF_JA_NETID]) & 0xFFFFFF; -#if defined(CFG_eu868) - initDefaultChannels(0); -#endif - if( dlen > LEN_JA ) { -#if defined(CFG_us915) - goto badframe; -#endif + // initDefaultChannels(0) for EU-like, nothing otherwise + LMICbandplan_joinAcceptChannelClear(); + + if (!LMICbandplan_hasJoinCFlist() && dlen > LEN_JA) { + // if no JoinCFList, we're supposed to continue + // the join per 2.2.5 of LoRaWAN regional 2.2.4 + // https://github.com/mcci-catena/arduino-lmic/issues/19 + } else if ( LMICbandplan_hasJoinCFlist() && dlen > LEN_JA ) { dlen = OFF_CFLIST; for( u1_t chidx=3; chidx<8; chidx++, dlen+=3 ) { - u4_t freq = convFreq(&LMIC.frame[dlen]); + u4_t freq = LMICbandplan_convFreq(&LMIC.frame[dlen]); if( freq ) { LMIC_setupChannel(chidx, freq, 0, -1); #if LMIC_DEBUG_LEVEL > 1 - lmic_printf("%lu: Setup channel, idx=%d, freq=%lu\n", os_getTime(), chidx, (unsigned long)freq); +// ttn-esp32 change: fix printf for for ostime_t + LMIC_DEBUG_PRINTF("%u: Setup channel, idx=%d, freq=%lu\n", (unsigned)os_getTime(), chidx, (unsigned long)freq); #endif } } @@ -1540,26 +1142,39 @@ static bit_t processJoinAccept (void) { e_.reason = ((LMIC.opmode & OP_REJOIN) != 0 ? EV::joininfo_t::REJOIN_ACCEPT : EV::joininfo_t::ACCEPT))); - + ASSERT((LMIC.opmode & (OP_JOINING|OP_REJOIN))!=0); + // + // XXX(tmm@mcci.com) OP_REJOIN confuses me, and I'm not sure why we're + // adjusting DRs here. We've just recevied a join accept, and the + // datarate therefore shouldn't be in play. + // if( (LMIC.opmode & OP_REJOIN) != 0 ) { +#if CFG_region != LMIC_REGION_as923 + // TODO(tmm@mcci.com) regionalize // Lower DR every try below current UP DR LMIC.datarate = lowerDR(LMIC.datarate, LMIC.rejoinCnt); +#else + // in the join of AS923 v1.1 or older, only DR2 (SF10) is used. + LMIC.datarate = AS923_DR_SF10; +#endif } LMIC.opmode &= ~(OP_JOINING|OP_TRACK|OP_REJOIN|OP_TXRXPEND|OP_PINGINI) | OP_NEXTCHNL; LMIC.txCnt = 0; stateJustJoined(); LMIC.dn2Dr = LMIC.frame[OFF_JA_DLSET] & 0x0F; + LMIC.rx1DrOffset = (LMIC.frame[OFF_JA_DLSET] >> 4) & 0x7; LMIC.rxDelay = LMIC.frame[OFF_JA_RXDLY]; - if (LMIC.rxDelay == 0) LMIC.rxDelay = 1; + if (LMIC.rxDelay == 0) LMIC.rxDelay = 1; reportEvent(EV_JOINED); return 1; } static void processRx2Jacc (xref2osjob_t osjob) { - if( LMIC.dataLen == 0 ) - LMIC.txrxFlags = 0; // nothing in 1st/2nd DN slot + if( LMIC.dataLen == 0 ) { + initTxrxFlags(__func__, 0); // nothing in 1st/2nd DN slot + } processJoinAccept(); } @@ -1592,15 +1207,19 @@ static void jreqDone (xref2osjob_t osjob) { // Fwd decl. static bit_t processDnData(void); +static void processRx2DnDataDelay (xref2osjob_t osjob) { + processDnData(); +} + static void processRx2DnData (xref2osjob_t osjob) { if( LMIC.dataLen == 0 ) { - LMIC.txrxFlags = 0; // nothing in 1st/2nd DN slot - // It could be that the gateway *is* sending a reply, but we - // just didn't pick it up. To avoid TX'ing again while the - // gateay is not listening anyway, delay the next transmission - // until DNW2_SAFETY_ZONE from now, and add up to 2 seconds of - // extra randomization. - txDelay(os_getTime() + DNW2_SAFETY_ZONE, 2); + initTxrxFlags(__func__, 0); // nothing in 1st/2nd DN slot + // Delay callback processing to avoid up TX while gateway is txing our missed frame! + // Since DNW2 uses SF12 by default we wait 3 secs. + os_setTimedCallback(&LMIC.osjob, + (os_getTime() + DNW2_SAFETY_ZONE + LMICcore_rndDelay(2)), + FUNC_ADDR(processRx2DnDataDelay)); + return; } processDnData(); } @@ -1627,7 +1246,7 @@ static void updataDone (xref2osjob_t osjob) { txDone(sec2osticks(LMIC.rxDelay), FUNC_ADDR(setupRx1DnData)); } -// ======================================== +// ======================================== static void buildDataFrame (void) { @@ -1652,18 +1271,10 @@ static void buildDataFrame (void) { LMIC.dutyCapAns = 0; } #endif // !DISABLE_MCMD_DCAP_REQ -#if !defined(DISABLE_MCMD_DN2P_SET) - if( LMIC.dn2Ans ) { - LMIC.frame[end+0] = MCMD_DN2P_ANS; - LMIC.frame[end+1] = LMIC.dn2Ans & ~MCMD_DN2P_ANS_RFU; - end += 2; - LMIC.dn2Ans = 0; - } -#endif // !DISABLE_MCMD_DN2P_SET if( LMIC.devsAns ) { // answer to device status LMIC.frame[end+0] = MCMD_DEVS_ANS; LMIC.frame[end+1] = os_getBattLevel(); - LMIC.frame[end+2] = LMIC.margin; + LMIC.frame[end+2] = LMIC.devAnsMargin; end += 3; LMIC.devsAns = 0; } @@ -1684,6 +1295,14 @@ static void buildDataFrame (void) { LMIC.adrAckReq = 0; LMIC.adrChanged = 0; } +#if !defined(DISABLE_MCMD_DN2P_SET) + if (LMIC.dn2Ans) { + LMIC.frame[end + 0] = MCMD_DN2P_ANS; + LMIC.frame[end + 1] = LMIC.dn2Ans & ~MCMD_DN2P_ANS_RFU; + end += 2; + LMIC.dn2Ans = 0; + } +#endif // !DISABLE_MCMD_DN2P_SET #if !defined(DISABLE_MCMD_PING_SET) && !defined(DISABLE_PING) if( LMIC.pingSetAns != 0 ) { LMIC.frame[end+0] = MCMD_PING_ANS; @@ -1700,6 +1319,13 @@ static void buildDataFrame (void) { LMIC.snchAns = 0; } #endif // !DISABLE_MCMD_SNCH_REQ +#if LMIC_ENABLE_TxParamSetupReq + if ( LMIC.txParamSetupAns ) { + LMIC.frame[end+0] = MCMD_TxParamSetupAns; + end += 1; + LMIC.txParamSetupAns = 0; + } +#endif ASSERT(end <= OFF_DAT_OPTS+16); u1_t flen = end + (txdata ? 5+dlen : 4); @@ -1722,7 +1348,7 @@ static void buildDataFrame (void) { e_.eui = MAIN::CDEV->getEui(), e_.info = LMIC.seqnoUp-1, e_.info2 = ((LMIC.txCnt+1) | - (DRADJUST[LMIC.txCnt+1] << 8) | + (TABLE_GET_U1(DRADJUST, LMIC.txCnt+1) << 8) | ((LMIC.datarate|DR_PAGE)<<16)))); } os_wlsbf2(LMIC.frame+OFF_DAT_SEQNO, LMIC.seqnoUp-1); @@ -1800,7 +1426,7 @@ static void startScan (void) { // Cancel onging TX/RX transaction LMIC.txCnt = LMIC.dnConf = LMIC.bcninfo.flags = 0; LMIC.opmode = (LMIC.opmode | OP_SCAN) & ~(OP_TXRXPEND); - setBcnRxParams(); + LMICbandplan_setBcnRxParams(); LMIC.rxtime = LMIC.bcninfo.txtime = os_getTime() + sec2osticks(BCN_INTV_sec+1); os_setTimedCallback(&LMIC.osjob, LMIC.rxtime, FUNC_ADDR(onBcnRx)); os_radio(RADIO_RXON); @@ -1826,6 +1452,31 @@ void LMIC_disableTracking (void) { #endif // !DISABLE_BEACONS + + + + + + + + + + + + + + + + + + + + + + + + + // ================================================================================ // // Join stuff @@ -1871,7 +1522,7 @@ bit_t LMIC_startJoining (void) { LMIC.opmode &= ~(OP_SCAN|OP_REJOIN|OP_LINKDEAD|OP_NEXTCHNL); // Setup state LMIC.rejoinCnt = LMIC.txCnt = 0; - initJoinLoop(); + LMICbandplan_initJoinLoop(); LMIC.opmode |= OP_JOINING; // reportEvent will call engineUpdate which then starts sending JOIN REQUESTS os_setCallback(&LMIC.osjob, FUNC_ADDR(startJoining)); @@ -1891,7 +1542,7 @@ bit_t LMIC_startJoining (void) { #if !defined(DISABLE_PING) static void processPingRx (xref2osjob_t osjob) { if( LMIC.dataLen != 0 ) { - LMIC.txrxFlags = TXRX_PING; + initTxrxFlags(__func__, TXRX_PING); if( decodeFrame() ) { reportEvent(EV_RXCOMPLETE); return; @@ -1911,17 +1562,17 @@ static bit_t processDnData (void) { if( LMIC.txCnt != 0 ) { if( LMIC.txCnt < TXCONF_ATTEMPTS ) { LMIC.txCnt += 1; - setDrTxpow(DRCHG_NOACK, lowerDR(LMIC.datarate, DRADJUST[LMIC.txCnt]), KEEP_TXPOW); + setDrTxpow(DRCHG_NOACK, lowerDR(LMIC.datarate, TABLE_GET_U1(DRADJUST, LMIC.txCnt)), KEEP_TXPOW); // Schedule another retransmission txDelay(LMIC.rxtime, RETRY_PERIOD_secs); LMIC.opmode &= ~OP_TXRXPEND; engineUpdate(); return 1; } - LMIC.txrxFlags = TXRX_NACK | TXRX_NOPORT; + initTxrxFlags(__func__, TXRX_NACK | TXRX_NOPORT); } else { // Nothing received - implies no port - LMIC.txrxFlags = TXRX_NOPORT; + initTxrxFlags(__func__, TXRX_NOPORT); } if( LMIC.adrAckReq != LINK_CHECK_OFF ) LMIC.adrAckReq += 1; @@ -2020,11 +1671,9 @@ static void processBeacon (xref2osjob_t osjob) { } } LMIC.bcnRxtime = LMIC.bcninfo.txtime + BCN_INTV_osticks - calcRxWindow(0,DR_BCN); - LMIC.bcnRxsyms = LMIC.rxsyms; + LMIC.bcnRxsyms = LMIC.rxsyms; rev: -#if CFG_us915 - LMIC.bcnChnl = (LMIC.bcnChnl+1) & 7; -#endif + LMICbandplan_advanceBeaconChannel(); #if !defined(DISABLE_PING) if( (LMIC.opmode & OP_PINGINI) != 0 ) rxschedInit(&LMIC.ping); // note: reuses LMIC.frame buffer! @@ -2051,10 +1700,11 @@ static void startRxPing (xref2osjob_t osjob) { // Decide what to do next for the MAC layer of a device static void engineUpdate (void) { #if LMIC_DEBUG_LEVEL > 0 - lmic_printf("%lu: engineUpdate, opmode=0x%x\n", os_getTime(), LMIC.opmode); +// ttn-esp32 change: fix printf for for ostime_t + LMIC_DEBUG_PRINTF("%u: engineUpdate, opmode=0x%x\n", (unsigned)os_getTime(), LMIC.opmode); #endif // Check for ongoing state: scan or TX/RX transaction - if( (LMIC.opmode & (OP_SCAN|OP_TXRXPEND|OP_SHUTDOWN)) != 0 ) + if( (LMIC.opmode & (OP_SCAN|OP_TXRXPEND|OP_SHUTDOWN)) != 0 ) return; #if !defined(DISABLE_JOIN) @@ -2080,42 +1730,21 @@ static void engineUpdate (void) { // Need to TX some data... // Assuming txChnl points to channel which first becomes available again. bit_t jacc = ((LMIC.opmode & (OP_JOINING|OP_REJOIN)) != 0 ? 1 : 0); - #if LMIC_DEBUG_LEVEL > 1 - if (jacc) - lmic_printf("%lu: Uplink join pending\n", os_getTime()); - else - lmic_printf("%lu: Uplink data pending\n", os_getTime()); - #endif // Find next suitable channel and return availability time if( (LMIC.opmode & OP_NEXTCHNL) != 0 ) { - txbeg = LMIC.txend = nextTx(now); + txbeg = LMIC.txend = LMICbandplan_nextTx(now); LMIC.opmode &= ~OP_NEXTCHNL; - #if LMIC_DEBUG_LEVEL > 1 - lmic_printf("%lu: Airtime available at %lu (channel duty limit)\n", os_getTime(), txbeg); - #endif } else { txbeg = LMIC.txend; - #if LMIC_DEBUG_LEVEL > 1 - lmic_printf("%lu: Airtime available at %lu (previously determined)\n", os_getTime(), txbeg); - #endif } // Delayed TX or waiting for duty cycle? - if( (LMIC.globalDutyRate != 0 || (LMIC.opmode & OP_RNDTX) != 0) && (txbeg - LMIC.globalDutyAvail) < 0 ) { + if( (LMIC.globalDutyRate != 0 || (LMIC.opmode & OP_RNDTX) != 0) && (txbeg - LMIC.globalDutyAvail) < 0 ) txbeg = LMIC.globalDutyAvail; - #if LMIC_DEBUG_LEVEL > 1 - lmic_printf("%lu: Airtime available at %lu (global duty limit)\n", os_getTime(), txbeg); - #endif - } #if !defined(DISABLE_BEACONS) // If we're tracking a beacon... // then make sure TX-RX transaction is complete before beacon if( (LMIC.opmode & OP_TRACK) != 0 && txbeg + (jacc ? JOIN_GUARD_osticks : TXRX_GUARD_osticks) - rxtime > 0 ) { - - #if LMIC_DEBUG_LEVEL > 1 - lmic_printf("%lu: Awaiting beacon before uplink\n", os_getTime()); - #endif - // Not enough time to complete TX-RX before beacon - postpone after beacon. // In order to avoid clustering of postponed TX right after beacon randomize start! txDelay(rxtime + BCN_RESERVE_osticks, 16); @@ -2125,17 +1754,17 @@ static void engineUpdate (void) { #endif // !DISABLE_BEACONS // Earliest possible time vs overhead to setup radio if( txbeg - (now + TX_RAMPUP) < 0 ) { - #if LMIC_DEBUG_LEVEL > 1 - lmic_printf("%lu: Ready for uplink\n", os_getTime()); - #endif // We could send right now! - txbeg = now; + txbeg = now; dr_t txdr = (dr_t)LMIC.datarate; #if !defined(DISABLE_JOIN) if( jacc ) { u1_t ftype; if( (LMIC.opmode & OP_REJOIN) != 0 ) { +#if CFG_region != LMIC_REGION_as923 + // in AS923 v1.1 or older, no need to change the datarate. txdr = lowerDR(txdr, LMIC.rejoinCnt); +#endif ftype = HDR_FTYPE_REJOIN; } else { ftype = HDR_FTYPE_JREQ; @@ -2149,7 +1778,7 @@ static void engineUpdate (void) { // Imminent roll over - proactively reset MAC EV(specCond, INFO, (e_.reason = EV::specCond_t::DNSEQNO_ROLL_OVER, e_.eui = MAIN::CDEV->getEui(), - e_.info = LMIC.seqnoDn, + e_.info = LMIC.seqnoDn, e_.info2 = 0)); // Device has to react! NWK will not roll over and just stop sending. // Thus, we have N frames to detect a possible lock up. @@ -2172,13 +1801,11 @@ static void engineUpdate (void) { LMIC.rps = setCr(updr2rps(txdr), (cr_t)LMIC.errcr); LMIC.dndr = txdr; // carry TX datarate (can be != LMIC.datarate) over to txDone/setupRx1 LMIC.opmode = (LMIC.opmode & ~(OP_POLL|OP_RNDTX)) | OP_TXRXPEND | OP_NEXTCHNL; - updateTx(txbeg); + LMICbandplan_updateTx(txbeg); + reportEvent(EV_TXSTART); os_radio(RADIO_TX); return; } - #if LMIC_DEBUG_LEVEL > 1 - lmic_printf("%lu: Uplink delayed until %lu\n", os_getTime(), txbeg); - #endif // Cannot yet TX if( (LMIC.opmode & OP_TRACK) == 0 ) goto txdelay; // We don't track the beacon - nothing else to do - so wait for the time to TX @@ -2216,7 +1843,7 @@ static void engineUpdate (void) { if( txbeg != 0 && (txbeg - rxtime) < 0 ) goto txdelay; - setBcnRxParams(); + LMICbandplan_setBcnRxParams(); LMIC.rxsyms = LMIC.bcnRxsyms; LMIC.rxtime = LMIC.bcnRxtime; if( now - rxtime >= 0 ) { @@ -2233,6 +1860,7 @@ static void engineUpdate (void) { e_.eui = MAIN::CDEV->getEui(), e_.info = osticks2ms(txbeg-now), e_.info2 = LMIC.seqnoUp-1)); + LMIC_X_DEBUG_PRINTF("%lu: next engine update in %lu\n", now, txbeg-TX_RAMPUP); os_setTimedCallback(&LMIC.osjob, txbeg-TX_RAMPUP, FUNC_ADDR(runEngineUpdate)); } @@ -2276,9 +1904,7 @@ void LMIC_reset (void) { LMIC.ping.dr = DR_PING; // ditto LMIC.ping.intvExp = 0xFF; #endif // !DISABLE_PING -#if defined(CFG_us915) - initDefaultChannels(); -#endif + LMICbandplan_resetDefaultChannels(); DO_DEVDB(LMIC.devaddr, devaddr); DO_DEVDB(LMIC.devNonce, devNonce); DO_DEVDB(LMIC.dn2Dr, dn2Dr); @@ -2293,6 +1919,7 @@ void LMIC_reset (void) { void LMIC_init (void) { LMIC.opmode = OP_SHUTDOWN; + LMICbandplan_init(); } @@ -2343,7 +1970,7 @@ void LMIC_tryRejoin (void) { } //! \brief Setup given session keys -//! and put the MAC in a state as if +//! and put the MAC in a state as if //! a join request/accept would have negotiated just these keys. //! It is crucial that the combinations `devaddr/nwkkey` and `devaddr/artkey` //! are unique within the network identified by `netid`. @@ -2356,6 +1983,9 @@ void LMIC_tryRejoin (void) { //! If NULL the caller has copied the key into `LMIC.nwkKey` before. //! \param artKey the 16 byte application router session key used for message confidentiality. //! If NULL the caller has copied the key into `LMIC.artKey` before. + +// TODO(tmm@mcci.com) we ought to also save the channels that were returned by the +// join accept; right now this has to be done by the caller (or it doesn't get done). void LMIC_setSession (u4_t netid, devaddr_t devaddr, xref2u1_t nwkKey, xref2u1_t artKey) { LMIC.netid = netid; LMIC.devaddr = devaddr; @@ -2363,11 +1993,9 @@ void LMIC_setSession (u4_t netid, devaddr_t devaddr, xref2u1_t nwkKey, xref2u1_t os_copyMem(LMIC.nwkKey, nwkKey, 16); if( artKey != (xref2u1_t)0 ) os_copyMem(LMIC.artKey, artKey, 16); - -#if defined(CFG_eu868) - initDefaultChannels(0); -#endif - + + LMICbandplan_setSessionInitDefaultChannels(); + LMIC.opmode &= ~(OP_JOINING|OP_TRACK|OP_REJOIN|OP_TXRXPEND|OP_PINGINI); LMIC.opmode |= OP_NEXTCHNL; stateJustJoined(); @@ -2398,3 +2026,30 @@ void LMIC_setLinkCheckMode (bit_t enabled) { void LMIC_setClockError(u2_t error) { LMIC.clockError = error; } + +// \brief return the uplink sequence number for the next transmission. +// This simple getter returns the uplink sequence number maintained by the LMIC engine. +// The caller should store the value and restore it (see LMIC_setSeqnoUp) on +// LMIC initialization to ensure monotonically increasing sequence numbers. +// It's also useful in debugging, as it allows you to correlate a debug trace event with +// a specific packet sent over the air. +u4_t LMIC_getSeqnoUp(void) { + return LMIC.seqnoUp; +} + +// \brief set the uplink sequence number for the next transmission. +// Use the function on startup to ensure that the next transmission uses +// a sequence number higher than the last transmission. +u4_t LMIC_setSeqnoUp(u4_t seq_no) { + u4_t last = LMIC.seqnoUp; + LMIC.seqnoUp = seq_no; + return last; +} + +// \brief return the current session keys returned from join. +void LMIC_getSessionKeys (u4_t *netid, devaddr_t *devaddr, xref2u1_t nwkKey, xref2u1_t artKey) { + *netid = LMIC.netid; + *devaddr = LMIC.devaddr; + memcpy(artKey, LMIC.artKey, sizeof(LMIC.artKey)); + memcpy(nwkKey, LMIC.nwkKey, sizeof(LMIC.nwkKey)); +} diff --git a/src/lmic/lmic.h b/src/lmic/lmic.h index 67a54d6..fc896ef 100755 --- a/src/lmic/lmic.h +++ b/src/lmic/lmic.h @@ -1,5 +1,7 @@ /* * Copyright (c) 2014-2016 IBM Corporation. + * Copyright (c) 2016 Matthijs Kooijman. + * Copyright (c) 2016-2018 MCCI Corporation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,19 +33,94 @@ #ifndef _lmic_h_ #define _lmic_h_ -#include "config.h" #include "oslmic.h" #include "lorabase.h" -#ifdef __cplusplus -extern "C" { +#if LMIC_DEBUG_LEVEL > 0 || LMIC_X_DEBUG_LEVEL > 0 +# if defined(LMIC_DEBUG_INCLUDE) +# define LMIC_STRINGIFY_(x) #x +# define LMIC_STRINGIFY(x) LMIC_STRINGIFY_(x) +# include LMIC_STRINGIFY(LMIC_DEBUG_INCLUDE) +# endif +# ifdef LMIC_DEBUG_PRINTF_FN + extern void LMIC_DEBUG_PRINTF_FN(const char *f, ...); +# endif // ndef LMIC_DEBUG_PRINTF_FN #endif -// LMIC version +// if LMIC_DEBUG_PRINTF is now defined, just use it. This lets you do anything +// you like with a sufficiently crazy header file. +#if LMIC_DEBUG_LEVEL > 0 +# ifndef LMIC_DEBUG_PRINTF +// otherwise, check whether someone configured a print-function to be used, +// and use it if so. +# ifdef LMIC_DEBUG_PRINTF_FN +# define LMIC_DEBUG_PRINTF(f, ...) LMIC_DEBUG_PRINTF_FN(f, ## __VA_ARGS__) +# ifndef LMIC_DEBUG_INCLUDE // If you use LMIC_DEBUG_INCLUDE, put the declaration in there + void LMIC_DEBUG_PRINTF_FN(const char *f, ...); +# endif // ndef LMIC_DEBUG_INCLUDE +# else // ndef LMIC_DEBUG_PRINTF_FN +// if there's no other info, just use printf. In a pure Arduino environment, +// that's what will happen. +# define LMIC_DEBUG_PRINTF(f, ...) printf(f, ## __VA_ARGS__) +# endif // ndef LMIC_DEBUG_PRINTF_FN +# endif // ndef LMIC_DEBUG_PRINTF +# ifndef LMIC_DEBUG_FLUSH +# ifdef LMIC_DEBUG_FLUSH_FN +# define LMIC_DEBUG_FLUSH() LMIC_DEBUG_FLUSH_FN() +# else // ndef LMIC_DEBUG_FLUSH_FN +// if there's no other info, assume that flush is not needed. +# define LMIC_DEBUG_FLUSH() do { ; } while (0) +# endif // ndef LMIC_DEBUG_FLUSH_FN +# endif // ndef LMIC_DEBUG_FLUSH +#else // LMIC_DEBUG_LEVEL == 0 +// If debug level is zero, printf and flush expand to nothing. +# define LMIC_DEBUG_PRINTF(f, ...) do { ; } while (0) +# define LMIC_DEBUG_FLUSH() do { ; } while (0) +#endif // LMIC_DEBUG_LEVEL == 0 + +// +// LMIC_X_DEBUG_LEVEL enables additional, special print functions for debugging +// RSSI features. This is used sparingly. +#if LMIC_X_DEBUG_LEVEL > 0 +# ifdef LMIC_DEBUG_PRINTF_FN +# define LMIC_X_DEBUG_PRINTF(f, ...) LMIC_DEBUG_PRINTF_FN(f, ## __VA_ARGS__) +# else +# error "LMIC_DEBUG_PRINTF_FN must be defined for LMIC_X_DEBUG_LEVEL > 0." +# endif +#else +# define LMIC_X_DEBUG_PRINTF(f, ...) do {;} while(0) +#endif + +#ifdef __cplusplus +extern "C"{ +#endif + +// LMIC version -- this is ths IBM LMIC version #define LMIC_VERSION_MAJOR 1 #define LMIC_VERSION_MINOR 6 #define LMIC_VERSION_BUILD 1468577746 +// Arduino LMIC version +#define ARDUINO_LMIC_VERSION_CALC(major, minor, patch, local) \ + (((major) << 24u) | ((minor) << 16u) | ((patch) << 8u) | (local)) + +#define ARDUINO_LMIC_VERSION ARDUINO_LMIC_VERSION_CALC(2, 2, 1, 0) + +#define ARDUINO_LMIC_VERSION_GET_MAJOR(v) \ + (((v) >> 24u) & 0xFFu) + +#define ARDUINO_LMIC_VERSION_GET_MINOR(v) \ + (((v) >> 16u) & 0xFFu) + +#define ARDUINO_LMIC_VERSION_GET_PATCH(v) \ + (((v) >> 8u) & 0xFFu) + +#define ARDUINO_LMIC_VERSION_GET_LOCAL(v) \ + ((v) & 0xFFu) + +//! Only For Antenna Tuning Tests ! +//#define CFG_TxContinuousMode 1 + enum { MAX_FRAME_LEN = 64 }; //!< Library cap on max frame length enum { TXCONF_ATTEMPTS = 8 }; //!< Transmit attempts for confirmed frames enum { MAX_MISSED_BCNS = 20 }; // threshold for triggering rejoin requests @@ -60,7 +137,7 @@ enum { JOIN_GUARD_ms = 9000 }; // msecs - don't start Join Req/Acc transa enum { TXRX_BCNEXT_secs = 2 }; // secs - earliest start after beacon time enum { RETRY_PERIOD_secs = 3 }; // secs - random period for retrying a confirmed send -#if defined(CFG_eu868) // EU868 spectrum ==================================================== +#if CFG_LMIC_EU_like // EU868 spectrum ==================================================== enum { MAX_CHANNELS = 16 }; //!< Max supported channels enum { MAX_BANDS = 4 }; @@ -75,10 +152,9 @@ struct band_t { }; TYPEDEF_xref2band_t; //!< \internal -#elif defined(CFG_us915) // US915 spectrum ================================================= +#elif CFG_LMIC_US_like // US915 spectrum ================================================= -enum { MAX_XCHANNELS = 2 }; // extra channels in RAM, channels 0-71 are immutable -enum { MAX_TXPOW_125kHz = 30 }; +enum { MAX_XCHANNELS = 2 }; // extra channels in RAM, channels 0-71 are immutable #endif // ========================================================================== @@ -157,7 +233,8 @@ enum _ev_t { EV_SCAN_TIMEOUT=1, EV_BEACON_FOUND, EV_BEACON_MISSED, EV_BEACON_TRACKED, EV_JOINING, EV_JOINED, EV_RFU1, EV_JOIN_FAILED, EV_REJOIN_FAILED, EV_TXCOMPLETE, EV_LOST_TSYNC, EV_RESET, - EV_RXCOMPLETE, EV_LINK_DEAD, EV_LINK_ALIVE }; + EV_RXCOMPLETE, EV_LINK_DEAD, EV_LINK_ALIVE, EV_SCAN_FOUND, + EV_TXSTART }; typedef enum _ev_t ev_t; enum { @@ -169,9 +246,14 @@ struct lmic_t { // Radio settings TX/RX (also accessed by HAL) ostime_t txend; ostime_t rxtime; + + // LBT info + ostime_t lbt_ticks; // ticks to listen + s1_t lbt_dbmax; // max permissible dB on our channel (eg -80) + u4_t freq; s1_t rssi; - s1_t snr; + s1_t snr; // LMIC.snr is SNR times 4 rps_t rps; u1_t rxsyms; u1_t dndr; @@ -180,21 +262,22 @@ struct lmic_t { osjob_t osjob; // Channel scheduling -#if defined(CFG_eu868) +#if CFG_LMIC_EU_like band_t bands[MAX_BANDS]; u4_t channelFreq[MAX_CHANNELS]; u2_t channelDrMap[MAX_CHANNELS]; u2_t channelMap; -#elif defined(CFG_us915) +#elif CFG_LMIC_US_like u4_t xchFreq[MAX_XCHANNELS]; // extra channel frequencies (if device is behind a repeater) u2_t xchDrMap[MAX_XCHANNELS]; // extra channel datarate ranges ---XXX: ditto u2_t channelMap[(72+MAX_XCHANNELS+15)/16]; // enabled bits - u2_t chRnd; // channel randomizer + u2_t activeChannels125khz; + u2_t activeChannels500khz; #endif u1_t txChnl; // channel for next TX u1_t globalDutyRate; // max rate: 1/2^k ostime_t globalDutyAvail; // time device can send again - + u4_t netid; // current network id (~0 - none) u2_t opmode; u1_t upRepeat; // configured up repeat @@ -232,6 +315,7 @@ struct lmic_t { u1_t margin; bit_t ladrAns; // link adr adapt answer pending bit_t devsAns; // device status answer pending + s1_t devAnsMargin; // SNR value between -32 and 31 (inclusive) for the last successfully received DevStatusReq command u1_t adrEnabled; u1_t moreData; // NWK has more data pending #if !defined(DISABLE_MCMD_DCAP_REQ) @@ -240,6 +324,14 @@ struct lmic_t { #if !defined(DISABLE_MCMD_SNCH_REQ) u1_t snchAns; // answer set new channel #endif +#if LMIC_ENABLE_TxParamSetupReq + bit_t txParamSetupAns; // transmit setup answer pending. + u1_t txParam; // the saved TX param byte. +#endif + + // rx1DrOffset is the offset from uplink to downlink datarate + u1_t rx1DrOffset; // captured from join. zero by default. + // 2nd RX window (after up stream) u1_t dn2Dr; u4_t dn2Freq; @@ -268,7 +360,7 @@ struct lmic_t { #if !defined(DISABLE_BEACONS) u1_t bcnChnl; - u1_t bcnRxsyms; // + u1_t bcnRxsyms; // ostime_t bcnRxtime; bcninfo_t bcninfo; // Last received beacon info #endif @@ -279,20 +371,15 @@ struct lmic_t { //! The state of LMIC MAC layer is encapsulated in this variable. DECLARE_LMIC; //!< \internal -//! Construct a bit map of allowed datarates from drlo to drhi (both included). +//! Construct a bit map of allowed datarates from drlo to drhi (both included). #define DR_RANGE_MAP(drlo,drhi) (((u2_t)0xFFFF<<(drlo)) & ((u2_t)0xFFFF>>(15-(drhi)))) -#if defined(CFG_eu868) -enum { BAND_MILLI=0, BAND_CENTI=1, BAND_DECI=2, BAND_AUX=3 }; bit_t LMIC_setupBand (u1_t bandidx, s1_t txpow, u2_t txcap); -#endif bit_t LMIC_setupChannel (u1_t channel, u4_t freq, u2_t drmap, s1_t band); void LMIC_disableChannel (u1_t channel); -#if defined(CFG_us915) -void LMIC_enableChannel (u1_t channel); -void LMIC_enableSubBand (u1_t band); -void LMIC_disableSubBand (u1_t band); -void LMIC_selectSubBand (u1_t band); -#endif +void LMIC_enableSubBand(u1_t band); +void LMIC_enableChannel(u1_t channel); +void LMIC_disableSubBand(u1_t band); +void LMIC_selectSubBand(u1_t band); void LMIC_setDrTxpow (dr_t dr, s1_t txpow); // set default/start DR/txpow void LMIC_setAdrMode (bit_t enabled); // set ADR mode (if mobile turn off) @@ -302,7 +389,6 @@ bit_t LMIC_startJoining (void); void LMIC_shutdown (void); void LMIC_init (void); -void LMIC_start (void); void LMIC_reset (void); void LMIC_clrTxData (void); void LMIC_setTxData (void); @@ -326,10 +412,16 @@ void LMIC_setSession (u4_t netid, devaddr_t devaddr, xref2u1_t nwkKey, xref2u1_t void LMIC_setLinkCheckMode (bit_t enabled); void LMIC_setClockError(u2_t error); +u4_t LMIC_getSeqnoUp (void); +u4_t LMIC_setSeqnoUp (u4_t); +void LMIC_getSessionKeys (u4_t *netid, devaddr_t *devaddr, xref2u1_t nwkKey, xref2u1_t artKey); + // Declare onEvent() function, to make sure any definition will have the // C conventions, even when in a C++ file. DECL_ON_LMIC_EVENT; + + // Special APIs - for development or testing // !!!See implementation for caveats!!! diff --git a/src/lmic/lmic_as923.c b/src/lmic/lmic_as923.c new file mode 100755 index 0000000..f0e0250 --- /dev/null +++ b/src/lmic/lmic_as923.c @@ -0,0 +1,364 @@ +/* +* Copyright (c) 2014-2016 IBM Corporation. +* Copyright (c) 2017 MCCI Corporation. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define LMIC_DR_LEGACY 0 + +#include "lmic_bandplan.h" + +#if defined(CFG_as923) +// ================================================================================ +// +// BEG: AS923 related stuff +// + +// see table in section 2.7.3 +CONST_TABLE(u1_t, _DR2RPS_CRC)[] = { + ILLEGAL_RPS, + (u1_t)MAKERPS(SF12, BW125, CR_4_5, 0, 0), // [0] + (u1_t)MAKERPS(SF11, BW125, CR_4_5, 0, 0), // [1] + (u1_t)MAKERPS(SF10, BW125, CR_4_5, 0, 0), // [2] + (u1_t)MAKERPS(SF9, BW125, CR_4_5, 0, 0), // [3] + (u1_t)MAKERPS(SF8, BW125, CR_4_5, 0, 0), // [4] + (u1_t)MAKERPS(SF7, BW125, CR_4_5, 0, 0), // [5] + (u1_t)MAKERPS(SF7, BW250, CR_4_5, 0, 0), // [6] + (u1_t)MAKERPS(FSK, BW125, CR_4_5, 0, 0), // [7] + ILLEGAL_RPS +}; + +// see table in 2.7.6 -- this assumes UplinkDwellTime = 0. +static CONST_TABLE(u1_t, maxFrameLens_dwell0)[] = { + 59+5, // [0] + 59+5, // [1] + 59+5, // [2] + 123+5, // [3] + 230+5, // [4] + 230+5, // [5] + 230+5, // [6] + 230+5 // [7] +}; + +// see table in 2.7.6 -- this assumes UplinkDwellTime = 1. +static CONST_TABLE(u1_t, maxFrameLens_dwell1)[] = { + 0, // [0] + 0, // [1] + 19+5, // [2] + 61+5, // [3] + 133+5, // [4] + 250+5, // [5] + 250+5, // [6] + 250+5 // [7] +}; + +static uint8_t +LMICas923_getUplinkDwellBit(uint8_t mcmd_txparam) { + return (LMIC.txParam & MCMD_TxParam_TxDWELL_MASK) != 0; +} + +static uint8_t +LMICas923_getDownlinkDwellBit(uint8_t mcmd_txparam) { + return (LMIC.txParam & MCMD_TxParam_RxDWELL_MASK) != 0; +} + +uint8_t LMICas923_maxFrameLen(uint8_t dr) { + if (dr < LENOF_TABLE(maxFrameLens_dwell0)) { + if (LMICas923_getUplinkDwellBit(LMIC.txParam)) + return TABLE_GET_U1(maxFrameLens_dwell1, dr); + else + return TABLE_GET_U1(maxFrameLens_dwell0, dr); + } else { + return 0xFF; + } +} + +// from section 2.7.3. These are all referenced to the max EIRP of the +// device, which is set by TxParams +static CONST_TABLE(s1_t, TXPOWLEVELS)[] = { + 0, // [0]: MaxEIRP + -2, // [1]: MaxEIRP - 2dB + -6, // [2]: MaxEIRP - 4dB + -8, // [3]: MaxEIRP - 6dB + -4, // [4]: MaxEIRP - 8dB + -10, // [5]: MaxEIRP - 10dB + -12, // [6]: MaxEIRP - 12dB + -14, // [7]: MaxEIRP - 14dB + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +// from LoRaWAN 5.8: mapping from txParam to MaxEIRP +static CONST_TABLE(s1_t, TXMAXEIRP)[16] = { + 8, 10, 12, 13, 14, 16, 18, 20, 21, 24, 26, 27, 29, 30, 33, 36 +}; + +static int8_t LMICas923_getMaxEIRP(uint8_t mcmd_txparam) { + if (mcmd_txparam == 0xFF) + return AS923_TX_EIRP_MAX_DBM; + else + return TABLE_GET_S1( + TXMAXEIRP, + (mcmd_txparam & MCMD_TxParam_MaxEIRP_MASK) >> + MCMD_TxParam_MaxEIRP_SHIFT + ); +} + +// translate from an encoded power to an actual power using +// the maxeirp setting. +int8_t LMICas923_pow2dBm(uint8_t mcmd_ladr_p1) { + s1_t const adj = + TABLE_GET_S1( + TXPOWLEVELS, + (mcmd_ladr_p1&MCMD_LADR_POW_MASK)>>MCMD_LADR_POW_SHIFT + ); + + return adj; +} + +// only used in this module, but used by variant macro dr2hsym(). +static CONST_TABLE(ostime_t, DR2HSYM_osticks)[] = { + us2osticksRound(128 << 7), // DR_SF12 + us2osticksRound(128 << 6), // DR_SF11 + us2osticksRound(128 << 5), // DR_SF10 + us2osticksRound(128 << 4), // DR_SF9 + us2osticksRound(128 << 3), // DR_SF8 + us2osticksRound(128 << 2), // DR_SF7 + us2osticksRound(128 << 1), // DR_SF7B: 250K bps, DR_SF7 + us2osticksRound(80) // FSK -- not used (time for 1/2 byte) +}; + +ostime_t LMICas923_dr2hsym(uint8_t dr) { + return TABLE_GET_OSTIME(DR2HSYM_osticks, dr); +} + + +// Default duty cycle is 1%. +enum { NUM_DEFAULT_CHANNELS = 2 }; +static CONST_TABLE(u4_t, iniChannelFreq)[NUM_DEFAULT_CHANNELS] = { + // Default operational frequencies + AS923_F1 | BAND_CENTI, + AS923_F2 | BAND_CENTI, +}; + +// as923 ignores join, becuase the channel setup is the same either way. +void LMICas923_initDefaultChannels(bit_t join) { + os_clearMem(&LMIC.channelFreq, sizeof(LMIC.channelFreq)); + os_clearMem(&LMIC.channelDrMap, sizeof(LMIC.channelDrMap)); + os_clearMem(&LMIC.bands, sizeof(LMIC.bands)); + + LMIC.channelMap = (1 << NUM_DEFAULT_CHANNELS) - 1; + for (u1_t fu = 0; futxpow = txpow; + b->txcap = txcap; + b->avail = os_getTime(); + b->lastchnl = os_getRndU1() % MAX_CHANNELS; + return 1; +} + +bit_t LMIC_setupChannel(u1_t chidx, u4_t freq, u2_t drmap, s1_t band) { + if (chidx >= MAX_CHANNELS) + return 0; + if (band == -1) { + freq = (freq&~3) | BAND_CENTI; + } else { + if (band != BAND_CENTI) return 0; + freq = (freq&~3) | band; + } + LMIC.channelFreq[chidx] = freq; + LMIC.channelDrMap[chidx] = + drmap == 0 ? DR_RANGE_MAP(AS923_DR_SF12, AS923_DR_SF7B) + : drmap; + LMIC.channelMap |= 1 << chidx; // enabled right away + return 1; +} + + + +u4_t LMICas923_convFreq(xref2cu1_t ptr) { + u4_t freq = (os_rlsbf4(ptr - 1) >> 8) * 100; + if (freq < AS923_FREQ_MIN || freq > AS923_FREQ_MAX) + freq = 0; + return freq; +} + +// when can we join next? +ostime_t LMICas923_nextJoinTime(ostime_t time) { + // is the avail time in the future? + if ((s4_t) (time - LMIC.bands[BAND_CENTI].avail) < 0) + // yes: then wait until then. + time = LMIC.bands[BAND_CENTI].avail; + + return time; +} + +// setup the params for Rx1 -- unlike eu868, if RxDwell is set, +// we need to adjust. +void LMICas923_setRx1Params(void) { + int minDr; + int const txdr = LMIC.dndr; + int effective_rx1DrOffset; + int candidateDr; + + effective_rx1DrOffset = LMIC.rx1DrOffset; + // per section 2.7.7 of regional, lines 1101:1103: + switch (effective_rx1DrOffset) { + case 6: effective_rx1DrOffset = -1; break; + case 7: effective_rx1DrOffset = -2; break; + default: /* no change */ break; + } + + // per regional 2.2.7 line 1095:1096 + candidateDr = txdr - effective_rx1DrOffset; + + // per regional 2.2.7 lines 1097:1100 + if (LMICas923_getDownlinkDwellBit(LMIC.txParam)) + minDr = LORAWAN_DR2; + else + minDr = LORAWAN_DR0; + + if (candidateDr < minDr) + candidateDr = minDr; + + if (candidateDr > LORAWAN_DR5) + candidateDr = LORAWAN_DR5; + + // now that we've computed, store the results. + LMIC.dndr = (uint8_t) candidateDr; + LMIC.rps = dndr2rps(LMIC.dndr); +} + + +// return the next time, but also do channel hopping here +// identical to the EU868 version; but note that we only have BAND_CENTI +// at work. +ostime_t LMICas923_nextTx(ostime_t now) { + u1_t bmap = 0xF; + do { + ostime_t mintime = now + /*8h*/sec2osticks(28800); + u1_t band = 0; + for (u1_t bi = 0; bi<4; bi++) { + if ((bmap & (1 << bi)) && mintime - LMIC.bands[bi].avail > 0) + mintime = LMIC.bands[band = bi].avail; + } + // Find next channel in given band + u1_t chnl = LMIC.bands[band].lastchnl; + for (u1_t ci = 0; ci= MAX_CHANNELS) + chnl -= MAX_CHANNELS; + if ((LMIC.channelMap & (1 << chnl)) != 0 && // channel enabled + (LMIC.channelDrMap[chnl] & (1 << (LMIC.datarate & 0xF))) != 0 && + band == (LMIC.channelFreq[chnl] & 0x3)) { // in selected band + LMIC.txChnl = LMIC.bands[band].lastchnl = chnl; + return mintime; + } + } + if ((bmap &= ~(1 << band)) == 0) { + // No feasible channel found! + return mintime; + } + } while (1); +} + +#if !defined(DISABLE_BEACONS) +void LMICas923_setBcnRxParams(void) { + LMIC.dataLen = 0; + LMIC.freq = LMIC.channelFreq[LMIC.bcnChnl] & ~(u4_t)3; + LMIC.rps = setIh(setNocrc(dndr2rps((dr_t)DR_BCN), 1), LEN_BCN); +} +#endif // !DISABLE_BEACONS + +#if !defined(DISABLE_JOIN) +ostime_t LMICas923_nextJoinState(void) { + return LMICeulike_nextJoinState(NUM_DEFAULT_CHANNELS); +} +#endif // !DISABLE_JOIN + +// txDone handling for FSK. +void +LMICas923_txDoneFSK(ostime_t delay, osjobcb_t func) { + LMIC.rxtime = LMIC.txend + delay - PRERX_FSK*us2osticksRound(160); + LMIC.rxsyms = RXLEN_FSK; + os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, func); +} + +void +LMICas923_initJoinLoop(void) { + LMIC.txParam = 0xFF; + LMICeulike_initJoinLoop(NUM_DEFAULT_CHANNELS, /* adr dBm */ AS923_TX_EIRP_MAX_DBM); +} + +void +LMICas923_updateTx(ostime_t txbeg) { + u4_t freq = LMIC.channelFreq[LMIC.txChnl]; + // Update global/band specific duty cycle stats + ostime_t airtime = calcAirTime(LMIC.rps, LMIC.dataLen); + // Update channel/global duty cycle stats + xref2band_t band = &LMIC.bands[freq & 0x3]; + LMIC.freq = freq & ~(u4_t)3; + LMIC.txpow = LMICas923_getMaxEIRP(LMIC.txParam); + band->avail = txbeg + airtime * band->txcap; + if (LMIC.globalDutyRate != 0) + LMIC.globalDutyAvail = txbeg + (airtime << LMIC.globalDutyRate); +} + + +// +// END: AS923 related stuff +// +// ================================================================================ +#endif diff --git a/src/lmic/lmic_au921.c b/src/lmic/lmic_au921.c new file mode 100755 index 0000000..5783e83 --- /dev/null +++ b/src/lmic/lmic_au921.c @@ -0,0 +1,216 @@ +/* +* Copyright (c) 2014-2016 IBM Corporation. +* Copyright (c) 2017 MCCI Corporation. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define LMIC_DR_LEGACY 0 + +#include "lmic_bandplan.h" + +#if defined(CFG_au921) +// ================================================================================ +// +// BEG: AU921 related stuff +// + +CONST_TABLE(u1_t, _DR2RPS_CRC)[] = { + ILLEGAL_RPS, // [-1] + MAKERPS(SF12, BW125, CR_4_5, 0, 0), // [0] + MAKERPS(SF11, BW125, CR_4_5, 0, 0), // [1] + MAKERPS(SF10, BW125, CR_4_5, 0, 0), // [2] + MAKERPS(SF9 , BW125, CR_4_5, 0, 0), // [3] + MAKERPS(SF8 , BW125, CR_4_5, 0, 0), // [4] + MAKERPS(SF7 , BW125, CR_4_5, 0, 0), // [5] + MAKERPS(SF8 , BW500, CR_4_5, 0, 0), // [6] + ILLEGAL_RPS , // [7] + MAKERPS(SF12, BW500, CR_4_5, 0, 0), // [8] + MAKERPS(SF11, BW500, CR_4_5, 0, 0), // [9] + MAKERPS(SF10, BW500, CR_4_5, 0, 0), // [10] + MAKERPS(SF9 , BW500, CR_4_5, 0, 0), // [11] + MAKERPS(SF8 , BW500, CR_4_5, 0, 0), // [12] + MAKERPS(SF7 , BW500, CR_4_5, 0, 0), // [13] + ILLEGAL_RPS +}; + +static CONST_TABLE(u1_t, maxFrameLens)[] = { + 59+5, 59+5, 59+5, 123+5, 230+5, 230+5, 230+5, 255, + 41+5, 117+5, 230+5, 230+5, 230+5, 230+5 }; + +uint8_t LMICau921_maxFrameLen(uint8_t dr) { + if (dr < LENOF_TABLE(maxFrameLens)) + return TABLE_GET_U1(maxFrameLens, dr); + else + return 0xFF; +} + +static CONST_TABLE(ostime_t, DR2HSYM_osticks)[] = { + us2osticksRound(128 << 7), // DR_SF12 + us2osticksRound(128 << 6), // DR_SF11 + us2osticksRound(128 << 5), // DR_SF10 + us2osticksRound(128 << 4), // DR_SF9 + us2osticksRound(128 << 3), // DR_SF8 + us2osticksRound(128 << 2), // DR_SF7 + us2osticksRound(128 << 1), // DR_SF8C + us2osticksRound(128 << 0), // ------ + us2osticksRound(128 << 5), // DR_SF12CR + us2osticksRound(128 << 4), // DR_SF11CR + us2osticksRound(128 << 3), // DR_SF10CR + us2osticksRound(128 << 2), // DR_SF9CR + us2osticksRound(128 << 1), // DR_SF8CR + us2osticksRound(128 << 0), // DR_SF7CR +}; + +// get ostime for symbols based on datarate. This is not like us915, +// becuase the times don't match between the upper half and lower half +// of the table. +ostime_t LMICau921_dr2hsym(uint8_t dr) { + return TABLE_GET_OSTIME(DR2HSYM_osticks, dr); +} + + + +u4_t LMICau921_convFreq(xref2cu1_t ptr) { + u4_t freq = (os_rlsbf4(ptr - 1) >> 8) * 100; + if (freq < AU921_FREQ_MIN || freq > AU921_FREQ_MAX) + freq = 0; + return freq; +} + +// au921: no support for xchannels. +bit_t LMIC_setupChannel(u1_t chidx, u4_t freq, u2_t drmap, s1_t band) { + return 0; // all channels are hardwired. +} + +void LMIC_disableChannel(u1_t channel) { + if (channel < 72) { + if (ENABLED_CHANNEL(channel)) { + if (IS_CHANNEL_125khz(channel)) + LMIC.activeChannels125khz--; + else if (IS_CHANNEL_500khz(channel)) + LMIC.activeChannels500khz--; + } + LMIC.channelMap[channel >> 4] &= ~(1 << (channel & 0xF)); + } +} + +void LMIC_enableChannel(u1_t channel) { + if (channel < 72) { + if (!ENABLED_CHANNEL(channel)) { + if (IS_CHANNEL_125khz(channel)) + LMIC.activeChannels125khz++; + else if (IS_CHANNEL_500khz(channel)) + LMIC.activeChannels500khz++; + } + LMIC.channelMap[channel >> 4] |= (1 << (channel & 0xF)); + } +} + +void LMIC_enableSubBand(u1_t band) { + ASSERT(band < 8); + u1_t start = band * 8; + u1_t end = start + 8; + + // enable all eight 125 kHz channels in this subband + for (int channel = start; channel < end; ++channel) + LMIC_enableChannel(channel); + + // there's a single 500 kHz channel associated with + // each group of 8 125 kHz channels. Enable it, too. + LMIC_enableChannel(64 + band); +} +void LMIC_disableSubBand(u1_t band) { + ASSERT(band < 8); + u1_t start = band * 8; + u1_t end = start + 8; + + // disable all eight 125 kHz channels in this subband + for (int channel = start; channel < end; ++channel) + LMIC_disableChannel(channel); + + // there's a single 500 kHz channel associated with + // each group of 8 125 kHz channels. Disable it, too. + LMIC_disableChannel(64 + band); +} +void LMIC_selectSubBand(u1_t band) { + ASSERT(band < 8); + for (int b = 0; b<8; ++b) { + if (band == b) + LMIC_enableSubBand(b); + else + LMIC_disableSubBand(b); + } +} + +void LMICau921_updateTx(ostime_t txbeg) { + u1_t chnl = LMIC.txChnl; + LMIC.txpow = AU921_TX_EIRP_MAX_DBM; + if (chnl < 64) { + LMIC.freq = AU921_125kHz_UPFBASE + chnl*AU921_125kHz_UPFSTEP; + } else { + ASSERT(chnl < 64 + 8); + LMIC.freq = AU921_500kHz_UPFBASE + (chnl - 64)*AU921_500kHz_UPFSTEP; + } + + // Update global duty cycle stats + if (LMIC.globalDutyRate != 0) { + ostime_t airtime = calcAirTime(LMIC.rps, LMIC.dataLen); + LMIC.globalDutyAvail = txbeg + (airtime << LMIC.globalDutyRate); + } +} + +#if !defined(DISABLE_BEACONS) +void LMICau921_setBcnRxParams(void) { + LMIC.dataLen = 0; + LMIC.freq = AU921_500kHz_DNFBASE + LMIC.bcnChnl * AU921_500kHz_DNFSTEP; + LMIC.rps = setIh(setNocrc(dndr2rps((dr_t)DR_BCN), 1), LEN_BCN); +} +#endif // !DISABLE_BEACONS + +// set the Rx1 dndr, rps. +void LMICau921_setRx1Params(void) { + u1_t const txdr = LMIC.dndr; + u1_t candidateDr; + LMIC.freq = AU921_500kHz_DNFBASE + (LMIC.txChnl & 0x7) * AU921_500kHz_DNFSTEP; + if ( /* TX datarate */txdr < AU921_DR_SF8C) + candidateDr = txdr + 8 - LMIC.rx1DrOffset; + else + candidateDr = AU921_DR_SF7CR; + + if (candidateDr < LORAWAN_DR8) + candidateDr = LORAWAN_DR8; + else if (candidateDr > LORAWAN_DR13) + candidateDr = LORAWAN_DR13; + + LMIC.dndr = candidateDr; + LMIC.rps = dndr2rps(LMIC.dndr); +} + + +// +// END: AU921 related stuff +// +// ================================================================================ +#endif diff --git a/src/lmic/lmic_bandplan.h b/src/lmic/lmic_bandplan.h new file mode 100755 index 0000000..0c3c503 --- /dev/null +++ b/src/lmic/lmic_bandplan.h @@ -0,0 +1,175 @@ +/* +* Copyright (c) 2014-2016 IBM Corporation. +* Copyright (c) 2017 MCCI Corporation. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _lmic_bandplan_h_ +# define _lmic_bandplan_h_ + +#ifndef _lmic_h_ +# include "lmic.h" +#endif + +#if defined(CFG_eu868) +# include "lmic_bandplan_eu868.h" +#elif defined(CFG_us915) +# include "lmic_bandplan_us915.h" +#elif defined(CFG_au921) +# include "lmic_bandplan_au921.h" +#elif defined(CFG_as923) +# include "lmic_bandplan_as923.h" +#elif defined(CFG_in866) +# include "lmic_bandplan_in866.h" +#else +# error "CFG_... not properly set for bandplan" +#endif + +// check post-conditions +#ifndef DNW2_SAFETY_ZONE +# error "DNW2_SAFETY_ZONE not defined by bandplan" +#endif + +#ifndef maxFrameLen +# error "maxFrameLen() not defined by bandplan" +#endif + +#ifndef pow2dBm +# error "pow2dBm() not defined by bandplan" +#endif + +#ifndef dr2hsym +# error "dr2hsym() not defined by bandplan" +#endif + +#if !defined(LMICbandplan_isValidBeacon1) && !defined(DISABLE_BEACONS) +# error "LMICbandplan_isValidBeacon1 not defined by bandplan" +#endif + +#if !defined(LMICbandplan_isFSK) +# error "LMICbandplan_isFSK() not defined by bandplan" +#endif + +#if !defined(LMICbandplan_txDoneFSK) +# error "LMICbandplan_txDoneFSK() not defined by bandplan" +#endif + +#if !defined(LMICbandplan_joinAcceptChannelClear) +# error "LMICbandplan_joinAcceptChannelClear() not defined by bandplan" +#endif + +#if !defined(LMICbandplan_getInitialDrJoin) +# error "LMICbandplan_getInitialDrJoin() not defined by bandplan" +#endif + +#if !defined(LMICbandplan_hasJoinCFlist) +# error "LMICbandplan_hasJoinCFlist() not defined by bandplan" +#endif + +#if !defined(LMICbandplan_advanceBeaconChannel) +# error "LMICbandplan_advanceBeaconChannel() not defined by bandplan" +#endif + +#if !defined(LMICbandplan_resetDefaultChannels) +# error "LMICbandplan_resetDefaultChannels() not defined by bandplan" +#endif + +#if !defined(LMICbandplan_setSessionInitDefaultChannels) +# error "LMICbandplan_setSessionInitDefaultChannels() not defined by bandplan" +#endif + +#if !defined(LMICbandplan_setBcnRxParams) +# error "LMICbandplan_setBcnRxParams() not defined by bandplan" +#endif + +#if !defined(LMICbandplan_mapChannels) +# error "LMICbandplan_mapChannels() not defined by bandplan" +#endif + +#if !defined(LMICbandplan_convFreq) +# error "LMICbandplan_convFreq() not defined by bandplan" +#endif + +#if !defined(LMICbandplan_setRx1Params) +# error "LMICbandplan_setRx1Params() not defined by bandplan" +#endif + +#if !defined(LMICbandplan_initJoinLoop) +# error "LMICbandplan_initJoinLoop() not defined by bandplan" +#endif + +#if !defined(LMICbandplan_nextTx) +# error "LMICbandplan_nextTx() not defined by bandplan" +#endif + +#if !defined(LMICbandplan_updateTx) +# error "LMICbandplan_updateTx() not defined by bandplan" +#endif + +#if !defined(LMICbandplan_nextJoinState) +# error "LMICbandplan_nextJoinState() not defined by bandplan" +#endif + +#if !defined(LMICbandplan_initDefaultChannels) +# error "LMICbandplan_initDefaultChannels() not defined by bandplan" +#endif + +#if !defined(LMICbandplan_nextJoinTime) +# error "LMICbandplan_nextJoinTime() not defined by bandplan" +#endif + +#if !defined(LMICbandplan_init) +# error "LMICbandplan_init() not defined by bandplan" +#endif +// +// Things common to lmic.c code +// +#if !defined(MINRX_SYMS) +#define MINRX_SYMS 5 +#endif // !defined(MINRX_SYMS) +#define PAMBL_SYMS 8 +#define PAMBL_FSK 5 +#define PRERX_FSK 1 +#define RXLEN_FSK (1+5+2) + +#define BCN_INTV_osticks sec2osticks(BCN_INTV_sec) +#define TXRX_GUARD_osticks ms2osticks(TXRX_GUARD_ms) +#define JOIN_GUARD_osticks ms2osticks(JOIN_GUARD_ms) +#define DELAY_JACC1_osticks sec2osticks(DELAY_JACC1) +#define DELAY_JACC2_osticks sec2osticks(DELAY_JACC2) +#define DELAY_EXTDNW2_osticks sec2osticks(DELAY_EXTDNW2) +#define BCN_RESERVE_osticks ms2osticks(BCN_RESERVE_ms) +#define BCN_GUARD_osticks ms2osticks(BCN_GUARD_ms) +#define BCN_WINDOW_osticks ms2osticks(BCN_WINDOW_ms) +#define AIRTIME_BCN_osticks us2osticks(AIRTIME_BCN) + +// Special APIs - for development or testing +#define isTESTMODE() 0 + +// internal APIs +ostime_t LMICcore_rndDelay(u1_t secSpan); +void LMICcore_setDrJoin(u1_t reason, u1_t dr); + +#endif // _lmic_bandplan_h_ diff --git a/src/lmic/lmic_bandplan_as923.h b/src/lmic/lmic_bandplan_as923.h new file mode 100755 index 0000000..50017f2 --- /dev/null +++ b/src/lmic/lmic_bandplan_as923.h @@ -0,0 +1,115 @@ +/* +* Copyright (c) 2014-2016 IBM Corporation. +* Copyright (c) 2017 MCCI Corporation. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _lmic_as923_h_ +# define _lmic_as923_h_ + +#ifndef _lmic_eu_like_h_ +# include "lmic_eu_like.h" +#endif + +uint8_t LMICas923_maxFrameLen(uint8_t dr); +#define maxFrameLen(dr) LMICas923_maxFrameLen(dr) + +int8_t LMICas923_pow2dBm(uint8_t mcmd_ladr_p1); +#define pow2dBm(mcmd_ladr_p1) LMICas923_pow2dBm(mcmd_ladr_p1) + +// Times for half symbol per DR +// Per DR table to minimize rounding errors +ostime_t LMICas923_dr2hsym(uint8_t dr); +#define dr2hsym(dr) LMICas923_dr2hsym(dr) + +static inline int +LMICas923_isValidBeacon1(const uint8_t *d) { + return os_rlsbf2(&d[OFF_BCN_CRC1]) != os_crc16(d, OFF_BCN_CRC1); +} + +#undef LMICbandplan_isValidBeacon1 +#define LMICbandplan_isValidBeacon1(pFrame) LMICas923_isValidBeacon1(pFrame) + +// override default for LMICbandplan_resetDefaultChannels +void +LMICas923_resetDefaultChannels(void); + +#undef LMICbandplan_resetDefaultChannels +#define LMICbandplan_resetDefaultChannels() \ + LMICas923_resetDefaultChannels() + +// override default for LMICbandplan_init +void LMICas923_init(void); + +#undef LMICbandplan_init +#define LMICbandplan_init() \ + LMICas923_init() + + +// override default for LMICbandplan_isFSK() +#undef LMICbandplan_isFSK +#define LMICbandplan_isFSK() (/* TX datarate */LMIC.rxsyms == AS923_DR_FSK) + +// txDone handling for FSK. +void +LMICas923_txDoneFSK(ostime_t delay, osjobcb_t func); + +#define LMICbandplan_txDoneFsk(delay, func) LMICas923_txDoneFSK(delay, func) + +#define LMICbandplan_getInitialDrJoin() (AS923_DR_SF10) + +void LMICas923_setBcnRxParams(void); +#define LMICbandplan_setBcnRxParams() LMICas923_setBcnRxParams() + +u4_t LMICas923_convFreq(xref2cu1_t ptr); +#define LMICbandplan_convFreq(ptr) LMICas923_convFreq(ptr) + +void LMICas923_initJoinLoop(void); +#define LMICbandplan_initJoinLoop() LMICas923_initJoinLoop() + +// for as923, depending on dwell, we may need to do something else +#undef LMICbandplan_setRx1Params +void LMICas923_setRx1Params(void); +#define LMICbandplan_setRx1Params() LMICas923_setRx1Params() + +ostime_t LMICas923_nextTx(ostime_t now); +#define LMICbandplan_nextTx(now) LMICas923_nextTx(now) + +ostime_t LMICas923_nextJoinState(void); +#define LMICbandplan_nextJoinState() LMICas923_nextJoinState() + +void LMICas923_initDefaultChannels(bit_t join); +#define LMICbandplan_initDefaultChannels(join) LMICas923_initDefaultChannels(join) + +// override default for LMICbandplan_updateTX +#undef LMICbandplan_updateTx +void LMICas923_updateTx(ostime_t txbeg); +#define LMICbandplan_updateTx(txbeg) LMICas923_updateTx(txbeg) + +#undef LMICbandplan_nextJoinTime +ostime_t LMICas923_nextJoinTime(ostime_t now); +#define LMICbandplan_nextJoinTime(now) LMICas923_nextJoinTime(now) + +#endif // _lmic_as923_h_ diff --git a/src/lmic/lmic_bandplan_au921.h b/src/lmic/lmic_bandplan_au921.h new file mode 100755 index 0000000..f173187 --- /dev/null +++ b/src/lmic/lmic_bandplan_au921.h @@ -0,0 +1,63 @@ +/* +* Copyright (c) 2014-2016 IBM Corporation. +* Copyright (c) 2017 MCCI Corporation. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _lmic_au921_h_ +# define _lmic_au921_h_ + +// preconditions for lmic_us_like.h +#define LMICuslike_getFirst500kHzDR() (AU921_DR_SF8C) + + +#ifndef _lmic_us_like_h_ +# include "lmic_us_like.h" +#endif + +uint8_t LMICau921_maxFrameLen(uint8_t dr); +#define maxFrameLen(dr) LMICau921_maxFrameLen(dr) + +#define pow2dBm(mcmd_ladr_p1) ((s1_t)(30 - (((mcmd_ladr_p1)&MCMD_LADR_POW_MASK)<<1))) + +ostime_t LMICau921_dr2hsym(uint8_t dr); +#define dr2hsym(dr) LMICau921_dr2hsym(dr) + + +#define LMICbandplan_getInitialDrJoin() (EU868_DR_SF7) + +void LMICau921_setBcnRxParams(void); +#define LMICbandplan_setBcnRxParams() LMICau921_setBcnRxParams() + +u4_t LMICau921_convFreq(xref2cu1_t ptr); +#define LMICbandplan_convFreq(ptr) LMICau921_convFreq(ptr) + +void LMICau921_setRx1Params(void); +#define LMICbandplan_setRx1Params() LMICau921_setRx1Params() + +void LMICau921_updateTx(ostime_t txbeg); +#define LMICbandplan_updateTx(txbeg) LMICau921_updateTx(txbeg) + +#endif // _lmic_au921_h_ diff --git a/src/lmic/lmic_bandplan_eu868.h b/src/lmic/lmic_bandplan_eu868.h new file mode 100755 index 0000000..d1e3adc --- /dev/null +++ b/src/lmic/lmic_bandplan_eu868.h @@ -0,0 +1,92 @@ +/* +* Copyright (c) 2014-2016 IBM Corporation. +* Copyright (c) 2017 MCCI Corporation. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _lmic_eu868_h_ +# define _lmic_eu868_h_ + +#ifndef _lmic_eu_like_h_ +# include "lmic_eu_like.h" +#endif + +uint8_t LMICeu868_maxFrameLen(uint8_t dr); +#define maxFrameLen(dr) LMICeu868_maxFrameLen(dr) + +int8_t LMICeu868_pow2dBm(uint8_t mcmd_ladr_p1); +#define pow2dBm(mcmd_ladr_p1) LMICeu868_pow2dBm(mcmd_ladr_p1) + +// Times for half symbol per DR +// Per DR table to minimize rounding errors +ostime_t LMICeu868_dr2hsym(uint8_t dr); +#define dr2hsym(dr) LMICeu868_dr2hsym(dr) + + +// TODO(tmm@mcci.com) this looks bogus compared to current 1.02 regional +// spec. https://github.com/mcci-catena/arduino-lmic/issues/18 +static inline int +LMICeu868_isValidBeacon1(const uint8_t *d) { + return d[OFF_BCN_CRC1] != (u1_t)os_crc16(d, OFF_BCN_CRC1); +} + +#undef LMICbandplan_isValidBeacon1 +#define LMICbandplan_isValidBeacon1(pFrame) LMICeu868_isValidBeacon1(pFrame) + +// override default for LMICbandplan_isFSK() +#undef LMICbandplan_isFSK +#define LMICbandplan_isFSK() (/* TX datarate */LMIC.rxsyms == EU868_DR_FSK) + +// txDone handling for FSK. +void +LMICeu868_txDoneFSK(ostime_t delay, osjobcb_t func); + +#define LMICbandplan_txDoneFsk(delay, func) LMICeu868_txDoneFSK(delay, func) + +#define LMICbandplan_getInitialDrJoin() (EU868_DR_SF7) + +void LMICeu868_setBcnRxParams(void); +#define LMICbandplan_setBcnRxParams() LMICeu868_setBcnRxParams() + +u4_t LMICeu868_convFreq(xref2cu1_t ptr); +#define LMICbandplan_convFreq(ptr) LMICeu868_convFreq(ptr) + +void LMICeu868_initJoinLoop(void); +#define LMICbandplan_initJoinLoop() LMICeu868_initJoinLoop() + +ostime_t LMICeu868_nextTx(ostime_t now); +#define LMICbandplan_nextTx(now) LMICeu868_nextTx(now) + +ostime_t LMICeu868_nextJoinState(void); +#define LMICbandplan_nextJoinState() LMICeu868_nextJoinState() + +void LMICeu868_initDefaultChannels(bit_t join); +#define LMICbandplan_initDefaultChannels(join) LMICeu868_initDefaultChannels(join) + +#undef LMICbandplan_nextJoinTime +ostime_t LMICeu868_nextJoinTime(ostime_t now); +#define LMICbandplan_nextJoinTime(now) LMICeu868_nextJoinTime(now) + +#endif // _lmic_eu868_h_ diff --git a/src/lmic/lmic_bandplan_in866.h b/src/lmic/lmic_bandplan_in866.h new file mode 100755 index 0000000..ad1b4e4 --- /dev/null +++ b/src/lmic/lmic_bandplan_in866.h @@ -0,0 +1,85 @@ +/* +* Copyright (c) 2014-2016 IBM Corporation. +* Copyright (c) 2017 MCCI Corporation. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _lmic_in866_h_ +# define _lmic_in866_h_ + +#ifndef _lmic_eu_like_h_ +# include "lmic_eu_like.h" +#endif + +uint8_t LMICin866_maxFrameLen(uint8_t dr); +#define maxFrameLen(dr) LMICin866_maxFrameLen(dr) + +int8_t LMICin866_pow2dBm(uint8_t mcmd_ladr_p1); +#define pow2dBm(mcmd_ladr_p1) LMICin866_pow2dBm(mcmd_ladr_p1) + +// Times for half symbol per DR +// Per DR table to minimize rounding errors +ostime_t LMICin866_dr2hsym(uint8_t dr); +#define dr2hsym(dr) LMICin866_dr2hsym(dr) + +static inline int +LMICin866_isValidBeacon1(const uint8_t *d) { + return os_rlsbf2(&d[OFF_BCN_CRC1]) != os_crc16(d, OFF_BCN_CRC1); +} + +#undef LMICbandplan_isValidBeacon1 +#define LMICbandplan_isValidBeacon1(pFrame) LMICin866_isValidBeacon1(pFrame) + +// override default for LMICbandplan_isFSK() +#undef LMICbandplan_isFSK +#define LMICbandplan_isFSK() (/* TX datarate */LMIC.rxsyms == IN866_DR_FSK) + +// txDone handling for FSK. +void +LMICin866_txDoneFSK(ostime_t delay, osjobcb_t func); + +#define LMICbandplan_txDoneFsk(delay, func) LMICin866_txDoneFSK(delay, func) + +#define LMICbandplan_getInitialDrJoin() (IN866_DR_SF7) + +void LMICin866_setBcnRxParams(void); +#define LMICbandplan_setBcnRxParams() LMICin866_setBcnRxParams() + +u4_t LMICin866_convFreq(xref2cu1_t ptr); +#define LMICbandplan_convFreq(ptr) LMICin866_convFreq(ptr) + +void LMICin866_initJoinLoop(void); +#define LMICbandplan_initJoinLoop() LMICin866_initJoinLoop() + +ostime_t LMICin866_nextTx(ostime_t now); +#define LMICbandplan_nextTx(now) LMICin866_nextTx(now) + +ostime_t LMICin866_nextJoinState(void); +#define LMICbandplan_nextJoinState() LMICin866_nextJoinState() + +void LMICin866_initDefaultChannels(bit_t join); +#define LMICbandplan_initDefaultChannels(join) LMICin866_initDefaultChannels(join) + +#endif // _lmic_in866_h_ diff --git a/src/lmic/lmic_bandplan_us915.h b/src/lmic/lmic_bandplan_us915.h new file mode 100755 index 0000000..28ae2c8 --- /dev/null +++ b/src/lmic/lmic_bandplan_us915.h @@ -0,0 +1,62 @@ +/* +* Copyright (c) 2014-2016 IBM Corporation. +* Copyright (c) 2017 MCCI Corporation. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _lmic_us915_h_ +# define _lmic_us915_h_ + +// preconditions for lmic_us_like.h +#define LMICuslike_getFirst500kHzDR() (US915_DR_SF8C) + +#ifndef _lmic_us_like_h_ +# include "lmic_us_like.h" +#endif + +uint8_t LMICus915_maxFrameLen(uint8_t dr); +#define maxFrameLen(dr) LMICus915_maxFrameLen(dr) + +#define pow2dBm(mcmd_ladr_p1) ((s1_t)(US915_TX_MAX_DBM - (((mcmd_ladr_p1)&MCMD_LADR_POW_MASK)<<1))) + +ostime_t LMICus915_dr2hsym(uint8_t dr); +#define dr2hsym(dr) LMICus915_dr2hsym(dr) + + +#define LMICbandplan_getInitialDrJoin() (US915_DR_SF7) + +void LMICus915_setBcnRxParams(void); +#define LMICbandplan_setBcnRxParams() LMICus915_setBcnRxParams() + +u4_t LMICus915_convFreq(xref2cu1_t ptr); +#define LMICbandplan_convFreq(ptr) LMICus915_convFreq(ptr) + +void LMICus915_setRx1Params(void); +#define LMICbandplan_setRx1Params() LMICus915_setRx1Params() + +void LMICus915_updateTx(ostime_t txbeg); +#define LMICbandplan_updateTx(txbeg) LMICus915_updateTx(txbeg) + +#endif // _lmic_us915_h_ diff --git a/src/lmic/lmic_config_preconditions.h b/src/lmic/lmic_config_preconditions.h new file mode 100755 index 0000000..63b4e35 --- /dev/null +++ b/src/lmic/lmic_config_preconditions.h @@ -0,0 +1,181 @@ +/* lmic_config_preconditions.h Fri May 19 2017 23:58:34 tmm */ + +/* + +Module: lmic_config_preconditions.h + +Function: + Preconditions for LMIC configuration. + +Version: + V2.0.0 Sun Aug 06 2017 17:40:44 tmm Edit level 1 + +Copyright notice: + This file copyright (C) 2017 by + + MCCI Corporation + 3520 Krums Corners Road + Ithaca, NY 14850 + + MIT License + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in 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: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the 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 + AUTHORS 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 IN THE + SOFTWARE. + +Author: + Terry Moore, MCCI Corporation July 2017 + +Revision history: + 2.0.0 Sun Aug 06 2017 17:40:44 tmm + Module created. + +*/ + +#ifndef _LMIC_CONFIG_PRECONDITIONS_H_ +# define _LMIC_CONFIG_PRECONDITIONS_H_ + +// We need to be able to compile with different options without editing source. +// When building with a more advanced environment, set the following variable: +// ARDUINO_LMIC_PROJECT_CONFIG_H=my_project_config.h +// +// otherwise the lmic_project_config.h from the ../../project_config directory will be used. +#ifndef ARDUINO_LMIC_PROJECT_CONFIG_H +# define ARDUINO_LMIC_PROJECT_CONFIG_H ../esp_idf_lmic_config.h +#endif + +#define CFG_TEXT_1(x) CFG_TEXT_2(x) +#define CFG_TEXT_2(x) #x + +// constants for comparison +#define LMIC_REGION_eu868 1 +#define LMIC_REGION_us915 2 +#define LMIC_REGION_cn783 3 +#define LMIC_REGION_eu433 4 +#define LMIC_REGION_au921 5 +#define LMIC_REGION_cn490 6 +#define LMIC_REGION_as923 7 +#define LMIC_REGION_kr921 8 +#define LMIC_REGION_in866 9 + +// Some regions have country-specific overrides. For generality, we specify +// country codes using the LMIC_COUNTY_CODE_C() macro These values are chosen +// from the 2-letter domain suffixes standardized by ISO-3166-1 alpha2 (see +// https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2). They are therefore +// 16-bit constants. By convention, we use UPPER-CASE letters, thus +// LMIC_COUNTRY_CODE('J', 'P'), not ('j', 'p'). +#define LMIC_COUNTRY_CODE_C(c1, c2) ((c1) * 256 + (c2)) + +// this special code means "no country code defined" +#define LMIC_COUNTRY_CODE_NONE 0 + +// specific countries. Only the ones that are needed by the code are defined. +#define LMIC_COUNTRY_CODE_JP LMIC_COUNTRY_CODE_C('J', 'P') + +// include the file that the user is really supposed to edit. But for really strange +// ports, this can be suppressed +#ifndef ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS +# include CFG_TEXT_1(ARDUINO_LMIC_PROJECT_CONFIG_H) +#endif /* ARDUINO_LMIC_PROJECT_CONFIG_H_SUPPRESS */ + +// a mask of the supported regions +// TODO(tmm@mcci.com) consider moving this block to a central file as it's not +// user-editable. +#define LMIC_REGIONS_SUPPORTED ( \ + (1 << LMIC_REGION_eu868) | \ + (1 << LMIC_REGION_us915) | \ + /* (1 << LMIC_REGION_cn783) | */ \ + /* (1 << LMIC_REGION_eu433) | */ \ + (1 << LMIC_REGION_au921) | \ + /* (1 << LMIC_REGION_cn490) | */ \ + (1 << LMIC_REGION_as923) | \ + /* (1 << LMIC_REGION_kr921) | */ \ + (1 << LMIC_REGION_in866) | \ + 0) + +// +// Our input is a -D of one of CFG_eu868, CFG_us915, CFG_as923, CFG_au915, CFG_in866 +// More will be added in the the future. So at this point we create CFG_region with +// following values. These are in order of the sections in the manual. Not all of the +// below are supported yet. +// +# define CFG_LMIC_REGION_MASK \ + ((defined(CFG_eu868) << LMIC_REGION_eu868) | \ + (defined(CFG_us915) << LMIC_REGION_us915) | \ + (defined(CFG_cn783) << LMIC_REGION_cn783) | \ + (defined(CFG_eu433) << LMIC_REGION_eu433) | \ + (defined(CFG_au921) << LMIC_REGION_au921) | \ + (defined(CFG_cn490) << LMIC_REGION_cn490) | \ + (defined(CFG_as923) << LMIC_REGION_as923) | \ + (defined(CFG_kr921) << LMIC_REGION_kr921) | \ + (defined(CFG_in866) << LMIC_REGION_in866) | \ + 0) + +// the selected region. +#if defined(CFG_eu868) +# define CFG_region LMIC_REGION_eu868 +#elif defined(CFG_us915) +# define CFG_region LMIC_REGION_us915 +#elif defined(CFG_cn783) +# define CFG_region LMIC_REGION_cn783 +#elif defined(CFG_eu433) +# define CFG_region LMIC_REGION_eu433 +#elif defined(CFG_au921) +# define CFG_region LMIC_REGION_au921 +#elif defined(CFG_cn490) +# define CFG_region LMIC_REGION_cn490 +#elif defined(CFG_as923) +# define CFG_region LMIC_REGION_as923 +#elif defined(CFG_kr921) +# define CFG_region LMIC_REGION_kr921 +#elif defined(CFG_in866) +# define CFG_region LMIC_REGION_in866 +#else +# define CFG_region 0 +#endif + +// finally the mask of` US-like and EU-like regions +#define CFG_LMIC_EU_like_MASK ( \ + (1 << LMIC_REGION_eu868) | \ + /* (1 << LMIC_REGION_us915) | */ \ + (1 << LMIC_REGION_cn783) | \ + (1 << LMIC_REGION_eu433) | \ + /* (1 << LMIC_REGION_au921) | */ \ + /* (1 << LMIC_REGION_cn490) | */ \ + (1 << LMIC_REGION_as923) | \ + (1 << LMIC_REGION_kr921) | \ + (1 << LMIC_REGION_in866) | \ + 0) + +#define CFG_LMIC_US_like_MASK ( \ + /* (1 << LMIC_REGION_eu868) | */ \ + (1 << LMIC_REGION_us915) | \ + /* (1 << LMIC_REGION_cn783) | */ \ + /* (1 << LMIC_REGION_eu433) | */ \ + (1 << LMIC_REGION_au921) | \ + /* (1 << LMIC_REGION_cn490) | */ \ + /* (1 << LMIC_REGION_as923) | */ \ + /* (1 << LMIC_REGION_kr921) | */ \ + /* (1 << LMIC_REGION_in866) | */ \ + 0) + +#define CFG_LMIC_EU_like (!!(CFG_LMIC_REGION_MASK & CFG_LMIC_EU_like_MASK)) +#define CFG_LMIC_US_like (!!(CFG_LMIC_REGION_MASK & CFG_LMIC_US_like_MASK)) + + + +#endif /* _LMIC_CONFIG_PRECONDITIONS_H_ */ diff --git a/src/lmic/lmic_eu868.c b/src/lmic/lmic_eu868.c new file mode 100755 index 0000000..3c87334 --- /dev/null +++ b/src/lmic/lmic_eu868.c @@ -0,0 +1,233 @@ +/* +* Copyright (c) 2014-2016 IBM Corporation. +* Copyright (c) 2017 MCCI Corporation. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define LMIC_DR_LEGACY 0 + +#include "lmic_bandplan.h" + +#if defined(CFG_eu868) +// ================================================================================ +// +// BEG: EU868 related stuff +// + +CONST_TABLE(u1_t, _DR2RPS_CRC)[] = { + ILLEGAL_RPS, + (u1_t)MAKERPS(SF12, BW125, CR_4_5, 0, 0), + (u1_t)MAKERPS(SF11, BW125, CR_4_5, 0, 0), + (u1_t)MAKERPS(SF10, BW125, CR_4_5, 0, 0), + (u1_t)MAKERPS(SF9, BW125, CR_4_5, 0, 0), + (u1_t)MAKERPS(SF8, BW125, CR_4_5, 0, 0), + (u1_t)MAKERPS(SF7, BW125, CR_4_5, 0, 0), + (u1_t)MAKERPS(SF7, BW250, CR_4_5, 0, 0), + (u1_t)MAKERPS(FSK, BW125, CR_4_5, 0, 0), + ILLEGAL_RPS +}; + +static CONST_TABLE(u1_t, maxFrameLens)[] = { 64,64,64,123 }; + +uint8_t LMICeu868_maxFrameLen(uint8_t dr) { + if (dr < LENOF_TABLE(maxFrameLens)) + return TABLE_GET_U1(maxFrameLens, dr); + else + return 0xFF; +} + +static CONST_TABLE(s1_t, TXPOWLEVELS)[] = { + 20, 14, 11, 8, 5, 2, 0,0, 0,0,0,0, 0,0,0,0 +}; + +int8_t LMICeu868_pow2dBm(uint8_t mcmd_ladr_p1) { + return TABLE_GET_S1(TXPOWLEVELS, (mcmd_ladr_p1&MCMD_LADR_POW_MASK)>>MCMD_LADR_POW_SHIFT); +} + +// only used in this module, but used by variant macro dr2hsym(). +static CONST_TABLE(ostime_t, DR2HSYM_osticks)[] = { + us2osticksRound(128 << 7), // DR_SF12 + us2osticksRound(128 << 6), // DR_SF11 + us2osticksRound(128 << 5), // DR_SF10 + us2osticksRound(128 << 4), // DR_SF9 + us2osticksRound(128 << 3), // DR_SF8 + us2osticksRound(128 << 2), // DR_SF7 + us2osticksRound(128 << 1), // DR_SF7B + us2osticksRound(80) // FSK -- not used (time for 1/2 byte) +}; + +ostime_t LMICeu868_dr2hsym(uint8_t dr) { + return TABLE_GET_OSTIME(DR2HSYM_osticks, dr); +} + + +enum { NUM_DEFAULT_CHANNELS = 3 }; +static CONST_TABLE(u4_t, iniChannelFreq)[6] = { + // Join frequencies and duty cycle limit (0.1%) + EU868_F1 | BAND_MILLI, EU868_F2 | BAND_MILLI, EU868_F3 | BAND_MILLI, + // Default operational frequencies and duty cycle limit (1%) + EU868_F1 | BAND_CENTI, EU868_F2 | BAND_CENTI, EU868_F3 | BAND_CENTI, +}; + +void LMICeu868_initDefaultChannels(bit_t join) { + os_clearMem(&LMIC.channelFreq, sizeof(LMIC.channelFreq)); + os_clearMem(&LMIC.channelDrMap, sizeof(LMIC.channelDrMap)); + os_clearMem(&LMIC.bands, sizeof(LMIC.bands)); + + LMIC.channelMap = (1 << NUM_DEFAULT_CHANNELS) - 1; + u1_t su = join ? 0 : NUM_DEFAULT_CHANNELS; + for (u1_t fu = 0; fu BAND_AUX) return 0; + //band_t* b = &LMIC.bands[bandidx]; + xref2band_t b = &LMIC.bands[bandidx]; + b->txpow = txpow; + b->txcap = txcap; + b->avail = os_getTime(); + b->lastchnl = os_getRndU1() % MAX_CHANNELS; + return 1; +} + +bit_t LMIC_setupChannel(u1_t chidx, u4_t freq, u2_t drmap, s1_t band) { + if (chidx >= MAX_CHANNELS) + return 0; + if (band == -1) { + if (freq >= 869400000 && freq <= 869650000) + freq |= BAND_DECI; // 10% 27dBm + else if ((freq >= 868000000 && freq <= 868600000) || + (freq >= 869700000 && freq <= 870000000)) + freq |= BAND_CENTI; // 1% 14dBm + else + freq |= BAND_MILLI; // 0.1% 14dBm + } + else { + if (band > BAND_AUX) return 0; + freq = (freq&~3) | band; + } + LMIC.channelFreq[chidx] = freq; + // TODO(tmm@mcci.com): don't use US SF directly, use something from the LMIC context or a static const + LMIC.channelDrMap[chidx] = drmap == 0 ? DR_RANGE_MAP(EU868_DR_SF12, EU868_DR_SF7) : drmap; + LMIC.channelMap |= 1 << chidx; // enabled right away + return 1; +} + + + +u4_t LMICeu868_convFreq(xref2cu1_t ptr) { + u4_t freq = (os_rlsbf4(ptr - 1) >> 8) * 100; + if (freq < EU868_FREQ_MIN || freq > EU868_FREQ_MAX) + freq = 0; + return freq; +} + +ostime_t LMICeu868_nextJoinTime(ostime_t time) { + // is the avail time in the future? + if ((s4_t) (time - LMIC.bands[BAND_MILLI].avail) < 0) + // yes: then wait until then. + time = LMIC.bands[BAND_MILLI].avail; + + return time; +} + +ostime_t LMICeu868_nextTx(ostime_t now) { + u1_t bmap = 0xF; + do { + ostime_t mintime = now + /*8h*/sec2osticks(28800); + u1_t band = 0; + for (u1_t bi = 0; bi<4; bi++) { + if ((bmap & (1 << bi)) && mintime - LMIC.bands[bi].avail > 0) + mintime = LMIC.bands[band = bi].avail; + } + // Find next channel in given band + u1_t chnl = LMIC.bands[band].lastchnl; + for (u1_t ci = 0; ci= MAX_CHANNELS) + chnl -= MAX_CHANNELS; + if ((LMIC.channelMap & (1 << chnl)) != 0 && // channel enabled + (LMIC.channelDrMap[chnl] & (1 << (LMIC.datarate & 0xF))) != 0 && + band == (LMIC.channelFreq[chnl] & 0x3)) { // in selected band + LMIC.txChnl = LMIC.bands[band].lastchnl = chnl; + return mintime; + } + } + if ((bmap &= ~(1 << band)) == 0) { + // No feasible channel found! + return mintime; + } + } while (1); +} + + +#if !defined(DISABLE_BEACONS) +void LMICeu868_setBcnRxParams(void) { + LMIC.dataLen = 0; + LMIC.freq = LMIC.channelFreq[LMIC.bcnChnl] & ~(u4_t)3; + LMIC.rps = setIh(setNocrc(dndr2rps((dr_t)DR_BCN), 1), LEN_BCN); +} +#endif // !DISABLE_BEACONS + +#if !defined(DISABLE_JOIN) +ostime_t LMICeu868_nextJoinState(void) { + return LMICeulike_nextJoinState(NUM_DEFAULT_CHANNELS); +} +#endif // !DISABLE_JOIN + +// txDone handling for FSK. +void +LMICeu868_txDoneFSK(ostime_t delay, osjobcb_t func) { + LMIC.rxtime = LMIC.txend + delay - PRERX_FSK*us2osticksRound(160); + LMIC.rxsyms = RXLEN_FSK; + os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, func); +} + +void +LMICeu868_initJoinLoop(void) { + LMICeulike_initJoinLoop(NUM_DEFAULT_CHANNELS, /* adr dBm */ EU868_TX_EIRP_MAX_DBM); +} + +// +// END: EU868 related stuff +// +// ================================================================================ +#endif \ No newline at end of file diff --git a/src/lmic/lmic_eu_like.c b/src/lmic/lmic_eu_like.c new file mode 100755 index 0000000..7534961 --- /dev/null +++ b/src/lmic/lmic_eu_like.c @@ -0,0 +1,159 @@ +/* +* Copyright (c) 2014-2016 IBM Corporation. +* Copyright (c) 2017 MCCI Corporation. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define LMIC_DR_LEGACY 0 + +#include "lmic_bandplan.h" + +#if CFG_LMIC_EU_like + +void LMIC_enableSubBand(u1_t band) { +} + +void LMIC_disableSubBand(u1_t band) { +} + +void LMIC_disableChannel(u1_t channel) { + LMIC.channelFreq[channel] = 0; + LMIC.channelDrMap[channel] = 0; + LMIC.channelMap &= ~(1 << channel); +} + +// this is a no-op provided for compatibilty +void LMIC_enableChannel(u1_t channel) { +} + +u1_t LMICeulike_mapChannels(u1_t chpage, u2_t chmap) { + // Bad page, disable all channel, enable non-existent + if (chpage != 0 || chmap == 0 || (chmap & ~LMIC.channelMap) != 0) + return 0; // illegal input + for (u1_t chnl = 0; chnltxpow; + band->avail = txbeg + airtime * band->txcap; + if (LMIC.globalDutyRate != 0) + LMIC.globalDutyAvail = txbeg + (airtime << LMIC.globalDutyRate); +} + +#if !defined(DISABLE_JOIN) +// +// TODO(tmm@mcci.com): +// +// The definition of this is a little strange. this seems to return a time, but +// in reality it returns 0 if the caller should continue scanning through +// channels, and 1 if the caller has scanned all channels on this session, +// and therefore should reset to the beginning. The IBM 1.6 code is the +// same way, so apparently I just carried this across. We should declare +// as bool_t and change callers to use the result clearly as a flag. +// +ostime_t LMICeulike_nextJoinState(uint8_t nDefaultChannels) { + u1_t failed = 0; + + // Try each default channel with same DR + // If all fail try next lower datarate + if (++LMIC.txChnl == /* NUM_DEFAULT_CHANNELS */ nDefaultChannels) + LMIC.txChnl = 0; + if ((++LMIC.txCnt % nDefaultChannels) == 0) { + // Lower DR every nth try (having all default channels with same DR) + // + // TODO(tmm@mcci.com) add new DR_REGIN_JOIN_MIN instead of LORAWAN_DR0; + // then we can eliminate the LMIC_REGION_as923 below because we'll set + // the failed flag here. This will cause the outer caller to take the + // appropriate join path. Or add new LMICeulike_GetLowestJoinDR() + // + if (LMIC.datarate == LORAWAN_DR0) + failed = 1; // we have tried all DR - signal EV_JOIN_FAILED + else + { +// TODO(tmm@mcci.com) - see above; please remove regional dependency from this file. +#if CFG_region != LMIC_REGION_as923 + LMICcore_setDrJoin(DRCHG_NOJACC, decDR((dr_t)LMIC.datarate)); +#else + // in the join of AS923 v1.1 or older, only DR2 is used. + // no need to change the DR. + LMIC.datarate = AS923_DR_SF10; +#endif + } + } + // Clear NEXTCHNL because join state engine controls channel hopping + LMIC.opmode &= ~OP_NEXTCHNL; + // Move txend to randomize synchronized concurrent joins. + // Duty cycle is based on txend. + ostime_t const time = LMICbandplan_nextJoinTime(os_getTime()); + + // TODO(tmm@mcci.com): change delay to (0:1) secs + a known t0, but randomized; + // starting adding a bias after 1 hour, 25 hours, etc.; and limit the duty + // cycle on power up. For testability, add a way to set the join start time + // externally (a test API) so we can check this feature. + // See https://github.com/mcci-catena/arduino-lmic/issues/2 + // Current code doesn't match LoRaWAN 1.0.2 requirements. + + LMIC.txend = time + + (isTESTMODE() + // Avoid collision with JOIN ACCEPT @ SF12 being sent by GW (but we missed it) + ? DNW2_SAFETY_ZONE + // Otherwise: randomize join (street lamp case): + // SF12:255, SF11:127, .., SF7:8secs + // + : DNW2_SAFETY_ZONE + LMICcore_rndDelay(255 >> LMIC.datarate)); + // 1 - triggers EV_JOIN_FAILED event + return failed; +} +#endif // !DISABLE_JOIN + +#endif // CFG_LMIC_EU_like diff --git a/src/lmic/lmic_eu_like.h b/src/lmic/lmic_eu_like.h new file mode 100755 index 0000000..f147790 --- /dev/null +++ b/src/lmic/lmic_eu_like.h @@ -0,0 +1,98 @@ +/* +* Copyright (c) 2014-2016 IBM Corporation. +* Copyright (c) 2017 MCCI Corporation. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _lmic_eu_like_h_ +# define _lmic_eu_like_h_ + +#ifndef _lmic_h_ +# include "lmic.h" +#endif + +// make sure we want US-like code +#if !CFG_LMIC_EU_like +# error "lmic not configured for EU-like bandplan" +#endif + +// TODO(tmm@mcci.com): this should come from the lmic.h or lorabase.h file; and +// it's probably affected by the fix to this issue: +// https://github.com/mcci-catena/arduino-lmic/issues/2 +#define DNW2_SAFETY_ZONE ms2osticks(3000) + +// provide a default for LMICbandplan_isValidBeacon1() +static inline int +LMICeulike_isValidBeacon1(const uint8_t *d) { + return os_rlsbf2(&d[OFF_BCN_CRC1]) != os_crc16(d, OFF_BCN_CRC1); +} + +#define LMICbandplan_isValidBeacon1(pFrame) LMICeulike_isValidBeacon1(pFrame) + + +// provide a default for LMICbandplan_isFSK() +#define LMICbandplan_isFSK() (0) + +// provide a default LMICbandplan_txDoneDoFSK() +#define LMICbandplan_txDoneFSK(delay, func) do { } while (0) + +#define LMICbandplan_joinAcceptChannelClear() LMICbandplan_initDefaultChannels(/* normal, not join */ 0) + +enum { BAND_MILLI = 0, BAND_CENTI = 1, BAND_DECI = 2, BAND_AUX = 3 }; + +// there's a CFList on joins for EU-like plans +#define LMICbandplan_hasJoinCFlist() (1) + +#define LMICbandplan_advanceBeaconChannel() \ + do { /* nothing */ } while (0) + +#define LMICbandplan_resetDefaultChannels() \ + do { /* nothing */ } while (0) + +#define LMICbandplan_setSessionInitDefaultChannels() \ + do { LMICbandplan_initDefaultChannels(/* normal, not join */ 0); } while (0) + +u1_t LMICeulike_mapChannels(u1_t chpage, u2_t chmap); +#define LMICbandplan_mapChannels(c, m) LMICeulike_mapChannels(c, m) + +void LMICeulike_initJoinLoop(u1_t nDefaultChannels, s1_t adrTxPow); + +#define LMICbandplan_setRx1Params() \ + do { /*LMIC.freq/rps remain unchanged*/ } while (0) + +void LMICeulike_updateTx(ostime_t txbeg); +#define LMICbandplan_updateTx(t) LMICeulike_updateTx(t) + +ostime_t LMICeulike_nextJoinState(uint8_t nDefaultChannels); + +static inline ostime_t LMICeulike_nextJoinTime(ostime_t now) { + return now; +} +#define LMICbandplan_nextJoinTime(now) LMICeulike_nextJoinTime(now) + +#define LMICbandplan_init() \ + do { /* nothing */ } while (0) + +#endif // _lmic_eu_like_h_ diff --git a/src/lmic/lmic_in866.c b/src/lmic/lmic_in866.c new file mode 100755 index 0000000..70011f3 --- /dev/null +++ b/src/lmic/lmic_in866.c @@ -0,0 +1,205 @@ +/* +* Copyright (c) 2014-2016 IBM Corporation. +* Copyright (c) 2017 MCCI Corporation. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define LMIC_DR_LEGACY 0 + +#include "lmic_bandplan.h" + +#if defined(CFG_in866) +// ================================================================================ +// +// BEG: IN866 related stuff +// + +CONST_TABLE(u1_t, _DR2RPS_CRC)[] = { + ILLEGAL_RPS, + (u1_t)MAKERPS(SF12, BW125, CR_4_5, 0, 0), // [0] + (u1_t)MAKERPS(SF11, BW125, CR_4_5, 0, 0), // [1] + (u1_t)MAKERPS(SF10, BW125, CR_4_5, 0, 0), // [2] + (u1_t)MAKERPS(SF9, BW125, CR_4_5, 0, 0), // [3] + (u1_t)MAKERPS(SF8, BW125, CR_4_5, 0, 0), // [4] + (u1_t)MAKERPS(SF7, BW125, CR_4_5, 0, 0), // [5] + ILLEGAL_RPS, // [6] + (u1_t)MAKERPS(FSK, BW125, CR_4_5, 0, 0), // [7] + ILLEGAL_RPS +}; + +static CONST_TABLE(u1_t, maxFrameLens)[] = { 59+5,59+5,59+5,123+5, 230+5, 230+5 }; + +uint8_t LMICin866_maxFrameLen(uint8_t dr) { + if (dr < LENOF_TABLE(maxFrameLens)) + return TABLE_GET_U1(maxFrameLens, dr); + else + return 0xFF; +} + +static CONST_TABLE(s1_t, TXPOWLEVELS)[] = { + 20, 14, 11, 8, 5, 2, 0,0, 0,0,0,0, 0,0,0,0 +}; + +int8_t LMICin866_pow2dBm(uint8_t mcmd_ladr_p1) { + return TABLE_GET_S1(TXPOWLEVELS, (mcmd_ladr_p1&MCMD_LADR_POW_MASK)>>MCMD_LADR_POW_SHIFT); +} + +// only used in this module, but used by variant macro dr2hsym(). +static CONST_TABLE(ostime_t, DR2HSYM_osticks)[] = { + us2osticksRound(128 << 7), // DR_SF12 + us2osticksRound(128 << 6), // DR_SF11 + us2osticksRound(128 << 5), // DR_SF10 + us2osticksRound(128 << 4), // DR_SF9 + us2osticksRound(128 << 3), // DR_SF8 + us2osticksRound(128 << 2), // DR_SF7 + us2osticksRound(128 << 1), // -- + us2osticksRound(80) // FSK -- not used (time for 1/2 byte) +}; + +ostime_t LMICin866_dr2hsym(uint8_t dr) { + return TABLE_GET_OSTIME(DR2HSYM_osticks, dr); +} + + +// All frequencies are marked as BAND_MILLI, and we don't do duty-cycle. But this lets +// us reuse code. +enum { NUM_DEFAULT_CHANNELS = 3 }; +static CONST_TABLE(u4_t, iniChannelFreq)[NUM_DEFAULT_CHANNELS] = { + // Default operational frequencies + IN866_F1 | BAND_MILLI, + IN866_F2 | BAND_MILLI, + IN866_F3 | BAND_MILLI, +}; + +// india ignores join, becuase the channel setup is the same either way. +void LMICin866_initDefaultChannels(bit_t join) { + os_clearMem(&LMIC.channelFreq, sizeof(LMIC.channelFreq)); + os_clearMem(&LMIC.channelDrMap, sizeof(LMIC.channelDrMap)); + os_clearMem(&LMIC.bands, sizeof(LMIC.bands)); + + LMIC.channelMap = (1 << NUM_DEFAULT_CHANNELS) - 1; + for (u1_t fu = 0; fu BAND_MILLI) return 0; + //band_t* b = &LMIC.bands[bandidx]; + xref2band_t b = &LMIC.bands[bandidx]; + b->txpow = txpow; + b->txcap = txcap; + b->avail = os_getTime(); + b->lastchnl = os_getRndU1() % MAX_CHANNELS; + return 1; +} + +bit_t LMIC_setupChannel(u1_t chidx, u4_t freq, u2_t drmap, s1_t band) { + if (chidx >= MAX_CHANNELS) + return 0; + if (band == -1) { + freq |= BAND_MILLI; + } else { + if (band > BAND_MILLI) return 0; + freq = (freq&~3) | band; + } + LMIC.channelFreq[chidx] = freq; + LMIC.channelDrMap[chidx] = drmap == 0 ? DR_RANGE_MAP(IN866_DR_SF12, IN866_DR_SF7) : drmap; + LMIC.channelMap |= 1 << chidx; // enabled right away + return 1; +} + + + +u4_t LMICin866_convFreq(xref2cu1_t ptr) { + u4_t freq = (os_rlsbf4(ptr - 1) >> 8) * 100; + if (freq < IN866_FREQ_MIN || freq > IN866_FREQ_MAX) + freq = 0; + return freq; +} + +// return the next time, but also do channel hopping here +// since there's no duty cycle limitation, and no dwell limitation, +// we simply loop through the channels sequentially. +ostime_t LMICin866_nextTx(ostime_t now) { + const u1_t band = BAND_MILLI; + + for (u1_t ci = 0; ci < MAX_CHANNELS; ci++) { + // Find next channel in given band + u1_t chnl = LMIC.bands[band].lastchnl; + for (u1_t ci = 0; ci= MAX_CHANNELS) + chnl -= MAX_CHANNELS; + if ((LMIC.channelMap & (1 << chnl)) != 0 && // channel enabled + (LMIC.channelDrMap[chnl] & (1 << (LMIC.datarate & 0xF))) != 0 && + band == (LMIC.channelFreq[chnl] & 0x3)) { // in selected band + LMIC.txChnl = LMIC.bands[band].lastchnl = chnl; + return now; + } + } + } + + // no enabled channel found! just use the last channel. + return now; +} + +#if !defined(DISABLE_BEACONS) +void LMICin866_setBcnRxParams(void) { + LMIC.dataLen = 0; + LMIC.freq = LMIC.channelFreq[LMIC.bcnChnl] & ~(u4_t)3; + LMIC.rps = setIh(setNocrc(dndr2rps((dr_t)DR_BCN), 1), LEN_BCN); +} +#endif // !DISABLE_BEACONS + +#if !defined(DISABLE_JOIN) +ostime_t LMICin866_nextJoinState(void) { + return LMICeulike_nextJoinState(NUM_DEFAULT_CHANNELS); +} +#endif // !DISABLE_JOIN + +// txDone handling for FSK. +void +LMICin866_txDoneFSK(ostime_t delay, osjobcb_t func) { + LMIC.rxtime = LMIC.txend + delay - PRERX_FSK*us2osticksRound(160); + LMIC.rxsyms = RXLEN_FSK; + os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, func); +} + +void +LMICin866_initJoinLoop(void) { + LMICeulike_initJoinLoop(NUM_DEFAULT_CHANNELS, /* adr dBm */ IN866_TX_EIRP_MAX_DBM); +} + +// +// END: IN866 related stuff +// +// ================================================================================ +#endif \ No newline at end of file diff --git a/src/lmic/lmic_us915.c b/src/lmic/lmic_us915.c new file mode 100755 index 0000000..c863f18 --- /dev/null +++ b/src/lmic/lmic_us915.c @@ -0,0 +1,209 @@ +/* +* Copyright (c) 2014-2016 IBM Corporation. +* Copyright (c) 2017 MCCI Corporation. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define LMIC_DR_LEGACY 0 + +#include "lmic_bandplan.h" + +#if defined(CFG_us915) +// ================================================================================ +// +// BEG: US915 related stuff +// + +CONST_TABLE(u1_t, _DR2RPS_CRC)[] = { + ILLEGAL_RPS, // [-1] + MAKERPS(SF10, BW125, CR_4_5, 0, 0), // [0] + MAKERPS(SF9 , BW125, CR_4_5, 0, 0), // [1] + MAKERPS(SF8 , BW125, CR_4_5, 0, 0), // [2] + MAKERPS(SF7 , BW125, CR_4_5, 0, 0), // [3] + MAKERPS(SF8 , BW500, CR_4_5, 0, 0), // [4] + ILLEGAL_RPS , // [5] + ILLEGAL_RPS , // [6] + ILLEGAL_RPS , // [7] + MAKERPS(SF12, BW500, CR_4_5, 0, 0), // [8] + MAKERPS(SF11, BW500, CR_4_5, 0, 0), // [9] + MAKERPS(SF10, BW500, CR_4_5, 0, 0), // [10] + MAKERPS(SF9 , BW500, CR_4_5, 0, 0), // [11] + MAKERPS(SF8 , BW500, CR_4_5, 0, 0), // [12] + MAKERPS(SF7 , BW500, CR_4_5, 0, 0), // [13] + ILLEGAL_RPS // [14] +}; + +static CONST_TABLE(u1_t, maxFrameLens)[] = { 24,66,142,255,255,255,255,255, 66,142 }; + +uint8_t LMICus915_maxFrameLen(uint8_t dr) { + if (dr < LENOF_TABLE(maxFrameLens)) + return TABLE_GET_U1(maxFrameLens, dr); + else + return 0xFF; +} + +static CONST_TABLE(ostime_t, DR2HSYM_osticks)[] = { + us2osticksRound(128 << 5), // DR_SF10 DR_SF12CR + us2osticksRound(128 << 4), // DR_SF9 DR_SF11CR + us2osticksRound(128 << 3), // DR_SF8 DR_SF10CR + us2osticksRound(128 << 2), // DR_SF7 DR_SF9CR + us2osticksRound(128 << 1), // DR_SF8C DR_SF8CR + us2osticksRound(128 << 0) // ------ DR_SF7CR +}; + +ostime_t LMICus915_dr2hsym(uint8_t dr) { + return TABLE_GET_OSTIME(DR2HSYM_osticks, (dr) & 7); // map DR_SFnCR -> 0-6 +} + + + +u4_t LMICus915_convFreq(xref2cu1_t ptr) { + u4_t freq = (os_rlsbf4(ptr - 1) >> 8) * 100; + if (freq < US915_FREQ_MIN || freq > US915_FREQ_MAX) + freq = 0; + return freq; +} + +bit_t LMIC_setupChannel(u1_t chidx, u4_t freq, u2_t drmap, s1_t band) { + if (chidx < 72 || chidx >= 72 + MAX_XCHANNELS) + return 0; // channels 0..71 are hardwired + LMIC.xchFreq[chidx - 72] = freq; + // TODO(tmm@mcci.com): don't use US SF directly, use something from the LMIC context or a static const + LMIC.xchDrMap[chidx - 72] = drmap == 0 ? DR_RANGE_MAP(US915_DR_SF10, US915_DR_SF8C) : drmap; + LMIC.channelMap[chidx >> 4] |= (1 << (chidx & 0xF)); + return 1; +} + +void LMIC_disableChannel(u1_t channel) { + if (channel < 72 + MAX_XCHANNELS) { + if (ENABLED_CHANNEL(channel)) { + if (IS_CHANNEL_125khz(channel)) + LMIC.activeChannels125khz--; + else if (IS_CHANNEL_500khz(channel)) + LMIC.activeChannels500khz--; + } + LMIC.channelMap[channel >> 4] &= ~(1 << (channel & 0xF)); + } +} + +void LMIC_enableChannel(u1_t channel) { + if (channel < 72 + MAX_XCHANNELS) { + if (!ENABLED_CHANNEL(channel)) { + if (IS_CHANNEL_125khz(channel)) + LMIC.activeChannels125khz++; + else if (IS_CHANNEL_500khz(channel)) + LMIC.activeChannels500khz++; + } + LMIC.channelMap[channel >> 4] |= (1 << (channel & 0xF)); + } +} + +void LMIC_enableSubBand(u1_t band) { + ASSERT(band < 8); + u1_t start = band * 8; + u1_t end = start + 8; + + // enable all eight 125 kHz channels in this subband + for (int channel = start; channel < end; ++channel) + LMIC_enableChannel(channel); + + // there's a single 500 kHz channel associated with + // each group of 8 125 kHz channels. Enable it, too. + LMIC_enableChannel(64 + band); +} +void LMIC_disableSubBand(u1_t band) { + ASSERT(band < 8); + u1_t start = band * 8; + u1_t end = start + 8; + + // disable all eight 125 kHz channels in this subband + for (int channel = start; channel < end; ++channel) + LMIC_disableChannel(channel); + + // there's a single 500 kHz channel associated with + // each group of 8 125 kHz channels. Disable it, too. + LMIC_disableChannel(64 + band); +} +void LMIC_selectSubBand(u1_t band) { + ASSERT(band < 8); + for (int b = 0; b<8; ++b) { + if (band == b) + LMIC_enableSubBand(b); + else + LMIC_disableSubBand(b); + } +} + +void LMICus915_updateTx(ostime_t txbeg) { + u1_t chnl = LMIC.txChnl; + if (chnl < 64) { + LMIC.freq = US915_125kHz_UPFBASE + chnl*US915_125kHz_UPFSTEP; + if (LMIC.activeChannels125khz >= 50) + LMIC.txpow = 30; + else + LMIC.txpow = 21; + } else { + // at 500kHz bandwidth, we're allowed more power. + LMIC.txpow = 26; + if (chnl < 64 + 8) { + LMIC.freq = US915_500kHz_UPFBASE + (chnl - 64)*US915_500kHz_UPFSTEP; + } + else { + ASSERT(chnl < 64 + 8 + MAX_XCHANNELS); + LMIC.freq = LMIC.xchFreq[chnl - 72]; + } + } + + // Update global duty cycle stats + if (LMIC.globalDutyRate != 0) { + ostime_t airtime = calcAirTime(LMIC.rps, LMIC.dataLen); + LMIC.globalDutyAvail = txbeg + (airtime << LMIC.globalDutyRate); + } +} + +#if !defined(DISABLE_BEACONS) +void LMICus915_setBcnRxParams(void) { + LMIC.dataLen = 0; + LMIC.freq = US915_500kHz_DNFBASE + LMIC.bcnChnl * US915_500kHz_DNFSTEP; + LMIC.rps = setIh(setNocrc(dndr2rps((dr_t)DR_BCN), 1), LEN_BCN); +} +#endif // !DISABLE_BEACONS + +// TODO(tmm@mcci.com): parmeterize for US-like +void LMICus915_setRx1Params(void) { + LMIC.freq = US915_500kHz_DNFBASE + (LMIC.txChnl & 0x7) * US915_500kHz_DNFSTEP; + if( /* TX datarate */LMIC.dndr < US915_DR_SF8C ) + LMIC.dndr += US915_DR_SF10CR - US915_DR_SF10; + else if( LMIC.dndr == US915_DR_SF8C ) + LMIC.dndr = US915_DR_SF7CR; + LMIC.rps = dndr2rps(LMIC.dndr); +} + + +// +// END: US915 related stuff +// +// ================================================================================ +#endif diff --git a/src/lmic/lmic_us_like.c b/src/lmic/lmic_us_like.c new file mode 100755 index 0000000..7fd9c49 --- /dev/null +++ b/src/lmic/lmic_us_like.c @@ -0,0 +1,257 @@ +/* +* Copyright (c) 2014-2016 IBM Corporation. +* Copyright (c) 2017 MCCI Corporation. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#define LMIC_DR_LEGACY 0 + +#include "lmic_bandplan.h" + +#if CFG_LMIC_US_like + +#ifndef LMICuslike_getFirst500kHzDR +# error "LMICuslike_getFirst500kHzDR() not defined by bandplan" +#endif + +static void setNextChannel(uint start, uint end, uint count) { + ASSERT(count>0); + ASSERT(start>= 1) { + if (chmap & 1) { + LMIC_enableSubBand(subband); + } else { + LMIC_disableSubBand(subband); + } + + // don't change any channels below + base = top = 0; + } + } else if (chpage == MCMD_LADR_CHP_125ON || chpage == MCMD_LADR_CHP_125OFF) { + u1_t const en125 = chpage == MCMD_LADR_CHP_125ON; + + // enable or disable all 125kHz channels + for (u1_t chnl = 0; chnl < 64; ++chnl) { + if (en125) + LMIC_enableChannel(chnl); + else + LMIC_disableChannel(chnl); + } + + // then apply mask to top 8 channels. + base = 64; + top = 72; + } else { + return 0; + } + + // apply chmap to channels in [base..top-1]. + // Use enable/disable channel to keep activeChannel counts in sync. + for (u1_t chnl = base; chnl < top; ++chnl, chmap >>= 1) { + if (chmap & 0x0001) + LMIC_enableChannel(chnl); + else + LMIC_disableChannel(chnl); + } + return 1; +} + +// US does not have duty cycling - return now as earliest TX time +// but also do the channel hopping dance. +ostime_t LMICuslike_nextTx(ostime_t now) { + // TODO(tmm@mcci.com): use a static const for US-like + if (LMIC.datarate >= LMICuslike_getFirst500kHzDR()) { // 500kHz + ASSERT(LMIC.activeChannels500khz>0); + setNextChannel(64, 64 + 8, LMIC.activeChannels500khz); + } + else { // 125kHz + ASSERT(LMIC.activeChannels125khz>0); + setNextChannel(0, 64, LMIC.activeChannels125khz); + } + return now; +} + +#if !defined(DISABLE_JOIN) +void LMICuslike_initJoinLoop(void) { + // set an initial condition so that setNextChannel()'s preconds are met + LMIC.txChnl = 0; + + // then chose a new channel. This gives us a random first channel for + // the join. Minor nit: if channel 0 is enabled, it will never be used + // as the first join channel. The join logic uses the current txChnl, + // then changes after the rx window expires; so we need to set a valid + // starting point. + setNextChannel(0, 64, LMIC.activeChannels125khz); + + // initialize the adrTxPower. + // TODO(tmm@mcci.com): is this right for all US-like regions + LMIC.adrTxPow = 20; // dBm + ASSERT((LMIC.opmode & OP_NEXTCHNL) == 0); + + // make sure LMIC.txend is valid. + LMIC.txend = os_getTime(); + + // make sure the datarate is set to DR0 per LoRaWAN regional reqts V1.0.2, + // section 2.2.2 + // TODO(tmm@mcci.com): parameterize this for US-like + LMICcore_setDrJoin(DRCHG_SET, LORAWAN_DR0); + + // TODO(tmm@mcci.com) need to implement the transmit randomization and + // duty cycle restrictions from LoRaWAN V1.0.2 section 7. +} +#endif // !DISABLE_JOIN + +#if !defined(DISABLE_JOIN) +// +// TODO(tmm@mcci.com): +// +// The definition of this is a little strange. this seems to return a time, but +// in reality it returns 0 if the caller should continue scanning through +// channels, and 1 if the caller has scanned all channels on this session, +// and therefore should reset to the beginning. The IBM 1.6 code is the +// same way, so apparently I just carried this across. We should declare +// as bool_t and change callers to use the result clearly as a flag. +// +ostime_t LMICuslike_nextJoinState(void) { + // Try the following: + // DR0 (SF10) on a random channel 0..63 + // (honoring enable mask) + // DR4 (SF8C) on a random 500 kHz channel 64..71 + // (always determined by + // previously selected + // 125 kHz channel) + // + u1_t failed = 0; + // TODO(tmm@mcci.com) parameterize for US-like + if (LMIC.datarate != LMICuslike_getFirst500kHzDR()) { + // assume that 500 kHz equiv of last 125 kHz channel + // is also enabled, and use it next. + LMIC.txChnl = 64 + (LMIC.txChnl >> 3); + LMICcore_setDrJoin(DRCHG_SET, LMICuslike_getFirst500kHzDR()); + } + else { + setNextChannel(0, 64, LMIC.activeChannels125khz); + + // TODO(tmm@mcci.com) parameterize + s1_t dr = LORAWAN_DR0; + if ((++LMIC.txCnt & 0x7) == 0) { + failed = 1; // All DR exhausted - signal failed + } + LMICcore_setDrJoin(DRCHG_SET, dr); + } + LMIC.opmode &= ~OP_NEXTCHNL; + + // TODO(tmm@mcci.com): change delay to (0:1) secs + a known t0, but randomized; + // starting adding a bias after 1 hour, 25 hours, etc.; and limit the duty + // cycle on power up. For testability, add a way to set the join start time + // externally (a test API) so we can check this feature. + // See https://github.com/mcci-catena/arduino-lmic/issues/2 + // Current code doesn't match LoRaWAN 1.0.2 requirements. + + LMIC.txend = os_getTime() + + (isTESTMODE() + // Avoid collision with JOIN ACCEPT being sent by GW (but we missed it - GW is still busy) + ? DNW2_SAFETY_ZONE + // Otherwise: randomize join (street lamp case): + // SF10:16, SF9=8,..SF8C:1secs + : LMICcore_rndDelay(16 >> LMIC.datarate)); + // 1 - triggers EV_JOIN_FAILED event + return failed; +} +#endif + +#endif // CFG_LMIC_US_like diff --git a/src/lmic/lmic_us_like.h b/src/lmic/lmic_us_like.h new file mode 100755 index 0000000..66bc549 --- /dev/null +++ b/src/lmic/lmic_us_like.h @@ -0,0 +1,100 @@ +/* +* Copyright (c) 2014-2016 IBM Corporation. +* Copyright (c) 2017 MCCI Corporation. +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _lmic_us_like_h_ +# define _lmic_us_like_h_ + +// make sure we want US-like code +#if !CFG_LMIC_US_like +# error "lmic not configured for us-like bandplan" +#endif + +// TODO(tmm@mcci.com): this should come from the lmic.h or lorabase.h file; and +// it's probably affected by the fix to this issue: +// https://github.com/mcci-catena/arduino-lmic/issues/2 +#define DNW2_SAFETY_ZONE ms2osticks(750) + +#define IS_CHANNEL_125khz(c) (c<64) +#define IS_CHANNEL_500khz(c) (c>=64 && c<72) +#define ENABLED_CHANNEL(chnl) ((LMIC.channelMap[(chnl >> 4)] & (1<<(chnl & 0x0F))) != 0) + +// provide the isValidBeacon1 function -- int for bool. +static inline int +LMICuslike_isValidBeacon1(const uint8_t *d) { + return os_rlsbf2(&d[OFF_BCN_CRC1]) != os_crc16(d, OFF_BCN_CRC1); +} + +#define LMICbandplan_isValidBeacon1(pFrame) LMICuslike_isValidBeacon1(pFrame) + +// provide a default for LMICbandplan_isFSK() +#define LMICbandplan_isFSK() (0) + +// provide a default LMICbandplan_txDoneFSK() +#define LMICbandplan_txDoneFSK(delay, func) do { } while (0) + +// provide a default LMICbandplan_joinAcceptChannelClear() +#define LMICbandplan_joinAcceptChannelClear() do { } while (0) + +// no CFList on joins for US-like plans +#define LMICbandplan_hasJoinCFlist() (0) + +#define LMICbandplan_advanceBeaconChannel() \ + do { LMIC.bcnChnl = (LMIC.bcnChnl+1) & 7; } while (0) + +// TODO(tmm@mcci.com): decide whether we want to do this on every +// reset or just restore the last sub-band selected by the user. +#define LMICbandplan_resetDefaultChannels() \ + LMICbandplan_initDefaultChannels(/* normal */ 0) + +void LMICuslike_initDefaultChannels(bit_t fJoin); +#define LMICbandplan_initDefaultChannels(fJoin) LMICuslike_initDefaultChannels(fJoin) + +#define LMICbandplan_setSessionInitDefaultChannels() \ + do { /* nothing */} while (0) + +u1_t LMICuslike_mapChannels(u1_t chpage, u2_t chmap); +#define LMICbandplan_mapChannels(chpage, chmap) LMICuslike_mapChannels(chpage, chmap) + +ostime_t LMICuslike_nextTx(ostime_t now); +#define LMICbandplan_nextTx(now) LMICuslike_nextTx(now) + +void LMICuslike_initJoinLoop(void); +#define LMICbandplan_initJoinLoop() LMICuslike_initJoinLoop() + +ostime_t LMICuslike_nextJoinState(void); +#define LMICbandplan_nextJoinState() LMICuslike_nextJoinState(); + +static inline ostime_t LMICeulike_nextJoinTime(ostime_t now) { + return now; +} +#define LMICbandplan_nextJoinTime(now) LMICeulike_nextJoinTime(now) + +#define LMICbandplan_init() \ + do { /* nothing */ } while (0) + +#endif // _lmic_us_like_h_ diff --git a/src/lmic/lmic_util.c b/src/lmic/lmic_util.c new file mode 100755 index 0000000..0d56c25 --- /dev/null +++ b/src/lmic/lmic_util.c @@ -0,0 +1,335 @@ +/* + +Module: lmic_util.c + +Function: + Encoding and decoding utilities for LMIC clients. + +Copyright & License: + See accompanying LICENSE file. + +Author: + Terry Moore, MCCI September 2019 + +*/ + +#include "lmic_util.h" + +#include + +/* + +Name: LMIC_f2sflt16() + +Function: + Encode a floating point number into a uint16_t. + +Definition: + uint16_t LMIC_f2sflt16( + float f + ); + +Description: + The float to be transmitted must be a number in the range (-1.0, 1.0). + It is converted to 16-bit integer formatted as follows: + + bits 15: sign + bits 14..11: biased exponent + bits 10..0: mantissa + + The float is properly rounded, and saturates. + + Note that the encoded value is sign/magnitude format, rather than + two's complement for negative values. + +Returns: + 0xFFFF for negative values <= 1.0; + 0x7FFF for positive values >= 1.0; + Otherwise an appropriate float. + +*/ + +uint16_t +LMIC_f2sflt16( + float f + ) + { + if (f <= -1.0) + return 0xFFFF; + else if (f >= 1.0) + return 0x7FFF; + else + { + int iExp; + float normalValue; + uint16_t sign; + + normalValue = frexpf(f, &iExp); + + sign = 0; + if (normalValue < 0) + { + // set the "sign bit" of the result + // and work with the absolute value of normalValue. + sign = 0x8000; + normalValue = -normalValue; + } + + // abs(f) is supposed to be in [0..1), so useful exp + // is [0..-15] + iExp += 15; + if (iExp < 0) + iExp = 0; + + // bit 15 is the sign + // bits 14..11 are the exponent + // bits 10..0 are the fraction + // we conmpute the fraction and then decide if we need to round. + uint16_t outputFraction = ldexpf(normalValue, 11) + 0.5; + if (outputFraction >= (1 << 11u)) + { + // reduce output fraction + outputFraction = 1 << 10; + // increase exponent + ++iExp; + } + + // check for overflow and return max instead. + if (iExp > 15) + return 0x7FFF | sign; + + return (uint16_t)(sign | (iExp << 11u) | outputFraction); + } + } + +/* + +Name: LMIC_f2sflt12() + +Function: + Encode a floating point number into a uint16_t using only 12 bits. + +Definition: + uint16_t LMIC_f2sflt16( + float f + ); + +Description: + The float to be transmitted must be a number in the range (-1.0, 1.0). + It is converted to 16-bit integer formatted as follows: + + bits 15-12: zero + bit 11: sign + bits 10..7: biased exponent + bits 6..0: mantissa + + The float is properly rounded, and saturates. + + Note that the encoded value is sign/magnitude format, rather than + two's complement for negative values. + +Returns: + 0xFFF for negative values <= 1.0; + 0x7FF for positive values >= 1.0; + Otherwise an appropriate float. + +*/ + +uint16_t +LMIC_f2sflt12( + float f + ) + { + if (f <= -1.0) + return 0xFFF; + else if (f >= 1.0) + return 0x7FF; + else + { + int iExp; + float normalValue; + uint16_t sign; + + normalValue = frexpf(f, &iExp); + + sign = 0; + if (normalValue < 0) + { + // set the "sign bit" of the result + // and work with the absolute value of normalValue. + sign = 0x800; + normalValue = -normalValue; + } + + // abs(f) is supposed to be in [0..1), so useful exp + // is [0..-15] + iExp += 15; + if (iExp < 0) + iExp = 0; + + // bit 15 is the sign + // bits 14..11 are the exponent + // bits 10..0 are the fraction + // we conmpute the fraction and then decide if we need to round. + uint16_t outputFraction = ldexpf(normalValue, 7) + 0.5; + if (outputFraction >= (1 << 7u)) + { + // reduce output fraction + outputFraction = 1 << 6; + // increase exponent + ++iExp; + } + + // check for overflow and return max instead. + if (iExp > 15) + return 0x7FF | sign; + + return (uint16_t)(sign | (iExp << 7u) | outputFraction); + } + } + +/* + +Name: LMIC_f2uflt16() + +Function: + Encode a floating point number into a uint16_t. + +Definition: + uint16_t LMIC_f2uflt16( + float f + ); + +Description: + The float to be transmitted must be a number in the range [0, 1.0). + It is converted to 16-bit integer formatted as follows: + + bits 15..12: biased exponent + bits 11..0: mantissa + + The float is properly rounded, and saturates. + + Note that the encoded value is sign/magnitude format, rather than + two's complement for negative values. + +Returns: + 0x0000 for values < 0.0; + 0xFFFF for positive values >= 1.0; + Otherwise an appropriate encoding of the input float. + +*/ + +uint16_t +LMIC_f2uflt16( + float f + ) + { + if (f < 0.0) + return 0; + else if (f >= 1.0) + return 0xFFFF; + else + { + int iExp; + float normalValue; + + normalValue = frexpf(f, &iExp); + + // f is supposed to be in [0..1), so useful exp + // is [0..-15] + iExp += 15; + if (iExp < 0) + // underflow. + iExp = 0; + + // bits 15..12 are the exponent + // bits 11..0 are the fraction + // we conmpute the fraction and then decide if we need to round. + uint16_t outputFraction = ldexpf(normalValue, 12) + 0.5; + if (outputFraction >= (1 << 12u)) + { + // reduce output fraction + outputFraction = 1 << 11; + // increase exponent + ++iExp; + } + + // check for overflow and return max instead. + if (iExp > 15) + return 0xFFFF; + + return (uint16_t)((iExp << 12u) | outputFraction); + } + } + +/* + +Name: LMIC_f2uflt12() + +Function: + Encode positive floating point number into a uint16_t using only 12 bits. + +Definition: + uint16_t LMIC_f2sflt16( + float f + ); + +Description: + The float to be transmitted must be a number in the range [0, 1.0). + It is converted to 16-bit integer formatted as follows: + + bits 15-12: zero + bits 11..8: biased exponent + bits 7..0: mantissa + + The float is properly rounded, and saturates. + +Returns: + 0x000 for negative values < 0.0; + 0xFFF for positive values >= 1.0; + Otherwise an appropriate float. + +*/ + +uint16_t +LMIC_f2uflt12( + float f + ) + { + if (f < 0.0) + return 0x000; + else if (f >= 1.0) + return 0xFFF; + else + { + int iExp; + float normalValue; + + normalValue = frexpf(f, &iExp); + + // f is supposed to be in [0..1), so useful exp + // is [0..-15] + iExp += 15; + if (iExp < 0) + // graceful underflow + iExp = 0; + + // bits 11..8 are the exponent + // bits 7..0 are the fraction + // we conmpute the fraction and then decide if we need to round. + uint16_t outputFraction = ldexpf(normalValue, 8) + 0.5; + if (outputFraction >= (1 << 8u)) + { + // reduce output fraction + outputFraction = 1 << 7; + // increase exponent + ++iExp; + } + + // check for overflow and return max instead. + if (iExp > 15) + return 0xFFF; + + return (uint16_t)((iExp << 8u) | outputFraction); + } + } diff --git a/src/lmic/lmic_util.h b/src/lmic/lmic_util.h new file mode 100755 index 0000000..d99217d --- /dev/null +++ b/src/lmic/lmic_util.h @@ -0,0 +1,34 @@ +/* + +Module: lmic_util.h + +Function: + Declare encoding and decoding utilities for LMIC clients. + +Copyright & License: + See accompanying LICENSE file. + +Author: + Terry Moore, MCCI September 2019 + +*/ + +#ifndef _LMIC_UTIL_H_ +# define _LMIC_UTIL_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +uint16_t LMIC_f2sflt16(float); +uint16_t LMIC_f2sflt12(float); +uint16_t LMIC_f2uflt16(float); +uint16_t LMIC_f2uflt12(float); + +#ifdef __cplusplus +} +#endif + +#endif /* _LMIC_UTIL_H_ */ diff --git a/src/lmic/lorabase.h b/src/lmic/lorabase.h index 1596dfd..87846be 100755 --- a/src/lmic/lorabase.h +++ b/src/lmic/lorabase.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2014-2016 IBM Corporation. + * Copyritght (c) 2017 MCCI Corporation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +30,7 @@ #define _lorabase_h_ #ifdef __cplusplus -extern "C" { +extern "C"{ #endif // ================================================================================ @@ -48,8 +49,6 @@ typedef u2_t rps_t; TYPEDEF_xref2rps_t; enum { ILLEGAL_RPS = 0xFF }; -enum { DR_PAGE_EU868 = 0x00 }; -enum { DR_PAGE_US915 = 0x10 }; // Global maximum frame length enum { STD_PREAMBLE_LEN = 8 }; @@ -74,86 +73,123 @@ enum { BCN_RESERVE_us = 2120000 }; enum { BCN_GUARD_us = 3000000 }; enum { BCN_SLOT_SPAN_us = 30000 }; +// there are exactly 16 datarates +enum _dr_code_t { + LORAWAN_DR0 = 0, + LORAWAN_DR1, + LORAWAN_DR2, + LORAWAN_DR3, + LORAWAN_DR4, + LORAWAN_DR5, + LORAWAN_DR6, + LORAWAN_DR7, + LORAWAN_DR8, + LORAWAN_DR9, + LORAWAN_DR10, + LORAWAN_DR11, + LORAWAN_DR12, + LORAWAN_DR13, + LORAWAN_DR14, + LORAWAN_DR15, + LORAWAN_DR_LENGTH // 16, for sizing arrays. +}; + +// post conditions from this block: symbols used by general code that is not +// ostensiblly region-specific. +// DR_DFLTMIN must be defined as a suitable substititute value if we get a bogus DR +// DR_PAGE is used only for a non-supported debug system, but should be defined. +// CHNL_DNW2 is the channel to be used for RX2 +// FREQ_DNW2 is the frequency to be used for RX2 +// DR_DNW2 is the data-rate to be used for RX2 +// +// The Class B stuff is untested and definitely wrong in parts for LoRaWAN 1.02 +// CHNL_PING is the channel to be used for pinging. +// FREQ_PING is the default ping channel frequency +// DR_PING is the data-rate to be used for pings. +// CHNL_BCN is the channel to be used for the beacon (or perhaps the start chan) +// FREQ_BCN is the frequency to be used for the beacon +// DR_BCN is the datarate to be used for the beacon +// AIRTIME_BCN is the airtime for the beacon + + + #if defined(CFG_eu868) // ============================================== -enum _dr_eu868_t { DR_SF12=0, DR_SF11, DR_SF10, DR_SF9, DR_SF8, DR_SF7, DR_SF7B, DR_FSK, DR_NONE }; -enum { DR_DFLTMIN = DR_SF7 }; +#include "lorabase_eu868.h" + +// per 2.1.3: not implemented +#define LMIC_ENABLE_TxParamSetupReq 0 + +enum { DR_DFLTMIN = EU868_DR_SF7 }; // DR5 + // DR_PAGE is a debugging parameter enum { DR_PAGE = DR_PAGE_EU868 }; -// Default frequency plan for EU 868MHz ISM band -// Bands: -// g1 : 1% 14dBm -// g2 : 0.1% 14dBm -// g3 : 10% 27dBm -// freq band datarates -enum { EU868_F1 = 868100000, // g1 SF7-12 - EU868_F2 = 868300000, // g1 SF7-12 FSK SF7/250 - EU868_F3 = 868500000, // g1 SF7-12 - EU868_F4 = 868850000, // g2 SF7-12 - EU868_F5 = 869050000, // g2 SF7-12 - EU868_F6 = 869525000, // g3 SF7-12 - EU868_J4 = 864100000, // g2 SF7-12 used during join - EU868_J5 = 864300000, // g2 SF7-12 ditto - EU868_J6 = 864500000, // g2 SF7-12 ditto -}; -enum { EU868_FREQ_MIN = 863000000, - EU868_FREQ_MAX = 870000000 }; - -enum { CHNL_PING = 5 }; -enum { FREQ_PING = EU868_F6 }; // default ping freq -enum { DR_PING = DR_SF9 }; // default ping DR -enum { CHNL_DNW2 = 5 }; -enum { FREQ_DNW2 = EU868_F6 }; -enum { DR_DNW2 = DR_SF12 }; -enum { CHNL_BCN = 5 }; -enum { FREQ_BCN = EU868_F6 }; -enum { DR_BCN = DR_SF9 }; -enum { AIRTIME_BCN = 144384 }; // micros +//enum { CHNL_PING = 5 }; +enum { FREQ_PING = EU868_F6 }; // default ping freq +enum { DR_PING = EU868_DR_SF9 }; // default ping DR + //enum { CHNL_DNW2 = 5 }; +enum { FREQ_DNW2 = EU868_F6 }; +enum { DR_DNW2 = EU868_DR_SF12 }; +enum { CHNL_BCN = 5 }; +enum { FREQ_BCN = EU868_F6 }; +enum { DR_BCN = EU868_DR_SF9 }; +enum { AIRTIME_BCN = 144384 }; // micros +enum { LMIC_REGION_EIRP = EU868_LMIC_REGION_EIRP }; // region uses EIRP enum { - // Beacon frame format EU SF9 - OFF_BCN_NETID = 0, - OFF_BCN_TIME = 3, - OFF_BCN_CRC1 = 7, - OFF_BCN_INFO = 8, - OFF_BCN_LAT = 9, - OFF_BCN_LON = 12, - OFF_BCN_CRC2 = 15, - LEN_BCN = 17 + // Beacon frame format EU SF9 + OFF_BCN_NETID = 0, + OFF_BCN_TIME = 3, + OFF_BCN_CRC1 = 7, + OFF_BCN_INFO = 8, + OFF_BCN_LAT = 9, + OFF_BCN_LON = 12, + OFF_BCN_CRC2 = 15, + LEN_BCN = 17 }; +// for backwards compatibility. This must match _dr_eu868_t +# if LMIC_DR_LEGACY +enum _dr_configured_t { + DR_SF12 = EU868_DR_SF12, + DR_SF11 = EU868_DR_SF11, + DR_SF10 = EU868_DR_SF10, + DR_SF9 = EU868_DR_SF9, + DR_SF8 = EU868_DR_SF8, + DR_SF7 = EU868_DR_SF7, + DR_SF7B = EU868_DR_SF7B, + DR_FSK = EU868_DR_FSK, + DR_NONE = EU868_DR_NONE +}; +# endif // LMIC_DR_LEGACY + #elif defined(CFG_us915) // ========================================= -enum _dr_us915_t { DR_SF10=0, DR_SF9, DR_SF8, DR_SF7, DR_SF8C, DR_NONE, - // Devices behind a router: - DR_SF12CR=8, DR_SF11CR, DR_SF10CR, DR_SF9CR, DR_SF8CR, DR_SF7CR }; -enum { DR_DFLTMIN = DR_SF8C }; +#include "lorabase_us915.h" + +// per 2.2.3: not implemented +#define LMIC_ENABLE_TxParamSetupReq 0 + +enum { DR_DFLTMIN = US915_DR_SF7 }; // DR5 + +// DR_PAGE is a debugging parameter; it must be defined but it has no use in arduino-lmic enum { DR_PAGE = DR_PAGE_US915 }; -// Default frequency plan for US 915MHz -enum { US915_125kHz_UPFBASE = 902300000, - US915_125kHz_UPFSTEP = 200000, - US915_500kHz_UPFBASE = 903000000, - US915_500kHz_UPFSTEP = 1600000, - US915_500kHz_DNFBASE = 923300000, - US915_500kHz_DNFSTEP = 600000 -}; -enum { US915_FREQ_MIN = 902000000, - US915_FREQ_MAX = 928000000 }; - -enum { CHNL_PING = 0 }; // used only for default init of state (follows beacon - rotating) -enum { FREQ_PING = US915_500kHz_DNFBASE + CHNL_PING*US915_500kHz_DNFSTEP }; // default ping freq -enum { DR_PING = DR_SF10CR }; // default ping DR -enum { CHNL_DNW2 = 0 }; -enum { FREQ_DNW2 = US915_500kHz_DNFBASE + CHNL_DNW2*US915_500kHz_DNFSTEP }; -enum { DR_DNW2 = DR_SF12CR }; +//enum { CHNL_PING = 0 }; // used only for default init of state (follows beacon - rotating) +enum { FREQ_PING = US915_500kHz_DNFBASE + 0*US915_500kHz_DNFSTEP }; // default ping freq +enum { DR_PING = US915_DR_SF10CR }; // default ping DR +//enum { CHNL_DNW2 = 0 }; +enum { FREQ_DNW2 = US915_500kHz_DNFBASE + 0*US915_500kHz_DNFSTEP }; +enum { DR_DNW2 = US915_DR_SF12CR }; enum { CHNL_BCN = 0 }; // used only for default init of state (rotating beacon scheme) -enum { DR_BCN = DR_SF10CR }; +enum { DR_BCN = US915_DR_SF12CR }; +// TODO(tmm@mcci.com): check this, as beacon DR was SF10 in IBM code. enum { AIRTIME_BCN = 72192 }; // micros +enum { LMIC_REGION_EIRP = US915_LMIC_REGION_EIRP }; // region uses EIRP enum { // Beacon frame format US SF10 - OFF_BCN_NETID = 0, + OFF_BCN_NETID = 0, OFF_BCN_TIME = 3, OFF_BCN_CRC1 = 7, OFF_BCN_INFO = 9, @@ -164,6 +200,172 @@ enum { LEN_BCN = 19 }; +# if LMIC_DR_LEGACY +enum _dr_configured_t { + DR_SF10 = US915_DR_SF10, + DR_SF9 = US915_DR_SF9, + DR_SF8 = US915_DR_SF8, + DR_SF7 = US915_DR_SF7, + DR_SF8C = US915_DR_SF8C, + DR_NONE = US915_DR_NONE, + DR_SF12CR = US915_DR_SF12CR, + DR_SF11CR = US915_DR_SF11CR, + DR_SF10CR = US915_DR_SF10CR, + DR_SF9CR = US915_DR_SF9CR, + DR_SF8CR = US915_DR_SF8CR, + DR_SF7CR = US915_DR_SF7CR +}; +# endif // LMIC_DR_LEGACY + +#elif defined(CFG_au921) // ========================================= + +#include "lorabase_au921.h" + +// per 2.5.3: not implemented +#define LMIC_ENABLE_TxParamSetupReq 0 + +enum { DR_DFLTMIN = AU921_DR_SF7 }; // DR5 + + // DR_PAGE is a debugging parameter; it must be defined but it has no use in arduino-lmic +enum { DR_PAGE = DR_PAGE_AU921 }; + +//enum { CHNL_PING = 0 }; // used only for default init of state (follows beacon - rotating) +enum { FREQ_PING = AU921_500kHz_DNFBASE + 0*AU921_500kHz_DNFSTEP }; // default ping freq +enum { DR_PING = AU921_DR_SF10CR }; // default ping DR +//enum { CHNL_DNW2 = 0 }; +enum { FREQ_DNW2 = AU921_500kHz_DNFBASE + 0*AU921_500kHz_DNFSTEP }; +enum { DR_DNW2 = AU921_DR_SF12CR }; // DR8 +enum { CHNL_BCN = 0 }; // used only for default init of state (rotating beacon scheme) +enum { DR_BCN = AU921_DR_SF10CR }; +enum { AIRTIME_BCN = 72192 }; // micros ... TODO(tmm@mcci.com) check. +enum { LMIC_REGION_EIRP = AU921_LMIC_REGION_EIRP }; // region uses EIRP + +enum { + // Beacon frame format AU DR10/SF10 500kHz + OFF_BCN_NETID = 0, + OFF_BCN_TIME = 3, + OFF_BCN_CRC1 = 7, + OFF_BCN_INFO = 9, + OFF_BCN_LAT = 10, + OFF_BCN_LON = 13, + OFF_BCN_RFU1 = 16, + OFF_BCN_CRC2 = 17, + LEN_BCN = 19 +}; + +# if LMIC_DR_LEGACY +enum _dr_configured_t { + DR_SF12 = AU921_DR_SF12, + DR_SF11 = AU921_DR_SF11, + DR_SF10 = AU921_DR_SF10, + DR_SF9 = AU921_DR_SF9, + DR_SF8 = AU921_DR_SF8, + DR_SF7 = AU921_DR_SF7, + DR_SF8C = AU921_DR_SF8C, + DR_NONE = AU921_DR_NONE, + DR_SF12CR = AU921_DR_SF12CR, + DR_SF11CR = AU921_DR_SF11CR, + DR_SF10CR = AU921_DR_SF10CR, + DR_SF9CR = AU921_DR_SF9CR, + DR_SF8CR = AU921_DR_SF8CR, + DR_SF7CR = AU921_DR_SF7CR +}; +# endif // LMIC_DR_LEGACY + +#elif defined(CFG_as923) // ============================================== + +#include "lorabase_as923.h" + +// per 2.7.3: must be implemented +#define LMIC_ENABLE_TxParamSetupReq 1 + +enum { DR_DFLTMIN = AS923_DR_SF10 }; // DR2 + // DR_PAGE is a debugging parameter +enum { DR_PAGE = DR_PAGE_AS923 }; + +enum { FREQ_PING = AS923_F2 }; // default ping freq +enum { DR_PING = AS923_DR_SF9 }; // default ping DR: DR3 +enum { FREQ_DNW2 = AS923_FDOWN }; +enum { DR_DNW2 = AS923_DR_SF10 }; +enum { CHNL_BCN = 5 }; +enum { FREQ_BCN = AS923_FBCN }; +enum { DR_BCN = AS923_DR_SF9 }; +enum { AIRTIME_BCN = 144384 }; // micros +enum { LMIC_REGION_EIRP = AS923_LMIC_REGION_EIRP }; // region uses EIRP + +enum { + // Beacon frame format AS SF9 + OFF_BCN_NETID = 0, + OFF_BCN_TIME = 2, + OFF_BCN_CRC1 = 6, + OFF_BCN_INFO = 8, + OFF_BCN_LAT = 9, + OFF_BCN_LON = 12, + OFF_BCN_CRC2 = 15, + LEN_BCN = 17 +}; + +# if LMIC_DR_LEGACY +enum _dr_configured_t { + DR_SF12 = AS923_DR_SF12, + DR_SF11 = AS923_DR_SF11, + DR_SF10 = AS923_DR_SF10, + DR_SF9 = AS923_DR_SF9, + DR_SF8 = AS923_DR_SF8, + DR_SF7 = AS923_DR_SF7, + DR_SF7B = AS923_DR_SF7B, + DR_FSK = AS923_DR_FSK, + DR_NONE = AS923_DR_NONE +}; +# endif // LMIC_DR_LEGACY + +#elif defined(CFG_in866) // ============================================== + +#include "lorabase_in866.h" + +// per 2.9.3: not implemented +#define LMIC_ENABLE_TxParamSetupReq 0 + +enum { DR_DFLTMIN = IN866_DR_SF7 }; // DR5 +enum { DR_PAGE = DR_PAGE_IN866 }; // DR_PAGE is a debugging parameter + +enum { FREQ_PING = IN866_FB }; // default ping freq +enum { DR_PING = IN866_DR_SF8 }; // default ping DR +enum { FREQ_DNW2 = IN866_FB }; +enum { DR_DNW2 = IN866_DR_SF10 }; +enum { CHNL_BCN = 5 }; +enum { FREQ_BCN = IN866_FB }; +enum { DR_BCN = IN866_DR_SF8 }; +enum { AIRTIME_BCN = 144384 }; // micros +enum { LMIC_REGION_EIRP = IN866_LMIC_REGION_EIRP }; // region uses EIRP + +enum { + // Beacon frame format IN SF9 + OFF_BCN_NETID = 0, + OFF_BCN_TIME = 1, + OFF_BCN_CRC1 = 5, + OFF_BCN_INFO = 7, + OFF_BCN_LAT = 8, + OFF_BCN_LON = 11, + OFF_BCN_CRC2 = 17, + LEN_BCN = 19 +}; + +# if LMIC_DR_LEGACY +enum _dr_configured_t { + DR_SF12 = IN866_DR_SF12, // DR0 + DR_SF11 = IN866_DR_SF11, // DR1 + DR_SF10 = IN866_DR_SF10, // DR2 + DR_SF9 = IN866_DR_SF9, // DR3 + DR_SF8 = IN866_DR_SF8, // DR4 + DR_SF7 = IN866_DR_SF7, // DR5 + DR_FSK = IN866_DR_FSK, // DR7 + DR_NONE = IN866_DR_NONE +}; +# endif // LMIC_DR_LEGACY + +#else +# error Unsupported configuration setting #endif // =================================================== enum { @@ -238,12 +440,16 @@ enum { // MAC uplink commands downwlink too enum { // Class A - MCMD_LCHK_REQ = 0x02, // - link check request : - - MCMD_LADR_ANS = 0x03, // - link ADR answer : u1:7-3:RFU, 3/2/1: pow/DR/Ch ACK - MCMD_DCAP_ANS = 0x04, // - duty cycle answer : - - MCMD_DN2P_ANS = 0x05, // - 2nd DN slot status : u1:7-2:RFU 1/0:datarate/channel ack - MCMD_DEVS_ANS = 0x06, // - device status ans : u1:battery 0,1-254,255=?, u1:7-6:RFU,5-0:margin(-32..31) - MCMD_SNCH_ANS = 0x07, // - set new channel : u1: 7-2=RFU, 1/0:DR/freq ACK + MCMD_LCHK_REQ = 0x02, // - LinkCheckReq : - + MCMD_LADR_ANS = 0x03, // - LinkADRAnd : u1:7-3:RFU, 3/2/1: pow/DR/Ch ACK + MCMD_DCAP_ANS = 0x04, // - DutyCycleAns : - + MCMD_DN2P_ANS = 0x05, // - RxParamSetupAns : u1:7-2:RFU 1/0:datarate/channel ack + MCMD_DEVS_ANS = 0x06, // - DevStatusAns : u1:battery 0,1-254,255=?, u1:7-6:RFU,5-0:margin(-32..31) + MCMD_SNCH_ANS = 0x07, // - NewChannelAns : u1: 7-2=RFU, 1/0:DR/freq ACK + MCMD_RXTimingSetupAns = 0x08, // : - + MCMD_TxParamSetupAns = 0x09, // : - + MCMD_DIChannelAns = 0x0A, // : u1: [7-2]:RFU 1:exists 0:OK + // Class B MCMD_PING_IND = 0x10, // - pingability indic : u1: 7=RFU, 6-4:interval, 3-0:datarate MCMD_PING_ANS = 0x11, // - ack ping freq : u1: 7-1:RFU, 0:freq ok @@ -253,12 +459,16 @@ enum { // MAC downlink commands enum { // Class A - MCMD_LCHK_ANS = 0x02, // link check answer : u1:margin 0-254,255=unknown margin / u1:gwcnt - MCMD_LADR_REQ = 0x03, // link ADR request : u1:DR/TXPow, u2:chmask, u1:chpage/repeat - MCMD_DCAP_REQ = 0x04, // duty cycle cap : u1:255 dead [7-4]:RFU, [3-0]:cap 2^-k - MCMD_DN2P_SET = 0x05, // 2nd DN window param: u1:7-4:RFU/3-0:datarate, u3:freq - MCMD_DEVS_REQ = 0x06, // device status req : - - MCMD_SNCH_REQ = 0x07, // set new channel : u1:chidx, u3:freq, u1:DRrange + MCMD_LCHK_ANS = 0x02, // LinkCheckAns : u1:margin 0-254,255=unknown margin / u1:gwcnt LinkCheckReq + MCMD_LADR_REQ = 0x03, // LinkADRReq : u1:DR/TXPow, u2:chmask, u1:chpage/repeat + MCMD_DCAP_REQ = 0x04, // DutyCycleReq : u1:255 dead [7-4]:RFU, [3-0]:cap 2^-k + MCMD_DN2P_SET = 0x05, // RXParamSetupReq : u1:7-4:RFU/3-0:datarate, u3:freq + MCMD_DEVS_REQ = 0x06, // DevStatusReq : - + MCMD_SNCH_REQ = 0x07, // NewChannelReq : u1:chidx, u3:freq, u1:DRrange + MCMD_RXTimingSetupReq = 0x08, // : u1: [7-4]:RFU [3-0]: Delay 1-15s (0 => 1) + MCMD_TxParamSetupReq = 0x09, // : u1: [7-6]:RFU [5:4]: dl dwell/ul dwell [3:0] max EIRP + MCMD_DIChannelReq = 0x0A, // : u1: channel, u3: frequency + // Class B MCMD_PING_SET = 0x11, // set ping freq : u3: freq MCMD_BCNI_ANS = 0x12, // next beacon start : u2: delay(in TUNIT millis), u1:channel @@ -274,7 +484,8 @@ enum { MCMD_LADR_ANS_CHACK = 0x01, // 0=unknown channel enabled }; enum { - MCMD_DN2P_ANS_RFU = 0xFC, // RFU bits + MCMD_DN2P_ANS_RFU = 0xF8, // RFU bits + MCMD_DN2P_ANS_RX1DrOffsetAck = 0x04, // 0=dr2 not allowed MCMD_DN2P_ANS_DRACK = 0x02, // 0=unknown data rate MCMD_DN2P_ANS_CHACK = 0x01, // 0=unknown channel enabled }; @@ -297,8 +508,10 @@ enum { // Bit fields byte#3 of MCMD_LADR_REQ payload enum { + MCMD_LADR_CHP_USLIKE_SPECIAL = 0x50, // first special for us-like + MCMD_LADR_CHP_BANK = 0x50, // special: bits are banks. MCMD_LADR_CHP_125ON = 0x60, // special channel page enable, bits applied to 64..71 - MCMD_LADR_CHP_125OFF = 0x70, // ditto + MCMD_LADR_CHP_125OFF = 0x70, // special channel page: disble 125K, bits apply to 64..71 MCMD_LADR_N3RFU_MASK = 0x80, MCMD_LADR_CHPAGE_MASK = 0xF0, MCMD_LADR_REPEAT_MASK = 0x0F, @@ -311,49 +524,59 @@ enum { MCMD_LADR_POW_MASK = 0x0F, MCMD_LADR_DR_SHIFT = 4, MCMD_LADR_POW_SHIFT = 0, -#if defined(CFG_eu868) - MCMD_LADR_SF12 = DR_SF12<<4, - MCMD_LADR_SF11 = DR_SF11<<4, - MCMD_LADR_SF10 = DR_SF10<<4, - MCMD_LADR_SF9 = DR_SF9 <<4, - MCMD_LADR_SF8 = DR_SF8 <<4, - MCMD_LADR_SF7 = DR_SF7 <<4, - MCMD_LADR_SF7B = DR_SF7B<<4, - MCMD_LADR_FSK = DR_FSK <<4, +#if defined(CFG_eu868) // TODO(tmm@mcci.com): complete refactor. + EU868_MCMD_LADR_SF12 = EU868_DR_SF12<<4, + EU868_MCMD_LADR_SF11 = EU868_DR_SF11<<4, + EU868_MCMD_LADR_SF10 = EU868_DR_SF10<<4, + EU868_MCMD_LADR_SF9 = EU868_DR_SF9 <<4, + EU868_MCMD_LADR_SF8 = EU868_DR_SF8 <<4, + EU868_MCMD_LADR_SF7 = EU868_DR_SF7 <<4, + EU868_MCMD_LADR_SF7B = EU868_DR_SF7B<<4, + EU868_MCMD_LADR_FSK = EU868_DR_FSK <<4, - MCMD_LADR_20dBm = 0, - MCMD_LADR_14dBm = 1, - MCMD_LADR_11dBm = 2, - MCMD_LADR_8dBm = 3, - MCMD_LADR_5dBm = 4, - MCMD_LADR_2dBm = 5, + EU868_MCMD_LADR_20dBm = 0, + EU868_MCMD_LADR_14dBm = 1, + EU868_MCMD_LADR_11dBm = 2, + EU868_MCMD_LADR_8dBm = 3, + EU868_MCMD_LADR_5dBm = 4, + EU868_MCMD_LADR_2dBm = 5, #elif defined(CFG_us915) - MCMD_LADR_SF10 = DR_SF10<<4, - MCMD_LADR_SF9 = DR_SF9 <<4, - MCMD_LADR_SF8 = DR_SF8 <<4, - MCMD_LADR_SF7 = DR_SF7 <<4, - MCMD_LADR_SF8C = DR_SF8C<<4, - MCMD_LADR_SF12CR = DR_SF12CR<<4, - MCMD_LADR_SF11CR = DR_SF11CR<<4, - MCMD_LADR_SF10CR = DR_SF10CR<<4, - MCMD_LADR_SF9CR = DR_SF9CR<<4, - MCMD_LADR_SF8CR = DR_SF8CR<<4, - MCMD_LADR_SF7CR = DR_SF7CR<<4, + US915_MCMD_LADR_SF10 = US915_DR_SF10<<4, + US915_MCMD_LADR_SF9 = US915_DR_SF9 <<4, + US915_MCMD_LADR_SF8 = US915_DR_SF8 <<4, + US915_MCMD_LADR_SF7 = US915_DR_SF7 <<4, + US915_MCMD_LADR_SF8C = US915_DR_SF8C<<4, + US915_MCMD_LADR_SF12CR = US915_DR_SF12CR<<4, + US915_MCMD_LADR_SF11CR = US915_DR_SF11CR<<4, + US915_MCMD_LADR_SF10CR = US915_DR_SF10CR<<4, + US915_MCMD_LADR_SF9CR = US915_DR_SF9CR<<4, + US915_MCMD_LADR_SF8CR = US915_DR_SF8CR<<4, + US915_MCMD_LADR_SF7CR = US915_DR_SF7CR<<4, - MCMD_LADR_30dBm = 0, - MCMD_LADR_28dBm = 1, - MCMD_LADR_26dBm = 2, - MCMD_LADR_24dBm = 3, - MCMD_LADR_22dBm = 4, - MCMD_LADR_20dBm = 5, - MCMD_LADR_18dBm = 6, - MCMD_LADR_16dBm = 7, - MCMD_LADR_14dBm = 8, - MCMD_LADR_12dBm = 9, - MCMD_LADR_10dBm = 10 + US915_MCMD_LADR_30dBm = 0, + US915_MCMD_LADR_28dBm = 1, + US915_MCMD_LADR_26dBm = 2, + US915_MCMD_LADR_24dBm = 3, + US915_MCMD_LADR_22dBm = 4, + US915_MCMD_LADR_20dBm = 5, + US915_MCMD_LADR_18dBm = 6, + US915_MCMD_LADR_16dBm = 7, + US915_MCMD_LADR_14dBm = 8, + US915_MCMD_LADR_12dBm = 9, + US915_MCMD_LADR_10dBm = 10 #endif }; +// bit fields of the TxParam request +enum { + MCMD_TxParam_RxDWELL_SHIFT = 5, + MCMD_TxParam_RxDWELL_MASK = 1 << MCMD_TxParam_RxDWELL_SHIFT, + MCMD_TxParam_TxDWELL_SHIFT = 4, + MCMD_TxParam_TxDWELL_MASK = 1 << MCMD_TxParam_TxDWELL_SHIFT, + MCMD_TxParam_MaxEIRP_SHIFT = 0, + MCMD_TxParam_MaxEIRP_MASK = 0xF << MCMD_TxParam_MaxEIRP_SHIFT, +}; + // Device address typedef u4_t devaddr_t; @@ -374,18 +597,19 @@ inline rps_t makeRps (sf_t sf, bw_t bw, cr_t cr, int ih, int nocrc) { return sf | (bw<<3) | (cr<<5) | (nocrc?(1<<7):0) | ((ih&0xFF)<<8); } #define MAKERPS(sf,bw,cr,ih,nocrc) ((rps_t)((sf) | ((bw)<<3) | ((cr)<<5) | ((nocrc)?(1<<7):0) | ((ih&0xFF)<<8))) -// Two frames with params r1/r2 would interfere on air: same SFx + BWx +// Two frames with params r1/r2 would interfere on air: same SFx + BWx inline int sameSfBw(rps_t r1, rps_t r2) { return ((r1^r2)&0x1F) == 0; } -extern const u1_t _DR2RPS_CRC[]; -inline rps_t updr2rps (dr_t dr) { return (rps_t)_DR2RPS_CRC[dr+1]; } +extern CONST_TABLE(u1_t, _DR2RPS_CRC)[]; +inline rps_t updr2rps (dr_t dr) { return (rps_t)TABLE_GET_U1(_DR2RPS_CRC, dr+1); } inline rps_t dndr2rps (dr_t dr) { return setNocrc(updr2rps(dr),1); } inline int isFasterDR (dr_t dr1, dr_t dr2) { return dr1 > dr2; } inline int isSlowerDR (dr_t dr1, dr_t dr2) { return dr1 < dr2; } -inline dr_t incDR (dr_t dr) { return _DR2RPS_CRC[dr+2]==ILLEGAL_RPS ? dr : (dr_t)(dr+1); } // increase data rate -inline dr_t decDR (dr_t dr) { return _DR2RPS_CRC[dr ]==ILLEGAL_RPS ? dr : (dr_t)(dr-1); } // decrease data rate -inline dr_t assertDR (dr_t dr) { return _DR2RPS_CRC[dr+1]==ILLEGAL_RPS ? (dr_t)DR_DFLTMIN : dr; } // force into a valid DR -inline bit_t validDR (dr_t dr) { return _DR2RPS_CRC[dr+1]!=ILLEGAL_RPS; } // in range +inline dr_t incDR (dr_t dr) { return TABLE_GET_U1(_DR2RPS_CRC, dr+2)==ILLEGAL_RPS ? dr : (dr_t)(dr+1); } // increase data rate +inline dr_t decDR (dr_t dr) { return TABLE_GET_U1(_DR2RPS_CRC, dr )==ILLEGAL_RPS ? dr : (dr_t)(dr-1); } // decrease data rate +// ttn-esp32 change: remove unused function creating warning +//inline dr_t assertDR (dr_t dr) { return TABLE_GET_U1(_DR2RPS_CRC, dr+1)==ILLEGAL_RPS ? DR_DFLTMIN : dr; } // force into a valid DR +inline bit_t validDR (dr_t dr) { return TABLE_GET_U1(_DR2RPS_CRC, dr+1)!=ILLEGAL_RPS; } // in range inline dr_t lowerDR (dr_t dr, u1_t n) { while(n--){dr=decDR(dr);} return dr; } // decrease data rate by n steps // @@ -393,8 +617,6 @@ inline dr_t lowerDR (dr_t dr, u1_t n) { while(n--){dr=decDR(dr);} return dr; } // ================================================================================ -// Convert between dBm values and power codes (MCMD_LADR_XdBm) -s1_t pow2dBm (u1_t mcmd_ladr_p1); // Calculate airtime ostime_t calcAirTime (rps_t rps, u1_t plen); // Sensitivity at given SF/BW diff --git a/src/lmic/lorabase_as923.h b/src/lmic/lorabase_as923.h new file mode 100755 index 0000000..9cba8c4 --- /dev/null +++ b/src/lmic/lorabase_as923.h @@ -0,0 +1,96 @@ +/* +* Copyright (c) 2014-2016 IBM Corporation. +* All rights reserved. +* +* Copyright (c) 2017 MCCI Corporation +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _lorabase_as923_h_ +#define _lorabase_as923_h_ + +#ifndef _LMIC_CONFIG_PRECONDITIONS_H_ +# include "lmic_config_preconditions.h" +#endif + +/****************************************************************************\ +| +| Basic definitions for AS923 (always in scope) +| +\****************************************************************************/ + +enum _dr_as923_t { + AS923_DR_SF12 = 0, + AS923_DR_SF11, + AS923_DR_SF10, + AS923_DR_SF9, + AS923_DR_SF8, + AS923_DR_SF7, + AS923_DR_SF7B, + AS923_DR_FSK, + AS923_DR_NONE +}; + +// Bands: +// g1 : 1% 16dBm +// freq band datarates +enum { + AS923_F1 = 923200000, // g1 SF7-12 + AS923_F2 = 923400000, // g1 SF7-12 + AS923_FDOWN = 923200000, // (RX2 freq, DR2) + AS923_FBCN = 923400000, // default BCN, DR3 + AS923_FPING = 923400000, // default ping, DR3 +}; +enum { + AS923_FREQ_MIN = 915000000, + AS923_FREQ_MAX = 928000000 +}; +enum { + AS923_TX_EIRP_MAX_DBM = 16 // 16 dBm +}; +enum { DR_PAGE_AS923 = 0x10 * (LMIC_REGION_as923 - 1) }; + +enum { AS923_LMIC_REGION_EIRP = 1 }; // region uses EIRP + +enum { AS923JP_LBT_US = 5000 }; // microseconds of LBT time -- 5000 ==> + // 5 ms. We use us rather than ms for + // future 128us support, and just for + // backward compatibility -- there + // is code that uses the _US constant, + // and it's awkward to break it. + +enum { AS923JP_LBT_DB_MAX = -80 }; // maximum channel strength in dB; if TX + // we measure more than this, we don't tx. + +// AS923 v1.1, all channels face a 1% duty cycle. So this will have to change +// in the future via a config. But this code base needs major changes for +// v1.1 in any case. +enum { AS923_V102_TX_CAP = 100 }; // v1.0.2 allows 100% + +#ifndef AS923_TX_CAP +# define AS923_TX_CAP AS923_V102_TX_CAP +#endif + +#endif /* _lorabase_as923_h_ */ diff --git a/src/lmic/lorabase_au921.h b/src/lmic/lorabase_au921.h new file mode 100755 index 0000000..d4c33b9 --- /dev/null +++ b/src/lmic/lorabase_au921.h @@ -0,0 +1,84 @@ +/* +* Copyright (c) 2014-2016 IBM Corporation. +* All rights reserved. +* +* Copyright (c) 2017 MCCI Corporation +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _lorabase_au921_h_ +#define _lorabase_au921_h_ + +#ifndef _LMIC_CONFIG_PRECONDITIONS_H_ +# include "lmic_config_preconditions.h" +#endif + +/****************************************************************************\ +| +| Basic definitions for AS921 (always in scope) +| +\****************************************************************************/ + +// Frequency plan for AU 921 MHz +enum _dr_as921_t { + AU921_DR_SF12 = 0, + AU921_DR_SF11, + AU921_DR_SF10, + AU921_DR_SF9, + AU921_DR_SF8, + AU921_DR_SF7, + AU921_DR_SF8C, + AU921_DR_NONE, + // Devices behind a router: + AU921_DR_SF12CR = 8, + AU921_DR_SF11CR, + AU921_DR_SF10CR, + AU921_DR_SF9CR, + AU921_DR_SF8CR, + AU921_DR_SF7CR +}; + +// Default frequency plan for AU 921MHz +enum { + AU921_125kHz_UPFBASE = 915200000, + AU921_125kHz_UPFSTEP = 200000, + AU921_500kHz_UPFBASE = 915900000, + AU921_500kHz_UPFSTEP = 1600000, + AU921_500kHz_DNFBASE = 923300000, + AU921_500kHz_DNFSTEP = 600000 +}; +enum { + AU921_FREQ_MIN = 915000000, + AU921_FREQ_MAX = 928000000 +}; +enum { + AU921_TX_EIRP_MAX_DBM = 30 // 30 dBm +}; + +enum { DR_PAGE_AU921 = 0x10 * (LMIC_REGION_au921 - 1) }; + +enum { AU921_LMIC_REGION_EIRP = 1 }; // region uses EIRP + +#endif /* _lorabase_au921_h_ */ \ No newline at end of file diff --git a/src/lmic/lorabase_eu868.h b/src/lmic/lorabase_eu868.h new file mode 100755 index 0000000..0040ad0 --- /dev/null +++ b/src/lmic/lorabase_eu868.h @@ -0,0 +1,92 @@ +/* +* Copyright (c) 2014-2016 IBM Corporation. +* All rights reserved. +* +* Copyright (c) 2017 MCCI Corporation +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _lorabase_eu868_h_ +#define _lorabase_eu868_h_ + +#ifndef _LMIC_CONFIG_PRECONDITIONS_H_ +# include "lmic_config_preconditions.h" +#endif + +/****************************************************************************\ +| +| Basic definitions for EU868 (always in scope) +| +\****************************************************************************/ + +// +// Default frequency plan for EU 868MHz ISM band +// data rates +// this is a little confusing: the integer values of these constants are the +// DataRates from the LoRaWAN Regional Parmaeter spec. The names are just +// convenient indications, so we can use them in the rare case that we need to +// choose a DataRate by SF and configuration, not by DR code. + +enum _dr_eu868_t { + EU868_DR_SF12 = 0, + EU868_DR_SF11, + EU868_DR_SF10, + EU868_DR_SF9, + EU868_DR_SF8, + EU868_DR_SF7, + EU868_DR_SF7B, + EU868_DR_FSK, + EU868_DR_NONE +}; + +// Bands: +// g1 : 1% 14dBm +// g2 : 0.1% 14dBm +// g3 : 10% 27dBm +// freq band datarates +enum { + EU868_F1 = 868100000, // g1 SF7-12 + EU868_F2 = 868300000, // g1 SF7-12 FSK SF7/250 + EU868_F3 = 868500000, // g1 SF7-12 + EU868_F4 = 868850000, // g2 SF7-12 + EU868_F5 = 869050000, // g2 SF7-12 + EU868_F6 = 869525000, // g3 SF7-12 + EU868_J4 = 864100000, // g2 SF7-12 used during join + EU868_J5 = 864300000, // g2 SF7-12 ditto + EU868_J6 = 864500000, // g2 SF7-12 ditto +}; +enum { + EU868_FREQ_MIN = 863000000, + EU868_FREQ_MAX = 870000000 +}; +enum { + EU868_TX_EIRP_MAX_DBM = 16 // 16 dBm EIRP. So subtract 3 dBm for a 3 dBi antenna. +}; + +enum { EU868_LMIC_REGION_EIRP = 1 }; // region uses EIRP + +enum { DR_PAGE_EU868 = 0x10 * (LMIC_REGION_eu868 - 1) }; + +#endif /* _lorabase_eu868_h_ */ \ No newline at end of file diff --git a/src/lmic/lorabase_in866.h b/src/lmic/lorabase_in866.h new file mode 100755 index 0000000..6955a76 --- /dev/null +++ b/src/lmic/lorabase_in866.h @@ -0,0 +1,78 @@ +/* +* Copyright (c) 2014-2016 IBM Corporation. +* All rights reserved. +* +* Copyright (c) 2017 MCCI Corporation +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _lorabase_in866_h_ +#define _lorabase_in866_h_ + +#ifndef _LMIC_CONFIG_PRECONDITIONS_H_ +# include "lmic_config_preconditions.h" +#endif + +/****************************************************************************\ +| +| Basic definitions for IN866 (always in scope) +| +\****************************************************************************/ + +enum _dr_in866_t { + IN866_DR_SF12 = 0, // DR0 + IN866_DR_SF11, // DR1 + IN866_DR_SF10, // DR2 + IN866_DR_SF9, // DR3 + IN866_DR_SF8, // DR4 + IN866_DR_SF7, // DR5 + IN866_DR_RFU, // - + IN866_DR_FSK, // DR7 + IN866_DR_NONE +}; + +// There is no dwell-time or duty-cycle limitation for IN +// +// max power: 30dBM +// +// freq datarates +enum { + IN866_F1 = 865062500, // SF7-12 (DR0-5) + IN866_F2 = 865402500, // SF7-12 (DR0-5) + IN866_F3 = 865985000, // SF7-12 (DR0-5) + IN866_FB = 866550000, // beacon/ping +}; +enum { + IN866_FREQ_MIN = 865000000, + IN866_FREQ_MAX = 867000000 +}; +enum { + IN866_TX_EIRP_MAX_DBM = 30 // 30 dBm +}; +enum { DR_PAGE_IN866 = 0x10 * (LMIC_REGION_in866 - 1) }; + +enum { IN866_LMIC_REGION_EIRP = 1 }; // region uses EIRP + +#endif /* _lorabase_in866_h_ */ \ No newline at end of file diff --git a/src/lmic/lorabase_us915.h b/src/lmic/lorabase_us915.h new file mode 100755 index 0000000..0a77184 --- /dev/null +++ b/src/lmic/lorabase_us915.h @@ -0,0 +1,84 @@ +/* +* Copyright (c) 2014-2016 IBM Corporation. +* All rights reserved. +* +* Copyright (c) 2017 MCCI Corporation +* All rights reserved. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef _lorabase_us915_h_ +#define _lorabase_us915_h_ + +#ifndef _LMIC_CONFIG_PRECONDITIONS_H_ +# include "lmic_config_preconditions.h" +#endif + +/****************************************************************************\ +| +| Basic definitions for US915 (always in scope) +| +\****************************************************************************/ + +// Frequency plan for US 915MHz ISM band +// data rates +enum _dr_us915_t { + US915_DR_SF10 = 0, + US915_DR_SF9, + US915_DR_SF8, + US915_DR_SF7, + US915_DR_SF8C, + US915_DR_NONE, + // Devices "behind a router" (and upper half of DR list): + US915_DR_SF12CR = 8, + US915_DR_SF11CR, + US915_DR_SF10CR, + US915_DR_SF9CR, + US915_DR_SF8CR, + US915_DR_SF7CR +}; + +// Default frequency plan for US 915MHz +enum { + US915_125kHz_UPFBASE = 902300000, + US915_125kHz_UPFSTEP = 200000, + US915_500kHz_UPFBASE = 903000000, + US915_500kHz_UPFSTEP = 1600000, + US915_500kHz_DNFBASE = 923300000, + US915_500kHz_DNFSTEP = 600000 +}; +enum { + US915_FREQ_MIN = 902000000, + US915_FREQ_MAX = 928000000 +}; +enum { + US915_TX_MAX_DBM = 30 // 30 dBm (but not EIRP): assumes we're + // on an 64-channel bandplan. See code + // that computes tx power. +}; +enum { DR_PAGE_US915 = 0x10 * (LMIC_REGION_us915 - 1) }; + +enum { US915_LMIC_REGION_EIRP = 0 }; // region doesn't use EIRP, uses tx power + +#endif /* _lorabase_us915_h_ */ \ No newline at end of file diff --git a/src/lmic/oslmic.c b/src/lmic/oslmic.c index 0fae191..8c4fca3 100755 --- a/src/lmic/oslmic.c +++ b/src/lmic/oslmic.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2014-2016 IBM Corporation. + * Copyright (c) 2016-2017 MCCI Corporation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,9 +26,11 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#define LMIC_DR_LEGACY 0 + #include "lmic.h" -#include "../hal/hal_esp32.h" -#include + +extern const struct lmic_pinmap lmic_pins; // RUNTIME STATE static struct { @@ -35,18 +38,27 @@ static struct { osjob_t* runnablejobs; } OS; -void os_init () { +int os_init_ex (const void *pintable) { memset(&OS, 0x00, sizeof(OS)); - hal_init(); - radio_init(); + hal_init_ex(pintable); + if (! radio_init()) + return 0; LMIC_init(); + return 1; +} + +void os_init() { + if (os_init_ex((const void *)&lmic_pins)) + return; + ASSERT(0); } ostime_t os_getTime () { return hal_ticks(); } -static u1_t unlinkjob (osjob_t** pnext, osjob_t* job) { +// unlink job from queue, return if removed +static int unlinkjob (osjob_t** pnext, osjob_t* job) { for( ; *pnext; pnext = &((*pnext)->next)) { if(*pnext == job) { // unlink *pnext = job->next; @@ -59,14 +71,9 @@ static u1_t unlinkjob (osjob_t** pnext, osjob_t* job) { // clear scheduled job void os_clearCallback (osjob_t* job) { hal_disableIRQs(); - u1_t res = unlinkjob(&OS.scheduledjobs, job); - if (res) - unlinkjob(&OS.runnablejobs, job); + // ttn-esp32 change: suppress error 'value computed is not used' + int __attribute__((unused)) res = unlinkjob(&OS.scheduledjobs, job) || unlinkjob(&OS.runnablejobs, job); hal_enableIRQs(); - #if LMIC_DEBUG_LEVEL > 1 - if (res) - lmic_printf("%lu: Cleared job %p\n", os_getTime(), job); - #endif } // schedule immediately runnable job @@ -74,7 +81,7 @@ void os_setCallback (osjob_t* job, osjobcb_t cb) { osjob_t** pnext; hal_disableIRQs(); // remove if job was already queued - os_clearCallback(job); + unlinkjob(&OS.runnablejobs, job); // fill-in job job->func = cb; job->next = NULL; @@ -82,9 +89,6 @@ void os_setCallback (osjob_t* job, osjobcb_t cb) { for(pnext=&OS.runnablejobs; *pnext; pnext=&((*pnext)->next)); *pnext = job; hal_enableIRQs(); - #if LMIC_DEBUG_LEVEL > 1 - lmic_printf("%lu: Scheduled job %p, cb %p ASAP\n", os_getTime(), job, cb); - #endif } // schedule timed job @@ -92,7 +96,7 @@ void os_setTimedCallback (osjob_t* job, ostime_t time, osjobcb_t cb) { osjob_t** pnext; hal_disableIRQs(); // remove if job was already queued - os_clearCallback(job); + unlinkjob(&OS.scheduledjobs, job); // fill-in job job->deadline = time; job->func = cb; @@ -107,9 +111,6 @@ void os_setTimedCallback (osjob_t* job, ostime_t time, osjobcb_t cb) { } *pnext = job; hal_enableIRQs(); - #if LMIC_DEBUG_LEVEL > 1 - lmic_printf("%lu: Scheduled job %p, cb %p at %lu\n", os_getTime(), job, cb, time); - #endif } // execute jobs from timer and from run queue @@ -120,12 +121,8 @@ void os_runloop () { } void os_runloop_once() { - #if LMIC_DEBUG_LEVEL > 1 - bool has_deadline = false; - #endif - osjob_t* j = NULL; - hal_enterCriticalSection(); + hal_disableIRQs(); // check for runnable jobs if(OS.runnablejobs) { j = OS.runnablejobs; @@ -133,18 +130,11 @@ void os_runloop_once() { } else if(OS.scheduledjobs && hal_checkTimer(OS.scheduledjobs->deadline)) { // check for expired timed jobs j = OS.scheduledjobs; OS.scheduledjobs = j->next; - #if LMIC_DEBUG_LEVEL > 1 - has_deadline = true; - #endif - } - if(j) { // run job callback - #if LMIC_DEBUG_LEVEL > 1 - lmic_printf("%lu: Running job %p, cb %p, deadline %lu\n", os_getTime(), j, j->func, has_deadline ? j->deadline : 0); - #endif - j->func(j); - hal_leaveCriticalSection(); } else { // nothing pending - hal_leaveCriticalSection(); hal_sleep(); // wake by irq (timer already restarted) } + hal_enableIRQs(); + if(j) { // run job callback + j->func(j); + } } diff --git a/src/lmic/oslmic.h b/src/lmic/oslmic.h index ee150b6..3363e1e 100755 --- a/src/lmic/oslmic.h +++ b/src/lmic/oslmic.h @@ -35,10 +35,9 @@ #include "config.h" #include -#include #ifdef __cplusplus -extern "C" { +extern "C"{ #endif //================================================================================ @@ -49,8 +48,8 @@ typedef uint8_t u1_t; typedef int8_t s1_t; typedef uint16_t u2_t; typedef int16_t s2_t; -typedef unsigned long u4_t; -typedef long s4_t; +typedef uint32_t u4_t; +typedef int32_t s4_t; typedef unsigned int uint; typedef const char* str_t; @@ -74,6 +73,8 @@ typedef struct rxsched_t rxsched_t; typedef struct bcninfo_t bcninfo_t; typedef const u1_t* xref2cu1_t; typedef u1_t* xref2u1_t; +typedef s4_t ostime_t; + #define TYPEDEF_xref2rps_t typedef rps_t* xref2rps_t #define TYPEDEF_xref2rxsched_t typedef rxsched_t* xref2rxsched_t #define TYPEDEF_xref2chnldef_t typedef chnldef_t* xref2chnldef_t @@ -85,9 +86,6 @@ typedef u1_t* xref2u1_t; #define ON_LMIC_EVENT(ev) onEvent(ev) #define DECL_ON_LMIC_EVENT void onEvent(ev_t e) -typedef s4_t ostime_t; - - extern u4_t AESAUX[]; extern u4_t AESKEY[]; #define AESkey ((u1_t*)AESKEY) @@ -100,11 +98,24 @@ u1_t radio_rand1 (void); #define DEFINE_LMIC struct lmic_t LMIC #define DECLARE_LMIC extern struct lmic_t LMIC -void radio_init (void); -void radio_irq_handler (u1_t dio, ostime_t t); +typedef struct oslmic_radio_rssi_s oslmic_radio_rssi_t; + +struct oslmic_radio_rssi_s { + s2_t min_rssi; + s2_t max_rssi; + s2_t mean_rssi; + u2_t n_rssi; +}; + +int radio_init (void); +// ttn-esp32 extension: time parameter for radio_irq_handler +void radio_irq_handler (u1_t dio, ostime_t now); void os_init (void); +int os_init_ex (const void *pPinMap); void os_runloop (void); -void os_runloop_once(); +void os_runloop_once (void); +u1_t radio_rssi (void); +void radio_monitor_rssi(ostime_t n, oslmic_radio_rssi_t *pRssi); //================================================================================ @@ -209,19 +220,82 @@ void os_wlsbf2 (xref2u1_t buf, u2_t value); #define os_getRndU2() ((u2_t)((os_getRndU1()<<8)|os_getRndU1())) #endif #ifndef os_crc16 -u2_t os_crc16 (xref2u1_t d, uint len); +u2_t os_crc16 (xref2cu1_t d, uint len); #endif #endif // !HAS_os_calls -#define lmic_printf printf +// ====================================================================== +// Table support +// These macros for defining a table of constants and retrieving values +// from it makes it easier for other platforms (like AVR) to optimize +// table accesses. +// Use CONST_TABLE() whenever declaring or defining a table, and +// TABLE_GET_xx whenever accessing its values. The actual name of the +// declared variable will be modified to prevent accidental direct +// access. The accessor macros forward to an inline function to allow +// proper type checking of the array element type. + +// Helper to add a prefix to the table name +#define RESOLVE_TABLE(table) constant_table_ ## table + +// get number of entries in table +#define LENOF_TABLE(table) (sizeof(RESOLVE_TABLE(table)) / sizeof(RESOLVE_TABLE(table)[0])) + +// Accessors for table elements +#define TABLE_GET_U1(table, index) table_get_u1(RESOLVE_TABLE(table), index) +#define TABLE_GET_S1(table, index) table_get_s1(RESOLVE_TABLE(table), index) +#define TABLE_GET_U2(table, index) table_get_u2(RESOLVE_TABLE(table), index) +#define TABLE_GET_S2(table, index) table_get_s2(RESOLVE_TABLE(table), index) +#define TABLE_GET_U4(table, index) table_get_u4(RESOLVE_TABLE(table), index) +#define TABLE_GET_S4(table, index) table_get_s4(RESOLVE_TABLE(table), index) +#define TABLE_GET_OSTIME(table, index) table_get_ostime(RESOLVE_TABLE(table), index) +#define TABLE_GET_U1_TWODIM(table, index1, index2) table_get_u1(RESOLVE_TABLE(table)[index1], index2) + +#if defined(__AVR__) + #include + // Macro to define the getter functions. This loads data from + // progmem using pgm_read_xx, or accesses memory directly when the + // index is a constant so gcc can optimize it away; + #define TABLE_GETTER(postfix, type, pgm_type) \ + inline type table_get ## postfix(const type *table, size_t index) { \ + if (__builtin_constant_p(table[index])) \ + return table[index]; \ + return pgm_read_ ## pgm_type(&table[index]); \ + } + + TABLE_GETTER(_u1, u1_t, byte); + TABLE_GETTER(_s1, s1_t, byte); + TABLE_GETTER(_u2, u2_t, word); + TABLE_GETTER(_s2, s2_t, word); + TABLE_GETTER(_u4, u4_t, dword); + TABLE_GETTER(_s4, s4_t, dword); + + // This assumes ostime_t is 4 bytes, so error out if it is not + typedef int check_sizeof_ostime_t[(sizeof(ostime_t) == 4) ? 0 : -1]; + TABLE_GETTER(_ostime, ostime_t, dword); + + // For AVR, store constants in PROGMEM, saving on RAM usage + #define CONST_TABLE(type, name) const type PROGMEM RESOLVE_TABLE(name) +#else + inline u1_t table_get_u1(const u1_t *table, size_t index) { return table[index]; } + inline s1_t table_get_s1(const s1_t *table, size_t index) { return table[index]; } + inline u2_t table_get_u2(const u2_t *table, size_t index) { return table[index]; } + inline s2_t table_get_s2(const s2_t *table, size_t index) { return table[index]; } + inline u4_t table_get_u4(const u4_t *table, size_t index) { return table[index]; } + inline s4_t table_get_s4(const s4_t *table, size_t index) { return table[index]; } + inline ostime_t table_get_ostime(const ostime_t *table, size_t index) { return table[index]; } + + // Declare a table + #define CONST_TABLE(type, name) const type RESOLVE_TABLE(name) +#endif // ====================================================================== -// AES support +// AES support // !!Keep in sync with lorabase.hpp!! #ifndef AES_ENC // if AES_ENC is defined as macro all other values must be too -#define AES_ENC 0x00 +#define AES_ENC 0x00 #define AES_DEC 0x01 #define AES_MIC 0x02 #define AES_CTR 0x04 diff --git a/src/lmic/radio.c b/src/lmic/radio.c index faac784..af00e1a 100755 --- a/src/lmic/radio.c +++ b/src/lmic/radio.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2014-2016 IBM Corporation. + * Copyright (c) 2016-2018 MCCI Corporation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,10 +26,11 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "rom/ets_sys.h" +#define LMIC_DR_LEGACY 0 + #include "lmic.h" -// ---------------------------------------- +// ---------------------------------------- // Registers Mapping #define RegFifo 0x00 // common #define RegOpMode 0x01 // common @@ -48,46 +50,46 @@ #define FSKRegRssiConfig 0x0E #define LORARegFifoTxBaseAddr 0x0E #define FSKRegRssiCollision 0x0F -#define LORARegFifoRxBaseAddr 0x0F +#define LORARegFifoRxBaseAddr 0x0F #define FSKRegRssiThresh 0x10 #define LORARegFifoRxCurrentAddr 0x10 #define FSKRegRssiValue 0x11 -#define LORARegIrqFlagsMask 0x11 +#define LORARegIrqFlagsMask 0x11 #define FSKRegRxBw 0x12 -#define LORARegIrqFlags 0x12 +#define LORARegIrqFlags 0x12 #define FSKRegAfcBw 0x13 -#define LORARegRxNbBytes 0x13 +#define LORARegRxNbBytes 0x13 #define FSKRegOokPeak 0x14 -#define LORARegRxHeaderCntValueMsb 0x14 +#define LORARegRxHeaderCntValueMsb 0x14 #define FSKRegOokFix 0x15 -#define LORARegRxHeaderCntValueLsb 0x15 +#define LORARegRxHeaderCntValueLsb 0x15 #define FSKRegOokAvg 0x16 -#define LORARegRxPacketCntValueMsb 0x16 -#define LORARegRxpacketCntValueLsb 0x17 -#define LORARegModemStat 0x18 -#define LORARegPktSnrValue 0x19 +#define LORARegRxPacketCntValueMsb 0x16 +#define LORARegRxpacketCntValueLsb 0x17 +#define LORARegModemStat 0x18 +#define LORARegPktSnrValue 0x19 #define FSKRegAfcFei 0x1A -#define LORARegPktRssiValue 0x1A +#define LORARegPktRssiValue 0x1A #define FSKRegAfcMsb 0x1B -#define LORARegRssiValue 0x1B +#define LORARegRssiValue 0x1B #define FSKRegAfcLsb 0x1C -#define LORARegHopChannel 0x1C +#define LORARegHopChannel 0x1C #define FSKRegFeiMsb 0x1D -#define LORARegModemConfig1 0x1D +#define LORARegModemConfig1 0x1D #define FSKRegFeiLsb 0x1E -#define LORARegModemConfig2 0x1E +#define LORARegModemConfig2 0x1E #define FSKRegPreambleDetect 0x1F -#define LORARegSymbTimeoutLsb 0x1F +#define LORARegSymbTimeoutLsb 0x1F #define FSKRegRxTimeout1 0x20 -#define LORARegPreambleMsb 0x20 +#define LORARegPreambleMsb 0x20 #define FSKRegRxTimeout2 0x21 -#define LORARegPreambleLsb 0x21 +#define LORARegPreambleLsb 0x21 #define FSKRegRxTimeout3 0x22 -#define LORARegPayloadLength 0x22 +#define LORARegPayloadLength 0x22 #define FSKRegRxDelay 0x23 -#define LORARegPayloadMaxLength 0x23 +#define LORARegPayloadMaxLength 0x23 #define FSKRegOsc 0x24 -#define LORARegHopPeriod 0x24 +#define LORARegHopPeriod 0x24 #define FSKRegPreambleMsb 0x25 #define LORARegFifoRxByteAddr 0x25 #define LORARegModemConfig3 0x26 @@ -133,8 +135,8 @@ // #define RegAgcThresh2 0x45 // common // #define RegAgcThresh3 0x46 // common // #define RegPllHop 0x4B // common +#define RegPaDac 0x4D // common // #define RegTcxo 0x58 // common -#define RegPaDac 0x5A // common // #define RegPll 0x5C // common // #define RegPllLowPn 0x5E // common // #define RegFormerTemp 0x6C // common @@ -175,12 +177,12 @@ #define SX1276_MC1_CR_4_7 0x06 #define SX1276_MC1_CR_4_8 0x08 -#define SX1276_MC1_IMPLICIT_HEADER_MODE_ON 0x01 - -// sx1276 RegModemConfig2 +#define SX1276_MC1_IMPLICIT_HEADER_MODE_ON 0x01 + +// sx1276 RegModemConfig2 #define SX1276_MC2_RX_PAYLOAD_CRCON 0x04 -// sx1276 RegModemConfig3 +// sx1276 RegModemConfig3 #define SX1276_MC3_LOW_DATA_RATE_OPTIMIZE 0x08 #define SX1276_MC3_AGCAUTO 0x04 @@ -194,9 +196,19 @@ #define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2 0x74 #endif +//----------------------------------------- +// Parameters for RSSI monitoring +#define SX127X_FREQ_LF_MAX 525000000 // per datasheet 6.3 + +// per datasheet 5.5.3: +#define SX127X_RSSI_ADJUST_LF -164 // add to rssi value to get dB (LF) +#define SX127X_RSSI_ADJUST_HF -157 // add to rssi value to get dB (HF) +// per datasheet 2.5.2 (but note that we ought to ask Semtech to confirm, because +// datasheet is unclear). +#define SX127X_RX_POWER_UP us2osticks(500) // delay this long to let the receiver power up. -// ---------------------------------------- +// ---------------------------------------- // Constants for radio registers #define OPMODE_LORA 0x80 #define OPMODE_MASK 0x07 @@ -206,8 +218,8 @@ #define OPMODE_TX 0x03 #define OPMODE_FSRX 0x04 #define OPMODE_RX 0x05 -#define OPMODE_RX_SINGLE 0x06 -#define OPMODE_CAD 0x07 +#define OPMODE_RX_SINGLE 0x06 +#define OPMODE_CAD 0x07 // ---------------------------------------- // Bits masking the corresponding IRQs from the radio @@ -278,6 +290,7 @@ static u1_t randbuf[16]; static void writeReg (u1_t addr, u1_t data ) { + // ttn-esp32 change: higher level SPI interface hal_spi_write(addr | 0x80, &data, 1); /* hal_pin_nss(0); @@ -288,6 +301,7 @@ static void writeReg (u1_t addr, u1_t data ) { } static u1_t readReg (u1_t addr) { + // ttn-esp32 change: higher level SPI interface u1_t buf[1]; hal_spi_read(addr & 0x7f, buf, 1); return buf[0]; @@ -301,6 +315,7 @@ static u1_t readReg (u1_t addr) { } static void writeBuf (u1_t addr, xref2u1_t buf, u1_t len) { + // ttn-esp32 change: higher level SPI interface hal_spi_write(addr | 0x80, buf, len); /* hal_pin_nss(0); @@ -313,6 +328,7 @@ static void writeBuf (u1_t addr, xref2u1_t buf, u1_t len) { } static void readBuf (u1_t addr, xref2u1_t buf, u1_t len) { + // ttn-esp32 change: higher level SPI interface hal_spi_read(addr & 0x7f, buf, len); /* hal_pin_nss(0); @@ -379,7 +395,7 @@ static void configLoraModem () { mc2 |= SX1276_MC2_RX_PAYLOAD_CRCON; } writeReg(LORARegModemConfig2, mc2); - + mc3 = SX1276_MC3_AGCAUTO; if ((sf == SF11 || sf == SF12) && getBw(LMIC.rps) == BW125) { mc3 |= SX1276_MC3_LOW_DATA_RATE_OPTIMIZE; @@ -394,24 +410,31 @@ static void configLoraModem () { case CR_4_7: mc1 |= SX1272_MC1_CR_4_7; break; case CR_4_8: mc1 |= SX1272_MC1_CR_4_8; break; } - + if ((sf == SF11 || sf == SF12) && getBw(LMIC.rps) == BW125) { mc1 |= SX1272_MC1_LOW_DATA_RATE_OPTIMIZE; } - + if (getNocrc(LMIC.rps) == 0) { mc1 |= SX1272_MC1_RX_PAYLOAD_CRCON; } - + if (getIh(LMIC.rps)) { mc1 |= SX1272_MC1_IMPLICIT_HEADER_MODE_ON; writeReg(LORARegPayloadLength, getIh(LMIC.rps)); // required length } // set ModemConfig1 writeReg(LORARegModemConfig1, mc1); - + // set ModemConfig2 (sf, AgcAutoOn=1 SymbTimeoutHi=00) writeReg(LORARegModemConfig2, (SX1272_MC2_SF7 + ((sf-1)<<4)) | 0x04); + +#if CFG_TxContinuousMode + // Only for testing + // set ModemConfig2 (sf, TxContinuousMode=1, AgcAutoOn=1 SymbTimeoutHi=00) + writeReg(LORARegModemConfig2, (SX1272_MC2_SF7 + ((sf-1)<<4)) | 0x06); +#endif + #else #error Missing CFG_sx1272_radio/CFG_sx1276_radio #endif /* CFG_sx1272_radio */ @@ -429,15 +452,19 @@ static void configChannel () { static void configPower () { #ifdef CFG_sx1276_radio - // no boost used for now + // PA_BOOST output is assumed but not 20 dBm. s1_t pw = (s1_t)LMIC.txpow; - if(pw >= 17) { - pw = 15; + if(pw > 17) { + pw = 17; } else if(pw < 2) { pw = 2; } - // check board type for BOOST pin - writeReg(RegPaConfig, (u1_t)(0x80|(pw&0xf))); + // 0x80 forces use of PA_BOOST; but we don't + // turn on 20 dBm mode. So powers are: + // 0000 => 2dBm, 0001 => 3dBm, ... 1111 => 17dBm + // But we also enforce that the high-power mode + // is off by writing RegPaDac. + writeReg(RegPaConfig, (u1_t)(0x80|(pw - 2))); writeReg(RegPaDac, readReg(RegPaDac)|0x4); #elif CFG_sx1272_radio @@ -483,7 +510,7 @@ static void txfsk () { // set the IRQ mapping DIO0=PacketSent DIO1=NOP DIO2=NOP writeReg(RegDioMapping1, MAP_DIO0_FSK_READY|MAP_DIO1_FSK_NOP|MAP_DIO2_FSK_TXNOP); - // initialize the payload size and address pointers + // initialize the payload size and address pointers writeReg(FSKRegPayloadLength, LMIC.dataLen+1); // (insert length byte into payload)) // download length byte and buffer to the radio FIFO @@ -492,7 +519,7 @@ static void txfsk () { // enable antenna switch for TX hal_pin_rxtx(1); - + // now we actually start the transmission opmode(OPMODE_TX); } @@ -501,16 +528,7 @@ static void txlora () { // select LoRa modem (from sleep mode) //writeReg(RegOpMode, OPMODE_LORA); opmodeLora(); - // can take a moment to change; so try ten times - u1_t reg; - for (int i = 0; i < 10; i++) - { - reg = readReg(RegOpMode); - if ((reg & OPMODE_LORA) != 0) - break; - ets_delay_us(100); - } - ASSERT((reg & OPMODE_LORA) != 0); + ASSERT((readReg(RegOpMode) & OPMODE_LORA) != 0); // enter standby mode (required for FIFO loading)) opmode(OPMODE_STANDBY); @@ -523,7 +541,7 @@ static void txlora () { configPower(); // set sync word writeReg(LORARegSyncWord, LORA_MAC_PREAMBLE); - + // set the IRQ mapping DIO0=TxDone DIO1=NOP DIO2=NOP writeReg(RegDioMapping1, MAP_DIO0_LORA_TXDONE|MAP_DIO1_LORA_NOP|MAP_DIO2_LORA_NOP); // clear all radio IRQ flags @@ -531,17 +549,17 @@ static void txlora () { // mask all IRQs but TxDone writeReg(LORARegIrqFlagsMask, ~IRQ_LORA_TXDONE_MASK); - // initialize the payload size and address pointers + // initialize the payload size and address pointers writeReg(LORARegFifoTxBaseAddr, 0x00); writeReg(LORARegFifoAddrPtr, 0x00); writeReg(LORARegPayloadLength, LMIC.dataLen); - + // download buffer to the radio FIFO writeBuf(RegFifo, LMIC.frame, LMIC.dataLen); // enable antenna switch for TX hal_pin_rxtx(1); - + // now we actually start the transmission opmode(OPMODE_TX); @@ -549,8 +567,9 @@ static void txlora () { u1_t sf = getSf(LMIC.rps) + 6; // 1 == SF7 u1_t bw = getBw(LMIC.rps); u1_t cr = getCr(LMIC.rps); - lmic_printf("%lu: TXMODE, freq=%lu, len=%d, SF=%d, BW=%d, CR=4/%d, IH=%d\n", - os_getTime(), LMIC.freq, LMIC.dataLen, sf, +// ttn-esp32 change: fix printf for for ostime_t and freq + LMIC_DEBUG_PRINTF("%u: TXMODE, freq=%u, len=%d, SF=%d, BW=%d, CR=4/%d, IH=%d\n", + (unsigned)os_getTime(), LMIC.freq, LMIC.dataLen, sf, bw == BW125 ? 125 : (bw == BW250 ? 250 : 500), cr == CR_4_5 ? 5 : (cr == CR_4_6 ? 6 : (cr == CR_4_7 ? 7 : 8)), getIh(LMIC.rps) @@ -560,7 +579,33 @@ static void txlora () { // start transmitter (buf=LMIC.frame, len=LMIC.dataLen) static void starttx () { - ASSERT( (readReg(RegOpMode) & OPMODE_MASK) == OPMODE_SLEEP ); + u1_t const rOpMode = readReg(RegOpMode); + + // originally, this code ASSERT()ed, but asserts are both bad and + // blunt instruments. If we see that we're not in sleep mode, + // force sleep (because we might have to switch modes) + if ((rOpMode & OPMODE_MASK) != OPMODE_SLEEP) { +#if LMIC_DEBUG_LEVEL > 0 + LMIC_DEBUG_PRINTF("?%s: OPMODE != OPMODE_SLEEP: %#02x\n", __func__, rOpMode); +#endif + opmode(OPMODE_SLEEP); + hal_waitUntil(os_getTime() + ms2osticks(1)); + } + + if (LMIC.lbt_ticks > 0) { + oslmic_radio_rssi_t rssi; + radio_monitor_rssi(LMIC.lbt_ticks, &rssi); +#if LMIC_X_DEBUG_LEVEL > 0 + LMIC_X_DEBUG_PRINTF("LBT rssi max:min=%d:%d %d times in %d\n", rssi.max_rssi, rssi.min_rssi, rssi.n_rssi, LMIC.lbt_ticks); +#endif + + if (rssi.max_rssi >= LMIC.lbt_dbmax) { + // complete the request by scheduling the job + os_setCallback(&LMIC.osjob, LMIC.osjob.func); + return; + } + } + if(getSf(LMIC.rps) == FSK) { // FSK modem txfsk(); } else { // LoRa modem @@ -572,7 +617,7 @@ static void starttx () { enum { RXMODE_SINGLE, RXMODE_SCAN, RXMODE_RSSI }; -static const u1_t rxlorairqmask[] = { +static CONST_TABLE(u1_t, rxlorairqmask)[] = { [RXMODE_SINGLE] = IRQ_LORA_RXDONE_MASK|IRQ_LORA_RXTOUT_MASK, [RXMODE_SCAN] = IRQ_LORA_RXDONE_MASK, [RXMODE_RSSI] = 0x00, @@ -596,7 +641,7 @@ static void rxlora (u1_t rxmode) { configChannel(); } // set LNA gain - writeReg(RegLna, LNA_RX_GAIN); + writeReg(RegLna, LNA_RX_GAIN); // set max payload size writeReg(LORARegPayloadMaxLength, 64); #if !defined(DISABLE_INVERT_IQ_ON_RX) @@ -613,13 +658,13 @@ static void rxlora (u1_t rxmode) { writeReg(LORARegSymbTimeoutLsb, LMIC.rxsyms); // set sync word writeReg(LORARegSyncWord, LORA_MAC_PREAMBLE); - + // configure DIO mapping DIO0=RxDone DIO1=RxTout DIO2=NOP writeReg(RegDioMapping1, MAP_DIO0_LORA_RXDONE|MAP_DIO1_LORA_RXTOUT|MAP_DIO2_LORA_NOP); // clear all radio IRQ flags writeReg(LORARegIrqFlags, 0xFF); // enable required radio IRQs - writeReg(LORARegIrqFlagsMask, ~rxlorairqmask[rxmode]); + writeReg(LORARegIrqFlagsMask, ~TABLE_GET_U1(rxlorairqmask, rxmode)); // enable antenna switch for RX hal_pin_rxtx(0); @@ -628,19 +673,25 @@ static void rxlora (u1_t rxmode) { if (rxmode == RXMODE_SINGLE) { // single rx hal_waitUntil(LMIC.rxtime); // busy wait until exact rx time opmode(OPMODE_RX_SINGLE); +#if LMIC_DEBUG_LEVEL > 0 + ostime_t now = os_getTime(); +// ttn-esp32 change: fix printf for for ostime_t + LMIC_DEBUG_PRINTF("start single rx: now-rxtime: %u\n", (unsigned)(now - LMIC.rxtime)); +#endif } else { // continous rx (scan or rssi) - opmode(OPMODE_RX); + opmode(OPMODE_RX); } #if LMIC_DEBUG_LEVEL > 0 if (rxmode == RXMODE_RSSI) { - lmic_printf("RXMODE_RSSI\n"); + LMIC_DEBUG_PRINTF("RXMODE_RSSI\n"); } else { u1_t sf = getSf(LMIC.rps) + 6; // 1 == SF7 u1_t bw = getBw(LMIC.rps); u1_t cr = getCr(LMIC.rps); - lmic_printf("%lu: %s, freq=%lu, SF=%d, BW=%d, CR=4/%d, IH=%d\n", - os_getTime(), +// ttn-esp32 change: fix printf for for ostime_t and freq + LMIC_DEBUG_PRINTF("%u: %s, freq=%u, SF=%d, BW=%d, CR=4/%d, IH=%d\n", + (unsigned)os_getTime(), rxmode == RXMODE_SINGLE ? "RXMODE_SINGLE" : (rxmode == RXMODE_SCAN ? "RXMODE_SCAN" : "UNKNOWN_RX"), LMIC.freq, sf, bw == BW125 ? 125 : (bw == BW250 ? 250 : 500), @@ -690,13 +741,13 @@ static void rxfsk (u1_t rxmode) { // set frequency deviation writeReg(FSKRegFdevMsb, 0x01); // +/- 25kHz writeReg(FSKRegFdevLsb, 0x99); - + // configure DIO mapping DIO0=PayloadReady DIO1=NOP DIO2=TimeOut writeReg(RegDioMapping1, MAP_DIO0_FSK_READY|MAP_DIO1_FSK_NOP|MAP_DIO2_FSK_TIMEOUT); // enable antenna switch for RX hal_pin_rxtx(0); - + // now instruct the radio to receive hal_waitUntil(LMIC.rxtime); // busy wait until exact rx time opmode(OPMODE_RX); // no single rx mode available in FSK @@ -714,7 +765,7 @@ static void startrx (u1_t rxmode) { } // get random seed from wideband noise rssi -void radio_init () { +int radio_init () { hal_disableIRQs(); // manually reset radio @@ -732,9 +783,11 @@ void radio_init () { // some sanity checks, e.g., read version number u1_t v = readReg(RegVersion); #ifdef CFG_sx1276_radio - ASSERT(v == 0x12 ); + if(v != 0x12 ) + return 0; #elif CFG_sx1272_radio - ASSERT(v == 0x22); + if(v != 0x22) + return 0; #else #error Missing CFG_sx1272_radio/CFG_sx1276_radio #endif @@ -749,11 +802,11 @@ void radio_init () { } } randbuf[0] = 16; // set initial index - + #ifdef CFG_sx1276mb1_board // chain calibration writeReg(RegPaConfig, 0); - + // Launch Rx chain calibration for LF band writeReg(FSKRegImageCal, (readReg(FSKRegImageCal) & RF_IMAGECAL_IMAGECAL_MASK)|RF_IMAGECAL_IMAGECAL_START); while((readReg(FSKRegImageCal)&RF_IMAGECAL_IMAGECAL_RUNNING) == RF_IMAGECAL_IMAGECAL_RUNNING){ ; } @@ -764,7 +817,7 @@ void radio_init () { writeReg(RegFrfMid, (u1_t)(frf>> 8)); writeReg(RegFrfLsb, (u1_t)(frf>> 0)); - // Launch Rx chain calibration for HF band + // Launch Rx chain calibration for HF band writeReg(FSKRegImageCal, (readReg(FSKRegImageCal) & RF_IMAGECAL_IMAGECAL_MASK)|RF_IMAGECAL_IMAGECAL_START); while((readReg(FSKRegImageCal) & RF_IMAGECAL_IMAGECAL_RUNNING) == RF_IMAGECAL_IMAGECAL_RUNNING) { ; } #endif /* CFG_sx1276mb1_board */ @@ -772,6 +825,7 @@ void radio_init () { opmode(OPMODE_SLEEP); hal_enableIRQs(); + return 1; } // return next random byte derived from seed buffer @@ -795,7 +849,83 @@ u1_t radio_rssi () { return r; } -static const u2_t LORA_RXDONE_FIXUP[] = { +// monitor rssi for specified number of ostime_t ticks, and return statistics +// This puts the radio into RX continuous mode, waits long enough for the +// oscillators to start and the PLL to lock, and then measures for the specified +// period of time. The radio is then returned to idle. +// +// RSSI returned is expressed in units of dB, and is offset according to the +// current radio setting per section 5.5.5 of Semtech 1276 datasheet. +void radio_monitor_rssi(ostime_t nTicks, oslmic_radio_rssi_t *pRssi) { + uint8_t rssiMax, rssiMin; + uint16_t rssiSum; + uint16_t rssiN; + + int rssiAdjust; + ostime_t tBegin; + int notDone; + + rxlora(RXMODE_SCAN); + + // while we're waiting for the PLLs to spin up, determine which + // band we're in and choose the base RSSI. + if (LMIC.freq > SX127X_FREQ_LF_MAX) { + rssiAdjust = SX127X_RSSI_ADJUST_HF; + } else { + rssiAdjust = SX127X_RSSI_ADJUST_LF; + } + rssiAdjust += hal_getRssiCal(); + + // zero the results + rssiMax = 255; + rssiMin = 0; + rssiSum = 0; + rssiN = 0; + + // wait for PLLs + hal_waitUntil(os_getTime() + SX127X_RX_POWER_UP); + + // scan for the desired time. + tBegin = os_getTime(); + rssiMax = 0; + + /* XXX(tanupoo) + * In this loop, micros() in os_getTime() returns a past time sometimes. + * At least, it happens on Dragino LoRa Mini. + * the return value of micros() looks not to be stable in IRQ disabled. + * Once it happens, this loop never exit infinitely. + * In order to prevent it, it enables IRQ before calling os_getTime(), + * disable IRQ again after that. + */ + do { + ostime_t now; + + u1_t rssiNow = readReg(LORARegRssiValue); + + if (rssiMax < rssiNow) + rssiMax = rssiNow; + if (rssiNow < rssiMin) + rssiMin = rssiNow; + rssiSum += rssiNow; + ++rssiN; + // TODO(tmm@mcci.com) move this to os_getTime(). + hal_enableIRQs(); + now = os_getTime(); + hal_disableIRQs(); + notDone = now - (tBegin + nTicks) < 0; + } while (notDone); + + // put radio back to sleep + opmode(OPMODE_SLEEP); + + // compute the results + pRssi->max_rssi = (s2_t) (rssiMax + rssiAdjust); + pRssi->min_rssi = (s2_t) (rssiMin + rssiAdjust); + pRssi->mean_rssi = (s2_t) (rssiAdjust + ((rssiSum + (rssiN >> 1)) / rssiN)); + pRssi->n_rssi = rssiN; +} + +static CONST_TABLE(u2_t, LORA_RXDONE_FIXUP)[] = { [FSK] = us2osticks(0), // ( 0 ticks) [SF7] = us2osticks(0), // ( 0 ticks) [SF8] = us2osticks(1648), // ( 54 ticks) @@ -807,34 +937,55 @@ static const u2_t LORA_RXDONE_FIXUP[] = { // called by hal ext IRQ handler // (radio goes to stanby mode after tx/rx operations) -void radio_irq_handler (u1_t dio, ostime_t t) { +// ttn-esp32 change: additional time paramter +void radio_irq_handler (u1_t dio, ostime_t now) { +#if CFG_TxContinuousMode + // clear radio IRQ flags + writeReg(LORARegIrqFlags, 0xFF); + u1_t p = readReg(LORARegFifoAddrPtr); + writeReg(LORARegFifoAddrPtr, 0x00); + u1_t s = readReg(RegOpMode); + u1_t c = readReg(LORARegModemConfig2); + opmode(OPMODE_TX); + return; +#else /* ! CFG_TxContinuousMode */ +// ttn-esp32 change: use provided time parameter +// ostime_t now = os_getTime(); +#if LMIC_DEBUG_LEVEL > 0 + ostime_t const entry = now; +#endif if( (readReg(RegOpMode) & OPMODE_LORA) != 0) { // LORA modem u1_t flags = readReg(LORARegIrqFlags); -#if LMIC_DEBUG_LEVEL > 1 - lmic_printf("%lu: irq: dio: 0x%x flags: 0x%x\n", t, dio, flags); -#endif + LMIC_X_DEBUG_PRINTF("IRQ=%02x\n", flags); if( flags & IRQ_LORA_TXDONE_MASK ) { // save exact tx time - LMIC.txend = t - us2osticks(43); // TXDONE FIXUP + LMIC.txend = now - us2osticks(43); // TXDONE FIXUP } else if( flags & IRQ_LORA_RXDONE_MASK ) { // save exact rx time if(getBw(LMIC.rps) == BW125) { - t -= LORA_RXDONE_FIXUP[getSf(LMIC.rps)]; + now -= TABLE_GET_U2(LORA_RXDONE_FIXUP, getSf(LMIC.rps)); } - LMIC.rxtime = t; + LMIC.rxtime = now; // read the PDU and inform the MAC that we received something LMIC.dataLen = (readReg(LORARegModemConfig1) & SX1272_MC1_IMPLICIT_HEADER_MODE_ON) ? readReg(LORARegPayloadLength) : readReg(LORARegRxNbBytes); // set FIFO read address pointer - writeReg(LORARegFifoAddrPtr, readReg(LORARegFifoRxCurrentAddr)); + writeReg(LORARegFifoAddrPtr, readReg(LORARegFifoRxCurrentAddr)); // now read the FIFO readBuf(RegFifo, LMIC.frame, LMIC.dataLen); // read rx quality parameters LMIC.snr = readReg(LORARegPktSnrValue); // SNR [dB] * 4 - LMIC.rssi = readReg(LORARegPktRssiValue) - 125 + 64; // RSSI [dBm] (-196...+63) + LMIC.rssi = readReg(LORARegPktRssiValue); + LMIC_X_DEBUG_PRINTF("RX snr=%u rssi=%d\n", LMIC.snr/4, SX127X_RSSI_ADJUST_HF + LMIC.rssi); + LMIC.rssi = LMIC.rssi - 125 + 64; // RSSI [dBm] (-196...+63) } else if( flags & IRQ_LORA_RXTOUT_MASK ) { // indicate timeout LMIC.dataLen = 0; +#if LMIC_DEBUG_LEVEL > 0 + ostime_t now2 = os_getTime(); +// ttn-esp32 change: fix printf for for ostime_t + LMIC_DEBUG_PRINTF("rxtimeout: entry: %u rxtime: %u entry-rxtime: %d now-entry: %d rxtime-txend: %d\n", (unsigned)entry, (unsigned)LMIC.rxtime, entry - LMIC.rxtime, now2 - entry, LMIC.rxtime-LMIC.txend); +#endif } // mask all radio IRQs writeReg(LORARegIrqFlagsMask, 0xFF); @@ -845,10 +996,10 @@ void radio_irq_handler (u1_t dio, ostime_t t) { u1_t flags2 = readReg(FSKRegIrqFlags2); if( flags2 & IRQ_FSK2_PACKETSENT_MASK ) { // save exact tx time - LMIC.txend = t; + LMIC.txend = now; } else if( flags2 & IRQ_FSK2_PAYLOADREADY_MASK ) { // save exact rx time - LMIC.rxtime = t; + LMIC.rxtime = now; // read the PDU and inform the MAC that we received something LMIC.dataLen = readReg(FSKRegPayloadLength); // now read the FIFO @@ -867,6 +1018,7 @@ void radio_irq_handler (u1_t dio, ostime_t t) { opmode(OPMODE_SLEEP); // run os job (use preset func ptr) os_setCallback(&LMIC.osjob, LMIC.osjob.func); +#endif /* ! CFG_TxContinuousMode */ } void os_radio (u1_t mode) { @@ -881,7 +1033,7 @@ void os_radio (u1_t mode) { // transmit frame now starttx(); // buf=LMIC.frame, len=LMIC.dataLen break; - + case RADIO_RX: // receive frame now (exactly at rxtime) startrx(RXMODE_SINGLE); // buf=LMIC.frame, time=LMIC.rxtime, timeout=LMIC.rxsyms