mirror of
https://github.com/manuelbl/ttn-esp32.git
synced 2025-03-15 02:24:28 +01:00
Use mcci-catena/arduino-lmic as the base library
This commit is contained in:
parent
0f97ce4e0f
commit
1fe8bf692c
61
esp_idf_lmic_config.h
Executable file
61
esp_idf_lmic_config.h
Executable file
@ -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 <stdio.h>
|
||||
#endif
|
@ -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
|
||||
|
||||
|
@ -27,14 +27,16 @@
|
||||
|
||||
#include "../lmic/oslmic.h"
|
||||
|
||||
#if defined(USE_ORIGINAL_AES)
|
||||
|
||||
#define AES_MICSUB 0x30 // internal use only
|
||||
|
||||
static const u4_t AES_RCON[10] = {
|
||||
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] = {
|
||||
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,
|
||||
@ -53,7 +55,7 @@ static const u1_t AES_S[256] = {
|
||||
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16,
|
||||
};
|
||||
|
||||
static const u4_t AES_E1[256] = {
|
||||
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,
|
||||
@ -88,7 +90,7 @@ static const u4_t AES_E1[256] = {
|
||||
0x824141C3, 0x299999B0, 0x5A2D2D77, 0x1E0F0F11, 0x7BB0B0CB, 0xA85454FC, 0x6DBBBBD6, 0x2C16163A,
|
||||
};
|
||||
|
||||
static const u4_t AES_E2[256] = {
|
||||
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,
|
||||
@ -123,7 +125,7 @@ static const u4_t AES_E2[256] = {
|
||||
0xC3824141, 0xB0299999, 0x775A2D2D, 0x111E0F0F, 0xCB7BB0B0, 0xFCA85454, 0xD66DBBBB, 0x3A2C1616,
|
||||
};
|
||||
|
||||
static const u4_t AES_E3[256] = {
|
||||
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,
|
||||
@ -158,7 +160,7 @@ static const u4_t AES_E3[256] = {
|
||||
0x41C38241, 0x99B02999, 0x2D775A2D, 0x0F111E0F, 0xB0CB7BB0, 0x54FCA854, 0xBBD66DBB, 0x163A2C16,
|
||||
};
|
||||
|
||||
static const u4_t AES_E4[256] = {
|
||||
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,
|
||||
@ -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)];
|
||||
@ -233,11 +235,11 @@ static void aesroundkeys () {
|
||||
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];
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -383,3 +386,4 @@ u4_t os_aes (u1_t mode, xref2u1_t buf, u2_t len) {
|
||||
return AESAUX[0];
|
||||
}
|
||||
|
||||
#endif
|
@ -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();
|
||||
|
@ -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;
|
||||
|
210
src/lmic/config.h
Normal file → Executable file
210
src/lmic/config.h
Normal file → Executable file
@ -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
|
||||
// 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)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#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 */
|
||||
|
||||
#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_
|
||||
|
@ -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,9 +29,6 @@
|
||||
#ifndef _hal_hpp_
|
||||
#define _hal_hpp_
|
||||
|
||||
#include "oslmic.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
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,6 +74,14 @@ 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
|
||||
@ -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_
|
||||
|
1179
src/lmic/lmic.c
1179
src/lmic/lmic.c
File diff suppressed because it is too large
Load Diff
126
src/lmic/lmic.h
126
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"
|
||||
|
||||
#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
|
||||
|
||||
// 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
|
||||
// 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 };
|
||||
|
||||
#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,16 +262,17 @@ 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
|
||||
@ -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;
|
||||
@ -281,18 +373,13 @@ DECLARE_LMIC; //!< \internal
|
||||
|
||||
//! 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_enableChannel(u1_t channel);
|
||||
void LMIC_disableSubBand(u1_t band);
|
||||
void LMIC_selectSubBand(u1_t band);
|
||||
#endif
|
||||
|
||||
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!!!
|
||||
|
||||
|
364
src/lmic/lmic_as923.c
Executable file
364
src/lmic/lmic_as923.c
Executable file
@ -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 <organization> 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 <COPYRIGHT HOLDER> 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; fu<NUM_DEFAULT_CHANNELS; fu++) {
|
||||
LMIC.channelFreq[fu] = TABLE_GET_U4(iniChannelFreq, fu);
|
||||
LMIC.channelDrMap[fu] = DR_RANGE_MAP(AS923_DR_SF12, AS923_DR_SF7B);
|
||||
}
|
||||
|
||||
LMIC.bands[BAND_CENTI].txcap = AS923_TX_CAP;
|
||||
LMIC.bands[BAND_CENTI].txpow = AS923_TX_EIRP_MAX_DBM;
|
||||
LMIC.bands[BAND_CENTI].lastchnl = os_getRndU1() % MAX_CHANNELS;
|
||||
LMIC.bands[BAND_CENTI].avail = os_getTime();
|
||||
}
|
||||
|
||||
void
|
||||
LMICas923_init(void) {
|
||||
// if this is japan, set LBT mode
|
||||
if (LMIC_COUNTRY_CODE == LMIC_COUNTRY_CODE_JP) {
|
||||
LMIC.lbt_ticks = us2osticks(AS923JP_LBT_US);
|
||||
LMIC.lbt_dbmax = AS923JP_LBT_DB_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LMICas923_resetDefaultChannels(void) {
|
||||
// if this is japan, set LBT mode
|
||||
if (LMIC_COUNTRY_CODE == LMIC_COUNTRY_CODE_JP) {
|
||||
LMIC.lbt_ticks = us2osticks(AS923JP_LBT_US);
|
||||
LMIC.lbt_dbmax = AS923JP_LBT_DB_MAX;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bit_t LMIC_setupBand(u1_t bandidx, s1_t txpow, u2_t txcap) {
|
||||
if (bandidx != BAND_CENTI) 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 = (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; ci++) {
|
||||
if ((chnl = (chnl + 1)) >= 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
|
216
src/lmic/lmic_au921.c
Executable file
216
src/lmic/lmic_au921.c
Executable file
@ -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 <organization> 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 <COPYRIGHT HOLDER> 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
|
175
src/lmic/lmic_bandplan.h
Executable file
175
src/lmic/lmic_bandplan.h
Executable file
@ -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 <organization> 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 <COPYRIGHT HOLDER> 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_
|
115
src/lmic/lmic_bandplan_as923.h
Executable file
115
src/lmic/lmic_bandplan_as923.h
Executable file
@ -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 <organization> 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 <COPYRIGHT HOLDER> 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_
|
63
src/lmic/lmic_bandplan_au921.h
Executable file
63
src/lmic/lmic_bandplan_au921.h
Executable file
@ -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 <organization> 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 <COPYRIGHT HOLDER> 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_
|
92
src/lmic/lmic_bandplan_eu868.h
Executable file
92
src/lmic/lmic_bandplan_eu868.h
Executable file
@ -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 <organization> 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 <COPYRIGHT HOLDER> 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_
|
85
src/lmic/lmic_bandplan_in866.h
Executable file
85
src/lmic/lmic_bandplan_in866.h
Executable file
@ -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 <organization> 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 <COPYRIGHT HOLDER> 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_
|
62
src/lmic/lmic_bandplan_us915.h
Executable file
62
src/lmic/lmic_bandplan_us915.h
Executable file
@ -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 <organization> 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 <COPYRIGHT HOLDER> 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_
|
181
src/lmic/lmic_config_preconditions.h
Executable file
181
src/lmic/lmic_config_preconditions.h
Executable file
@ -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_ */
|
233
src/lmic/lmic_eu868.c
Executable file
233
src/lmic/lmic_eu868.c
Executable file
@ -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 <organization> 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 <COPYRIGHT HOLDER> 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<NUM_DEFAULT_CHANNELS; fu++, su++) {
|
||||
LMIC.channelFreq[fu] = TABLE_GET_U4(iniChannelFreq, su);
|
||||
// TODO(tmm@mcci.com): don't use EU DR directly, use something from the LMIC context or a static const
|
||||
LMIC.channelDrMap[fu] = DR_RANGE_MAP(EU868_DR_SF12, EU868_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];
|
||||
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; ci++) {
|
||||
if ((chnl = (chnl + 1)) >= 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
|
159
src/lmic/lmic_eu_like.c
Executable file
159
src/lmic/lmic_eu_like.c
Executable file
@ -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 <organization> 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 <COPYRIGHT HOLDER> 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; chnl<MAX_CHANNELS; chnl++) {
|
||||
if ((chmap & (1 << chnl)) != 0 && LMIC.channelFreq[chnl] == 0)
|
||||
chmap &= ~(1 << chnl); // ignore - channel is not defined
|
||||
}
|
||||
LMIC.channelMap = chmap;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if !defined(DISABLE_JOIN)
|
||||
void LMICeulike_initJoinLoop(uint8_t nDefaultChannels, s1_t adrTxPow) {
|
||||
#if CFG_TxContinuousMode
|
||||
LMIC.txChnl = 0
|
||||
#else
|
||||
LMIC.txChnl = os_getRndU1() % nDefaultChannels;
|
||||
#endif
|
||||
LMIC.adrTxPow = adrTxPow;
|
||||
// TODO(tmm@mcci.com) don't use EU directly, use a table. That
|
||||
// will allow support for EU-style bandplans with similar code.
|
||||
LMICcore_setDrJoin(DRCHG_SET, LMICbandplan_getInitialDrJoin());
|
||||
LMICbandplan_initDefaultChannels(/* put into join mode */ 1);
|
||||
ASSERT((LMIC.opmode & OP_NEXTCHNL) == 0);
|
||||
LMIC.txend = os_getTime() + LMICcore_rndDelay(8);
|
||||
}
|
||||
#endif // DISABLE_JOIN
|
||||
|
||||
void LMICeulike_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 = band->txpow;
|
||||
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
|
98
src/lmic/lmic_eu_like.h
Executable file
98
src/lmic/lmic_eu_like.h
Executable file
@ -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 <organization> 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 <COPYRIGHT HOLDER> 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_
|
205
src/lmic/lmic_in866.c
Executable file
205
src/lmic/lmic_in866.c
Executable file
@ -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 <organization> 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 <COPYRIGHT HOLDER> 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<NUM_DEFAULT_CHANNELS; fu++) {
|
||||
LMIC.channelFreq[fu] = TABLE_GET_U4(iniChannelFreq, fu);
|
||||
LMIC.channelDrMap[fu] = DR_RANGE_MAP(IN866_DR_SF12, IN866_DR_SF7);
|
||||
}
|
||||
|
||||
LMIC.bands[BAND_MILLI].txcap = 1; // no limit, in effect.
|
||||
LMIC.bands[BAND_MILLI].txpow = IN866_TX_EIRP_MAX_DBM;
|
||||
LMIC.bands[BAND_MILLI].lastchnl = os_getRndU1() % MAX_CHANNELS;
|
||||
LMIC.bands[BAND_MILLI].avail = os_getTime();
|
||||
}
|
||||
|
||||
bit_t LMIC_setupBand(u1_t bandidx, s1_t txpow, u2_t txcap) {
|
||||
if (bandidx > 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; ci++) {
|
||||
if ((chnl = (chnl + 1)) >= 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
|
209
src/lmic/lmic_us915.c
Executable file
209
src/lmic/lmic_us915.c
Executable file
@ -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 <organization> 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 <COPYRIGHT HOLDER> 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
|
257
src/lmic/lmic_us_like.c
Executable file
257
src/lmic/lmic_us_like.c
Executable file
@ -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 <organization> 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 <COPYRIGHT HOLDER> 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<end);
|
||||
ASSERT(count <= (end - start));
|
||||
// We used to pick a random channel once and then just increment. That is not per spec.
|
||||
// Now we use a new random number each time, because they are not very expensive.
|
||||
// Regarding the algo below, we cannot pick a number and scan until we hit an enabled channel.
|
||||
// That would result in the first enabled channel following a set of disabled ones
|
||||
// being used more frequently than the other enabled channels.
|
||||
|
||||
// Last used channel is in range. It is not a candidate, per spec.
|
||||
uint lastTxChan = LMIC.txChnl;
|
||||
if (start <= lastTxChan && lastTxChan<end &&
|
||||
// Adjust count only if still enabled. Otherwise, no chance of selection.
|
||||
ENABLED_CHANNEL(lastTxChan)) {
|
||||
--count;
|
||||
if (count == 0) {
|
||||
return; // Only one active channel, so keep using it.
|
||||
}
|
||||
}
|
||||
|
||||
uint nth = os_getRndU1() % count;
|
||||
for (u1_t chnl = start; chnl<end; chnl++) {
|
||||
// Scan for nth enabled channel that is not the last channel used
|
||||
if (chnl != lastTxChan && ENABLED_CHANNEL(chnl) && (nth--) == 0) {
|
||||
LMIC.txChnl = chnl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// No feasible channel found! Keep old one.
|
||||
}
|
||||
|
||||
|
||||
|
||||
bit_t LMIC_setupBand(u1_t bandidx, s1_t txpow, u2_t txcap) {
|
||||
// nothing; just succeed.
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void LMICuslike_initDefaultChannels(bit_t fJoin) {
|
||||
// things work the same for join as normal.
|
||||
for (u1_t i = 0; i<4; i++)
|
||||
LMIC.channelMap[i] = 0xFFFF;
|
||||
LMIC.channelMap[4] = 0x00FF;
|
||||
LMIC.activeChannels125khz = 64;
|
||||
LMIC.activeChannels500khz = 8;
|
||||
}
|
||||
|
||||
u1_t LMICuslike_mapChannels(u1_t chpage, u2_t chmap) {
|
||||
/*
|
||||
|| MCMD_LADR_CHP_125ON and MCMD_LADR_CHP_125OFF are special. The
|
||||
|| channel map appllies to 500kHz (ch 64..71) and in addition
|
||||
|| all channels 0..63 are turned off or on. MCMC_LADR_CHP_BANK
|
||||
|| is also special, in that it enables subbands.
|
||||
*/
|
||||
u1_t base, top;
|
||||
|
||||
if (chpage < MCMD_LADR_CHP_USLIKE_SPECIAL) {
|
||||
// operate on channels 0..15, 16..31, 32..47, 48..63
|
||||
base = chpage << 4;
|
||||
top = base + 16;
|
||||
if (base == 64) {
|
||||
if (chmap & 0xFF00) {
|
||||
// those are reserved bits, fail.
|
||||
return 0;
|
||||
}
|
||||
top = 72;
|
||||
}
|
||||
} else if (chpage == MCMD_LADR_CHP_BANK) {
|
||||
if (chmap & 0xFF00) {
|
||||
// those are resreved bits, fail.
|
||||
return 0;
|
||||
}
|
||||
// each bit enables a bank of channels
|
||||
for (u1_t subband = 0; subband < 8; ++subband, chmap >>= 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
|
100
src/lmic/lmic_us_like.h
Executable file
100
src/lmic/lmic_us_like.h
Executable file
@ -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 <organization> 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 <COPYRIGHT HOLDER> 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_
|
335
src/lmic/lmic_util.c
Executable file
335
src/lmic/lmic_util.c
Executable file
@ -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 <math.h>
|
||||
|
||||
/*
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
34
src/lmic/lmic_util.h
Executable file
34
src/lmic/lmic_util.h
Executable file
@ -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 <stdint.h>
|
||||
|
||||
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_ */
|
@ -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
|
||||
@ -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,41 +73,68 @@ 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 { CHNL_PING = 5 };
|
||||
enum { FREQ_PING = EU868_F6 }; // default ping freq
|
||||
enum { DR_PING = DR_SF9 }; // default ping DR
|
||||
enum { CHNL_DNW2 = 5 };
|
||||
enum { DR_PING = EU868_DR_SF9 }; // default ping DR
|
||||
//enum { CHNL_DNW2 = 5 };
|
||||
enum { FREQ_DNW2 = EU868_F6 };
|
||||
enum { DR_DNW2 = DR_SF12 };
|
||||
enum { DR_DNW2 = EU868_DR_SF12 };
|
||||
enum { CHNL_BCN = 5 };
|
||||
enum { FREQ_BCN = EU868_F6 };
|
||||
enum { DR_BCN = DR_SF9 };
|
||||
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
|
||||
@ -122,34 +148,44 @@ enum {
|
||||
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
|
||||
@ -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;
|
||||
|
||||
@ -377,15 +600,16 @@ inline rps_t makeRps (sf_t sf, bw_t bw, cr_t cr, int ih, int nocrc) {
|
||||
// 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
|
||||
|
96
src/lmic/lorabase_as923.h
Executable file
96
src/lmic/lorabase_as923.h
Executable file
@ -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 <organization> 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 <COPYRIGHT HOLDER> 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_ */
|
84
src/lmic/lorabase_au921.h
Executable file
84
src/lmic/lorabase_au921.h
Executable file
@ -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 <organization> 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 <COPYRIGHT HOLDER> 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_ */
|
92
src/lmic/lorabase_eu868.h
Executable file
92
src/lmic/lorabase_eu868.h
Executable file
@ -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 <organization> 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 <COPYRIGHT HOLDER> 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_ */
|
78
src/lmic/lorabase_in866.h
Executable file
78
src/lmic/lorabase_in866.h
Executable file
@ -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 <organization> 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 <COPYRIGHT HOLDER> 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_ */
|
84
src/lmic/lorabase_us915.h
Executable file
84
src/lmic/lorabase_us915.h
Executable file
@ -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 <organization> 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 <COPYRIGHT HOLDER> 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_ */
|
@ -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 <stdbool.h>
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,6 @@
|
||||
|
||||
#include "config.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
@ -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,12 +220,75 @@ 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 <avr/pgmspace.h>
|
||||
// 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
|
||||
|
230
src/lmic/radio.c
230
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,7 +26,8 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "rom/ets_sys.h"
|
||||
#define LMIC_DR_LEGACY 0
|
||||
|
||||
#include "lmic.h"
|
||||
|
||||
// ----------------------------------------
|
||||
@ -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
|
||||
@ -194,7 +196,17 @@
|
||||
#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
|
||||
@ -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);
|
||||
@ -412,6 +428,13 @@ static void configLoraModem () {
|
||||
|
||||
// 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
|
||||
@ -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);
|
||||
@ -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,
|
||||
@ -619,7 +664,7 @@ static void rxlora (u1_t rxmode) {
|
||||
// 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);
|
||||
}
|
||||
|
||||
#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),
|
||||
@ -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
|
||||
@ -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,21 +937,35 @@ 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);
|
||||
@ -831,10 +975,17 @@ void radio_irq_handler (u1_t dio, ostime_t t) {
|
||||
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) {
|
||||
|
Loading…
Reference in New Issue
Block a user