mirror of
https://github.com/manuelbl/ttn-esp32.git
synced 2025-07-17 16:12:52 +02:00
Compare commits
14 Commits
2.2.2
...
lmic-maste
Author | SHA1 | Date | |
---|---|---|---|
27b63d955a | |||
31b859cdf4 | |||
1c88b1f5be | |||
f01b29a3b2 | |||
d7e8a920c8 | |||
267e04c833 | |||
f899c38663 | |||
6afdfe4caf | |||
9bb6788a7b | |||
58116219bb | |||
f03b5c51fd | |||
99420c6a75 | |||
47063256a3 | |||
ee08d2a3c1 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@ sdkconfig
|
|||||||
sdkconfig.old
|
sdkconfig.old
|
||||||
dev_keys.txt
|
dev_keys.txt
|
||||||
ttn-esp32
|
ttn-esp32
|
||||||
|
.vscode/
|
||||||
|
2
.vscode/c_cpp_properties.json
vendored
2
.vscode/c_cpp_properties.json
vendored
@ -28,7 +28,7 @@
|
|||||||
],
|
],
|
||||||
"compilerPath": "/usr/bin/clang",
|
"compilerPath": "/usr/bin/clang",
|
||||||
"cStandard": "c11",
|
"cStandard": "c11",
|
||||||
"cppStandard": "c++17",
|
"cppStandard": "c++11",
|
||||||
"intelliSenseMode": "clang-x64"
|
"intelliSenseMode": "clang-x64"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
14
CMakeLists.txt
Normal file
14
CMakeLists.txt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
set(COMPONENT_SRCDIRS
|
||||||
|
"src"
|
||||||
|
"src/aes"
|
||||||
|
"src/hal"
|
||||||
|
"src/lmic"
|
||||||
|
)
|
||||||
|
set(COMPONENT_ADD_INCLUDEDIRS
|
||||||
|
"include"
|
||||||
|
)
|
||||||
|
set(COMPONENT_REQUIRES
|
||||||
|
nvs_flash
|
||||||
|
)
|
||||||
|
|
||||||
|
register_component()
|
23
Kconfig
23
Kconfig
@ -14,16 +14,19 @@ config TTN_LORA_FREQ_EU_868
|
|||||||
bool "Europe (868 MHz)"
|
bool "Europe (868 MHz)"
|
||||||
|
|
||||||
config TTN_LORA_FREQ_US_915
|
config TTN_LORA_FREQ_US_915
|
||||||
bool "North America (915 Mhz)"
|
bool "North America (915 MHz)"
|
||||||
|
|
||||||
config TTN_LORA_FREQ_AU_921
|
config TTN_LORA_FREQ_AU_921
|
||||||
bool "Australia (921 Mhz)"
|
bool "Australia (921 MHz)"
|
||||||
|
|
||||||
config TTN_LORA_FREQ_AS_923
|
config TTN_LORA_FREQ_AS_923
|
||||||
bool "Asia (923 Mhz)"
|
bool "Asia (923 MHz)"
|
||||||
|
|
||||||
|
config TTN_LORA_FREQ_AS_923_JP
|
||||||
|
bool "Asia, region Japan (923 MHz)"
|
||||||
|
|
||||||
config TTN_LORA_FREQ_IN_866
|
config TTN_LORA_FREQ_IN_866
|
||||||
bool "India (866 Mhz)"
|
bool "India (866 MHz)"
|
||||||
|
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
@ -79,22 +82,22 @@ config TTN_BG_TASK_PRIO
|
|||||||
|
|
||||||
|
|
||||||
choice TTN_PROVISION_UART
|
choice TTN_PROVISION_UART
|
||||||
prompt "UART for provisioning"
|
prompt "AT commands"
|
||||||
default TTN_PROVISION_UART_DEFAULT
|
default TTN_PROVISION_UART_DEFAULT
|
||||||
help
|
help
|
||||||
Select whether to use UART for listening for provisioning commands.
|
Select whether to listen on UART for AT commands.
|
||||||
|
|
||||||
- Default is to use UART0 on pins GPIO1(TX) and GPIO3(RX).
|
- Default is to use UART0 on pins GPIO1(TX) and GPIO3(RX).
|
||||||
- If "Custom" is selected, UART0 or UART1 can be chosen,
|
- If "Custom" is selected, UART0 or UART1 can be chosen,
|
||||||
and any pins can be selected.
|
and any pins can be selected.
|
||||||
- If "None" is selected, the feature is not available.
|
- If "None" is selected, AT commands are not available.
|
||||||
|
|
||||||
config TTN_PROVISION_UART_DEFAULT
|
config TTN_PROVISION_UART_DEFAULT
|
||||||
bool "Default: UART0, TX=GPIO1, RX=GPIO3, 115,200 baud"
|
bool "Enabled - default settings: UART0, TX=GPIO1, RX=GPIO3, 115,200 baud"
|
||||||
config TTN_PROVISION_UART_CUSTOM
|
config TTN_PROVISION_UART_CUSTOM
|
||||||
bool "Custom"
|
bool "Enabled - custom UART settings"
|
||||||
config TTN_PROVISION_UART_NONE
|
config TTN_PROVISION_UART_NONE
|
||||||
bool "None"
|
bool "Disabled"
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
choice TTN_PROVISION_UART_NUM
|
choice TTN_PROVISION_UART_NUM
|
||||||
|
@ -20,6 +20,9 @@
|
|||||||
#define CFG_au921 1
|
#define CFG_au921 1
|
||||||
#elif defined(CONFIG_TTN_LORA_FREQ_AS_923)
|
#elif defined(CONFIG_TTN_LORA_FREQ_AS_923)
|
||||||
#define CFG_as923 1
|
#define CFG_as923 1
|
||||||
|
#elif defined(CONFIG_TTN_LORA_FREQ_AS_923_JP)
|
||||||
|
#define CFG_as923 1
|
||||||
|
#define LMIC_COUNTRY_CODE LMIC_COUNTRY_CODE_JP
|
||||||
#elif defined(CONFIG_TTN_LORA_FREQ_IN_866)
|
#elif defined(CONFIG_TTN_LORA_FREQ_IN_866)
|
||||||
#define CFG_in866 1
|
#define CFG_in866 1
|
||||||
#else
|
#else
|
||||||
@ -55,6 +58,14 @@
|
|||||||
#error TTN timer must be configured using 'make menuconfig'
|
#error TTN timer must be configured using 'make menuconfig'
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(CONFIG_TTN_PROVISION_UART_NONE)
|
||||||
|
#define TTN_HAS_AT_COMMANDS 1
|
||||||
|
#if defined(CONFIG_TTN_PROVISION_UART_CONFIG_YES)
|
||||||
|
#define TTN_CONFIG_UART 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// 16 μs per tick
|
// 16 μs per tick
|
||||||
// LMIC requires ticks to be 15.5μs - 100 μs long
|
// LMIC requires ticks to be 15.5μs - 100 μs long
|
||||||
#define US_PER_OSTICK 16
|
#define US_PER_OSTICK 16
|
||||||
|
6
examples/hello_world/CMakeLists.txt
Normal file
6
examples/hello_world/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# The following lines of boilerplate have to be in your project's
|
||||||
|
# CMakeLists in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(hello_world)
|
@ -1,3 +1,5 @@
|
|||||||
PROJECT_NAME := hello_world
|
PROJECT_NAME := hello_world
|
||||||
|
|
||||||
|
EXTRA_COMPONENT_DIRS := $(abspath ../..)
|
||||||
|
|
||||||
include $(IDF_PATH)/make/project.mk
|
include $(IDF_PATH)/make/project.mk
|
||||||
|
4
examples/hello_world/main/CMakeLists.txt
Normal file
4
examples/hello_world/main/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
set(COMPONENT_SRCS "main.cpp")
|
||||||
|
set(COMPONENT_ADD_INCLUDEDIRS "")
|
||||||
|
|
||||||
|
register_component()
|
@ -89,7 +89,7 @@ extern "C" void app_main(void)
|
|||||||
if (ttn.join())
|
if (ttn.join())
|
||||||
{
|
{
|
||||||
printf("Joined.\n");
|
printf("Joined.\n");
|
||||||
xTaskCreate(sendMessages, "send_messages", 1024 * 4, (void* )0, 3, NULL);
|
xTaskCreate(sendMessages, "send_messages", 1024 * 4, (void* )0, 3, nullptr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
6
examples/mac_address/CMakeLists.txt
Normal file
6
examples/mac_address/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# The following lines of boilerplate have to be in your project's
|
||||||
|
# CMakeLists in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(mac_address)
|
@ -1,3 +1,5 @@
|
|||||||
PROJECT_NAME := mac_address
|
PROJECT_NAME := mac_address
|
||||||
|
|
||||||
|
EXTRA_COMPONENT_DIRS := $(abspath ../..)
|
||||||
|
|
||||||
include $(IDF_PATH)/make/project.mk
|
include $(IDF_PATH)/make/project.mk
|
||||||
|
4
examples/mac_address/main/CMakeLists.txt
Normal file
4
examples/mac_address/main/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
set(COMPONENT_SRCS "main.cpp")
|
||||||
|
set(COMPONENT_ADD_INCLUDEDIRS "")
|
||||||
|
|
||||||
|
register_component()
|
@ -87,7 +87,7 @@ extern "C" void app_main(void)
|
|||||||
if (ttn.join())
|
if (ttn.join())
|
||||||
{
|
{
|
||||||
printf("Joined.\n");
|
printf("Joined.\n");
|
||||||
xTaskCreate(sendMessages, "send_messages", 1024 * 4, (void* )0, 3, NULL);
|
xTaskCreate(sendMessages, "send_messages", 1024 * 4, (void* )0, 3, nullptr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
6
examples/provisioning/CMakeLists.txt
Normal file
6
examples/provisioning/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# The following lines of boilerplate have to be in your project's
|
||||||
|
# CMakeLists in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(provisioning)
|
@ -1,3 +1,5 @@
|
|||||||
PROJECT_NAME := provisioning
|
PROJECT_NAME := provisioning
|
||||||
|
|
||||||
|
EXTRA_COMPONENT_DIRS := $(abspath ../..)
|
||||||
|
|
||||||
include $(IDF_PATH)/make/project.mk
|
include $(IDF_PATH)/make/project.mk
|
||||||
|
4
examples/provisioning/main/CMakeLists.txt
Normal file
4
examples/provisioning/main/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
set(COMPONENT_SRCS "main.cpp")
|
||||||
|
set(COMPONENT_ADD_INCLUDEDIRS "")
|
||||||
|
|
||||||
|
register_component()
|
@ -82,7 +82,7 @@ extern "C" void app_main(void)
|
|||||||
if (ttn.join())
|
if (ttn.join())
|
||||||
{
|
{
|
||||||
printf("Joined.\n");
|
printf("Joined.\n");
|
||||||
xTaskCreate(sendMessages, "send_messages", 1024 * 4, (void* )0, 3, NULL);
|
xTaskCreate(sendMessages, "send_messages", 1024 * 4, (void* )0, 3, nullptr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
6
examples/send_recv/CMakeLists.txt
Normal file
6
examples/send_recv/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# The following lines of boilerplate have to be in your project's
|
||||||
|
# CMakeLists in this exact order for cmake to work correctly
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
|
||||||
|
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||||
|
project(send_recv)
|
@ -1,3 +1,5 @@
|
|||||||
PROJECT_NAME := send_recv
|
PROJECT_NAME := send_recv
|
||||||
|
|
||||||
|
EXTRA_COMPONENT_DIRS := $(abspath ../..)
|
||||||
|
|
||||||
include $(IDF_PATH)/make/project.mk
|
include $(IDF_PATH)/make/project.mk
|
||||||
|
4
examples/send_recv/main/CMakeLists.txt
Normal file
4
examples/send_recv/main/CMakeLists.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
set(COMPONENT_SRCS "main.cpp")
|
||||||
|
set(COMPONENT_ADD_INCLUDEDIRS "")
|
||||||
|
|
||||||
|
register_component()
|
@ -99,7 +99,7 @@ extern "C" void app_main(void)
|
|||||||
if (ttn.join())
|
if (ttn.join())
|
||||||
{
|
{
|
||||||
printf("Joined.\n");
|
printf("Joined.\n");
|
||||||
xTaskCreate(sendMessages, "send_messages", 1024 * 4, (void* )0, 3, NULL);
|
xTaskCreate(sendMessages, "send_messages", 1024 * 4, (void* )0, 3, nullptr);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -130,7 +130,7 @@ public:
|
|||||||
bool provisionWithMAC(const char *appEui, const char *appKey);
|
bool provisionWithMAC(const char *appEui, const char *appKey);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Start task that listens on configured UART for provisioning commands.
|
* @brief Start task that listens on configured UART for AT commands.
|
||||||
*
|
*
|
||||||
* Run 'make menuconfig' to configure it.
|
* Run 'make menuconfig' to configure it.
|
||||||
*/
|
*/
|
||||||
|
27
library.json
Normal file
27
library.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"name": "ttn-esp32",
|
||||||
|
"description": "The Things Network device library for ESP32 (ESP-IDF) and SX127x based devices",
|
||||||
|
"keywords": "esp32, ttn, espidf, lorawan, sx1276, sx1272, rfm92, rfm95, lmic",
|
||||||
|
"authors": {
|
||||||
|
"name": "Manuel Bl",
|
||||||
|
"email": "manuel.bleichenbacher@gmail.com",
|
||||||
|
"url": "https://github.com/manuelbl/ttn-esp32",
|
||||||
|
"maintainer": true
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/manuelbl/ttn-esp32.git",
|
||||||
|
"branch": "dev"
|
||||||
|
},
|
||||||
|
"version": "2.3.2",
|
||||||
|
"license": "MIT License",
|
||||||
|
"export": {
|
||||||
|
"include": [
|
||||||
|
"include",
|
||||||
|
"src",
|
||||||
|
"esp_idf_lmic_config.h"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"frameworks": "espidf",
|
||||||
|
"platforms": "espressif32"
|
||||||
|
}
|
@ -16,48 +16,28 @@
|
|||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "esp_system.h"
|
#include "esp_system.h"
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
#include "provisioning.h"
|
#include "TTNProvisioning.h"
|
||||||
#include "lmic/lmic.h"
|
#include "lmic/lmic.h"
|
||||||
#include "hal/hal_esp32.h"
|
#include "hal/hal_esp32.h"
|
||||||
|
|
||||||
#define UART_NUM CONFIG_TTN_PROVISION_UART_NUM
|
#if defined(TTN_HAS_AT_COMMANDS)
|
||||||
#define MAX_LINE_LENGTH 128
|
const uart_port_t UART_NUM = (uart_port_t) CONFIG_TTN_PROVISION_UART_NUM;
|
||||||
|
const int MAX_LINE_LENGTH = 128;
|
||||||
|
#endif
|
||||||
|
|
||||||
static const char *TAG = "ttn_prov";
|
static const char* const TAG = "ttn_prov";
|
||||||
static const char *NVS_FLASH_PARTITION = "ttn";
|
static const char* const NVS_FLASH_PARTITION = "ttn";
|
||||||
static const char *NVS_FLASH_KEY_DEV_EUI = "devEui";
|
static const char* const NVS_FLASH_KEY_DEV_EUI = "devEui";
|
||||||
static const char *NVS_FLASH_KEY_APP_EUI = "appEui";
|
static const char* const NVS_FLASH_KEY_APP_EUI = "appEui";
|
||||||
static const char *NVS_FLASH_KEY_APP_KEY = "appKey";
|
static const char* const NVS_FLASH_KEY_APP_KEY = "appKey";
|
||||||
|
|
||||||
static bool provisioning_decode(bool incl_dev_eui, const char *dev_eui, const char *app_eui, const char *app_key);
|
|
||||||
static void provisioning_task(void* pvParameter);
|
|
||||||
static void provisioning_add_line_data(int numBytes);
|
|
||||||
static void provisioning_detect_line_end(int start_at);
|
|
||||||
static void provisioning_process_line();
|
|
||||||
static bool read_nvs_value(nvs_handle handle, const char* key, uint8_t* data, size_t expected_length, bool silent);
|
|
||||||
static bool write_nvs_value(nvs_handle handle, const char* key, const uint8_t* data, size_t len);
|
|
||||||
static bool hex_str_to_bin(const char *hex, uint8_t *buf, int len);
|
|
||||||
static int hex_tuple_to_byte(const char *hex);
|
|
||||||
static int hex_digit_to_val(char ch);
|
|
||||||
static void bin_to_hex_str(const uint8_t* buf, int len, char* hex);
|
|
||||||
static char val_to_hex_digit(int val);
|
|
||||||
static void swap_bytes(uint8_t* buf, int len);
|
|
||||||
static bool is_all_zeroes(const uint8_t* buf, int len);
|
|
||||||
|
|
||||||
|
|
||||||
static QueueHandle_t uart_queue = NULL;
|
|
||||||
static char* line_buf;
|
|
||||||
static int line_length;
|
|
||||||
static uint8_t last_line_end_char = 0;
|
|
||||||
static uint8_t global_dev_eui[8];
|
static uint8_t global_dev_eui[8];
|
||||||
static uint8_t global_app_eui[8];
|
static uint8_t global_app_eui[8];
|
||||||
static uint8_t global_app_key[16];
|
static uint8_t global_app_key[16];
|
||||||
static bool have_keys = false;
|
|
||||||
static bool quit_task = false;
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(CONFIG_TTN_PROVISION_UART_CONFIG_YES)
|
#if defined(TTN_HAS_AT_COMMANDS)
|
||||||
static void provisioning_config_uart();
|
void ttn_provisioning_task_caller(void* pvParameter);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -86,22 +66,40 @@ void os_getDevKey (u1_t* buf)
|
|||||||
memcpy(buf, global_app_key, 16);
|
memcpy(buf, global_app_key, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Constructor
|
||||||
|
|
||||||
|
TTNProvisioning::TTNProvisioning()
|
||||||
|
: have_keys(false)
|
||||||
|
#if defined(TTN_HAS_AT_COMMANDS)
|
||||||
|
, uart_queue(nullptr), line_buf(nullptr), line_length(0), last_line_end_char(0), quit_task(false)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// --- Provisioning task
|
// --- Provisioning task
|
||||||
|
|
||||||
void provisioning_start_task()
|
#if defined(TTN_HAS_AT_COMMANDS)
|
||||||
|
|
||||||
|
void TTNProvisioning::startTask()
|
||||||
{
|
{
|
||||||
#if defined(CONFIG_TTN_PROVISION_UART_CONFIG_YES)
|
#if defined(TTN_CONFIG_UART)
|
||||||
provisioning_config_uart();
|
configUART();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
esp_err_t err = uart_driver_install(UART_NUM, 2048, 2048, 20, &uart_queue, 0);
|
esp_err_t err = uart_driver_install(UART_NUM, 2048, 2048, 20, &uart_queue, 0);
|
||||||
ESP_ERROR_CHECK(err);
|
ESP_ERROR_CHECK(err);
|
||||||
|
|
||||||
xTaskCreate(provisioning_task, "provisioning", 2048, NULL, 1, NULL);
|
xTaskCreate(ttn_provisioning_task_caller, "provisioning", 2048, this, 1, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void provisioning_task(void* pvParameter)
|
void ttn_provisioning_task_caller(void* pvParameter)
|
||||||
|
{
|
||||||
|
TTNProvisioning* provisioning = (TTNProvisioning*)pvParameter;
|
||||||
|
provisioning->provisioningTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TTNProvisioning::provisioningTask()
|
||||||
{
|
{
|
||||||
line_buf = (char*)malloc(MAX_LINE_LENGTH + 1);
|
line_buf = (char*)malloc(MAX_LINE_LENGTH + 1);
|
||||||
line_length = 0;
|
line_length = 0;
|
||||||
@ -118,7 +116,7 @@ void provisioning_task(void* pvParameter)
|
|||||||
switch (event.type)
|
switch (event.type)
|
||||||
{
|
{
|
||||||
case UART_DATA:
|
case UART_DATA:
|
||||||
provisioning_add_line_data(event.size);
|
addLineData(event.size);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UART_FIFO_OVF:
|
case UART_FIFO_OVF:
|
||||||
@ -134,10 +132,10 @@ void provisioning_task(void* pvParameter)
|
|||||||
|
|
||||||
free(line_buf);
|
free(line_buf);
|
||||||
uart_driver_delete(UART_NUM);
|
uart_driver_delete(UART_NUM);
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void provisioning_add_line_data(int numBytes)
|
void TTNProvisioning::addLineData(int numBytes)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
top:
|
top:
|
||||||
@ -149,7 +147,7 @@ top:
|
|||||||
int start_at = line_length;
|
int start_at = line_length;
|
||||||
line_length += n;
|
line_length += n;
|
||||||
|
|
||||||
provisioning_detect_line_end(start_at);
|
detectLineEnd(start_at);
|
||||||
|
|
||||||
if (n < numBytes)
|
if (n < numBytes)
|
||||||
{
|
{
|
||||||
@ -158,7 +156,7 @@ top:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void provisioning_detect_line_end(int start_at)
|
void TTNProvisioning::detectLineEnd(int start_at)
|
||||||
{
|
{
|
||||||
top:
|
top:
|
||||||
for (int p = start_at; p < line_length; p++)
|
for (int p = start_at; p < line_length; p++)
|
||||||
@ -175,7 +173,7 @@ top:
|
|||||||
last_line_end_char = ch;
|
last_line_end_char = ch;
|
||||||
|
|
||||||
if (p > 0)
|
if (p > 0)
|
||||||
provisioning_process_line();
|
processLine();
|
||||||
|
|
||||||
memcpy(line_buf, line_buf + p + 1, line_length - p - 1);
|
memcpy(line_buf, line_buf + p + 1, line_length - p - 1);
|
||||||
line_length -= p + 1;
|
line_length -= p + 1;
|
||||||
@ -191,7 +189,7 @@ top:
|
|||||||
line_length = 0; // Line too long; flush it
|
line_length = 0; // Line too long; flush it
|
||||||
}
|
}
|
||||||
|
|
||||||
void provisioning_process_line()
|
void TTNProvisioning::processLine()
|
||||||
{
|
{
|
||||||
bool is_ok = true;
|
bool is_ok = true;
|
||||||
bool reset_needed = false;
|
bool reset_needed = false;
|
||||||
@ -209,14 +207,14 @@ void provisioning_process_line()
|
|||||||
char hexbuf[16];
|
char hexbuf[16];
|
||||||
|
|
||||||
memcpy(binbuf, global_dev_eui, 8);
|
memcpy(binbuf, global_dev_eui, 8);
|
||||||
swap_bytes(binbuf, 8);
|
swapBytes(binbuf, 8);
|
||||||
bin_to_hex_str(binbuf, 8, hexbuf);
|
binToHexStr(binbuf, 8, hexbuf);
|
||||||
uart_write_bytes(UART_NUM, hexbuf, 16);
|
uart_write_bytes(UART_NUM, hexbuf, 16);
|
||||||
uart_write_bytes(UART_NUM, "-", 1);
|
uart_write_bytes(UART_NUM, "-", 1);
|
||||||
|
|
||||||
memcpy(binbuf, global_app_eui, 8);
|
memcpy(binbuf, global_app_eui, 8);
|
||||||
swap_bytes(binbuf, 8);
|
swapBytes(binbuf, 8);
|
||||||
bin_to_hex_str(binbuf, 8, hexbuf);
|
binToHexStr(binbuf, 8, hexbuf);
|
||||||
uart_write_bytes(UART_NUM, hexbuf, 16);
|
uart_write_bytes(UART_NUM, hexbuf, 16);
|
||||||
|
|
||||||
uart_write_bytes(UART_NUM, "-00000000000000000000000000000000\r\n", 35);
|
uart_write_bytes(UART_NUM, "-00000000000000000000000000000000\r\n", 35);
|
||||||
@ -228,7 +226,7 @@ void provisioning_process_line()
|
|||||||
{
|
{
|
||||||
line_buf[24] = 0;
|
line_buf[24] = 0;
|
||||||
line_buf[41] = 0;
|
line_buf[41] = 0;
|
||||||
is_ok = provisioning_decode_keys(line_buf + 8, line_buf + 25, line_buf + 42);
|
is_ok = decodeKeys(line_buf + 8, line_buf + 25, line_buf + 42);
|
||||||
reset_needed = is_ok;
|
reset_needed = is_ok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,7 +236,7 @@ void provisioning_process_line()
|
|||||||
if (is_ok)
|
if (is_ok)
|
||||||
{
|
{
|
||||||
line_buf[25] = 0;
|
line_buf[25] = 0;
|
||||||
is_ok = provisioning_from_mac(line_buf + 9, line_buf + 26);
|
is_ok = fromMAC(line_buf + 9, line_buf + 26);
|
||||||
reset_needed = is_ok;
|
reset_needed = is_ok;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -250,7 +248,7 @@ void provisioning_process_line()
|
|||||||
esp_err_t err = esp_efuse_mac_get_default(mac);
|
esp_err_t err = esp_efuse_mac_get_default(mac);
|
||||||
ESP_ERROR_CHECK(err);
|
ESP_ERROR_CHECK(err);
|
||||||
|
|
||||||
bin_to_hex_str(mac, 6, hexbuf);
|
binToHexStr(mac, 6, hexbuf);
|
||||||
for (int i = 0; i < 12; i += 2) {
|
for (int i = 0; i < 12; i += 2) {
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
uart_write_bytes(UART_NUM, ":", 1);
|
uart_write_bytes(UART_NUM, ":", 1);
|
||||||
@ -266,7 +264,7 @@ void provisioning_process_line()
|
|||||||
esp_err_t err = esp_efuse_mac_get_default(mac);
|
esp_err_t err = esp_efuse_mac_get_default(mac);
|
||||||
ESP_ERROR_CHECK(err);
|
ESP_ERROR_CHECK(err);
|
||||||
|
|
||||||
bin_to_hex_str(mac, 6, hexbuf);
|
binToHexStr(mac, 6, hexbuf);
|
||||||
for (int i = 0; i < 12; i += 2) {
|
for (int i = 0; i < 12; i += 2) {
|
||||||
uart_write_bytes(UART_NUM, hexbuf + i, 2);
|
uart_write_bytes(UART_NUM, hexbuf + i, 2);
|
||||||
if (i == 4)
|
if (i == 4)
|
||||||
@ -285,18 +283,21 @@ void provisioning_process_line()
|
|||||||
|
|
||||||
if (reset_needed)
|
if (reset_needed)
|
||||||
{
|
{
|
||||||
hal_enterCriticalSection();
|
ttn_hal.enterCriticalSection();
|
||||||
LMIC_reset();
|
LMIC_reset();
|
||||||
hal_leaveCriticalSection();
|
ttn_hal.leaveCriticalSection();
|
||||||
onEvent(EV_RESET);
|
onEvent(EV_RESET);
|
||||||
}
|
}
|
||||||
|
|
||||||
uart_write_bytes(UART_NUM, is_ok ? "OK\r\n" : "ERROR\r\n", is_ok ? 4 : 7);
|
uart_write_bytes(UART_NUM, is_ok ? "OK\r\n" : "ERROR\r\n", is_ok ? 4 : 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(CONFIG_TTN_PROVISION_UART_CONFIG_YES)
|
#endif
|
||||||
|
|
||||||
void provisioning_config_uart()
|
|
||||||
|
#if defined(TTN_CONFIG_UART)
|
||||||
|
|
||||||
|
void TTNProvisioning::configUART()
|
||||||
{
|
{
|
||||||
esp_err_t err;
|
esp_err_t err;
|
||||||
|
|
||||||
@ -305,7 +306,9 @@ void provisioning_config_uart()
|
|||||||
.data_bits = UART_DATA_8_BITS,
|
.data_bits = UART_DATA_8_BITS,
|
||||||
.parity = UART_PARITY_DISABLE,
|
.parity = UART_PARITY_DISABLE,
|
||||||
.stop_bits = UART_STOP_BITS_1,
|
.stop_bits = UART_STOP_BITS_1,
|
||||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE
|
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||||
|
.rx_flow_ctrl_thresh = 0,
|
||||||
|
.use_ref_tick = false
|
||||||
};
|
};
|
||||||
err = uart_param_config(UART_NUM, &uart_config);
|
err = uart_param_config(UART_NUM, &uart_config);
|
||||||
ESP_ERROR_CHECK(err);
|
ESP_ERROR_CHECK(err);
|
||||||
@ -319,17 +322,17 @@ void provisioning_config_uart()
|
|||||||
|
|
||||||
// --- Key handling
|
// --- Key handling
|
||||||
|
|
||||||
bool provisioning_have_keys()
|
bool TTNProvisioning::haveKeys()
|
||||||
{
|
{
|
||||||
return have_keys;
|
return have_keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool provisioning_decode_keys(const char *dev_eui, const char *app_eui, const char *app_key)
|
bool TTNProvisioning::decodeKeys(const char *dev_eui, const char *app_eui, const char *app_key)
|
||||||
{
|
{
|
||||||
return provisioning_decode(true, dev_eui, app_eui, app_key);
|
return decode(true, dev_eui, app_eui, app_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool provisioning_from_mac(const char *app_eui, const char *app_key)
|
bool TTNProvisioning::fromMAC(const char *app_eui, const char *app_key)
|
||||||
{
|
{
|
||||||
uint8_t mac[6];
|
uint8_t mac[6];
|
||||||
esp_err_t err = esp_efuse_mac_get_default(mac);
|
esp_err_t err = esp_efuse_mac_get_default(mac);
|
||||||
@ -344,33 +347,33 @@ bool provisioning_from_mac(const char *app_eui, const char *app_key)
|
|||||||
global_dev_eui[1] = mac[4];
|
global_dev_eui[1] = mac[4];
|
||||||
global_dev_eui[0] = mac[5];
|
global_dev_eui[0] = mac[5];
|
||||||
|
|
||||||
return provisioning_decode(false, NULL, app_eui, app_key);
|
return decode(false, nullptr, app_eui, app_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool provisioning_decode(bool incl_dev_eui, const char *dev_eui, const char *app_eui, const char *app_key)
|
bool TTNProvisioning::decode(bool incl_dev_eui, const char *dev_eui, const char *app_eui, const char *app_key)
|
||||||
{
|
{
|
||||||
uint8_t buf_dev_eui[8];
|
uint8_t buf_dev_eui[8];
|
||||||
uint8_t buf_app_eui[8];
|
uint8_t buf_app_eui[8];
|
||||||
uint8_t buf_app_key[16];
|
uint8_t buf_app_key[16];
|
||||||
|
|
||||||
if (incl_dev_eui && (strlen(dev_eui) != 16 || !hex_str_to_bin(dev_eui, buf_dev_eui, 8)))
|
if (incl_dev_eui && (strlen(dev_eui) != 16 || !hexStrToBin(dev_eui, buf_dev_eui, 8)))
|
||||||
{
|
{
|
||||||
ESP_LOGW(TAG, "Invalid device EUI: %s", dev_eui);
|
ESP_LOGW(TAG, "Invalid device EUI: %s", dev_eui);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (incl_dev_eui)
|
if (incl_dev_eui)
|
||||||
swap_bytes(buf_dev_eui, 8);
|
swapBytes(buf_dev_eui, 8);
|
||||||
|
|
||||||
if (strlen(app_eui) != 16 || !hex_str_to_bin(app_eui, buf_app_eui, 8))
|
if (strlen(app_eui) != 16 || !hexStrToBin(app_eui, buf_app_eui, 8))
|
||||||
{
|
{
|
||||||
ESP_LOGW(TAG, "Invalid application EUI: %s", app_eui);
|
ESP_LOGW(TAG, "Invalid application EUI: %s", app_eui);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
swap_bytes(buf_app_eui, 8);
|
swapBytes(buf_app_eui, 8);
|
||||||
|
|
||||||
if (strlen(app_key) != 32 || !hex_str_to_bin(app_key, buf_app_key, 16))
|
if (strlen(app_key) != 32 || !hexStrToBin(app_key, buf_app_key, 16))
|
||||||
{
|
{
|
||||||
ESP_LOGW(TAG, "Invalid application key: %s", app_key);
|
ESP_LOGW(TAG, "Invalid application key: %s", app_key);
|
||||||
return false;
|
return false;
|
||||||
@ -381,11 +384,11 @@ bool provisioning_decode(bool incl_dev_eui, const char *dev_eui, const char *app
|
|||||||
memcpy(global_app_eui, buf_app_eui, sizeof(global_app_eui));
|
memcpy(global_app_eui, buf_app_eui, sizeof(global_app_eui));
|
||||||
memcpy(global_app_key, buf_app_key, sizeof(global_app_key));
|
memcpy(global_app_key, buf_app_key, sizeof(global_app_key));
|
||||||
|
|
||||||
have_keys = !is_all_zeroes(global_dev_eui, sizeof(global_dev_eui))
|
have_keys = !isAllZeros(global_dev_eui, sizeof(global_dev_eui))
|
||||||
&& !is_all_zeroes(global_app_eui, sizeof(global_app_eui))
|
&& !isAllZeros(global_app_eui, sizeof(global_app_eui))
|
||||||
&& !is_all_zeroes(global_app_key, sizeof(global_app_key));
|
&& !isAllZeros(global_app_key, sizeof(global_app_key));
|
||||||
|
|
||||||
if (!provisioning_save_keys())
|
if (!saveKeys())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -394,7 +397,7 @@ bool provisioning_decode(bool incl_dev_eui, const char *dev_eui, const char *app
|
|||||||
|
|
||||||
// --- Non-volatile storage
|
// --- Non-volatile storage
|
||||||
|
|
||||||
bool provisioning_save_keys()
|
bool TTNProvisioning::saveKeys()
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
@ -409,13 +412,13 @@ bool provisioning_save_keys()
|
|||||||
if (res != ESP_OK)
|
if (res != ESP_OK)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (!write_nvs_value(handle, NVS_FLASH_KEY_DEV_EUI, global_dev_eui, sizeof(global_dev_eui)))
|
if (!writeNvsValue(handle, NVS_FLASH_KEY_DEV_EUI, global_dev_eui, sizeof(global_dev_eui)))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (!write_nvs_value(handle, NVS_FLASH_KEY_APP_EUI, global_app_eui, sizeof(global_app_eui)))
|
if (!writeNvsValue(handle, NVS_FLASH_KEY_APP_EUI, global_app_eui, sizeof(global_app_eui)))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (!write_nvs_value(handle, NVS_FLASH_KEY_APP_KEY, global_app_key, sizeof(global_app_key)))
|
if (!writeNvsValue(handle, NVS_FLASH_KEY_APP_KEY, global_app_key, sizeof(global_app_key)))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
res = nvs_commit(handle);
|
res = nvs_commit(handle);
|
||||||
@ -429,7 +432,7 @@ done:
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool provisioning_restore_keys(bool silent)
|
bool TTNProvisioning::restoreKeys(bool silent)
|
||||||
{
|
{
|
||||||
uint8_t buf_dev_eui[8];
|
uint8_t buf_dev_eui[8];
|
||||||
uint8_t buf_app_eui[8];
|
uint8_t buf_app_eui[8];
|
||||||
@ -448,22 +451,22 @@ bool provisioning_restore_keys(bool silent)
|
|||||||
if (res != ESP_OK)
|
if (res != ESP_OK)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (!read_nvs_value(handle, NVS_FLASH_KEY_DEV_EUI, buf_dev_eui, sizeof(global_dev_eui), silent))
|
if (!readNvsValue(handle, NVS_FLASH_KEY_DEV_EUI, buf_dev_eui, sizeof(global_dev_eui), silent))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (!read_nvs_value(handle, NVS_FLASH_KEY_APP_EUI, buf_app_eui, sizeof(global_app_eui), silent))
|
if (!readNvsValue(handle, NVS_FLASH_KEY_APP_EUI, buf_app_eui, sizeof(global_app_eui), silent))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (!read_nvs_value(handle, NVS_FLASH_KEY_APP_KEY, buf_app_key, sizeof(global_app_key), silent))
|
if (!readNvsValue(handle, NVS_FLASH_KEY_APP_KEY, buf_app_key, sizeof(global_app_key), silent))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
memcpy(global_dev_eui, buf_dev_eui, sizeof(global_dev_eui));
|
memcpy(global_dev_eui, buf_dev_eui, sizeof(global_dev_eui));
|
||||||
memcpy(global_app_eui, buf_app_eui, sizeof(global_app_eui));
|
memcpy(global_app_eui, buf_app_eui, sizeof(global_app_eui));
|
||||||
memcpy(global_app_key, buf_app_key, sizeof(global_app_key));
|
memcpy(global_app_key, buf_app_key, sizeof(global_app_key));
|
||||||
|
|
||||||
have_keys = !is_all_zeroes(global_dev_eui, sizeof(global_dev_eui))
|
have_keys = !isAllZeros(global_dev_eui, sizeof(global_dev_eui))
|
||||||
&& !is_all_zeroes(global_app_eui, sizeof(global_app_eui))
|
&& !isAllZeros(global_app_eui, sizeof(global_app_eui))
|
||||||
&& !is_all_zeroes(global_app_key, sizeof(global_app_key));
|
&& !isAllZeros(global_app_key, sizeof(global_app_key));
|
||||||
|
|
||||||
if (have_keys)
|
if (have_keys)
|
||||||
{
|
{
|
||||||
@ -479,7 +482,7 @@ done:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool read_nvs_value(nvs_handle handle, const char* key, uint8_t* data, size_t expected_length, bool silent)
|
bool TTNProvisioning::readNvsValue(nvs_handle handle, const char* key, uint8_t* data, size_t expected_length, bool silent)
|
||||||
{
|
{
|
||||||
size_t size = expected_length;
|
size_t size = expected_length;
|
||||||
esp_err_t res = nvs_get_blob(handle, key, data, &size);
|
esp_err_t res = nvs_get_blob(handle, key, data, &size);
|
||||||
@ -504,10 +507,10 @@ bool read_nvs_value(nvs_handle handle, const char* key, uint8_t* data, size_t ex
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool write_nvs_value(nvs_handle handle, const char* key, const uint8_t* data, size_t len)
|
bool TTNProvisioning::writeNvsValue(nvs_handle handle, const char* key, const uint8_t* data, size_t len)
|
||||||
{
|
{
|
||||||
uint8_t buf[16];
|
uint8_t buf[16];
|
||||||
if (read_nvs_value(handle, key, buf, len, true) && memcmp(buf, data, len) == 0)
|
if (readNvsValue(handle, key, buf, len, true) && memcmp(buf, data, len) == 0)
|
||||||
return true; // unchanged
|
return true; // unchanged
|
||||||
|
|
||||||
esp_err_t res = nvs_set_blob(handle, key, data, len);
|
esp_err_t res = nvs_set_blob(handle, key, data, len);
|
||||||
@ -519,12 +522,12 @@ bool write_nvs_value(nvs_handle handle, const char* key, const uint8_t* data, si
|
|||||||
|
|
||||||
// --- Helper functions ---
|
// --- Helper functions ---
|
||||||
|
|
||||||
bool hex_str_to_bin(const char *hex, uint8_t *buf, int len)
|
bool TTNProvisioning::hexStrToBin(const char *hex, uint8_t *buf, int len)
|
||||||
{
|
{
|
||||||
const char* ptr = hex;
|
const char* ptr = hex;
|
||||||
for (int i = 0; i < len; i++)
|
for (int i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
int val = hex_tuple_to_byte(ptr);
|
int val = hexTupleToByte(ptr);
|
||||||
if (val < 0)
|
if (val < 0)
|
||||||
return false;
|
return false;
|
||||||
buf[i] = val;
|
buf[i] = val;
|
||||||
@ -533,18 +536,18 @@ bool hex_str_to_bin(const char *hex, uint8_t *buf, int len)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hex_tuple_to_byte(const char *hex)
|
int TTNProvisioning::hexTupleToByte(const char *hex)
|
||||||
{
|
{
|
||||||
int nibble1 = hex_digit_to_val(hex[0]);
|
int nibble1 = hexDigitToVal(hex[0]);
|
||||||
if (nibble1 < 0)
|
if (nibble1 < 0)
|
||||||
return -1;
|
return -1;
|
||||||
int nibble2 = hex_digit_to_val(hex[1]);
|
int nibble2 = hexDigitToVal(hex[1]);
|
||||||
if (nibble2 < 0)
|
if (nibble2 < 0)
|
||||||
return -1;
|
return -1;
|
||||||
return (nibble1 << 4) | nibble2;
|
return (nibble1 << 4) | nibble2;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hex_digit_to_val(char ch)
|
int TTNProvisioning::hexDigitToVal(char ch)
|
||||||
{
|
{
|
||||||
if (ch >= '0' && ch <= '9')
|
if (ch >= '0' && ch <= '9')
|
||||||
return ch - '0';
|
return ch - '0';
|
||||||
@ -555,24 +558,24 @@ int hex_digit_to_val(char ch)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bin_to_hex_str(const uint8_t* buf, int len, char* hex)
|
void TTNProvisioning::binToHexStr(const uint8_t* buf, int len, char* hex)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < len; i++)
|
for (int i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
uint8_t b = buf[i];
|
uint8_t b = buf[i];
|
||||||
*hex = val_to_hex_digit((b & 0xf0) >> 4);
|
*hex = valToHexDigit((b & 0xf0) >> 4);
|
||||||
hex++;
|
hex++;
|
||||||
*hex = val_to_hex_digit(b & 0x0f);
|
*hex = valToHexDigit(b & 0x0f);
|
||||||
hex++;
|
hex++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char val_to_hex_digit(int val)
|
char TTNProvisioning::valToHexDigit(int val)
|
||||||
{
|
{
|
||||||
return "0123456789ABCDEF"[val];
|
return "0123456789ABCDEF"[val];
|
||||||
}
|
}
|
||||||
|
|
||||||
void swap_bytes(uint8_t* buf, int len)
|
void TTNProvisioning::swapBytes(uint8_t* buf, int len)
|
||||||
{
|
{
|
||||||
uint8_t* p1 = buf;
|
uint8_t* p1 = buf;
|
||||||
uint8_t* p2 = buf + len - 1;
|
uint8_t* p2 = buf + len - 1;
|
||||||
@ -586,7 +589,7 @@ void swap_bytes(uint8_t* buf, int len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_all_zeroes(const uint8_t* buf, int len)
|
bool TTNProvisioning::isAllZeros(const uint8_t* buf, int len)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < len; i++)
|
for (int i = 0; i < len; i++)
|
||||||
if (buf[i] != 0)
|
if (buf[i] != 0)
|
73
src/TTNProvisioning.h
Normal file
73
src/TTNProvisioning.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* Task listening on a UART port for provisioning commands.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _ttnprovisioning_h_
|
||||||
|
#define _ttnprovisioning_h_
|
||||||
|
|
||||||
|
#include "lmic/oslmic.h"
|
||||||
|
#include "nvs_flash.h"
|
||||||
|
|
||||||
|
|
||||||
|
class TTNProvisioning
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TTNProvisioning();
|
||||||
|
|
||||||
|
bool haveKeys();
|
||||||
|
bool decodeKeys(const char *dev_eui, const char *app_eui, const char *app_key);
|
||||||
|
bool fromMAC(const char *app_eui, const char *app_key);
|
||||||
|
bool saveKeys();
|
||||||
|
bool restoreKeys(bool silent);
|
||||||
|
|
||||||
|
#if defined(TTN_HAS_AT_COMMANDS)
|
||||||
|
void startTask();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool decode(bool incl_dev_eui, const char *dev_eui, const char *app_eui, const char *app_key);
|
||||||
|
bool readNvsValue(nvs_handle handle, const char* key, uint8_t* data, size_t expected_length, bool silent);
|
||||||
|
bool writeNvsValue(nvs_handle handle, const char* key, const uint8_t* data, size_t len);
|
||||||
|
|
||||||
|
#if defined(TTN_HAS_AT_COMMANDS)
|
||||||
|
void provisioningTask();
|
||||||
|
void addLineData(int numBytes);
|
||||||
|
void detectLineEnd(int start_at);
|
||||||
|
void processLine();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(TTN_CONFIG_UART)
|
||||||
|
void configUART();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static bool hexStrToBin(const char *hex, uint8_t *buf, int len);
|
||||||
|
static int hexTupleToByte(const char *hex);
|
||||||
|
static int hexDigitToVal(char ch);
|
||||||
|
static void binToHexStr(const uint8_t* buf, int len, char* hex);
|
||||||
|
static char valToHexDigit(int val);
|
||||||
|
static void swapBytes(uint8_t* buf, int len);
|
||||||
|
static bool isAllZeros(const uint8_t* buf, int len);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool have_keys = false;
|
||||||
|
|
||||||
|
#if defined(TTN_HAS_AT_COMMANDS)
|
||||||
|
QueueHandle_t uart_queue;
|
||||||
|
char* line_buf;
|
||||||
|
int line_length;
|
||||||
|
uint8_t last_line_end_char;
|
||||||
|
bool quit_task;
|
||||||
|
|
||||||
|
friend void ttn_provisioning_task_caller(void* pvParameter);
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
@ -16,7 +16,7 @@
|
|||||||
#include "TheThingsNetwork.h"
|
#include "TheThingsNetwork.h"
|
||||||
#include "hal/hal_esp32.h"
|
#include "hal/hal_esp32.h"
|
||||||
#include "lmic/lmic.h"
|
#include "lmic/lmic.h"
|
||||||
#include "provisioning.h"
|
#include "TTNProvisioning.h"
|
||||||
|
|
||||||
|
|
||||||
enum ClientAction
|
enum ClientAction
|
||||||
@ -31,10 +31,11 @@ static const char *TAG = "ttn";
|
|||||||
static TheThingsNetwork* ttnInstance;
|
static TheThingsNetwork* ttnInstance;
|
||||||
static QueueHandle_t resultQueue;
|
static QueueHandle_t resultQueue;
|
||||||
static ClientAction clientAction = eActionUnrelated;
|
static ClientAction clientAction = eActionUnrelated;
|
||||||
|
static TTNProvisioning provisioning;
|
||||||
|
|
||||||
|
|
||||||
TheThingsNetwork::TheThingsNetwork()
|
TheThingsNetwork::TheThingsNetwork()
|
||||||
: messageCallback(NULL)
|
: messageCallback(nullptr)
|
||||||
{
|
{
|
||||||
#if defined(TTN_IS_DISABLED)
|
#if defined(TTN_IS_DISABLED)
|
||||||
ESP_LOGE(TAG, "TTN is disabled. Configure a frequency plan using 'make menuconfig'");
|
ESP_LOGE(TAG, "TTN is disabled. Configure a frequency plan using 'make menuconfig'");
|
||||||
@ -42,9 +43,9 @@ TheThingsNetwork::TheThingsNetwork()
|
|||||||
esp_restart();
|
esp_restart();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ASSERT(ttnInstance == NULL);
|
ASSERT(ttnInstance == nullptr);
|
||||||
ttnInstance = this;
|
ttnInstance = this;
|
||||||
hal_initCriticalSection();
|
ttn_hal.initCriticalSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
TheThingsNetwork::~TheThingsNetwork()
|
TheThingsNetwork::~TheThingsNetwork()
|
||||||
@ -65,59 +66,68 @@ void TheThingsNetwork::configurePins(spi_host_device_t spi_host, uint8_t nss, ui
|
|||||||
reset();
|
reset();
|
||||||
|
|
||||||
resultQueue = xQueueCreate(12, sizeof(int));
|
resultQueue = xQueueCreate(12, sizeof(int));
|
||||||
ASSERT(resultQueue != NULL);
|
ASSERT(resultQueue != nullptr);
|
||||||
hal_startBgTask();
|
ttn_hal.startBackgroundTask();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TheThingsNetwork::reset()
|
void TheThingsNetwork::reset()
|
||||||
{
|
{
|
||||||
hal_enterCriticalSection();
|
ttn_hal.enterCriticalSection();
|
||||||
LMIC_reset();
|
LMIC_reset();
|
||||||
hal_leaveCriticalSection();
|
ttn_hal.leaveCriticalSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TheThingsNetwork::provision(const char *devEui, const char *appEui, const char *appKey)
|
bool TheThingsNetwork::provision(const char *devEui, const char *appEui, const char *appKey)
|
||||||
{
|
{
|
||||||
if (!provisioning_decode_keys(devEui, appEui, appKey))
|
if (!provisioning.decodeKeys(devEui, appEui, appKey))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return provisioning_save_keys();
|
return provisioning.saveKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TheThingsNetwork::provisionWithMAC(const char *appEui, const char *appKey)
|
bool TheThingsNetwork::provisionWithMAC(const char *appEui, const char *appKey)
|
||||||
{
|
{
|
||||||
if (!provisioning_from_mac(appEui, appKey))
|
if (!provisioning.fromMAC(appEui, appKey))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return provisioning_save_keys();
|
return provisioning.saveKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TheThingsNetwork::startProvisioningTask()
|
void TheThingsNetwork::startProvisioningTask()
|
||||||
{
|
{
|
||||||
#if !defined(CONFIG_TTN_PROVISION_UART_NONE)
|
#if defined(TTN_HAS_AT_COMMANDS)
|
||||||
provisioning_start_task();
|
provisioning.startTask();
|
||||||
|
#else
|
||||||
|
ESP_LOGE(TAG, "AT commands are disabled. Change the configuration using 'make menuconfig'");
|
||||||
|
ASSERT(0);
|
||||||
|
esp_restart();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void TheThingsNetwork::waitForProvisioning()
|
void TheThingsNetwork::waitForProvisioning()
|
||||||
{
|
{
|
||||||
#if !defined(CONFIG_TTN_PROVISION_UART_NONE)
|
#if defined(TTN_HAS_AT_COMMANDS)
|
||||||
if (isProvisioned())
|
if (isProvisioned())
|
||||||
{
|
{
|
||||||
ESP_LOGI(TAG, "Device is already provisioned");
|
ESP_LOGI(TAG, "Device is already provisioned");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!provisioning_have_keys())
|
while (!provisioning.haveKeys())
|
||||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Device successfully provisioned");
|
ESP_LOGI(TAG, "Device successfully provisioned");
|
||||||
|
#else
|
||||||
|
ESP_LOGE(TAG, "AT commands are disabled. Change the configuration using 'make menuconfig'");
|
||||||
|
ASSERT(0);
|
||||||
|
esp_restart();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TheThingsNetwork::join(const char *devEui, const char *appEui, const char *appKey)
|
bool TheThingsNetwork::join(const char *devEui, const char *appEui, const char *appKey)
|
||||||
{
|
{
|
||||||
if (!provisioning_decode_keys(devEui, appEui, appKey))
|
if (!provisioning.decodeKeys(devEui, appEui, appKey))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return joinCore();
|
return joinCore();
|
||||||
@ -125,9 +135,9 @@ bool TheThingsNetwork::join(const char *devEui, const char *appEui, const char *
|
|||||||
|
|
||||||
bool TheThingsNetwork::join()
|
bool TheThingsNetwork::join()
|
||||||
{
|
{
|
||||||
if (!provisioning_have_keys())
|
if (!provisioning.haveKeys())
|
||||||
{
|
{
|
||||||
if (!provisioning_restore_keys(false))
|
if (!provisioning.restoreKeys(false))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,17 +146,17 @@ bool TheThingsNetwork::join()
|
|||||||
|
|
||||||
bool TheThingsNetwork::joinCore()
|
bool TheThingsNetwork::joinCore()
|
||||||
{
|
{
|
||||||
if (!provisioning_have_keys())
|
if (!provisioning.haveKeys())
|
||||||
{
|
{
|
||||||
ESP_LOGW(TAG, "Device EUI, App EUI and/or App key have not been provided");
|
ESP_LOGW(TAG, "Device EUI, App EUI and/or App key have not been provided");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
hal_enterCriticalSection();
|
ttn_hal.enterCriticalSection();
|
||||||
clientAction = eActionJoining;
|
clientAction = eActionJoining;
|
||||||
LMIC_startJoining();
|
LMIC_startJoining();
|
||||||
hal_wakeUp();
|
ttn_hal.wakeUp();
|
||||||
hal_leaveCriticalSection();
|
ttn_hal.leaveCriticalSection();
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
xQueueReceive(resultQueue, &result, portMAX_DELAY);
|
xQueueReceive(resultQueue, &result, portMAX_DELAY);
|
||||||
@ -155,17 +165,17 @@ bool TheThingsNetwork::joinCore()
|
|||||||
|
|
||||||
TTNResponseCode TheThingsNetwork::transmitMessage(const uint8_t *payload, size_t length, port_t port, bool confirm)
|
TTNResponseCode TheThingsNetwork::transmitMessage(const uint8_t *payload, size_t length, port_t port, bool confirm)
|
||||||
{
|
{
|
||||||
hal_enterCriticalSection();
|
ttn_hal.enterCriticalSection();
|
||||||
if (LMIC.opmode & OP_TXRXPEND)
|
if (LMIC.opmode & OP_TXRXPEND)
|
||||||
{
|
{
|
||||||
hal_leaveCriticalSection();
|
ttn_hal.leaveCriticalSection();
|
||||||
return kTTNErrorTransmissionFailed;
|
return kTTNErrorTransmissionFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
clientAction = eActionSending;
|
clientAction = eActionSending;
|
||||||
LMIC_setTxData2(port, (xref2u1_t)payload, length, confirm);
|
LMIC_setTxData2(port, (xref2u1_t)payload, length, confirm);
|
||||||
hal_wakeUp();
|
ttn_hal.wakeUp();
|
||||||
hal_leaveCriticalSection();
|
ttn_hal.leaveCriticalSection();
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
xQueueReceive(resultQueue, &result, portMAX_DELAY);
|
xQueueReceive(resultQueue, &result, portMAX_DELAY);
|
||||||
@ -173,12 +183,12 @@ TTNResponseCode TheThingsNetwork::transmitMessage(const uint8_t *payload, size_t
|
|||||||
if (result == EV_TXCOMPLETE)
|
if (result == EV_TXCOMPLETE)
|
||||||
{
|
{
|
||||||
bool hasRecevied = (LMIC.txrxFlags & (TXRX_DNW1 | TXRX_DNW2)) != 0;
|
bool hasRecevied = (LMIC.txrxFlags & (TXRX_DNW1 | TXRX_DNW2)) != 0;
|
||||||
if (hasRecevied && messageCallback != NULL)
|
if (hasRecevied && messageCallback != nullptr)
|
||||||
{
|
{
|
||||||
port_t port = 0;
|
port_t port = 0;
|
||||||
if ((LMIC.txrxFlags & TXRX_PORT))
|
if ((LMIC.txrxFlags & TXRX_PORT))
|
||||||
port = LMIC.frame[LMIC.dataBeg - 1];
|
port = LMIC.frame[LMIC.dataBeg - 1];
|
||||||
const uint8_t* msg = NULL;
|
const uint8_t* msg = nullptr;
|
||||||
if (LMIC.dataLen > 0)
|
if (LMIC.dataLen > 0)
|
||||||
msg = LMIC.frame + LMIC.dataBeg;
|
msg = LMIC.frame + LMIC.dataBeg;
|
||||||
messageCallback(msg, LMIC.dataLen, port);
|
messageCallback(msg, LMIC.dataLen, port);
|
||||||
@ -198,12 +208,12 @@ void TheThingsNetwork::onMessage(TTNMessageCallback callback)
|
|||||||
|
|
||||||
bool TheThingsNetwork::isProvisioned()
|
bool TheThingsNetwork::isProvisioned()
|
||||||
{
|
{
|
||||||
if (provisioning_have_keys())
|
if (provisioning.haveKeys())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
provisioning_restore_keys(true);
|
provisioning.restoreKeys(true);
|
||||||
|
|
||||||
return provisioning_have_keys();
|
return provisioning.haveKeys();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -211,7 +221,7 @@ bool TheThingsNetwork::isProvisioned()
|
|||||||
|
|
||||||
#if CONFIG_LOG_DEFAULT_LEVEL >= 3
|
#if CONFIG_LOG_DEFAULT_LEVEL >= 3
|
||||||
static const char *eventNames[] = {
|
static const char *eventNames[] = {
|
||||||
NULL,
|
nullptr,
|
||||||
"EV_SCAN_TIMEOUT", "EV_BEACON_FOUND",
|
"EV_SCAN_TIMEOUT", "EV_BEACON_FOUND",
|
||||||
"EV_BEACON_MISSED", "EV_BEACON_TRACKED", "EV_JOINING",
|
"EV_BEACON_MISSED", "EV_BEACON_TRACKED", "EV_JOINING",
|
||||||
"EV_JOINED", "EV_RFU1", "EV_JOIN_FAILED", "EV_REJOIN_FAILED",
|
"EV_JOINED", "EV_RFU1", "EV_JOIN_FAILED", "EV_REJOIN_FAILED",
|
||||||
|
@ -262,9 +262,6 @@ u4_t os_aes (u1_t mode, xref2u1_t buf, u2_t len) {
|
|||||||
u4_t a0, a1, a2, a3;
|
u4_t a0, a1, a2, a3;
|
||||||
u4_t t0, t1, t2, t3;
|
u4_t t0, t1, t2, t3;
|
||||||
u4_t *ki, *ke;
|
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;
|
|
||||||
|
|
||||||
// load input block
|
// load input block
|
||||||
if( (mode & AES_CTR) || ((mode & AES_MIC) && (mode & AES_MICNOAUX)==0) ) { // load CTR block or first MIC block
|
if( (mode & AES_CTR) || ((mode & AES_MIC) && (mode & AES_MICNOAUX)==0) ) { // load CTR block or first MIC block
|
||||||
|
0
src/aes/other.c
Normal file → Executable file
0
src/aes/other.c
Normal file → Executable file
@ -22,44 +22,44 @@
|
|||||||
|
|
||||||
#define LMIC_UNUSED_PIN 0xff
|
#define LMIC_UNUSED_PIN 0xff
|
||||||
|
|
||||||
static const char *TAG = "ttn_hal";
|
static const char * const TAG = "ttn_hal";
|
||||||
|
|
||||||
lmic_pinmap lmic_pins;
|
lmic_pinmap lmic_pins;
|
||||||
|
HAL_ESP32 ttn_hal;
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
DIO0 = 0,
|
|
||||||
DIO1,
|
|
||||||
DIO2,
|
|
||||||
TIMER,
|
|
||||||
WAKEUP
|
|
||||||
} event_t;
|
|
||||||
|
|
||||||
typedef struct {
|
struct HALQueueItem {
|
||||||
ostime_t time;
|
ostime_t time;
|
||||||
event_t ev;
|
HAL_Event ev;
|
||||||
} queue_item_t;
|
|
||||||
|
HALQueueItem() : time(0), ev(DIO0) { }
|
||||||
|
HALQueueItem(HAL_Event e, ostime_t t = 0)
|
||||||
|
: time(t), ev(e) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------------
|
||||||
|
// Constructor
|
||||||
|
|
||||||
|
HAL_ESP32::HAL_ESP32()
|
||||||
|
: nextTimerEvent(0x200000000)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// I/O
|
// I/O
|
||||||
|
|
||||||
static QueueHandle_t dio_queue;
|
void IRAM_ATTR HAL_ESP32::dioIrqHandler(void *arg)
|
||||||
|
|
||||||
void IRAM_ATTR dio_irq_handler(void *arg)
|
|
||||||
{
|
{
|
||||||
uint64_t now;
|
uint64_t now;
|
||||||
timer_get_counter_value(TTN_TIMER_GROUP, TTN_TIMER, &now);
|
timer_get_counter_value(TTN_TIMER_GROUP, TTN_TIMER, &now);
|
||||||
event_t ev = (long)arg;
|
BaseType_t higherPrioTaskWoken = pdFALSE;
|
||||||
BaseType_t higher_prio_task_woken = pdFALSE;
|
HALQueueItem item { (HAL_Event)(long)arg, (ostime_t)now };
|
||||||
queue_item_t item = {
|
xQueueSendFromISR(ttn_hal.dioQueue, &item, &higherPrioTaskWoken);
|
||||||
.time = (ostime_t)now,
|
if (higherPrioTaskWoken)
|
||||||
.ev = ev
|
|
||||||
};
|
|
||||||
xQueueSendFromISR(dio_queue, &item, &higher_prio_task_woken);
|
|
||||||
if (higher_prio_task_woken)
|
|
||||||
portYIELD_FROM_ISR();
|
portYIELD_FROM_ISR();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hal_io_init()
|
void HAL_ESP32::ioInit()
|
||||||
{
|
{
|
||||||
// NSS and DIO0 and DIO1 are required
|
// NSS and DIO0 and DIO1 are required
|
||||||
ASSERT(lmic_pins.nss != LMIC_UNUSED_PIN);
|
ASSERT(lmic_pins.nss != LMIC_UNUSED_PIN);
|
||||||
@ -67,35 +67,35 @@ static void hal_io_init()
|
|||||||
ASSERT(lmic_pins.dio1 != LMIC_UNUSED_PIN);
|
ASSERT(lmic_pins.dio1 != LMIC_UNUSED_PIN);
|
||||||
|
|
||||||
gpio_pad_select_gpio(lmic_pins.nss);
|
gpio_pad_select_gpio(lmic_pins.nss);
|
||||||
gpio_set_level(lmic_pins.nss, 0);
|
gpio_set_level((gpio_num_t)lmic_pins.nss, 0);
|
||||||
gpio_set_direction(lmic_pins.nss, GPIO_MODE_OUTPUT);
|
gpio_set_direction((gpio_num_t)lmic_pins.nss, GPIO_MODE_OUTPUT);
|
||||||
|
|
||||||
if (lmic_pins.rxtx != LMIC_UNUSED_PIN)
|
if (lmic_pins.rxtx != LMIC_UNUSED_PIN)
|
||||||
{
|
{
|
||||||
gpio_pad_select_gpio(lmic_pins.rxtx);
|
gpio_pad_select_gpio(lmic_pins.rxtx);
|
||||||
gpio_set_level(lmic_pins.rxtx, 0);
|
gpio_set_level((gpio_num_t)lmic_pins.rxtx, 0);
|
||||||
gpio_set_direction(lmic_pins.rxtx, GPIO_MODE_OUTPUT);
|
gpio_set_direction((gpio_num_t)lmic_pins.rxtx, GPIO_MODE_OUTPUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lmic_pins.rst != LMIC_UNUSED_PIN)
|
if (lmic_pins.rst != LMIC_UNUSED_PIN)
|
||||||
{
|
{
|
||||||
gpio_pad_select_gpio(lmic_pins.rst);
|
gpio_pad_select_gpio((gpio_num_t)lmic_pins.rst);
|
||||||
gpio_set_level(lmic_pins.rst, 0);
|
gpio_set_level((gpio_num_t)lmic_pins.rst, 0);
|
||||||
gpio_set_direction(lmic_pins.rst, GPIO_MODE_OUTPUT);
|
gpio_set_direction((gpio_num_t)lmic_pins.rst, GPIO_MODE_OUTPUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
dio_queue = xQueueCreate(12, sizeof(queue_item_t));
|
dioQueue = xQueueCreate(12, sizeof(HALQueueItem));
|
||||||
ASSERT(dio_queue != NULL);
|
ASSERT(dioQueue != NULL);
|
||||||
|
|
||||||
gpio_pad_select_gpio(lmic_pins.dio0);
|
gpio_pad_select_gpio(lmic_pins.dio0);
|
||||||
gpio_set_direction(lmic_pins.dio0, GPIO_MODE_INPUT);
|
gpio_set_direction((gpio_num_t)lmic_pins.dio0, GPIO_MODE_INPUT);
|
||||||
gpio_set_intr_type(lmic_pins.dio0, GPIO_INTR_POSEDGE);
|
gpio_set_intr_type((gpio_num_t)lmic_pins.dio0, GPIO_INTR_POSEDGE);
|
||||||
gpio_isr_handler_add(lmic_pins.dio0, dio_irq_handler, (void *)0);
|
gpio_isr_handler_add((gpio_num_t)lmic_pins.dio0, dioIrqHandler, (void *)0);
|
||||||
|
|
||||||
gpio_pad_select_gpio(lmic_pins.dio1);
|
gpio_pad_select_gpio((gpio_num_t)lmic_pins.dio1);
|
||||||
gpio_set_direction(lmic_pins.dio1, GPIO_MODE_INPUT);
|
gpio_set_direction((gpio_num_t)lmic_pins.dio1, GPIO_MODE_INPUT);
|
||||||
gpio_set_intr_type(lmic_pins.dio1, GPIO_INTR_POSEDGE);
|
gpio_set_intr_type((gpio_num_t)lmic_pins.dio1, GPIO_INTR_POSEDGE);
|
||||||
gpio_isr_handler_add(lmic_pins.dio1, dio_irq_handler, (void *)1);
|
gpio_isr_handler_add((gpio_num_t)lmic_pins.dio1, dioIrqHandler, (void *)1);
|
||||||
|
|
||||||
ESP_LOGI(TAG, "IO initialized");
|
ESP_LOGI(TAG, "IO initialized");
|
||||||
}
|
}
|
||||||
@ -105,7 +105,7 @@ void hal_pin_rxtx(u1_t val)
|
|||||||
if (lmic_pins.rxtx == LMIC_UNUSED_PIN)
|
if (lmic_pins.rxtx == LMIC_UNUSED_PIN)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
gpio_set_level(lmic_pins.rxtx, val);
|
gpio_set_level((gpio_num_t)lmic_pins.rxtx, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hal_pin_rst(u1_t val)
|
void hal_pin_rst(u1_t val)
|
||||||
@ -115,110 +115,85 @@ void hal_pin_rst(u1_t val)
|
|||||||
|
|
||||||
if (val == 0 || val == 1)
|
if (val == 0 || val == 1)
|
||||||
{ // drive pin
|
{ // drive pin
|
||||||
gpio_set_level(lmic_pins.rst, val);
|
gpio_set_level((gpio_num_t)lmic_pins.rst, val);
|
||||||
gpio_set_direction(lmic_pins.rst, GPIO_MODE_OUTPUT);
|
gpio_set_direction((gpio_num_t)lmic_pins.rst, GPIO_MODE_OUTPUT);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // keep pin floating
|
{ // keep pin floating
|
||||||
gpio_set_level(lmic_pins.rst, val);
|
gpio_set_level((gpio_num_t)lmic_pins.rst, val);
|
||||||
gpio_set_direction(lmic_pins.rst, GPIO_MODE_INPUT);
|
gpio_set_direction((gpio_num_t)lmic_pins.rst, GPIO_MODE_INPUT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
s1_t hal_getRssiCal (void) {
|
s1_t hal_getRssiCal (void)
|
||||||
|
{
|
||||||
return lmic_pins.rssi_cal;
|
return lmic_pins.rssi_cal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ostime_t hal_setModuleActive (bit_t val)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bit_t hal_queryUsingTcxo(void)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// SPI
|
// SPI
|
||||||
|
|
||||||
#define SPI_QUEUE_SIZE 4
|
void HAL_ESP32::spiInit()
|
||||||
#define SPI_NUM_TRX_SLOTS (SPI_QUEUE_SIZE + 1)
|
|
||||||
|
|
||||||
static spi_device_handle_t spi_handle;
|
|
||||||
static spi_transaction_t spi_trx_queue[SPI_NUM_TRX_SLOTS];
|
|
||||||
static int spi_trx_queue_head = 0;
|
|
||||||
static int spi_num_outstanding_trx = 0;
|
|
||||||
|
|
||||||
static spi_transaction_t* get_next_spi_trx_desc()
|
|
||||||
{
|
|
||||||
spi_transaction_t* trx = spi_trx_queue + spi_trx_queue_head;
|
|
||||||
memset(trx, 0, sizeof(spi_transaction_t));
|
|
||||||
return trx;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void collect_spi_result()
|
|
||||||
{
|
|
||||||
int head = spi_trx_queue_head;
|
|
||||||
int tail = head - spi_num_outstanding_trx;
|
|
||||||
if (tail < 0)
|
|
||||||
tail += SPI_NUM_TRX_SLOTS;
|
|
||||||
|
|
||||||
spi_transaction_t* trx;
|
|
||||||
esp_err_t err = spi_device_get_trans_result(spi_handle, &trx, 100 / portTICK_PERIOD_MS);
|
|
||||||
ESP_ERROR_CHECK(err);
|
|
||||||
ASSERT(trx == spi_trx_queue + tail);
|
|
||||||
spi_num_outstanding_trx--;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void submit_spi_trx()
|
|
||||||
{
|
|
||||||
if (spi_num_outstanding_trx >= SPI_QUEUE_SIZE)
|
|
||||||
collect_spi_result();
|
|
||||||
|
|
||||||
int head = spi_trx_queue_head;
|
|
||||||
esp_err_t err = spi_device_queue_trans(spi_handle, spi_trx_queue + head, 100 / portTICK_PERIOD_MS);
|
|
||||||
ESP_ERROR_CHECK(err);
|
|
||||||
spi_num_outstanding_trx++;
|
|
||||||
|
|
||||||
head++;
|
|
||||||
if (head >= SPI_NUM_TRX_SLOTS)
|
|
||||||
head = 0;
|
|
||||||
spi_trx_queue_head = head;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hal_spi_init()
|
|
||||||
{
|
{
|
||||||
// init device
|
// init device
|
||||||
spi_device_interface_config_t spi_device_intf_config = {
|
spi_device_interface_config_t spiConfig;
|
||||||
.mode = 1,
|
memset(&spiConfig, 0, sizeof(spiConfig));
|
||||||
.clock_speed_hz = CONFIG_TTN_SPI_FREQ,
|
spiConfig.mode = 1;
|
||||||
.command_bits = 0,
|
spiConfig.clock_speed_hz = CONFIG_TTN_SPI_FREQ;
|
||||||
.address_bits = 8,
|
spiConfig.command_bits = 0;
|
||||||
.spics_io_num = lmic_pins.nss,
|
spiConfig.address_bits = 8;
|
||||||
.queue_size = SPI_QUEUE_SIZE,
|
spiConfig.spics_io_num = lmic_pins.nss;
|
||||||
.cs_ena_posttrans = 2
|
spiConfig.queue_size = 1;
|
||||||
};
|
spiConfig.cs_ena_posttrans = 2;
|
||||||
|
|
||||||
esp_err_t ret = spi_bus_add_device(lmic_pins.spi_host, &spi_device_intf_config, &spi_handle);
|
esp_err_t ret = spi_bus_add_device(lmic_pins.spi_host, &spiConfig, &spiHandle);
|
||||||
ESP_ERROR_CHECK(ret);
|
ESP_ERROR_CHECK(ret);
|
||||||
|
|
||||||
ESP_LOGI(TAG, "SPI initialized");
|
ESP_LOGI(TAG, "SPI initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
void hal_spi_write(u1_t cmd, const u1_t *buf, int len)
|
void hal_spi_write(u1_t cmd, const u1_t *buf, size_t len)
|
||||||
{
|
{
|
||||||
spi_transaction_t* trx = get_next_spi_trx_desc();
|
ttn_hal.spiWrite(cmd, buf, len);
|
||||||
trx->addr = cmd;
|
|
||||||
trx->length = 8 * len;
|
|
||||||
trx->tx_buffer = buf;
|
|
||||||
submit_spi_trx();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void hal_spi_read(u1_t cmd, u1_t *buf, int len)
|
void HAL_ESP32::spiWrite(uint8_t cmd, const uint8_t *buf, size_t len)
|
||||||
|
{
|
||||||
|
memset(&spiTransaction, 0, sizeof(spiTransaction));
|
||||||
|
spiTransaction.addr = cmd;
|
||||||
|
spiTransaction.length = 8 * len;
|
||||||
|
spiTransaction.tx_buffer = buf;
|
||||||
|
esp_err_t err = spi_device_transmit(spiHandle, &spiTransaction);
|
||||||
|
ESP_ERROR_CHECK(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hal_spi_read(u1_t cmd, u1_t *buf, size_t len)
|
||||||
|
{
|
||||||
|
ttn_hal.spiRead(cmd, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HAL_ESP32::spiRead(uint8_t cmd, uint8_t *buf, size_t len)
|
||||||
{
|
{
|
||||||
memset(buf, 0, len);
|
memset(buf, 0, len);
|
||||||
spi_transaction_t* trx = get_next_spi_trx_desc();
|
memset(&spiTransaction, 0, sizeof(spiTransaction));
|
||||||
trx->addr = cmd;
|
spiTransaction.addr = cmd;
|
||||||
trx->length = 8 * len;
|
spiTransaction.length = 8 * len;
|
||||||
trx->rxlength = 8 * len;
|
spiTransaction.rxlength = 8 * len;
|
||||||
trx->tx_buffer = buf;
|
spiTransaction.tx_buffer = buf;
|
||||||
trx->rx_buffer = buf;
|
spiTransaction.rx_buffer = buf;
|
||||||
submit_spi_trx();
|
esp_err_t err = spi_device_transmit(spiHandle, &spiTransaction);
|
||||||
|
ESP_ERROR_CHECK(err);
|
||||||
while (spi_num_outstanding_trx > 0)
|
|
||||||
collect_spi_result();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@ -243,13 +218,9 @@ void hal_spi_read(u1_t cmd, u1_t *buf, int len)
|
|||||||
* by 0x100000000.
|
* by 0x100000000.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define OVERRUN_TRESHOLD 0x10000 // approx 10 seconds
|
static const ostime_t OVERRUN_TRESHOLD = 0x10000; // approx 10 seconds
|
||||||
|
|
||||||
static uint64_t next_timer_event = 0x200000000;
|
void HAL_ESP32::timerInit()
|
||||||
|
|
||||||
static void IRAM_ATTR hal_timer_irq_handler(void *arg);
|
|
||||||
|
|
||||||
static void hal_time_init()
|
|
||||||
{
|
{
|
||||||
timer_config_t config = {
|
timer_config_t config = {
|
||||||
.alarm_en = false,
|
.alarm_en = false,
|
||||||
@ -261,13 +232,13 @@ static void hal_time_init()
|
|||||||
};
|
};
|
||||||
timer_init(TTN_TIMER_GROUP, TTN_TIMER, &config);
|
timer_init(TTN_TIMER_GROUP, TTN_TIMER, &config);
|
||||||
timer_set_counter_value(TTN_TIMER_GROUP, TTN_TIMER, 0x0);
|
timer_set_counter_value(TTN_TIMER_GROUP, TTN_TIMER, 0x0);
|
||||||
timer_isr_register(TTN_TIMER_GROUP, TTN_TIMER, hal_timer_irq_handler, NULL, ESP_INTR_FLAG_IRAM, NULL);
|
timer_isr_register(TTN_TIMER_GROUP, TTN_TIMER, timerIrqHandler, NULL, ESP_INTR_FLAG_IRAM, NULL);
|
||||||
timer_start(TTN_TIMER_GROUP, TTN_TIMER);
|
timer_start(TTN_TIMER_GROUP, TTN_TIMER);
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Timer initialized");
|
ESP_LOGI(TAG, "Timer initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hal_prepare_next_alarm(u4_t time)
|
void HAL_ESP32::prepareNextAlarm(u4_t time)
|
||||||
{
|
{
|
||||||
uint64_t now;
|
uint64_t now;
|
||||||
timer_get_counter_value(TTN_TIMER_GROUP, TTN_TIMER, &now);
|
timer_get_counter_value(TTN_TIMER_GROUP, TTN_TIMER, &now);
|
||||||
@ -282,74 +253,65 @@ static void hal_prepare_next_alarm(u4_t time)
|
|||||||
timer_start(TTN_TIMER_GROUP, TTN_TIMER);
|
timer_start(TTN_TIMER_GROUP, TTN_TIMER);
|
||||||
}
|
}
|
||||||
|
|
||||||
next_timer_event = time;
|
nextTimerEvent = time;
|
||||||
if (now32 > time && now32 - time > OVERRUN_TRESHOLD)
|
if (now32 > time && now32 - time > OVERRUN_TRESHOLD)
|
||||||
next_timer_event += 0x100000000;
|
nextTimerEvent += 0x100000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hal_arm_timer()
|
void HAL_ESP32::armTimer()
|
||||||
{
|
{
|
||||||
timer_set_alarm(TTN_TIMER_GROUP, TTN_TIMER, TIMER_ALARM_DIS);
|
timer_set_alarm(TTN_TIMER_GROUP, TTN_TIMER, TIMER_ALARM_DIS);
|
||||||
timer_set_alarm_value(TTN_TIMER_GROUP, TTN_TIMER, next_timer_event);
|
timer_set_alarm_value(TTN_TIMER_GROUP, TTN_TIMER, nextTimerEvent);
|
||||||
timer_set_alarm(TTN_TIMER_GROUP, TTN_TIMER, TIMER_ALARM_EN);
|
timer_set_alarm(TTN_TIMER_GROUP, TTN_TIMER, TIMER_ALARM_EN);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hal_disarm_timer()
|
void HAL_ESP32::disarmTimer()
|
||||||
{
|
{
|
||||||
timer_set_alarm(TTN_TIMER_GROUP, TTN_TIMER, TIMER_ALARM_DIS);
|
timer_set_alarm(TTN_TIMER_GROUP, TTN_TIMER, TIMER_ALARM_DIS);
|
||||||
next_timer_event = 0x200000000; // wait indefinitely (almost)
|
nextTimerEvent = 0x200000000; // wait indefinitely (almost)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void IRAM_ATTR hal_timer_irq_handler(void *arg)
|
void IRAM_ATTR HAL_ESP32::timerIrqHandler(void *arg)
|
||||||
{
|
{
|
||||||
TTN_CLEAR_TIMER_ALARM;
|
TTN_CLEAR_TIMER_ALARM;
|
||||||
BaseType_t higher_prio_task_woken = pdFALSE;
|
BaseType_t higherPrioTaskWoken = pdFALSE;
|
||||||
queue_item_t item = {
|
HALQueueItem item { TIMER };
|
||||||
.ev = TIMER
|
xQueueSendFromISR(ttn_hal.dioQueue, &item, &higherPrioTaskWoken);
|
||||||
};
|
if (higherPrioTaskWoken)
|
||||||
|
|
||||||
xQueueSendFromISR(dio_queue, &item, &higher_prio_task_woken);
|
|
||||||
if (higher_prio_task_woken)
|
|
||||||
portYIELD_FROM_ISR();
|
portYIELD_FROM_ISR();
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef enum {
|
bool HAL_ESP32::wait(WaitKind waitKind)
|
||||||
CHECK_IO,
|
|
||||||
WAIT_FOR_ANY_EVENT,
|
|
||||||
WAIT_FOR_TIMER
|
|
||||||
} wait_open_e;
|
|
||||||
|
|
||||||
static bool hal_wait(wait_open_e wait_option)
|
|
||||||
{
|
{
|
||||||
TickType_t ticks_to_wait = wait_option == CHECK_IO ? 0 : portMAX_DELAY;
|
TickType_t ticksToWait = waitKind == CHECK_IO ? 0 : portMAX_DELAY;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
queue_item_t item;
|
HALQueueItem item;
|
||||||
if (xQueueReceive(dio_queue, &item, ticks_to_wait) == pdFALSE)
|
if (xQueueReceive(dioQueue, &item, ticksToWait) == pdFALSE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (item.ev == WAKEUP)
|
if (item.ev == WAKEUP)
|
||||||
{
|
{
|
||||||
if (wait_option != WAIT_FOR_TIMER)
|
if (waitKind != WAIT_FOR_TIMER)
|
||||||
{
|
{
|
||||||
hal_disarm_timer();
|
disarmTimer();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (item.ev == TIMER)
|
else if (item.ev == TIMER)
|
||||||
{
|
{
|
||||||
hal_disarm_timer();
|
disarmTimer();
|
||||||
if (wait_option != CHECK_IO)
|
if (waitKind != CHECK_IO)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else // IO interrupt
|
else // IO interrupt
|
||||||
{
|
{
|
||||||
if (wait_option != WAIT_FOR_TIMER)
|
if (waitKind != WAIT_FOR_TIMER)
|
||||||
hal_disarm_timer();
|
disarmTimer();
|
||||||
hal_enterCriticalSection();
|
enterCriticalSection();
|
||||||
radio_irq_handler_v2(item.ev, item.time);
|
radio_irq_handler_v2(item.ev, item.time);
|
||||||
hal_leaveCriticalSection();
|
leaveCriticalSection();
|
||||||
if (wait_option != WAIT_FOR_TIMER)
|
if (waitKind != WAIT_FOR_TIMER)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -364,21 +326,29 @@ u4_t hal_ticks()
|
|||||||
|
|
||||||
void hal_waitUntil(u4_t time)
|
void hal_waitUntil(u4_t time)
|
||||||
{
|
{
|
||||||
hal_prepare_next_alarm(time);
|
ttn_hal.waitUntil(time);
|
||||||
hal_arm_timer();
|
|
||||||
hal_wait(WAIT_FOR_TIMER);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void hal_wakeUp()
|
void HAL_ESP32::waitUntil(uint32_t time)
|
||||||
{
|
{
|
||||||
queue_item_t item = {
|
prepareNextAlarm(time);
|
||||||
.ev = WAKEUP
|
armTimer();
|
||||||
};
|
wait(WAIT_FOR_TIMER);
|
||||||
xQueueSend(dio_queue, &item, 0);
|
}
|
||||||
|
|
||||||
|
void HAL_ESP32::wakeUp()
|
||||||
|
{
|
||||||
|
HALQueueItem item { WAKEUP };
|
||||||
|
xQueueSend(dioQueue, &item, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// check and rewind for target time
|
// check and rewind for target time
|
||||||
u1_t hal_checkTimer(u4_t time)
|
u1_t hal_checkTimer(u4_t time)
|
||||||
|
{
|
||||||
|
return ttn_hal.checkTimer(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t HAL_ESP32::checkTimer(uint32_t time)
|
||||||
{
|
{
|
||||||
uint64_t now;
|
uint64_t now;
|
||||||
timer_get_counter_value(TTN_TIMER_GROUP, TTN_TIMER, &now);
|
timer_get_counter_value(TTN_TIMER_GROUP, TTN_TIMER, &now);
|
||||||
@ -395,19 +365,25 @@ u1_t hal_checkTimer(u4_t time)
|
|||||||
return 1; // timer has expired recently
|
return 1; // timer has expired recently
|
||||||
}
|
}
|
||||||
|
|
||||||
hal_prepare_next_alarm(time);
|
prepareNextAlarm(time);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void hal_sleep()
|
void hal_sleep()
|
||||||
{
|
{
|
||||||
if (hal_wait(CHECK_IO))
|
ttn_hal.sleep();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HAL_ESP32::sleep()
|
||||||
|
{
|
||||||
|
if (wait(CHECK_IO))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
hal_arm_timer();
|
armTimer();
|
||||||
hal_wait(WAIT_FOR_ANY_EVENT);
|
wait(WAIT_FOR_ANY_EVENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// IRQ
|
// IRQ
|
||||||
|
|
||||||
@ -423,44 +399,48 @@ void hal_enableIRQs()
|
|||||||
// and don't access any shared data structures
|
// and don't access any shared data structures
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
// Synchronization between application code and background task
|
// Synchronization between application code and background task
|
||||||
|
|
||||||
static SemaphoreHandle_t mutex;
|
void HAL_ESP32::initCriticalSection()
|
||||||
|
|
||||||
void hal_initCriticalSection()
|
|
||||||
{
|
{
|
||||||
mutex = xSemaphoreCreateRecursiveMutex();
|
mutex = xSemaphoreCreateRecursiveMutex();
|
||||||
}
|
}
|
||||||
|
|
||||||
void hal_enterCriticalSection()
|
void HAL_ESP32::enterCriticalSection()
|
||||||
{
|
{
|
||||||
xSemaphoreTakeRecursive(mutex, portMAX_DELAY);
|
xSemaphoreTakeRecursive(mutex, portMAX_DELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hal_leaveCriticalSection()
|
void HAL_ESP32::leaveCriticalSection()
|
||||||
{
|
{
|
||||||
xSemaphoreGiveRecursive(mutex);
|
xSemaphoreGiveRecursive(mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
static void hal_bgTask(void* pvParameter) {
|
void HAL_ESP32::backgroundTask(void* pvParameter) {
|
||||||
os_runloop();
|
os_runloop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void hal_init_ex(const void *pContext)
|
void hal_init_ex(const void *pContext)
|
||||||
{
|
{
|
||||||
// configure radio I/O and interrupt handler
|
ttn_hal.init();
|
||||||
hal_io_init();
|
|
||||||
// configure radio SPI
|
|
||||||
hal_spi_init();
|
|
||||||
// configure timer and interrupt handler
|
|
||||||
hal_time_init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void hal_startBgTask() {
|
void HAL_ESP32::init()
|
||||||
xTaskCreate(hal_bgTask, "ttn_lora_task", 1024 * 4, NULL, CONFIG_TTN_BG_TASK_PRIO, NULL);
|
{
|
||||||
|
// configure radio I/O and interrupt handler
|
||||||
|
ioInit();
|
||||||
|
// configure radio SPI
|
||||||
|
spiInit();
|
||||||
|
// configure timer and interrupt handler
|
||||||
|
timerInit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HAL_ESP32::startBackgroundTask() {
|
||||||
|
xTaskCreate(backgroundTask, "ttn_lora_task", 1024 * 4, NULL, CONFIG_TTN_BG_TASK_PRIO, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hal_failed(const char *file, u2_t line)
|
void hal_failed(const char *file, u2_t line)
|
@ -14,13 +14,13 @@
|
|||||||
#define _hal_esp32_h_
|
#define _hal_esp32_h_
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/queue.h>
|
||||||
#include "driver/spi_master.h"
|
#include "driver/spi_master.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef struct lmic_pinmap {
|
typedef struct lmic_pinmap {
|
||||||
spi_host_device_t spi_host;
|
spi_host_device_t spi_host;
|
||||||
uint8_t nss;
|
uint8_t nss;
|
||||||
uint8_t rxtx;
|
uint8_t rxtx;
|
||||||
@ -28,19 +28,67 @@ typedef struct lmic_pinmap {
|
|||||||
uint8_t dio0;
|
uint8_t dio0;
|
||||||
uint8_t dio1;
|
uint8_t dio1;
|
||||||
int8_t rssi_cal; // cal in dB -- added to RSSI measured prior to decision. Must include noise guardband!
|
int8_t rssi_cal; // cal in dB -- added to RSSI measured prior to decision. Must include noise guardband!
|
||||||
} lmic_pinmap;
|
} lmic_pinmap;
|
||||||
|
|
||||||
extern lmic_pinmap lmic_pins;
|
extern lmic_pinmap lmic_pins;
|
||||||
|
|
||||||
void hal_startBgTask();
|
|
||||||
void hal_wakeUp();
|
|
||||||
void hal_initCriticalSection();
|
|
||||||
void hal_enterCriticalSection();
|
|
||||||
void hal_leaveCriticalSection();
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
enum HAL_Event {
|
||||||
|
DIO0 = 0,
|
||||||
|
DIO1,
|
||||||
|
DIO2,
|
||||||
|
TIMER,
|
||||||
|
WAKEUP
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum WaitKind {
|
||||||
|
CHECK_IO,
|
||||||
|
WAIT_FOR_ANY_EVENT,
|
||||||
|
WAIT_FOR_TIMER
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class HAL_ESP32
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
HAL_ESP32();
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void startBackgroundTask();
|
||||||
|
void wakeUp();
|
||||||
|
void initCriticalSection();
|
||||||
|
void enterCriticalSection();
|
||||||
|
void leaveCriticalSection();
|
||||||
|
void spiWrite(uint8_t cmd, const uint8_t *buf, size_t len);
|
||||||
|
void spiRead(uint8_t cmd, uint8_t *buf, size_t len);
|
||||||
|
uint8_t checkTimer(uint32_t time);
|
||||||
|
void sleep();
|
||||||
|
void waitUntil(uint32_t time);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void backgroundTask(void* pvParameter);
|
||||||
|
static void dioIrqHandler(void* arg);
|
||||||
|
void ioInit();
|
||||||
|
void spiInit();
|
||||||
|
void timerInit();
|
||||||
|
void prepareNextAlarm(uint32_t time);
|
||||||
|
void armTimer();
|
||||||
|
void disarmTimer();
|
||||||
|
static void IRAM_ATTR timerIrqHandler(void *arg);
|
||||||
|
bool wait(WaitKind waitKind);
|
||||||
|
|
||||||
|
QueueHandle_t dioQueue;
|
||||||
|
spi_device_handle_t spiHandle;
|
||||||
|
spi_transaction_t spiTransaction;
|
||||||
|
uint64_t nextTimerEvent;
|
||||||
|
SemaphoreHandle_t mutex;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern HAL_ESP32 ttn_hal;
|
||||||
|
|
||||||
|
|
||||||
#endif // _hal_esp32_h_
|
#endif // _hal_esp32_h_
|
@ -123,15 +123,7 @@
|
|||||||
//#define DISABLE_MCMD_PING_SET // set ping freq, automatically disabled by DISABLE_PING
|
//#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
|
//#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
|
// DEPRECATED(tmm@mcci.com); replaced by LMIC.noRXIQinversion (dynamic). Don't define this.
|
||||||
// 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
|
//#define DISABLE_INVERT_IQ_ON_RX
|
||||||
|
|
||||||
// This allows choosing between multiple included AES implementations.
|
// This allows choosing between multiple included AES implementations.
|
||||||
@ -171,4 +163,31 @@
|
|||||||
# endif // defined(LMIC_DISABLE_DR_LEGACY)
|
# endif // defined(LMIC_DISABLE_DR_LEGACY)
|
||||||
#endif // LMIC_DR_LEGACY
|
#endif // LMIC_DR_LEGACY
|
||||||
|
|
||||||
|
// LMIC_ENABLE_DeviceTimeReq
|
||||||
|
// enable support for MCMD_DeviceTimeReq and MCMD_DeviceTimeAns
|
||||||
|
// this is always defined, and non-zero to enable it.
|
||||||
|
#if !defined(LMIC_ENABLE_DeviceTimeReq)
|
||||||
|
# define LMIC_ENABLE_DeviceTimeReq 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// LMIC_ENABLE_user_events
|
||||||
|
// Enable/disable support for programmable callbacks for events, rx, and tx.
|
||||||
|
// This is always defined, and non-zero to enable. Default is enabled.
|
||||||
|
#if !defined(LMIC_ENABLE_user_events)
|
||||||
|
# define LMIC_ENABLE_user_events 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// LMIC_ENABLE_onEvent
|
||||||
|
// Enable/disable support for out-call to user-supplied `onEvent()` function.
|
||||||
|
// This is always defined, and non-zero to enable. Default is enabled.
|
||||||
|
#if !defined(LMIC_ENABLE_onEvent)
|
||||||
|
# define LMIC_ENABLE_onEvent 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// LMIC_ENABLE_long_messages
|
||||||
|
// LMIC certification requires that this be enabled.
|
||||||
|
#if !defined(LMIC_ENABLE_long_messages)
|
||||||
|
# define LMIC_ENABLE_long_messages 1 /* PARAM */
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // _lmic_config_h_
|
#endif // _lmic_config_h_
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016 IBM Corporation.
|
* Copyright (c) 2014-2016 IBM Corporation.
|
||||||
* Copyright (c) 2016, 2018 MCCI Corporation.
|
* Copyright (c) 2016, 2018-2019 MCCI Corporation.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -26,30 +26,40 @@
|
|||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _hal_hpp_
|
#ifndef _lmic_hal_h_
|
||||||
#define _hal_hpp_
|
#define _lmic_hal_h_
|
||||||
|
|
||||||
|
#ifndef _oslmic_types_h_
|
||||||
|
# include "oslmic_types.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef _lmic_env_h_
|
||||||
|
# include "lmic_env.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"{
|
extern "C"{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// The type of an optional user-defined failure handler routine
|
||||||
|
typedef void LMIC_ABI_STD hal_failure_handler_t(const char* const file, const uint16_t line);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize hardware (IO, SPI, TIMER, IRQ).
|
* initialize hardware (IO, SPI, TIMER, IRQ).
|
||||||
|
* This API is deprecated as it uses the const global lmic_pins,
|
||||||
|
* which the platform can't control or change.
|
||||||
*/
|
*/
|
||||||
void hal_init (void);
|
void hal_init (void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* initialize hardware, passing in platform-specific context
|
* Initialize hardware, passing in platform-specific context
|
||||||
|
* The pointer is to a HalPinmap_t.
|
||||||
*/
|
*/
|
||||||
void hal_init_ex (const void *pContext);
|
void hal_init_ex (const void *pContext);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* drive radio NSS pin (0=low, 1=high).
|
* drive radio RX/TX pins (0=rx, 1=tx). Actual polarity
|
||||||
*/
|
* is determined by the value of HalPinmap_t::rxtx_rx_active.
|
||||||
void hal_pin_nss (u1_t val);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* drive radio RX/TX pins (0=rx, 1=tx).
|
|
||||||
*/
|
*/
|
||||||
void hal_pin_rxtx (u1_t val);
|
void hal_pin_rxtx (u1_t val);
|
||||||
|
|
||||||
@ -58,29 +68,19 @@ void hal_pin_rxtx (u1_t val);
|
|||||||
*/
|
*/
|
||||||
void hal_pin_rst (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
|
* Perform SPI write transaction with radio chip
|
||||||
* - write the command byte 'cmd'
|
* - write the command byte 'cmd'
|
||||||
* - write 'len' bytes in 'buf'
|
* - write 'len' bytes out of 'buf'
|
||||||
*/
|
*/
|
||||||
void hal_spi_write(u1_t cmd, const u1_t* buf, int len);
|
void hal_spi_write(u1_t cmd, const u1_t* buf, size_t len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* perform SPI read transaction with radio
|
* Perform SPI read transaction with radio chip
|
||||||
* - write the command byte 'cmd'
|
* - write the command byte 'cmd'
|
||||||
* - read 'len' bytes into 'buf'
|
* - read 'len' bytes into 'buf'
|
||||||
*/
|
*/
|
||||||
void hal_spi_read(u1_t cmd, u1_t* buf, int len);
|
void hal_spi_read(u1_t cmd, u1_t* buf, size_t 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.
|
* disable all CPU interrupts.
|
||||||
@ -94,6 +94,11 @@ void hal_disableIRQs (void);
|
|||||||
*/
|
*/
|
||||||
void hal_enableIRQs (void);
|
void hal_enableIRQs (void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* return CPU interrupt nesting count
|
||||||
|
*/
|
||||||
|
uint8_t hal_getIrqLevel (void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* put system and CPU in low-power mode, sleep until interrupt.
|
* put system and CPU in low-power mode, sleep until interrupt.
|
||||||
*/
|
*/
|
||||||
@ -123,13 +128,29 @@ u1_t hal_checkTimer (u4_t targettime);
|
|||||||
*/
|
*/
|
||||||
void hal_failed (const char *file, u2_t line);
|
void hal_failed (const char *file, u2_t line);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* set a custom hal failure handler routine. The default behaviour, defined in
|
||||||
|
* hal_failed(), is to halt by looping infintely.
|
||||||
|
*/
|
||||||
|
void hal_set_failure_handler(const hal_failure_handler_t* const);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get the calibration value for radio_rssi
|
* get the calibration value for radio_rssi
|
||||||
*/
|
*/
|
||||||
s1_t hal_getRssiCal (void);
|
s1_t hal_getRssiCal (void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* control the radio state
|
||||||
|
* - if val == 0, turn tcxo off and otherwise prepare for sleep
|
||||||
|
* - if val == 1, turn tcxo on and otherwise prep for activity
|
||||||
|
* - return the number of ticks that we need to wait
|
||||||
|
*/
|
||||||
|
ostime_t hal_setModuleActive (bit_t val);
|
||||||
|
|
||||||
|
bit_t hal_queryUsingTcxo(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // _hal_hpp_
|
#endif // _lmic_hal_h_
|
||||||
|
713
src/lmic/lmic.c
Normal file → Executable file
713
src/lmic/lmic.c
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
262
src/lmic/lmic.h
Normal file → Executable file
262
src/lmic/lmic.h
Normal file → Executable file
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016 IBM Corporation.
|
* Copyright (c) 2014-2016 IBM Corporation.
|
||||||
* Copyright (c) 2016 Matthijs Kooijman.
|
* Copyright (c) 2016 Matthijs Kooijman.
|
||||||
* Copyright (c) 2016-2018 MCCI Corporation.
|
* Copyright (c) 2016-2019 MCCI Corporation.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -105,7 +105,7 @@ extern "C"{
|
|||||||
#define ARDUINO_LMIC_VERSION_CALC(major, minor, patch, local) \
|
#define ARDUINO_LMIC_VERSION_CALC(major, minor, patch, local) \
|
||||||
(((major) << 24u) | ((minor) << 16u) | ((patch) << 8u) | (local))
|
(((major) << 24u) | ((minor) << 16u) | ((patch) << 8u) | (local))
|
||||||
|
|
||||||
#define ARDUINO_LMIC_VERSION ARDUINO_LMIC_VERSION_CALC(2, 2, 2, 0)
|
#define ARDUINO_LMIC_VERSION ARDUINO_LMIC_VERSION_CALC(2, 3, 2, 50) /* v2.3.2.50 */
|
||||||
|
|
||||||
#define ARDUINO_LMIC_VERSION_GET_MAJOR(v) \
|
#define ARDUINO_LMIC_VERSION_GET_MAJOR(v) \
|
||||||
(((v) >> 24u) & 0xFFu)
|
(((v) >> 24u) & 0xFFu)
|
||||||
@ -122,14 +122,17 @@ extern "C"{
|
|||||||
//! Only For Antenna Tuning Tests !
|
//! Only For Antenna Tuning Tests !
|
||||||
//#define CFG_TxContinuousMode 1
|
//#define CFG_TxContinuousMode 1
|
||||||
|
|
||||||
enum { MAX_FRAME_LEN = 64 }; //!< Library cap on max frame length
|
// since this was annouunced as the API variable, we keep it. But it's not used,
|
||||||
|
// MAX_LEN_FRAME is what the code uses.
|
||||||
|
enum { MAX_FRAME_LEN = MAX_LEN_FRAME }; //!< Library cap on max frame length
|
||||||
|
|
||||||
enum { TXCONF_ATTEMPTS = 8 }; //!< Transmit attempts for confirmed frames
|
enum { TXCONF_ATTEMPTS = 8 }; //!< Transmit attempts for confirmed frames
|
||||||
enum { MAX_MISSED_BCNS = 20 }; // threshold for triggering rejoin requests
|
enum { MAX_MISSED_BCNS = 20 }; // threshold for triggering rejoin requests
|
||||||
enum { MAX_RXSYMS = 100 }; // stop tracking beacon beyond this
|
enum { MAX_RXSYMS = 100 }; // stop tracking beacon beyond this
|
||||||
|
|
||||||
enum { LINK_CHECK_CONT = 12 , // continue with this after reported dead link
|
enum { LINK_CHECK_CONT = 0 , // continue with this after reported dead link
|
||||||
LINK_CHECK_DEAD = 24 , // after this UP frames and no response from NWK assume link is dead
|
LINK_CHECK_DEAD = 32 , // after this UP frames and no response to ack from NWK assume link is dead (ADR_ACK_DELAY)
|
||||||
LINK_CHECK_INIT = -12 , // UP frame count until we inc datarate
|
LINK_CHECK_INIT = -64 , // UP frame count until we ask for ack (ADR_ACK_LIMIT)
|
||||||
LINK_CHECK_OFF =-128 }; // link check disabled
|
LINK_CHECK_OFF =-128 }; // link check disabled
|
||||||
|
|
||||||
enum { TIME_RESYNC = 6*128 }; // secs
|
enum { TIME_RESYNC = 6*128 }; // secs
|
||||||
@ -153,12 +156,23 @@ struct band_t {
|
|||||||
};
|
};
|
||||||
TYPEDEF_xref2band_t; //!< \internal
|
TYPEDEF_xref2band_t; //!< \internal
|
||||||
|
|
||||||
|
struct lmic_saved_adr_state_s {
|
||||||
|
u4_t channelFreq[MAX_CHANNELS];
|
||||||
|
u2_t channelMap;
|
||||||
|
};
|
||||||
|
|
||||||
#elif CFG_LMIC_US_like // US915 spectrum =================================================
|
#elif CFG_LMIC_US_like // US915 spectrum =================================================
|
||||||
|
|
||||||
enum { MAX_XCHANNELS = 2 }; // extra channels in RAM, channels 0-71 are immutable
|
enum { MAX_XCHANNELS = 2 }; // extra channels in RAM, channels 0-71 are immutable
|
||||||
|
|
||||||
|
struct lmic_saved_adr_state_s {
|
||||||
|
u2_t channelMap[(72+MAX_XCHANNELS+15)/16]; // enabled bits
|
||||||
|
};
|
||||||
|
|
||||||
#endif // ==========================================================================
|
#endif // ==========================================================================
|
||||||
|
|
||||||
|
typedef struct lmic_saved_adr_state_s lmic_saved_adr_state_t;
|
||||||
|
|
||||||
// Keep in sync with evdefs.hpp::drChange
|
// Keep in sync with evdefs.hpp::drChange
|
||||||
enum { DRCHG_SET, DRCHG_NOJACC, DRCHG_NOACK, DRCHG_NOADRACK, DRCHG_NWKCMD };
|
enum { DRCHG_SET, DRCHG_NOJACC, DRCHG_NOACK, DRCHG_NOADRACK, DRCHG_NWKCMD };
|
||||||
enum { KEEP_TXPOW = -128 };
|
enum { KEEP_TXPOW = -128 };
|
||||||
@ -189,14 +203,14 @@ enum { BCN_NONE = 0x00, //!< No beacon received
|
|||||||
//! Information about the last and previous beacons.
|
//! Information about the last and previous beacons.
|
||||||
struct bcninfo_t {
|
struct bcninfo_t {
|
||||||
ostime_t txtime; //!< Time when the beacon was sent
|
ostime_t txtime; //!< Time when the beacon was sent
|
||||||
|
u4_t time; //!< GPS time in seconds of last beacon (received or surrogate)
|
||||||
|
s4_t lat; //!< Lat field of last beacon (valid only if BCN_FULL set)
|
||||||
|
s4_t lon; //!< Lon field of last beacon (valid only if BCN_FULL set)
|
||||||
s1_t rssi; //!< Adjusted RSSI value of last received beacon
|
s1_t rssi; //!< Adjusted RSSI value of last received beacon
|
||||||
s1_t snr; //!< Scaled SNR value of last received beacon
|
s1_t snr; //!< Scaled SNR value of last received beacon
|
||||||
u1_t flags; //!< Last beacon reception and tracking states. See BCN_* values.
|
u1_t flags; //!< Last beacon reception and tracking states. See BCN_* values.
|
||||||
u4_t time; //!< GPS time in seconds of last beacon (received or surrogate)
|
|
||||||
//
|
//
|
||||||
u1_t info; //!< Info field of last beacon (valid only if BCN_FULL set)
|
u1_t info; //!< Info field of last beacon (valid only if BCN_FULL set)
|
||||||
s4_t lat; //!< Lat field of last beacon (valid only if BCN_FULL set)
|
|
||||||
s4_t lon; //!< Lon field of last beacon (valid only if BCN_FULL set)
|
|
||||||
};
|
};
|
||||||
#endif // !DISABLE_BEACONS
|
#endif // !DISABLE_BEACONS
|
||||||
|
|
||||||
@ -235,7 +249,7 @@ enum _ev_t { EV_SCAN_TIMEOUT=1, EV_BEACON_FOUND,
|
|||||||
EV_JOINED, EV_RFU1, EV_JOIN_FAILED, EV_REJOIN_FAILED,
|
EV_JOINED, EV_RFU1, EV_JOIN_FAILED, EV_REJOIN_FAILED,
|
||||||
EV_TXCOMPLETE, EV_LOST_TSYNC, EV_RESET,
|
EV_TXCOMPLETE, EV_LOST_TSYNC, EV_RESET,
|
||||||
EV_RXCOMPLETE, EV_LINK_DEAD, EV_LINK_ALIVE, EV_SCAN_FOUND,
|
EV_RXCOMPLETE, EV_LINK_DEAD, EV_LINK_ALIVE, EV_SCAN_FOUND,
|
||||||
EV_TXSTART };
|
EV_TXSTART, EV_TXCANCELED, EV_RXSTART, EV_JOIN_TXCOMPLETE };
|
||||||
typedef enum _ev_t ev_t;
|
typedef enum _ev_t ev_t;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@ -243,26 +257,143 @@ enum {
|
|||||||
MAX_CLOCK_ERROR = 65536,
|
MAX_CLOCK_ERROR = 65536,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// callbacks for client alerts.
|
||||||
|
// types and functions are always defined, to reduce #ifs in example code and libraries.
|
||||||
|
typedef void LMIC_ABI_STD lmic_rxmessage_cb_t(void *pUserData, uint8_t port, const uint8_t *pMessage, size_t nMessage);
|
||||||
|
typedef void LMIC_ABI_STD lmic_txmessage_cb_t(void *pUserData, int fSuccess);
|
||||||
|
typedef void LMIC_ABI_STD lmic_event_cb_t(void *pUserData, ev_t e);
|
||||||
|
|
||||||
|
// network time request callback function
|
||||||
|
// defined unconditionally, because APIs and types can't change based on config.
|
||||||
|
// This is called when a time-request succeeds or when we get a downlink
|
||||||
|
// without time request, "completing" the pending time request.
|
||||||
|
typedef void LMIC_ABI_STD lmic_request_network_time_cb_t(void *pUserData, int flagSuccess);
|
||||||
|
|
||||||
|
// how the network represents time.
|
||||||
|
typedef u4_t lmic_gpstime_t;
|
||||||
|
|
||||||
|
// rather than deal with 1/256 second tick, we adjust ostime back
|
||||||
|
// (as it's high res) to match tNetwork.
|
||||||
|
typedef struct lmic_time_reference_s lmic_time_reference_t;
|
||||||
|
|
||||||
|
struct lmic_time_reference_s {
|
||||||
|
// our best idea of when we sent the uplink (end of packet).
|
||||||
|
ostime_t tLocal;
|
||||||
|
// the network's best idea of when we sent the uplink.
|
||||||
|
lmic_gpstime_t tNetwork;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum lmic_request_time_state_e {
|
||||||
|
lmic_RequestTimeState_idle = 0, // we're not doing anything
|
||||||
|
lmic_RequestTimeState_tx, // we want to tx a time request on next uplink
|
||||||
|
lmic_RequestTimeState_rx, // we have tx'ed, next downlink completes.
|
||||||
|
lmic_RequestTimeState_success // we sucessfully got time.
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef u1_t lmic_request_time_state_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Structure: lmic_client_data_t
|
||||||
|
|
||||||
|
Function:
|
||||||
|
Holds LMIC client data that must live through LMIC_reset().
|
||||||
|
|
||||||
|
Description:
|
||||||
|
There are a variety of client registration linkage items that
|
||||||
|
must live through LMIC_reset(), because LMIC_reset() is called
|
||||||
|
at frame rollover time. We group them together into a structure
|
||||||
|
to make copies easy.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
//! abstract type for collection of client data that survives LMIC_reset().
|
||||||
|
typedef struct lmic_client_data_s lmic_client_data_t;
|
||||||
|
|
||||||
|
//! contents of lmic_client_data_t
|
||||||
|
struct lmic_client_data_s {
|
||||||
|
|
||||||
|
/* pointer-width things come first */
|
||||||
|
#if LMIC_ENABLE_DeviceTimeReq
|
||||||
|
lmic_request_network_time_cb_t *pNetworkTimeCb; //! call-back routine for network time
|
||||||
|
void *pNetworkTimeUserData; //! call-back data for network time.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LMIC_ENABLE_user_events
|
||||||
|
lmic_event_cb_t *eventCb; //! user-supplied callback function for events.
|
||||||
|
void *eventUserData; //! data for eventCb
|
||||||
|
lmic_rxmessage_cb_t *rxMessageCb; //! user-supplied message-received callback
|
||||||
|
void *rxMessageUserData; //! data for rxMessageCb
|
||||||
|
lmic_txmessage_cb_t *txMessageCb; //! transmit-complete message handler; reset on each tx complete.
|
||||||
|
void *txMessageUserData; //! data for txMessageCb.
|
||||||
|
#endif // LMIC_ENABLE_user_events
|
||||||
|
|
||||||
|
/* next we have things that are (u)int32_t */
|
||||||
|
/* none at the moment */
|
||||||
|
|
||||||
|
/* next we have things that are (u)int16_t */
|
||||||
|
|
||||||
|
u2_t clockError; //! Inaccuracy in the clock. CLOCK_ERROR_MAX represents +/-100% error
|
||||||
|
|
||||||
|
/* finally, things that are (u)int8_t */
|
||||||
|
/* none at the moment */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Structure: lmic_t
|
||||||
|
|
||||||
|
Function:
|
||||||
|
Provides the instance data for the LMIC.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
struct lmic_t {
|
struct lmic_t {
|
||||||
|
// client setup data, survives LMIC_reset().
|
||||||
|
lmic_client_data_t client;
|
||||||
|
|
||||||
|
// the OS job object. pointer alignment.
|
||||||
|
osjob_t osjob;
|
||||||
|
|
||||||
|
#if !defined(DISABLE_BEACONS)
|
||||||
|
bcninfo_t bcninfo; // Last received beacon info
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(DISABLE_PING)
|
||||||
|
rxsched_t ping; // pingable setup
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* (u)int32_t things */
|
||||||
|
|
||||||
// Radio settings TX/RX (also accessed by HAL)
|
// Radio settings TX/RX (also accessed by HAL)
|
||||||
ostime_t txend;
|
ostime_t txend;
|
||||||
ostime_t rxtime;
|
ostime_t rxtime;
|
||||||
|
|
||||||
// LBT info
|
// LBT info
|
||||||
ostime_t lbt_ticks; // ticks to listen
|
ostime_t lbt_ticks; // ticks to listen
|
||||||
s1_t lbt_dbmax; // max permissible dB on our channel (eg -80)
|
|
||||||
|
|
||||||
u4_t freq;
|
u4_t freq;
|
||||||
s1_t rssi;
|
|
||||||
s1_t snr; // LMIC.snr is SNR times 4
|
|
||||||
rps_t rps;
|
|
||||||
u1_t rxsyms;
|
|
||||||
u1_t dndr;
|
|
||||||
s1_t txpow; // dBm
|
|
||||||
|
|
||||||
osjob_t osjob;
|
ostime_t globalDutyAvail; // time device can send again
|
||||||
|
|
||||||
// Channel scheduling
|
u4_t netid; // current network id (~0 - none)
|
||||||
|
devaddr_t devaddr;
|
||||||
|
u4_t seqnoDn; // device level down stream seqno
|
||||||
|
u4_t seqnoUp;
|
||||||
|
u4_t dn2Freq;
|
||||||
|
|
||||||
|
#if !defined(DISABLE_BEACONS)
|
||||||
|
ostime_t bcnRxtime;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if LMIC_ENABLE_DeviceTimeReq
|
||||||
|
// put here for alignment, to reduce RAM use.
|
||||||
|
ostime_t localDeviceTime; // the LMIC.txend value for last DeviceTimeAns
|
||||||
|
lmic_gpstime_t netDeviceTime; // the netDeviceTime for lastDeviceTimeAns
|
||||||
|
// zero ==> not valid.
|
||||||
|
#endif // LMIC_ENABLE_DeviceTimeReq
|
||||||
|
|
||||||
|
// Channel scheduling -- very much private
|
||||||
#if CFG_LMIC_EU_like
|
#if CFG_LMIC_EU_like
|
||||||
band_t bands[MAX_BANDS];
|
band_t bands[MAX_BANDS];
|
||||||
u4_t channelFreq[MAX_CHANNELS];
|
u4_t channelFreq[MAX_CHANNELS];
|
||||||
@ -275,37 +406,46 @@ struct lmic_t {
|
|||||||
u2_t activeChannels125khz;
|
u2_t activeChannels125khz;
|
||||||
u2_t activeChannels500khz;
|
u2_t activeChannels500khz;
|
||||||
#endif
|
#endif
|
||||||
u1_t txChnl; // channel for next TX
|
|
||||||
u1_t globalDutyRate; // max rate: 1/2^k
|
|
||||||
ostime_t globalDutyAvail; // time device can send again
|
|
||||||
|
|
||||||
u4_t netid; // current network id (~0 - none)
|
/* (u)int16_t things */
|
||||||
u2_t opmode;
|
|
||||||
u1_t upRepeat; // configured up repeat
|
rps_t rps; // radio parameter selections: SF, BW, CodingRate, NoCrc, implicit hdr
|
||||||
s1_t adrTxPow; // ADR adjusted TX power
|
u2_t opmode; // engineUpdate() operating mode flags
|
||||||
u1_t datarate; // current data rate
|
u2_t devNonce; // last generated nonce
|
||||||
u1_t errcr; // error coding rate (used for TX only)
|
|
||||||
u1_t rejoinCnt; // adjustment for rejoin datarate
|
|
||||||
#if !defined(DISABLE_BEACONS)
|
#if !defined(DISABLE_BEACONS)
|
||||||
s2_t drift; // last measured drift
|
s2_t drift; // last measured drift
|
||||||
s2_t lastDriftDiff;
|
s2_t lastDriftDiff;
|
||||||
s2_t maxDriftDiff;
|
s2_t maxDriftDiff;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
u2_t clockError; // Inaccuracy in the clock. CLOCK_ERROR_MAX
|
/* (u)int8_t things */
|
||||||
// represents +/-100% error
|
s1_t rssi;
|
||||||
|
s1_t snr; // LMIC.snr is SNR times 4
|
||||||
|
u1_t rxsyms;
|
||||||
|
u1_t dndr;
|
||||||
|
s1_t txpow; // transmit dBm (administrative)
|
||||||
|
s1_t radio_txpow; // the radio driver's copy of txpow, limited by adrTxPow.
|
||||||
|
s1_t lbt_dbmax; // max permissible dB on our channel (eg -80)
|
||||||
|
|
||||||
|
u1_t txChnl; // channel for next TX
|
||||||
|
u1_t globalDutyRate; // max rate: 1/2^k
|
||||||
|
|
||||||
|
u1_t upRepeat; // configured up repeat
|
||||||
|
s1_t adrTxPow; // ADR adjusted TX power
|
||||||
|
u1_t datarate; // current data rate
|
||||||
|
u1_t errcr; // error coding rate (used for TX only)
|
||||||
|
u1_t rejoinCnt; // adjustment for rejoin datarate
|
||||||
|
|
||||||
|
bit_t initBandplanAfterReset; // cleared by LMIC_reset(), set by first join. See issue #244
|
||||||
|
|
||||||
u1_t pendTxPort;
|
u1_t pendTxPort;
|
||||||
u1_t pendTxConf; // confirmed data
|
u1_t pendTxConf; // confirmed data
|
||||||
u1_t pendTxLen; // +0x80 = confirmed
|
u1_t pendTxLen; // +0x80 = confirmed
|
||||||
u1_t pendTxData[MAX_LEN_PAYLOAD];
|
u1_t pendTxData[MAX_LEN_PAYLOAD];
|
||||||
|
|
||||||
u2_t devNonce; // last generated nonce
|
|
||||||
u1_t nwkKey[16]; // network session key
|
u1_t nwkKey[16]; // network session key
|
||||||
u1_t artKey[16]; // application router session key
|
u1_t artKey[16]; // application router session key
|
||||||
devaddr_t devaddr;
|
|
||||||
u4_t seqnoDn; // device level down stream seqno
|
|
||||||
u4_t seqnoUp;
|
|
||||||
|
|
||||||
u1_t dnConf; // dn frame confirm pending: LORA::FCT_ACK or 0
|
u1_t dnConf; // dn frame confirm pending: LORA::FCT_ACK or 0
|
||||||
s1_t adrAckReq; // counter until we reset data rate (0=off)
|
s1_t adrAckReq; // counter until we reset data rate (0=off)
|
||||||
@ -329,13 +469,16 @@ struct lmic_t {
|
|||||||
bit_t txParamSetupAns; // transmit setup answer pending.
|
bit_t txParamSetupAns; // transmit setup answer pending.
|
||||||
u1_t txParam; // the saved TX param byte.
|
u1_t txParam; // the saved TX param byte.
|
||||||
#endif
|
#endif
|
||||||
|
#if LMIC_ENABLE_DeviceTimeReq
|
||||||
|
lmic_request_time_state_t txDeviceTimeReqState; // current state, initially idle.
|
||||||
|
u1_t netDeviceTimeFrac; // updated on any DeviceTimeAns.
|
||||||
|
#endif
|
||||||
|
|
||||||
// rx1DrOffset is the offset from uplink to downlink datarate
|
// rx1DrOffset is the offset from uplink to downlink datarate
|
||||||
u1_t rx1DrOffset; // captured from join. zero by default.
|
u1_t rx1DrOffset; // captured from join. zero by default.
|
||||||
|
|
||||||
// 2nd RX window (after up stream)
|
// 2nd RX window (after up stream)
|
||||||
u1_t dn2Dr;
|
u1_t dn2Dr;
|
||||||
u4_t dn2Freq;
|
|
||||||
#if !defined(DISABLE_MCMD_DN2P_SET)
|
#if !defined(DISABLE_MCMD_DN2P_SET)
|
||||||
u1_t dn2Ans; // 0=no answer pend, 0x80+ACKs
|
u1_t dn2Ans; // 0=no answer pend, 0x80+ACKs
|
||||||
#endif
|
#endif
|
||||||
@ -348,10 +491,6 @@ struct lmic_t {
|
|||||||
#if !defined(DISABLE_MCMD_PING_SET) && !defined(DISABLE_PING)
|
#if !defined(DISABLE_MCMD_PING_SET) && !defined(DISABLE_PING)
|
||||||
u1_t pingSetAns; // answer set cmd and ACK bits
|
u1_t pingSetAns; // answer set cmd and ACK bits
|
||||||
#endif
|
#endif
|
||||||
#if !defined(DISABLE_PING)
|
|
||||||
rxsched_t ping; // pingable setup
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Public part of MAC state
|
// Public part of MAC state
|
||||||
u1_t txCnt;
|
u1_t txCnt;
|
||||||
u1_t txrxFlags; // transaction flags (TX-RX combo)
|
u1_t txrxFlags; // transaction flags (TX-RX combo)
|
||||||
@ -362,12 +501,12 @@ struct lmic_t {
|
|||||||
#if !defined(DISABLE_BEACONS)
|
#if !defined(DISABLE_BEACONS)
|
||||||
u1_t bcnChnl;
|
u1_t bcnChnl;
|
||||||
u1_t bcnRxsyms; //
|
u1_t bcnRxsyms; //
|
||||||
ostime_t bcnRxtime;
|
|
||||||
bcninfo_t bcninfo; // Last received beacon info
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
u1_t noRXIQinversion;
|
u1_t noRXIQinversion;
|
||||||
|
u1_t saveIrqFlags; // last LoRa IRQ flags
|
||||||
};
|
};
|
||||||
|
|
||||||
//! \var struct lmic_t LMIC
|
//! \var struct lmic_t LMIC
|
||||||
//! The state of LMIC MAC layer is encapsulated in this variable.
|
//! The state of LMIC MAC layer is encapsulated in this variable.
|
||||||
DECLARE_LMIC; //!< \internal
|
DECLARE_LMIC; //!< \internal
|
||||||
@ -376,16 +515,19 @@ DECLARE_LMIC; //!< \internal
|
|||||||
#define DR_RANGE_MAP(drlo,drhi) (((u2_t)0xFFFF<<(drlo)) & ((u2_t)0xFFFF>>(15-(drhi))))
|
#define DR_RANGE_MAP(drlo,drhi) (((u2_t)0xFFFF<<(drlo)) & ((u2_t)0xFFFF>>(15-(drhi))))
|
||||||
bit_t LMIC_setupBand (u1_t bandidx, s1_t txpow, u2_t txcap);
|
bit_t LMIC_setupBand (u1_t bandidx, s1_t txpow, u2_t txcap);
|
||||||
bit_t LMIC_setupChannel (u1_t channel, u4_t freq, u2_t drmap, s1_t band);
|
bit_t LMIC_setupChannel (u1_t channel, u4_t freq, u2_t drmap, s1_t band);
|
||||||
void LMIC_disableChannel (u1_t channel);
|
bit_t LMIC_disableChannel (u1_t channel);
|
||||||
void LMIC_enableSubBand(u1_t band);
|
bit_t LMIC_enableSubBand(u1_t band);
|
||||||
void LMIC_enableChannel(u1_t channel);
|
bit_t LMIC_enableChannel(u1_t channel);
|
||||||
void LMIC_disableSubBand(u1_t band);
|
bit_t LMIC_disableSubBand(u1_t band);
|
||||||
void LMIC_selectSubBand(u1_t band);
|
bit_t LMIC_selectSubBand(u1_t band);
|
||||||
|
|
||||||
void LMIC_setDrTxpow (dr_t dr, s1_t txpow); // set default/start DR/txpow
|
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)
|
void LMIC_setAdrMode (bit_t enabled); // set ADR mode (if mobile turn off)
|
||||||
|
|
||||||
#if !defined(DISABLE_JOIN)
|
#if !defined(DISABLE_JOIN)
|
||||||
bit_t LMIC_startJoining (void);
|
bit_t LMIC_startJoining (void);
|
||||||
|
void LMIC_tryRejoin (void);
|
||||||
|
void LMIC_unjoin (void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void LMIC_shutdown (void);
|
void LMIC_shutdown (void);
|
||||||
@ -394,6 +536,7 @@ void LMIC_reset (void);
|
|||||||
void LMIC_clrTxData (void);
|
void LMIC_clrTxData (void);
|
||||||
void LMIC_setTxData (void);
|
void LMIC_setTxData (void);
|
||||||
int LMIC_setTxData2 (u1_t port, xref2u1_t data, u1_t dlen, u1_t confirmed);
|
int LMIC_setTxData2 (u1_t port, xref2u1_t data, u1_t dlen, u1_t confirmed);
|
||||||
|
int LMIC_sendWithCallback(u1_t port, xref2u1_t data, u1_t dlen, u1_t confirmed, lmic_txmessage_cb_t *pCb, void *pUserData);
|
||||||
void LMIC_sendAlive (void);
|
void LMIC_sendAlive (void);
|
||||||
|
|
||||||
#if !defined(DISABLE_BEACONS)
|
#if !defined(DISABLE_BEACONS)
|
||||||
@ -405,9 +548,6 @@ void LMIC_disableTracking (void);
|
|||||||
void LMIC_stopPingable (void);
|
void LMIC_stopPingable (void);
|
||||||
void LMIC_setPingable (u1_t intvExp);
|
void LMIC_setPingable (u1_t intvExp);
|
||||||
#endif
|
#endif
|
||||||
#if !defined(DISABLE_JOIN)
|
|
||||||
void LMIC_tryRejoin (void);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void LMIC_setSession (u4_t netid, devaddr_t devaddr, xref2u1_t nwkKey, xref2u1_t artKey);
|
void LMIC_setSession (u4_t netid, devaddr_t devaddr, xref2u1_t nwkKey, xref2u1_t artKey);
|
||||||
void LMIC_setLinkCheckMode (bit_t enabled);
|
void LMIC_setLinkCheckMode (bit_t enabled);
|
||||||
@ -417,11 +557,29 @@ u4_t LMIC_getSeqnoUp (void);
|
|||||||
u4_t LMIC_setSeqnoUp (u4_t);
|
u4_t LMIC_setSeqnoUp (u4_t);
|
||||||
void LMIC_getSessionKeys (u4_t *netid, devaddr_t *devaddr, xref2u1_t nwkKey, xref2u1_t artKey);
|
void LMIC_getSessionKeys (u4_t *netid, devaddr_t *devaddr, xref2u1_t nwkKey, xref2u1_t artKey);
|
||||||
|
|
||||||
|
void LMIC_requestNetworkTime(lmic_request_network_time_cb_t *pCallbackfn, void *pUserData);
|
||||||
|
int LMIC_getNetworkTimeReference(lmic_time_reference_t *pReference);
|
||||||
|
|
||||||
|
int LMIC_registerRxMessageCb(lmic_rxmessage_cb_t *pRxMessageCb, void *pUserData);
|
||||||
|
int LMIC_registerEventCb(lmic_event_cb_t *pEventCb, void *pUserData);
|
||||||
|
|
||||||
|
// APIs for client half of compliance.
|
||||||
|
typedef u1_t lmic_compliance_rx_action_t;
|
||||||
|
|
||||||
|
enum lmic_compliance_rx_action_e {
|
||||||
|
LMIC_COMPLIANCE_RX_ACTION_PROCESS = 0, // process this message normally
|
||||||
|
LMIC_COMPLIANCE_RX_ACTION_START, // enter compliance mode, discard this message
|
||||||
|
LMIC_COMPLIANCE_RX_ACTION_IGNORE, // continue in compliance mode, discard this message
|
||||||
|
LMIC_COMPLIANCE_RX_ACTION_END // exit compliance mode, discard this message
|
||||||
|
};
|
||||||
|
|
||||||
|
lmic_compliance_rx_action_t LMIC_complianceRxMessage(u1_t port, const u1_t *pMessage, size_t nMessage);
|
||||||
|
|
||||||
// Declare onEvent() function, to make sure any definition will have the
|
// Declare onEvent() function, to make sure any definition will have the
|
||||||
// C conventions, even when in a C++ file.
|
// C conventions, even when in a C++ file.
|
||||||
|
#if LMIC_ENABLE_onEvent
|
||||||
DECL_ON_LMIC_EVENT;
|
DECL_ON_LMIC_EVENT;
|
||||||
|
#endif /* LMIC_ENABLE_onEvent */
|
||||||
|
|
||||||
|
|
||||||
// Special APIs - for development or testing
|
// Special APIs - for development or testing
|
||||||
// !!!See implementation for caveats!!!
|
// !!!See implementation for caveats!!!
|
||||||
|
4
src/lmic/lmic_as923.c
Normal file → Executable file
4
src/lmic/lmic_as923.c
Normal file → Executable file
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016 IBM Corporation.
|
* Copyright (c) 2014-2016 IBM Corporation.
|
||||||
* Copyright (c) 2017 MCCI Corporation.
|
* Copyright (c) 2017, 2019 MCCI Corporation.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -138,7 +138,7 @@ int8_t LMICas923_pow2dBm(uint8_t mcmd_ladr_p1) {
|
|||||||
(mcmd_ladr_p1&MCMD_LADR_POW_MASK)>>MCMD_LADR_POW_SHIFT
|
(mcmd_ladr_p1&MCMD_LADR_POW_MASK)>>MCMD_LADR_POW_SHIFT
|
||||||
);
|
);
|
||||||
|
|
||||||
return adj;
|
return LMICas923_getMaxEIRP(LMIC.txParam) + adj;
|
||||||
}
|
}
|
||||||
|
|
||||||
// only used in this module, but used by variant macro dr2hsym().
|
// only used in this module, but used by variant macro dr2hsym().
|
||||||
|
46
src/lmic/lmic_au921.c
Normal file → Executable file
46
src/lmic/lmic_au921.c
Normal file → Executable file
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016 IBM Corporation.
|
* Copyright (c) 2014-2016 IBM Corporation.
|
||||||
* Copyright (c) 2017 MCCI Corporation.
|
* Copyright (c) 2017, 2019 MCCI Corporation.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -109,9 +109,11 @@ bit_t LMIC_setupChannel(u1_t chidx, u4_t freq, u2_t drmap, s1_t band) {
|
|||||||
return 0; // all channels are hardwired.
|
return 0; // all channels are hardwired.
|
||||||
}
|
}
|
||||||
|
|
||||||
void LMIC_disableChannel(u1_t channel) {
|
bit_t LMIC_disableChannel(u1_t channel) {
|
||||||
|
bit_t result = 0;
|
||||||
if (channel < 72) {
|
if (channel < 72) {
|
||||||
if (ENABLED_CHANNEL(channel)) {
|
if (ENABLED_CHANNEL(channel)) {
|
||||||
|
result = 1;
|
||||||
if (IS_CHANNEL_125khz(channel))
|
if (IS_CHANNEL_125khz(channel))
|
||||||
LMIC.activeChannels125khz--;
|
LMIC.activeChannels125khz--;
|
||||||
else if (IS_CHANNEL_500khz(channel))
|
else if (IS_CHANNEL_500khz(channel))
|
||||||
@ -119,11 +121,14 @@ void LMIC_disableChannel(u1_t channel) {
|
|||||||
}
|
}
|
||||||
LMIC.channelMap[channel >> 4] &= ~(1 << (channel & 0xF));
|
LMIC.channelMap[channel >> 4] &= ~(1 << (channel & 0xF));
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LMIC_enableChannel(u1_t channel) {
|
bit_t LMIC_enableChannel(u1_t channel) {
|
||||||
|
bit_t result = 0;
|
||||||
if (channel < 72) {
|
if (channel < 72) {
|
||||||
if (!ENABLED_CHANNEL(channel)) {
|
if (!ENABLED_CHANNEL(channel)) {
|
||||||
|
result = 1;
|
||||||
if (IS_CHANNEL_125khz(channel))
|
if (IS_CHANNEL_125khz(channel))
|
||||||
LMIC.activeChannels125khz++;
|
LMIC.activeChannels125khz++;
|
||||||
else if (IS_CHANNEL_500khz(channel))
|
else if (IS_CHANNEL_500khz(channel))
|
||||||
@ -131,42 +136,52 @@ void LMIC_enableChannel(u1_t channel) {
|
|||||||
}
|
}
|
||||||
LMIC.channelMap[channel >> 4] |= (1 << (channel & 0xF));
|
LMIC.channelMap[channel >> 4] |= (1 << (channel & 0xF));
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LMIC_enableSubBand(u1_t band) {
|
bit_t LMIC_enableSubBand(u1_t band) {
|
||||||
ASSERT(band < 8);
|
ASSERT(band < 8);
|
||||||
u1_t start = band * 8;
|
u1_t start = band * 8;
|
||||||
u1_t end = start + 8;
|
u1_t end = start + 8;
|
||||||
|
bit_t result = 0;
|
||||||
|
|
||||||
// enable all eight 125 kHz channels in this subband
|
// enable all eight 125 kHz channels in this subband
|
||||||
for (int channel = start; channel < end; ++channel)
|
for (int channel = start; channel < end; ++channel)
|
||||||
LMIC_enableChannel(channel);
|
result |= LMIC_enableChannel(channel);
|
||||||
|
|
||||||
// there's a single 500 kHz channel associated with
|
// there's a single 500 kHz channel associated with
|
||||||
// each group of 8 125 kHz channels. Enable it, too.
|
// each group of 8 125 kHz channels. Enable it, too.
|
||||||
LMIC_enableChannel(64 + band);
|
result |= LMIC_enableChannel(64 + band);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
void LMIC_disableSubBand(u1_t band) {
|
|
||||||
|
bit_t LMIC_disableSubBand(u1_t band) {
|
||||||
ASSERT(band < 8);
|
ASSERT(band < 8);
|
||||||
u1_t start = band * 8;
|
u1_t start = band * 8;
|
||||||
u1_t end = start + 8;
|
u1_t end = start + 8;
|
||||||
|
bit_t result = 0;
|
||||||
|
|
||||||
// disable all eight 125 kHz channels in this subband
|
// disable all eight 125 kHz channels in this subband
|
||||||
for (int channel = start; channel < end; ++channel)
|
for (int channel = start; channel < end; ++channel)
|
||||||
LMIC_disableChannel(channel);
|
result |= LMIC_disableChannel(channel);
|
||||||
|
|
||||||
// there's a single 500 kHz channel associated with
|
// there's a single 500 kHz channel associated with
|
||||||
// each group of 8 125 kHz channels. Disable it, too.
|
// each group of 8 125 kHz channels. Disable it, too.
|
||||||
LMIC_disableChannel(64 + band);
|
result |= LMIC_disableChannel(64 + band);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
void LMIC_selectSubBand(u1_t band) {
|
|
||||||
|
bit_t LMIC_selectSubBand(u1_t band) {
|
||||||
|
bit_t result = 0;
|
||||||
|
|
||||||
ASSERT(band < 8);
|
ASSERT(band < 8);
|
||||||
for (int b = 0; b<8; ++b) {
|
for (int b = 0; b<8; ++b) {
|
||||||
if (band == b)
|
if (band == b)
|
||||||
LMIC_enableSubBand(b);
|
result |= LMIC_enableSubBand(b);
|
||||||
else
|
else
|
||||||
LMIC_disableSubBand(b);
|
result |= LMIC_disableSubBand(b);
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LMICau921_updateTx(ostime_t txbeg) {
|
void LMICau921_updateTx(ostime_t txbeg) {
|
||||||
@ -213,6 +228,13 @@ void LMICau921_setRx1Params(void) {
|
|||||||
LMIC.rps = dndr2rps(LMIC.dndr);
|
LMIC.rps = dndr2rps(LMIC.dndr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LMICau921_initJoinLoop(void) {
|
||||||
|
LMICuslike_initJoinLoop();
|
||||||
|
|
||||||
|
// initialize the adrTxPower.
|
||||||
|
LMIC.adrTxPow = 30; // dBm
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// END: AU921 related stuff
|
// END: AU921 related stuff
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016 IBM Corporation.
|
* Copyright (c) 2014-2016 IBM Corporation.
|
||||||
* Copyright (c) 2017 MCCI Corporation.
|
* Copyright (c) 2017, 2019 MCCI Corporation.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -104,6 +104,10 @@
|
|||||||
# error "LMICbandplan_setBcnRxParams() not defined by bandplan"
|
# error "LMICbandplan_setBcnRxParams() not defined by bandplan"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(LMICbandplan_canMapChannels)
|
||||||
|
# error "LMICbandplan_canMapChannels() not defined by bandplan"
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(LMICbandplan_mapChannels)
|
#if !defined(LMICbandplan_mapChannels)
|
||||||
# error "LMICbandplan_mapChannels() not defined by bandplan"
|
# error "LMICbandplan_mapChannels() not defined by bandplan"
|
||||||
#endif
|
#endif
|
||||||
@ -143,6 +147,15 @@
|
|||||||
#if !defined(LMICbandplan_init)
|
#if !defined(LMICbandplan_init)
|
||||||
# error "LMICbandplan_init() not defined by bandplan"
|
# error "LMICbandplan_init() not defined by bandplan"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(LMICbandplan_saveAdrState)
|
||||||
|
# error "LMICbandplan_saveAdrState() not defined by bandplan"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(LMICbandplan_compareAdrState)
|
||||||
|
# error "LMICbandplan_compareAdrState() not defined by bandplan"
|
||||||
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
// Things common to lmic.c code
|
// Things common to lmic.c code
|
||||||
//
|
//
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016 IBM Corporation.
|
* Copyright (c) 2014-2016 IBM Corporation.
|
||||||
* Copyright (c) 2017 MCCI Corporation.
|
* Copyright (c) 2017, 2019 MCCI Corporation.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -26,8 +26,8 @@
|
|||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _lmic_as923_h_
|
#ifndef _lmic_bandplan_as923_h_
|
||||||
# define _lmic_as923_h_
|
# define _lmic_bandplan_as923_h_
|
||||||
|
|
||||||
#ifndef _lmic_eu_like_h_
|
#ifndef _lmic_eu_like_h_
|
||||||
# include "lmic_eu_like.h"
|
# include "lmic_eu_like.h"
|
||||||
@ -112,4 +112,4 @@ void LMICas923_updateTx(ostime_t txbeg);
|
|||||||
ostime_t LMICas923_nextJoinTime(ostime_t now);
|
ostime_t LMICas923_nextJoinTime(ostime_t now);
|
||||||
#define LMICbandplan_nextJoinTime(now) LMICas923_nextJoinTime(now)
|
#define LMICbandplan_nextJoinTime(now) LMICas923_nextJoinTime(now)
|
||||||
|
|
||||||
#endif // _lmic_as923_h_
|
#endif // _lmic_bandplan_as923_h_
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016 IBM Corporation.
|
* Copyright (c) 2014-2016 IBM Corporation.
|
||||||
* Copyright (c) 2017 MCCI Corporation.
|
* Copyright (c) 2017, 2019 MCCI Corporation.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -26,12 +26,12 @@
|
|||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _lmic_au921_h_
|
#ifndef _lmic_bandplan_au921_h_
|
||||||
# define _lmic_au921_h_
|
# define _lmic_bandplan_au921_h_
|
||||||
|
|
||||||
// preconditions for lmic_us_like.h
|
// preconditions for lmic_us_like.h
|
||||||
#define LMICuslike_getFirst500kHzDR() (AU921_DR_SF8C)
|
#define LMICuslike_getFirst500kHzDR() (LORAWAN_DR6)
|
||||||
|
#define LMICuslike_getJoin125kHzDR() (LORAWAN_DR2)
|
||||||
|
|
||||||
#ifndef _lmic_us_like_h_
|
#ifndef _lmic_us_like_h_
|
||||||
# include "lmic_us_like.h"
|
# include "lmic_us_like.h"
|
||||||
@ -46,7 +46,10 @@ ostime_t LMICau921_dr2hsym(uint8_t dr);
|
|||||||
#define dr2hsym(dr) LMICau921_dr2hsym(dr)
|
#define dr2hsym(dr) LMICau921_dr2hsym(dr)
|
||||||
|
|
||||||
|
|
||||||
#define LMICbandplan_getInitialDrJoin() (EU868_DR_SF7)
|
#define LMICbandplan_getInitialDrJoin() (LORAWAN_DR2)
|
||||||
|
|
||||||
|
void LMICau921_initJoinLoop(void);
|
||||||
|
#define LMICbandplan_initJoinLoop() LMICau921_initJoinLoop()
|
||||||
|
|
||||||
void LMICau921_setBcnRxParams(void);
|
void LMICau921_setBcnRxParams(void);
|
||||||
#define LMICbandplan_setBcnRxParams() LMICau921_setBcnRxParams()
|
#define LMICbandplan_setBcnRxParams() LMICau921_setBcnRxParams()
|
||||||
@ -60,4 +63,4 @@ void LMICau921_setRx1Params(void);
|
|||||||
void LMICau921_updateTx(ostime_t txbeg);
|
void LMICau921_updateTx(ostime_t txbeg);
|
||||||
#define LMICbandplan_updateTx(txbeg) LMICau921_updateTx(txbeg)
|
#define LMICbandplan_updateTx(txbeg) LMICau921_updateTx(txbeg)
|
||||||
|
|
||||||
#endif // _lmic_au921_h_
|
#endif // _lmic_bandplan_au921_h_
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016 IBM Corporation.
|
* Copyright (c) 2014-2016 IBM Corporation.
|
||||||
* Copyright (c) 2017 MCCI Corporation.
|
* Copyright (c) 2017, 2019 MCCI Corporation.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -89,4 +89,7 @@ void LMICeu868_initDefaultChannels(bit_t join);
|
|||||||
ostime_t LMICeu868_nextJoinTime(ostime_t now);
|
ostime_t LMICeu868_nextJoinTime(ostime_t now);
|
||||||
#define LMICbandplan_nextJoinTime(now) LMICeu868_nextJoinTime(now)
|
#define LMICbandplan_nextJoinTime(now) LMICeu868_nextJoinTime(now)
|
||||||
|
|
||||||
|
void LMICeu868_setRx1Params(void);
|
||||||
|
#define LMICbandplan_setRx1Params() LMICeu868_setRx1Params()
|
||||||
|
|
||||||
#endif // _lmic_eu868_h_
|
#endif // _lmic_eu868_h_
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016 IBM Corporation.
|
* Copyright (c) 2014-2016 IBM Corporation.
|
||||||
* Copyright (c) 2017 MCCI Corporation.
|
* Copyright (c) 2017, 2019 MCCI Corporation.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -26,8 +26,8 @@
|
|||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _lmic_in866_h_
|
#ifndef _lmic_bandplan_in866_h_
|
||||||
# define _lmic_in866_h_
|
# define _lmic_bandplan_in866_h_
|
||||||
|
|
||||||
#ifndef _lmic_eu_like_h_
|
#ifndef _lmic_eu_like_h_
|
||||||
# include "lmic_eu_like.h"
|
# include "lmic_eu_like.h"
|
||||||
@ -82,4 +82,7 @@ ostime_t LMICin866_nextJoinState(void);
|
|||||||
void LMICin866_initDefaultChannels(bit_t join);
|
void LMICin866_initDefaultChannels(bit_t join);
|
||||||
#define LMICbandplan_initDefaultChannels(join) LMICin866_initDefaultChannels(join)
|
#define LMICbandplan_initDefaultChannels(join) LMICin866_initDefaultChannels(join)
|
||||||
|
|
||||||
#endif // _lmic_in866_h_
|
void LMICin866_setRx1Params(void);
|
||||||
|
#define LMICbandplan_setRx1Params() LMICin866_setRx1Params()
|
||||||
|
|
||||||
|
#endif // _lmic_bandplan_in866_h_
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016 IBM Corporation.
|
* Copyright (c) 2014-2016 IBM Corporation.
|
||||||
* Copyright (c) 2017 MCCI Corporation.
|
* Copyright (c) 2017, 2019 MCCI Corporation.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -26,11 +26,12 @@
|
|||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _lmic_us915_h_
|
#ifndef _lmic_bandplan_us915_h_
|
||||||
# define _lmic_us915_h_
|
# define _lmic_bandplan_us915_h_
|
||||||
|
|
||||||
// preconditions for lmic_us_like.h
|
// preconditions for lmic_us_like.h
|
||||||
#define LMICuslike_getFirst500kHzDR() (US915_DR_SF8C)
|
#define LMICuslike_getFirst500kHzDR() (LORAWAN_DR4)
|
||||||
|
#define LMICuslike_getJoin125kHzDR() (LORAWAN_DR0)
|
||||||
|
|
||||||
#ifndef _lmic_us_like_h_
|
#ifndef _lmic_us_like_h_
|
||||||
# include "lmic_us_like.h"
|
# include "lmic_us_like.h"
|
||||||
@ -45,7 +46,7 @@ ostime_t LMICus915_dr2hsym(uint8_t dr);
|
|||||||
#define dr2hsym(dr) LMICus915_dr2hsym(dr)
|
#define dr2hsym(dr) LMICus915_dr2hsym(dr)
|
||||||
|
|
||||||
|
|
||||||
#define LMICbandplan_getInitialDrJoin() (US915_DR_SF7)
|
#define LMICbandplan_getInitialDrJoin() (LORAWAN_DR0)
|
||||||
|
|
||||||
void LMICus915_setBcnRxParams(void);
|
void LMICus915_setBcnRxParams(void);
|
||||||
#define LMICbandplan_setBcnRxParams() LMICus915_setBcnRxParams()
|
#define LMICbandplan_setBcnRxParams() LMICus915_setBcnRxParams()
|
||||||
@ -53,10 +54,13 @@ void LMICus915_setBcnRxParams(void);
|
|||||||
u4_t LMICus915_convFreq(xref2cu1_t ptr);
|
u4_t LMICus915_convFreq(xref2cu1_t ptr);
|
||||||
#define LMICbandplan_convFreq(ptr) LMICus915_convFreq(ptr)
|
#define LMICbandplan_convFreq(ptr) LMICus915_convFreq(ptr)
|
||||||
|
|
||||||
|
void LMICus915_initJoinLoop(void);
|
||||||
|
#define LMICbandplan_initJoinLoop() LMICus915_initJoinLoop()
|
||||||
|
|
||||||
void LMICus915_setRx1Params(void);
|
void LMICus915_setRx1Params(void);
|
||||||
#define LMICbandplan_setRx1Params() LMICus915_setRx1Params()
|
#define LMICbandplan_setRx1Params() LMICus915_setRx1Params()
|
||||||
|
|
||||||
void LMICus915_updateTx(ostime_t txbeg);
|
void LMICus915_updateTx(ostime_t txbeg);
|
||||||
#define LMICbandplan_updateTx(txbeg) LMICus915_updateTx(txbeg)
|
#define LMICbandplan_updateTx(txbeg) LMICus915_updateTx(txbeg)
|
||||||
|
|
||||||
#endif // _lmic_us915_h_
|
#endif // _lmic_bandplan_us915_h_
|
||||||
|
31
src/lmic/lmic_config_preconditions.h
Normal file → Executable file
31
src/lmic/lmic_config_preconditions.h
Normal file → Executable file
@ -114,6 +114,12 @@ Revision history:
|
|||||||
// following values. These are in order of the sections in the manual. Not all of the
|
// following values. These are in order of the sections in the manual. Not all of the
|
||||||
// below are supported yet.
|
// below are supported yet.
|
||||||
//
|
//
|
||||||
|
// CFG_as923jp is treated as a special case of CFG_as923, so it's not included in
|
||||||
|
// the below.
|
||||||
|
//
|
||||||
|
// TODO(tmm@mcci.com) consider moving this block to a central file as it's not
|
||||||
|
// user-editable.
|
||||||
|
//
|
||||||
# define CFG_LMIC_REGION_MASK \
|
# define CFG_LMIC_REGION_MASK \
|
||||||
((defined(CFG_eu868) << LMIC_REGION_eu868) | \
|
((defined(CFG_eu868) << LMIC_REGION_eu868) | \
|
||||||
(defined(CFG_us915) << LMIC_REGION_us915) | \
|
(defined(CFG_us915) << LMIC_REGION_us915) | \
|
||||||
@ -127,6 +133,8 @@ Revision history:
|
|||||||
0)
|
0)
|
||||||
|
|
||||||
// the selected region.
|
// the selected region.
|
||||||
|
// TODO(tmm@mcci.com) consider moving this block to a central file as it's not
|
||||||
|
// user-editable.
|
||||||
#if defined(CFG_eu868)
|
#if defined(CFG_eu868)
|
||||||
# define CFG_region LMIC_REGION_eu868
|
# define CFG_region LMIC_REGION_eu868
|
||||||
#elif defined(CFG_us915)
|
#elif defined(CFG_us915)
|
||||||
@ -139,6 +147,10 @@ Revision history:
|
|||||||
# define CFG_region LMIC_REGION_au921
|
# define CFG_region LMIC_REGION_au921
|
||||||
#elif defined(CFG_cn490)
|
#elif defined(CFG_cn490)
|
||||||
# define CFG_region LMIC_REGION_cn490
|
# define CFG_region LMIC_REGION_cn490
|
||||||
|
#elif defined(CFG_as923jp)
|
||||||
|
# define CFG_as923 1 /* CFG_as923jp implies CFG_as923 */
|
||||||
|
# define CFG_region LMIC_REGION_as923
|
||||||
|
# define LMIC_COUNTRY_CODE LMIC_COUNTRY_CODE_JP
|
||||||
#elif defined(CFG_as923)
|
#elif defined(CFG_as923)
|
||||||
# define CFG_region LMIC_REGION_as923
|
# define CFG_region LMIC_REGION_as923
|
||||||
#elif defined(CFG_kr921)
|
#elif defined(CFG_kr921)
|
||||||
@ -149,7 +161,11 @@ Revision history:
|
|||||||
# define CFG_region 0
|
# define CFG_region 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// finally the mask of` US-like and EU-like regions
|
// a bitmask of EU-like regions -- these are regions which have up to 16
|
||||||
|
// channels indidually programmable via downloink.
|
||||||
|
//
|
||||||
|
// TODO(tmm@mcci.com) consider moving this block to a central file as it's not
|
||||||
|
// user-editable.
|
||||||
#define CFG_LMIC_EU_like_MASK ( \
|
#define CFG_LMIC_EU_like_MASK ( \
|
||||||
(1 << LMIC_REGION_eu868) | \
|
(1 << LMIC_REGION_eu868) | \
|
||||||
/* (1 << LMIC_REGION_us915) | */ \
|
/* (1 << LMIC_REGION_us915) | */ \
|
||||||
@ -162,6 +178,12 @@ Revision history:
|
|||||||
(1 << LMIC_REGION_in866) | \
|
(1 << LMIC_REGION_in866) | \
|
||||||
0)
|
0)
|
||||||
|
|
||||||
|
// a bitmask of` US-like regions -- these are regions with 64 fixed 125 kHz channels
|
||||||
|
// overlaid by 8 500 kHz channels. The channel frequencies can't be changed, but
|
||||||
|
// subsets of channels can be selected via masks.
|
||||||
|
//
|
||||||
|
// TODO(tmm@mcci.com) consider moving this block to a central file as it's not
|
||||||
|
// user-editable.
|
||||||
#define CFG_LMIC_US_like_MASK ( \
|
#define CFG_LMIC_US_like_MASK ( \
|
||||||
/* (1 << LMIC_REGION_eu868) | */ \
|
/* (1 << LMIC_REGION_eu868) | */ \
|
||||||
(1 << LMIC_REGION_us915) | \
|
(1 << LMIC_REGION_us915) | \
|
||||||
@ -174,9 +196,12 @@ Revision history:
|
|||||||
/* (1 << LMIC_REGION_in866) | */ \
|
/* (1 << LMIC_REGION_in866) | */ \
|
||||||
0)
|
0)
|
||||||
|
|
||||||
|
//
|
||||||
|
// booleans that are true if the configured region is EU-like or US-like.
|
||||||
|
// TODO(tmm@mcci.com) consider moving this block to a central file as it's not
|
||||||
|
// user-editable.
|
||||||
|
//
|
||||||
#define CFG_LMIC_EU_like (!!(CFG_LMIC_REGION_MASK & CFG_LMIC_EU_like_MASK))
|
#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))
|
#define CFG_LMIC_US_like (!!(CFG_LMIC_REGION_MASK & CFG_LMIC_US_like_MASK))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* _LMIC_CONFIG_PRECONDITIONS_H_ */
|
#endif /* _LMIC_CONFIG_PRECONDITIONS_H_ */
|
||||||
|
251
src/lmic/lmic_env.h
Executable file
251
src/lmic/lmic_env.h
Executable file
@ -0,0 +1,251 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Module: lmic_env.h
|
||||||
|
|
||||||
|
Function:
|
||||||
|
Sets up macros etc. to make things a little easier for portabilty
|
||||||
|
|
||||||
|
Copyright notice and license info:
|
||||||
|
See LICENSE file accompanying this project.
|
||||||
|
|
||||||
|
Author:
|
||||||
|
Terry Moore, MCCI Corporation November 2018
|
||||||
|
|
||||||
|
Description:
|
||||||
|
This file is an adaptation of MCCI's standard IOCTL framework.
|
||||||
|
We duplicate a bit of functionality that we might get from other
|
||||||
|
libraries, so that the LMIC library can continue to stand alone.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _lmic_env_h_ /* prevent multiple includes */
|
||||||
|
#define _lmic_env_h_
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Macro: LMIC_C_ASSERT()
|
||||||
|
|
||||||
|
Function:
|
||||||
|
Declaration-like macro that will cause a compile error if arg is FALSE.
|
||||||
|
|
||||||
|
Definition:
|
||||||
|
LMIC_C_ASSERT(
|
||||||
|
BOOL fErrorIfFalse
|
||||||
|
);
|
||||||
|
|
||||||
|
Description:
|
||||||
|
This macro, if used where an external reference declarataion is
|
||||||
|
permitted, will either compile cleanly, or will cause a compilation
|
||||||
|
error. The results of using this macro where a declaration is not
|
||||||
|
permitted are unspecified.
|
||||||
|
|
||||||
|
This is different from #if !(fErrorIfFalse) / #error in that the
|
||||||
|
expression is evaluated by the compiler rather than by the pre-
|
||||||
|
processor. Therefore things like sizeof() can be used.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
No explicit result -- either compiles cleanly or causes a compile
|
||||||
|
error.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LMIC_C_ASSERT
|
||||||
|
# define LMIC_C_ASSERT(e) \
|
||||||
|
void LMIC_C_ASSERT__(int LMIC_C_ASSERT_x[(e) ? 1: -1])
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/****************************************************************************\
|
||||||
|
|
|
||||||
|
| Define the begin/end declaration tags for C++ co-existance
|
||||||
|
|
|
||||||
|
\****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
# define LMIC_BEGIN_DECLS extern "C" {
|
||||||
|
# define LMIC_END_DECLS }
|
||||||
|
#else
|
||||||
|
# define LMIC_BEGIN_DECLS /* nothing */
|
||||||
|
# define LMIC_END_DECLS /* nothing */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
// Annotations to avoid various "unused" warnings. These must appear as a
|
||||||
|
// statement in the function body; the macro annotates the variable to quiet
|
||||||
|
// compiler warnings. The way this is done is compiler-specific, and so these
|
||||||
|
// definitions are fall-backs, which might be overridden.
|
||||||
|
//
|
||||||
|
// Although these are all similar, we don't want extra macro expansions,
|
||||||
|
// so we define each one explicitly rather than relying on a common macro.
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// signal that a parameter is intentionally unused.
|
||||||
|
#ifndef LMIC_UNREFERENCED_PARAMETER
|
||||||
|
# define LMIC_UNREFERENCED_PARAMETER(v) do { (void) (v); } while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// an API parameter is a parameter that is required by an API definition, but
|
||||||
|
// happens to be unreferenced in this implementation. This is a stronger
|
||||||
|
// assertion than LMIC_UNREFERENCED_PARAMETER(): this parameter is here
|
||||||
|
// becuase of an API contract, but we have no use for it in this function.
|
||||||
|
#ifndef LMIC_API_PARAMETER
|
||||||
|
# define LMIC_API_PARAMETER(v) do { (void) (v); } while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// an intentionally-unreferenced variable.
|
||||||
|
#ifndef LMIC_UNREFERENCED_VARIABLE
|
||||||
|
# define LMIC_UNREFERENCED_VARIABLE(v) do { (void) (v); } while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// we have three (!) debug levels (LMIC_DEBUG_LEVEL > 0, LMIC_DEBUG_LEVEL > 1,
|
||||||
|
// and LMIC_X_DEBUG_LEVEL > 0. In each case we might have parameters or
|
||||||
|
// or varables that are only refereneced at the target debug level.
|
||||||
|
|
||||||
|
// Parameter referenced only if debugging at level > 0.
|
||||||
|
#ifndef LMIC_DEBUG1_PARAMETER
|
||||||
|
# if LMIC_DEBUG_LEVEL > 0
|
||||||
|
# define LMIC_DEBUG1_PARAMETER(v) do { ; } while (0)
|
||||||
|
# else
|
||||||
|
# define LMIC_DEBUG1_PARAMETER(v) do { (void) (v); } while (0)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// variable referenced only if debugging at level > 0
|
||||||
|
#ifndef LMIC_DEBUG1_VARIABLE
|
||||||
|
# if LMIC_DEBUG_LEVEL > 0
|
||||||
|
# define LMIC_DEBUG1_VARIABLE(v) do { ; } while (0)
|
||||||
|
# else
|
||||||
|
# define LMIC_DEBUG1_VARIABLE(v) do { (void) (v); } while (0)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// parameter referenced only if debugging at level > 1
|
||||||
|
#ifndef LMIC_DEBUG2_PARAMETER
|
||||||
|
# if LMIC_DEBUG_LEVEL > 1
|
||||||
|
# define LMIC_DEBUG2_PARAMETER(v) do { ; } while (0)
|
||||||
|
# else
|
||||||
|
# define LMIC_DEBUG2_PARAMETER(v) do { (void) (v); } while (0)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// variable referenced only if debugging at level > 1
|
||||||
|
#ifndef LMIC_DEBUG2_VARIABLE
|
||||||
|
# if LMIC_DEBUG_LEVEL > 1
|
||||||
|
# define LMIC_DEBUG2_VARIABLE(v) do { ; } while (0)
|
||||||
|
# else
|
||||||
|
# define LMIC_DEBUG2_VARIABLE(v) do { (void) (v); } while (0)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// parameter referenced only if LMIC_X_DEBUG_LEVEL > 0
|
||||||
|
#ifndef LMIC_X_DEBUG_PARAMETER
|
||||||
|
# if LMIC_X_DEBUG_LEVEL > 0
|
||||||
|
# define LMIC_X_DEBUG_PARAMETER(v) do { ; } while (0)
|
||||||
|
# else
|
||||||
|
# define LMIC_X_DEBUG_PARAMETER(v) do { (void) (v); } while (0)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// variable referenced only if LMIC_X_DEBUG_LEVEL > 0
|
||||||
|
#ifndef LMIC_X_DEBUG_VARIABLE
|
||||||
|
# if LMIC_X_DEBUG_LEVEL > 0
|
||||||
|
# define LMIC_X_DEBUG_VARIABLE(v) do { ; } while (0)
|
||||||
|
# else
|
||||||
|
# define LMIC_X_DEBUG_VARIABLE(v) do { (void) (v); } while (0)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// parameter referenced only if EV() macro is enabled (which it never is)
|
||||||
|
// TODO(tmm@mcci.com) take out the EV() framework as it reuqires C++, and
|
||||||
|
// this code is really C-99 to its bones.
|
||||||
|
#ifndef LMIC_EV_PARAMETER
|
||||||
|
# define LMIC_EV_PARAMETER(v) do { (void) (v); } while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// variable referenced only if EV() macro is defined.
|
||||||
|
#ifndef LMIC_EV_VARIABLE
|
||||||
|
# define LMIC_EV_VARIABLE(v) do { (void) (v); } while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Macro: LMIC_ABI_STD
|
||||||
|
|
||||||
|
Index: Macro: LMIC_ABI_VARARGS
|
||||||
|
|
||||||
|
Function:
|
||||||
|
Annotation macros to force a particular binary calling sequence.
|
||||||
|
|
||||||
|
Definition:
|
||||||
|
#define LMIC_ABI_STD compiler-specific
|
||||||
|
#define LMIC_ABI_VARARGS compiler-specific
|
||||||
|
|
||||||
|
Description:
|
||||||
|
These macros are used when declaring a function type, and indicate
|
||||||
|
that a particular calling sequence is to be used. They are normally
|
||||||
|
used between the type portion of the function declaration and the
|
||||||
|
name of the function. For example:
|
||||||
|
|
||||||
|
typedef void LMIC_ABI_STD myCallBack_t(void);
|
||||||
|
|
||||||
|
It's important to use this in libraries on platforms with multiple
|
||||||
|
calling sequences, because different components can be compiled with
|
||||||
|
different defaults.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Not applicable.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ABI marker for normal (fixed parameter count) functions -- used for function types */
|
||||||
|
#ifndef LMIC_ABI_STD
|
||||||
|
# ifdef _MSC_VER
|
||||||
|
# define LMIC_ABI_STD __stdcall
|
||||||
|
# else
|
||||||
|
# define LMIC_ABI_STD /* nothing */
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* ABI marker for VARARG functions -- used for function types */
|
||||||
|
#ifndef LMIC_ABI_VARARGS
|
||||||
|
# ifdef _MSC_VER
|
||||||
|
# define LMIC_ABI_VARARGS __cdecl
|
||||||
|
# else
|
||||||
|
# define LMIC_ABI_VARARGS /* nothing */
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Macro: LMIC_DECLARE_FUNCTION_WEAK()
|
||||||
|
|
||||||
|
Function:
|
||||||
|
Declare an external function as a weak reference.
|
||||||
|
|
||||||
|
Definition:
|
||||||
|
#define LMIC_DECLARE_FUNCTION_WEAK(ReturnType, FunctionName, Params) ...
|
||||||
|
|
||||||
|
Description:
|
||||||
|
This macro generates a weak reference to the specified function.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
LMIC_DECLARE_FUNCTION_WEAK(void, onEvent, (ev_t e));
|
||||||
|
|
||||||
|
This saya that onEvent is a weak external reference. When calling
|
||||||
|
onEvent, you must always first check whether it's supplied:
|
||||||
|
|
||||||
|
if (onEvent != NULL)
|
||||||
|
onEvent(e);
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
This macro expands to a declaration, without a trailing semicolon.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
This form allows for compilers that use _Pragma(weak, name) instead
|
||||||
|
of inline attributes.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LMIC_DECLARE_FUNCTION_WEAK(a_ReturnType, a_FunctionName, a_Params) \
|
||||||
|
a_ReturnType __attribute__((__weak__)) a_FunctionName a_Params
|
||||||
|
|
||||||
|
#endif /* _lmic_env_h_ */
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016 IBM Corporation.
|
* Copyright (c) 2014-2016 IBM Corporation.
|
||||||
* Copyright (c) 2017 MCCI Corporation.
|
* Copyright (c) 2017, 2019 MCCI Corporation.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -59,7 +59,7 @@ uint8_t LMICeu868_maxFrameLen(uint8_t dr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static CONST_TABLE(s1_t, TXPOWLEVELS)[] = {
|
static CONST_TABLE(s1_t, TXPOWLEVELS)[] = {
|
||||||
20, 14, 11, 8, 5, 2, 0,0, 0,0,0,0, 0,0,0,0
|
16, 14, 12, 10, 8, 6, 4, 2, 0,0,0,0, 0,0,0,0
|
||||||
};
|
};
|
||||||
|
|
||||||
int8_t LMICeu868_pow2dBm(uint8_t mcmd_ladr_p1) {
|
int8_t LMICeu868_pow2dBm(uint8_t mcmd_ladr_p1) {
|
||||||
@ -221,6 +221,28 @@ LMICeu868_txDoneFSK(ostime_t delay, osjobcb_t func) {
|
|||||||
os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, func);
|
os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, func);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set the Rx1 dndr, rps.
|
||||||
|
void LMICeu868_setRx1Params(void) {
|
||||||
|
u1_t const txdr = LMIC.dndr;
|
||||||
|
s1_t drOffset;
|
||||||
|
s1_t candidateDr;
|
||||||
|
|
||||||
|
if ( LMIC.rx1DrOffset <= 5)
|
||||||
|
drOffset = (s1_t) LMIC.rx1DrOffset;
|
||||||
|
else
|
||||||
|
// make a reasonable assumption for unspecified value.
|
||||||
|
drOffset = 5;
|
||||||
|
|
||||||
|
candidateDr = (s1_t) txdr - drOffset;
|
||||||
|
if (candidateDr < LORAWAN_DR0)
|
||||||
|
candidateDr = 0;
|
||||||
|
else if (candidateDr > LORAWAN_DR7)
|
||||||
|
candidateDr = LORAWAN_DR7;
|
||||||
|
|
||||||
|
LMIC.dndr = (u1_t) candidateDr;
|
||||||
|
LMIC.rps = dndr2rps(LMIC.dndr);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LMICeu868_initJoinLoop(void) {
|
LMICeu868_initJoinLoop(void) {
|
||||||
LMICeulike_initJoinLoop(NUM_DEFAULT_CHANNELS, /* adr dBm */ EU868_TX_EIRP_MAX_DBM);
|
LMICeulike_initJoinLoop(NUM_DEFAULT_CHANNELS, /* adr dBm */ EU868_TX_EIRP_MAX_DBM);
|
||||||
|
45
src/lmic/lmic_eu_like.c
Normal file → Executable file
45
src/lmic/lmic_eu_like.c
Normal file → Executable file
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016 IBM Corporation.
|
* Copyright (c) 2014-2016 IBM Corporation.
|
||||||
* Copyright (c) 2017 MCCI Corporation.
|
* Copyright (c) 2017, 2019 MCCI Corporation.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -32,37 +32,47 @@
|
|||||||
|
|
||||||
#if CFG_LMIC_EU_like
|
#if CFG_LMIC_EU_like
|
||||||
|
|
||||||
void LMIC_enableSubBand(u1_t band) {
|
bit_t LMIC_enableSubBand(u1_t band) {
|
||||||
LMIC_API_PARAMETER(band);
|
LMIC_API_PARAMETER(band);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LMIC_disableSubBand(u1_t band) {
|
bit_t LMIC_disableSubBand(u1_t band) {
|
||||||
LMIC_API_PARAMETER(band);
|
LMIC_API_PARAMETER(band);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LMIC_disableChannel(u1_t channel) {
|
bit_t LMIC_disableChannel(u1_t channel) {
|
||||||
|
u2_t old_chmap = LMIC.channelMap;
|
||||||
LMIC.channelFreq[channel] = 0;
|
LMIC.channelFreq[channel] = 0;
|
||||||
LMIC.channelDrMap[channel] = 0;
|
LMIC.channelDrMap[channel] = 0;
|
||||||
LMIC.channelMap &= ~(1 << channel);
|
LMIC.channelMap = old_chmap & ~(1 << channel);
|
||||||
|
return LMIC.channelMap != old_chmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is a no-op provided for compatibilty
|
// this is a no-op provided for compatibilty
|
||||||
void LMIC_enableChannel(u1_t channel) {
|
bit_t LMIC_enableChannel(u1_t channel) {
|
||||||
LMIC_API_PARAMETER(channel);
|
LMIC_API_PARAMETER(channel);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
u1_t LMICeulike_mapChannels(u1_t chpage, u2_t chmap) {
|
bit_t LMICeulike_canMapChannels(u1_t chpage, u2_t chmap) {
|
||||||
// Bad page, disable all channel, enable non-existent
|
|
||||||
if (chpage != 0 || chmap == 0 || (chmap & ~LMIC.channelMap) != 0)
|
if (chpage != 0 || chmap == 0 || (chmap & ~LMIC.channelMap) != 0)
|
||||||
return 0; // illegal input
|
return 0; // illegal input
|
||||||
for (u1_t chnl = 0; chnl<MAX_CHANNELS; chnl++) {
|
for (u1_t chnl = 0; chnl<MAX_CHANNELS; chnl++) {
|
||||||
if ((chmap & (1 << chnl)) != 0 && LMIC.channelFreq[chnl] == 0)
|
if ((chmap & (1 << chnl)) != 0 && LMIC.channelFreq[chnl] == 0)
|
||||||
chmap &= ~(1 << chnl); // ignore - channel is not defined
|
return 0; // fail - channel is not defined
|
||||||
}
|
}
|
||||||
LMIC.channelMap = chmap;
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// assumes that LMICeulike_canMapChannels passed. Return true if something changed.
|
||||||
|
bit_t LMICeulike_mapChannels(u1_t chpage, u2_t chmap) {
|
||||||
|
u2_t const old_chmap = LMIC.channelMap;
|
||||||
|
LMIC.channelMap = chmap;
|
||||||
|
return old_chmap != chmap;
|
||||||
|
}
|
||||||
|
|
||||||
#if !defined(DISABLE_JOIN)
|
#if !defined(DISABLE_JOIN)
|
||||||
void LMICeulike_initJoinLoop(uint8_t nDefaultChannels, s1_t adrTxPow) {
|
void LMICeulike_initJoinLoop(uint8_t nDefaultChannels, s1_t adrTxPow) {
|
||||||
#if CFG_TxContinuousMode
|
#if CFG_TxContinuousMode
|
||||||
@ -159,4 +169,19 @@ ostime_t LMICeulike_nextJoinState(uint8_t nDefaultChannels) {
|
|||||||
}
|
}
|
||||||
#endif // !DISABLE_JOIN
|
#endif // !DISABLE_JOIN
|
||||||
|
|
||||||
|
void LMICeulike_saveAdrState(lmic_saved_adr_state_t *pStateBuffer) {
|
||||||
|
memcpy(
|
||||||
|
pStateBuffer->channelFreq,
|
||||||
|
LMIC.channelFreq,
|
||||||
|
sizeof(LMIC.channelFreq)
|
||||||
|
);
|
||||||
|
pStateBuffer->channelMap = LMIC.channelMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
bit_t LMICeulike_compareAdrState(const lmic_saved_adr_state_t *pStateBuffer) {
|
||||||
|
if (memcmp(pStateBuffer->channelFreq, LMIC.channelFreq, sizeof(LMIC.channelFreq)) != 0)
|
||||||
|
return 1;
|
||||||
|
return pStateBuffer->channelMap != LMIC.channelMap;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // CFG_LMIC_EU_like
|
#endif // CFG_LMIC_EU_like
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016 IBM Corporation.
|
* Copyright (c) 2014-2016 IBM Corporation.
|
||||||
* Copyright (c) 2017 MCCI Corporation.
|
* Copyright (c) 2017, 2019 MCCI Corporation.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -74,14 +74,14 @@ enum { BAND_MILLI = 0, BAND_CENTI = 1, BAND_DECI = 2, BAND_AUX = 3 };
|
|||||||
#define LMICbandplan_setSessionInitDefaultChannels() \
|
#define LMICbandplan_setSessionInitDefaultChannels() \
|
||||||
do { LMICbandplan_initDefaultChannels(/* normal, not join */ 0); } while (0)
|
do { LMICbandplan_initDefaultChannels(/* normal, not join */ 0); } while (0)
|
||||||
|
|
||||||
u1_t LMICeulike_mapChannels(u1_t chpage, u2_t chmap);
|
bit_t LMICeulike_canMapChannels(u1_t chpage, u2_t chmap);
|
||||||
|
#define LMICbandplan_canMapChannels(c, m) LMICeulike_canMapChannels(c, m)
|
||||||
|
|
||||||
|
bit_t LMICeulike_mapChannels(u1_t chpage, u2_t chmap);
|
||||||
#define LMICbandplan_mapChannels(c, m) LMICeulike_mapChannels(c, m)
|
#define LMICbandplan_mapChannels(c, m) LMICeulike_mapChannels(c, m)
|
||||||
|
|
||||||
void LMICeulike_initJoinLoop(u1_t nDefaultChannels, s1_t adrTxPow);
|
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);
|
void LMICeulike_updateTx(ostime_t txbeg);
|
||||||
#define LMICbandplan_updateTx(t) LMICeulike_updateTx(t)
|
#define LMICbandplan_updateTx(t) LMICeulike_updateTx(t)
|
||||||
|
|
||||||
@ -95,4 +95,10 @@ static inline ostime_t LMICeulike_nextJoinTime(ostime_t now) {
|
|||||||
#define LMICbandplan_init() \
|
#define LMICbandplan_init() \
|
||||||
do { /* nothing */ } while (0)
|
do { /* nothing */ } while (0)
|
||||||
|
|
||||||
|
void LMICeulike_saveAdrState(lmic_saved_adr_state_t *pStateBuffer);
|
||||||
|
#define LMICbandplan_saveAdrState(pState) LMICeulike_saveAdrState(pState)
|
||||||
|
|
||||||
|
bit_t LMICeulike_compareAdrState(const lmic_saved_adr_state_t *pStateBuffer);
|
||||||
|
#define LMICbandplan_compareAdrState(pState) LMICeulike_compareAdrState(pState)
|
||||||
|
|
||||||
#endif // _lmic_eu_like_h_
|
#endif // _lmic_eu_like_h_
|
||||||
|
25
src/lmic/lmic_in866.c
Normal file → Executable file
25
src/lmic/lmic_in866.c
Normal file → Executable file
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016 IBM Corporation.
|
* Copyright (c) 2014-2016 IBM Corporation.
|
||||||
* Copyright (c) 2017 MCCI Corporation.
|
* Copyright (c) 2017, 2019 MCCI Corporation.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -59,7 +59,7 @@ uint8_t LMICin866_maxFrameLen(uint8_t dr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static CONST_TABLE(s1_t, TXPOWLEVELS)[] = {
|
static CONST_TABLE(s1_t, TXPOWLEVELS)[] = {
|
||||||
20, 14, 11, 8, 5, 2, 0,0, 0,0,0,0, 0,0,0,0
|
30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 0, 0,0,0,0
|
||||||
};
|
};
|
||||||
|
|
||||||
int8_t LMICin866_pow2dBm(uint8_t mcmd_ladr_p1) {
|
int8_t LMICin866_pow2dBm(uint8_t mcmd_ladr_p1) {
|
||||||
@ -195,6 +195,27 @@ LMICin866_txDoneFSK(ostime_t delay, osjobcb_t func) {
|
|||||||
os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, func);
|
os_setTimedCallback(&LMIC.osjob, LMIC.rxtime - RX_RAMPUP, func);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// set the Rx1 dndr, rps.
|
||||||
|
void LMICin866_setRx1Params(void) {
|
||||||
|
u1_t const txdr = LMIC.dndr;
|
||||||
|
s1_t drOffset;
|
||||||
|
s1_t candidateDr;
|
||||||
|
|
||||||
|
if ( LMIC.rx1DrOffset <= 5)
|
||||||
|
drOffset = (s1_t) LMIC.rx1DrOffset;
|
||||||
|
else
|
||||||
|
drOffset = 5 - (s1_t) LMIC.rx1DrOffset;
|
||||||
|
|
||||||
|
candidateDr = (s1_t) txdr - drOffset;
|
||||||
|
if (candidateDr < LORAWAN_DR0)
|
||||||
|
candidateDr = 0;
|
||||||
|
else if (candidateDr > LORAWAN_DR5)
|
||||||
|
candidateDr = LORAWAN_DR5;
|
||||||
|
|
||||||
|
LMIC.dndr = (u1_t) candidateDr;
|
||||||
|
LMIC.rps = dndr2rps(LMIC.dndr);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
LMICin866_initJoinLoop(void) {
|
LMICin866_initJoinLoop(void) {
|
||||||
LMICeulike_initJoinLoop(NUM_DEFAULT_CHANNELS, /* adr dBm */ IN866_TX_EIRP_MAX_DBM);
|
LMICeulike_initJoinLoop(NUM_DEFAULT_CHANNELS, /* adr dBm */ IN866_TX_EIRP_MAX_DBM);
|
||||||
|
64
src/lmic/lmic_us915.c
Normal file → Executable file
64
src/lmic/lmic_us915.c
Normal file → Executable file
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016 IBM Corporation.
|
* Copyright (c) 2014-2016 IBM Corporation.
|
||||||
* Copyright (c) 2017 MCCI Corporation.
|
* Copyright (c) 2017, 2019 MCCI Corporation.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -98,9 +98,11 @@ bit_t LMIC_setupChannel(u1_t chidx, u4_t freq, u2_t drmap, s1_t band) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LMIC_disableChannel(u1_t channel) {
|
bit_t LMIC_disableChannel(u1_t channel) {
|
||||||
|
bit_t result = 0;
|
||||||
if (channel < 72 + MAX_XCHANNELS) {
|
if (channel < 72 + MAX_XCHANNELS) {
|
||||||
if (ENABLED_CHANNEL(channel)) {
|
if (ENABLED_CHANNEL(channel)) {
|
||||||
|
result = 1;
|
||||||
if (IS_CHANNEL_125khz(channel))
|
if (IS_CHANNEL_125khz(channel))
|
||||||
LMIC.activeChannels125khz--;
|
LMIC.activeChannels125khz--;
|
||||||
else if (IS_CHANNEL_500khz(channel))
|
else if (IS_CHANNEL_500khz(channel))
|
||||||
@ -108,11 +110,14 @@ void LMIC_disableChannel(u1_t channel) {
|
|||||||
}
|
}
|
||||||
LMIC.channelMap[channel >> 4] &= ~(1 << (channel & 0xF));
|
LMIC.channelMap[channel >> 4] &= ~(1 << (channel & 0xF));
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LMIC_enableChannel(u1_t channel) {
|
bit_t LMIC_enableChannel(u1_t channel) {
|
||||||
|
bit_t result = 0;
|
||||||
if (channel < 72 + MAX_XCHANNELS) {
|
if (channel < 72 + MAX_XCHANNELS) {
|
||||||
if (!ENABLED_CHANNEL(channel)) {
|
if (!ENABLED_CHANNEL(channel)) {
|
||||||
|
result = 1;
|
||||||
if (IS_CHANNEL_125khz(channel))
|
if (IS_CHANNEL_125khz(channel))
|
||||||
LMIC.activeChannels125khz++;
|
LMIC.activeChannels125khz++;
|
||||||
else if (IS_CHANNEL_500khz(channel))
|
else if (IS_CHANNEL_500khz(channel))
|
||||||
@ -120,42 +125,52 @@ void LMIC_enableChannel(u1_t channel) {
|
|||||||
}
|
}
|
||||||
LMIC.channelMap[channel >> 4] |= (1 << (channel & 0xF));
|
LMIC.channelMap[channel >> 4] |= (1 << (channel & 0xF));
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LMIC_enableSubBand(u1_t band) {
|
bit_t LMIC_enableSubBand(u1_t band) {
|
||||||
ASSERT(band < 8);
|
ASSERT(band < 8);
|
||||||
u1_t start = band * 8;
|
u1_t start = band * 8;
|
||||||
u1_t end = start + 8;
|
u1_t end = start + 8;
|
||||||
|
bit_t result = 0;
|
||||||
|
|
||||||
// enable all eight 125 kHz channels in this subband
|
// enable all eight 125 kHz channels in this subband
|
||||||
for (int channel = start; channel < end; ++channel)
|
for (int channel = start; channel < end; ++channel)
|
||||||
LMIC_enableChannel(channel);
|
result |= LMIC_enableChannel(channel);
|
||||||
|
|
||||||
// there's a single 500 kHz channel associated with
|
// there's a single 500 kHz channel associated with
|
||||||
// each group of 8 125 kHz channels. Enable it, too.
|
// each group of 8 125 kHz channels. Enable it, too.
|
||||||
LMIC_enableChannel(64 + band);
|
result |= LMIC_enableChannel(64 + band);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
void LMIC_disableSubBand(u1_t band) {
|
|
||||||
|
bit_t LMIC_disableSubBand(u1_t band) {
|
||||||
ASSERT(band < 8);
|
ASSERT(band < 8);
|
||||||
u1_t start = band * 8;
|
u1_t start = band * 8;
|
||||||
u1_t end = start + 8;
|
u1_t end = start + 8;
|
||||||
|
bit_t result = 0;
|
||||||
|
|
||||||
// disable all eight 125 kHz channels in this subband
|
// disable all eight 125 kHz channels in this subband
|
||||||
for (int channel = start; channel < end; ++channel)
|
for (int channel = start; channel < end; ++channel)
|
||||||
LMIC_disableChannel(channel);
|
result |= LMIC_disableChannel(channel);
|
||||||
|
|
||||||
// there's a single 500 kHz channel associated with
|
// there's a single 500 kHz channel associated with
|
||||||
// each group of 8 125 kHz channels. Disable it, too.
|
// each group of 8 125 kHz channels. Disable it, too.
|
||||||
LMIC_disableChannel(64 + band);
|
result |= LMIC_disableChannel(64 + band);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
void LMIC_selectSubBand(u1_t band) {
|
|
||||||
|
bit_t LMIC_selectSubBand(u1_t band) {
|
||||||
|
bit_t result = 0;
|
||||||
|
|
||||||
ASSERT(band < 8);
|
ASSERT(band < 8);
|
||||||
for (int b = 0; b<8; ++b) {
|
for (int b = 0; b<8; ++b) {
|
||||||
if (band == b)
|
if (band == b)
|
||||||
LMIC_enableSubBand(b);
|
result |= LMIC_enableSubBand(b);
|
||||||
else
|
else
|
||||||
LMIC_disableSubBand(b);
|
result |= LMIC_disableSubBand(b);
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LMICus915_updateTx(ostime_t txbeg) {
|
void LMICus915_updateTx(ostime_t txbeg) {
|
||||||
@ -193,16 +208,31 @@ void LMICus915_setBcnRxParams(void) {
|
|||||||
}
|
}
|
||||||
#endif // !DISABLE_BEACONS
|
#endif // !DISABLE_BEACONS
|
||||||
|
|
||||||
// TODO(tmm@mcci.com): parmeterize for US-like
|
// set the Rx1 dndr, rps.
|
||||||
void LMICus915_setRx1Params(void) {
|
void LMICus915_setRx1Params(void) {
|
||||||
|
u1_t const txdr = LMIC.dndr;
|
||||||
|
u1_t candidateDr;
|
||||||
LMIC.freq = US915_500kHz_DNFBASE + (LMIC.txChnl & 0x7) * US915_500kHz_DNFSTEP;
|
LMIC.freq = US915_500kHz_DNFBASE + (LMIC.txChnl & 0x7) * US915_500kHz_DNFSTEP;
|
||||||
if( /* TX datarate */LMIC.dndr < US915_DR_SF8C )
|
if ( /* TX datarate */txdr < LORAWAN_DR4)
|
||||||
LMIC.dndr += US915_DR_SF10CR - US915_DR_SF10;
|
candidateDr = txdr + 10 - LMIC.rx1DrOffset;
|
||||||
else if( LMIC.dndr == US915_DR_SF8C )
|
else
|
||||||
LMIC.dndr = US915_DR_SF7CR;
|
candidateDr = LORAWAN_DR13 - LMIC.rx1DrOffset;
|
||||||
|
|
||||||
|
if (candidateDr < LORAWAN_DR8)
|
||||||
|
candidateDr = LORAWAN_DR8;
|
||||||
|
else if (candidateDr > LORAWAN_DR13)
|
||||||
|
candidateDr = LORAWAN_DR13;
|
||||||
|
|
||||||
|
LMIC.dndr = candidateDr;
|
||||||
LMIC.rps = dndr2rps(LMIC.dndr);
|
LMIC.rps = dndr2rps(LMIC.dndr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LMICus915_initJoinLoop(void) {
|
||||||
|
LMICuslike_initJoinLoop();
|
||||||
|
|
||||||
|
// initialize the adrTxPower.
|
||||||
|
LMIC.adrTxPow = 20; // dBm
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// END: US915 related stuff
|
// END: US915 related stuff
|
||||||
|
118
src/lmic/lmic_us_like.c
Normal file → Executable file
118
src/lmic/lmic_us_like.c
Normal file → Executable file
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016 IBM Corporation.
|
* Copyright (c) 2014-2016 IBM Corporation.
|
||||||
* Copyright (c) 2017 MCCI Corporation.
|
* Copyright (c) 2017, 2019 MCCI Corporation.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -91,7 +91,46 @@ void LMICuslike_initDefaultChannels(bit_t fJoin) {
|
|||||||
LMIC.activeChannels500khz = 8;
|
LMIC.activeChannels500khz = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
u1_t LMICuslike_mapChannels(u1_t chpage, u2_t chmap) {
|
// verify that a given setting is permitted
|
||||||
|
bit_t LMICuslike_canMapChannels(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.
|
||||||
|
*/
|
||||||
|
if (chpage < MCMD_LADR_CHP_USLIKE_SPECIAL) {
|
||||||
|
if (chmap == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// operate on channels 0..15, 16..31, 32..47, 48..63, 64..71
|
||||||
|
if (chpage == (64 >> 4)) {
|
||||||
|
if (chmap & 0xFF00) {
|
||||||
|
// those are reserved bits, fail.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (chpage == MCMD_LADR_CHP_BANK) {
|
||||||
|
if (chmap == 0 || (chmap & 0xFF00) != 0) {
|
||||||
|
// no bits set, or reserved bitsset , fail.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (chpage == MCMD_LADR_CHP_125ON || chpage == MCMD_LADR_CHP_125OFF) {
|
||||||
|
u1_t const en125 = chpage == MCMD_LADR_CHP_125ON;
|
||||||
|
|
||||||
|
// if disabling all 125kHz chans, must have at least one 500kHz chan
|
||||||
|
// don't allow reserved bits to be set in chmap.
|
||||||
|
if ((! en125 && chmap == 0) || (chmap & 0xFF00) != 0)
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we get here, it looks legal.
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bit_t LMICuslike_mapChannels(u1_t chpage, u2_t chmap) {
|
||||||
/*
|
/*
|
||||||
|| MCMD_LADR_CHP_125ON and MCMD_LADR_CHP_125OFF are special. The
|
|| MCMD_LADR_CHP_125ON and MCMD_LADR_CHP_125OFF are special. The
|
||||||
|| channel map appllies to 500kHz (ch 64..71) and in addition
|
|| channel map appllies to 500kHz (ch 64..71) and in addition
|
||||||
@ -99,61 +138,53 @@ u1_t LMICuslike_mapChannels(u1_t chpage, u2_t chmap) {
|
|||||||
|| is also special, in that it enables subbands.
|
|| is also special, in that it enables subbands.
|
||||||
*/
|
*/
|
||||||
u1_t base, top;
|
u1_t base, top;
|
||||||
|
bit_t result = 0;
|
||||||
|
|
||||||
|
if (chpage == MCMD_LADR_CHP_BANK) {
|
||||||
|
// each bit enables a bank of channels
|
||||||
|
for (u1_t subband = 0; subband < 8; ++subband, chmap >>= 1) {
|
||||||
|
if (chmap & 1) {
|
||||||
|
result |= LMIC_enableSubBand(subband);
|
||||||
|
} else {
|
||||||
|
result |= LMIC_disableSubBand(subband);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
if (chpage < MCMD_LADR_CHP_USLIKE_SPECIAL) {
|
if (chpage < MCMD_LADR_CHP_USLIKE_SPECIAL) {
|
||||||
// operate on channels 0..15, 16..31, 32..47, 48..63
|
// operate on channels 0..15, 16..31, 32..47, 48..63
|
||||||
base = chpage << 4;
|
base = chpage << 4;
|
||||||
top = base + 16;
|
top = base + 16;
|
||||||
if (base == 64) {
|
if (base == 64) {
|
||||||
if (chmap & 0xFF00) {
|
|
||||||
// those are reserved bits, fail.
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
top = 72;
|
top = 72;
|
||||||
}
|
}
|
||||||
} else if (chpage == MCMD_LADR_CHP_BANK) {
|
} else /* if (chpage == MCMD_LADR_CHP_125ON || chpage == MCMD_LADR_CHP_125OFF) */ {
|
||||||
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;
|
u1_t const en125 = chpage == MCMD_LADR_CHP_125ON;
|
||||||
|
|
||||||
// enable or disable all 125kHz channels
|
// enable or disable all 125kHz channels
|
||||||
for (u1_t chnl = 0; chnl < 64; ++chnl) {
|
for (u1_t chnl = 0; chnl < 64; ++chnl) {
|
||||||
if (en125)
|
if (en125)
|
||||||
LMIC_enableChannel(chnl);
|
result |= LMIC_enableChannel(chnl);
|
||||||
else
|
else
|
||||||
LMIC_disableChannel(chnl);
|
result |= LMIC_disableChannel(chnl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// then apply mask to top 8 channels.
|
// then apply mask to top 8 channels.
|
||||||
base = 64;
|
base = 64;
|
||||||
top = 72;
|
top = 72;
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply chmap to channels in [base..top-1].
|
// apply chmap to channels in [base..top-1].
|
||||||
// Use enable/disable channel to keep activeChannel counts in sync.
|
// Use enable/disable channel to keep activeChannel counts in sync.
|
||||||
for (u1_t chnl = base; chnl < top; ++chnl, chmap >>= 1) {
|
for (u1_t chnl = base; chnl < top; ++chnl, chmap >>= 1) {
|
||||||
if (chmap & 0x0001)
|
if (chmap & 0x0001)
|
||||||
LMIC_enableChannel(chnl);
|
result |= LMIC_enableChannel(chnl);
|
||||||
else
|
else
|
||||||
LMIC_disableChannel(chnl);
|
result |= LMIC_disableChannel(chnl);
|
||||||
}
|
}
|
||||||
return 1;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// US does not have duty cycling - return now as earliest TX time
|
// US does not have duty cycling - return now as earliest TX time
|
||||||
@ -183,18 +214,13 @@ void LMICuslike_initJoinLoop(void) {
|
|||||||
// starting point.
|
// starting point.
|
||||||
setNextChannel(0, 64, LMIC.activeChannels125khz);
|
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.
|
// make sure LMIC.txend is valid.
|
||||||
LMIC.txend = os_getTime();
|
LMIC.txend = os_getTime();
|
||||||
|
ASSERT((LMIC.opmode & OP_NEXTCHNL) == 0);
|
||||||
|
|
||||||
// make sure the datarate is set to DR0 per LoRaWAN regional reqts V1.0.2,
|
// make sure the datarate is set to DR2 per LoRaWAN regional reqts V1.0.2,
|
||||||
// section 2.2.2
|
// section 2.*.2
|
||||||
// TODO(tmm@mcci.com): parameterize this for US-like
|
LMICcore_setDrJoin(DRCHG_SET, LMICbandplan_getInitialDrJoin());
|
||||||
LMICcore_setDrJoin(DRCHG_SET, LORAWAN_DR0);
|
|
||||||
|
|
||||||
// TODO(tmm@mcci.com) need to implement the transmit randomization and
|
// TODO(tmm@mcci.com) need to implement the transmit randomization and
|
||||||
// duty cycle restrictions from LoRaWAN V1.0.2 section 7.
|
// duty cycle restrictions from LoRaWAN V1.0.2 section 7.
|
||||||
@ -233,7 +259,7 @@ ostime_t LMICuslike_nextJoinState(void) {
|
|||||||
setNextChannel(0, 64, LMIC.activeChannels125khz);
|
setNextChannel(0, 64, LMIC.activeChannels125khz);
|
||||||
|
|
||||||
// TODO(tmm@mcci.com) parameterize
|
// TODO(tmm@mcci.com) parameterize
|
||||||
s1_t dr = LORAWAN_DR0;
|
s1_t dr = LMICuslike_getJoin125kHzDR();
|
||||||
if ((++LMIC.txCnt & 0x7) == 0) {
|
if ((++LMIC.txCnt & 0x7) == 0) {
|
||||||
failed = 1; // All DR exhausted - signal failed
|
failed = 1; // All DR exhausted - signal failed
|
||||||
}
|
}
|
||||||
@ -260,4 +286,16 @@ ostime_t LMICuslike_nextJoinState(void) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void LMICuslike_saveAdrState(lmic_saved_adr_state_t *pStateBuffer) {
|
||||||
|
memcpy(
|
||||||
|
pStateBuffer->channelMap,
|
||||||
|
LMIC.channelMap,
|
||||||
|
sizeof(LMIC.channelMap)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bit_t LMICuslike_compareAdrState(const lmic_saved_adr_state_t *pStateBuffer) {
|
||||||
|
return memcmp(pStateBuffer->channelMap, LMIC.channelMap, sizeof(LMIC.channelMap)) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // CFG_LMIC_US_like
|
#endif // CFG_LMIC_US_like
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016 IBM Corporation.
|
* Copyright (c) 2014-2016 IBM Corporation.
|
||||||
* Copyright (c) 2017 MCCI Corporation.
|
* Copyright (c) 2017, 2019 MCCI Corporation.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -43,6 +43,9 @@
|
|||||||
#define IS_CHANNEL_500khz(c) (c>=64 && c<72)
|
#define IS_CHANNEL_500khz(c) (c>=64 && c<72)
|
||||||
#define ENABLED_CHANNEL(chnl) ((LMIC.channelMap[(chnl >> 4)] & (1<<(chnl & 0x0F))) != 0)
|
#define ENABLED_CHANNEL(chnl) ((LMIC.channelMap[(chnl >> 4)] & (1<<(chnl & 0x0F))) != 0)
|
||||||
|
|
||||||
|
// library functions: called from bandplan
|
||||||
|
void LMICuslike_initJoinLoop(void);
|
||||||
|
|
||||||
// provide the isValidBeacon1 function -- int for bool.
|
// provide the isValidBeacon1 function -- int for bool.
|
||||||
static inline int
|
static inline int
|
||||||
LMICuslike_isValidBeacon1(const uint8_t *d) {
|
LMICuslike_isValidBeacon1(const uint8_t *d) {
|
||||||
@ -77,24 +80,30 @@ void LMICuslike_initDefaultChannels(bit_t fJoin);
|
|||||||
#define LMICbandplan_setSessionInitDefaultChannels() \
|
#define LMICbandplan_setSessionInitDefaultChannels() \
|
||||||
do { /* nothing */} while (0)
|
do { /* nothing */} while (0)
|
||||||
|
|
||||||
u1_t LMICuslike_mapChannels(u1_t chpage, u2_t chmap);
|
bit_t LMICuslike_canMapChannels(u1_t chpage, u2_t chmap);
|
||||||
|
#define LMICbandplan_canMapChannels(chpage, chmap) LMICuslike_canMapChannels(chpage, chmap)
|
||||||
|
|
||||||
|
bit_t LMICuslike_mapChannels(u1_t chpage, u2_t chmap);
|
||||||
#define LMICbandplan_mapChannels(chpage, chmap) LMICuslike_mapChannels(chpage, chmap)
|
#define LMICbandplan_mapChannels(chpage, chmap) LMICuslike_mapChannels(chpage, chmap)
|
||||||
|
|
||||||
ostime_t LMICuslike_nextTx(ostime_t now);
|
ostime_t LMICuslike_nextTx(ostime_t now);
|
||||||
#define LMICbandplan_nextTx(now) LMICuslike_nextTx(now)
|
#define LMICbandplan_nextTx(now) LMICuslike_nextTx(now)
|
||||||
|
|
||||||
void LMICuslike_initJoinLoop(void);
|
|
||||||
#define LMICbandplan_initJoinLoop() LMICuslike_initJoinLoop()
|
|
||||||
|
|
||||||
ostime_t LMICuslike_nextJoinState(void);
|
ostime_t LMICuslike_nextJoinState(void);
|
||||||
#define LMICbandplan_nextJoinState() LMICuslike_nextJoinState();
|
#define LMICbandplan_nextJoinState() LMICuslike_nextJoinState();
|
||||||
|
|
||||||
static inline ostime_t LMICeulike_nextJoinTime(ostime_t now) {
|
static inline ostime_t LMICuslike_nextJoinTime(ostime_t now) {
|
||||||
return now;
|
return now;
|
||||||
}
|
}
|
||||||
#define LMICbandplan_nextJoinTime(now) LMICeulike_nextJoinTime(now)
|
#define LMICbandplan_nextJoinTime(now) LMICuslike_nextJoinTime(now)
|
||||||
|
|
||||||
#define LMICbandplan_init() \
|
#define LMICbandplan_init() \
|
||||||
do { /* nothing */ } while (0)
|
do { /* nothing */ } while (0)
|
||||||
|
|
||||||
|
void LMICuslike_saveAdrState(lmic_saved_adr_state_t *pStateBuffer);
|
||||||
|
#define LMICbandplan_saveAdrState(pState) LMICuslike_saveAdrState(pState)
|
||||||
|
|
||||||
|
bit_t LMICuslike_compareAdrState(const lmic_saved_adr_state_t *pStateBuffer);
|
||||||
|
#define LMICbandplan_compareAdrState(pState) LMICuslike_compareAdrState(pState)
|
||||||
|
|
||||||
#endif // _lmic_us_like_h_
|
#endif // _lmic_us_like_h_
|
||||||
|
@ -9,7 +9,7 @@ Copyright & License:
|
|||||||
See accompanying LICENSE file.
|
See accompanying LICENSE file.
|
||||||
|
|
||||||
Author:
|
Author:
|
||||||
Terry Moore, MCCI September 2019
|
Terry Moore, MCCI September 2018
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
12
src/lmic/lorabase.h
Normal file → Executable file
12
src/lmic/lorabase.h
Normal file → Executable file
@ -44,7 +44,14 @@ typedef u1_t cr_t;
|
|||||||
typedef u1_t sf_t;
|
typedef u1_t sf_t;
|
||||||
typedef u1_t bw_t;
|
typedef u1_t bw_t;
|
||||||
typedef u1_t dr_t;
|
typedef u1_t dr_t;
|
||||||
|
|
||||||
// Radio parameter set (encodes SF/BW/CR/IH/NOCRC)
|
// Radio parameter set (encodes SF/BW/CR/IH/NOCRC)
|
||||||
|
// 2..0: Spreading factor
|
||||||
|
// 4..3: bandwidth: 0 == 125kHz, 1 == 250 kHz, 2 == 500 kHz. 3 == reserved.
|
||||||
|
// 6..5: coding rate: 0 == 4/5, 1 == 4/6, 2 == 4/7, 3 == 4/8
|
||||||
|
// 7: nocrc: 0 == with crc, 1 == without crc
|
||||||
|
// 15..8: Implicit header control: 0 ==> none, 1..0xFF ==> length in bytes.
|
||||||
|
|
||||||
typedef u2_t rps_t;
|
typedef u2_t rps_t;
|
||||||
TYPEDEF_xref2rps_t;
|
TYPEDEF_xref2rps_t;
|
||||||
|
|
||||||
@ -52,7 +59,7 @@ enum { ILLEGAL_RPS = 0xFF };
|
|||||||
|
|
||||||
// Global maximum frame length
|
// Global maximum frame length
|
||||||
enum { STD_PREAMBLE_LEN = 8 };
|
enum { STD_PREAMBLE_LEN = 8 };
|
||||||
enum { MAX_LEN_FRAME = 64 };
|
enum { MAX_LEN_FRAME = LMIC_ENABLE_long_messages ? 255 : 64 };
|
||||||
enum { LEN_DEVNONCE = 2 };
|
enum { LEN_DEVNONCE = 2 };
|
||||||
enum { LEN_ARTNONCE = 3 };
|
enum { LEN_ARTNONCE = 3 };
|
||||||
enum { LEN_NETID = 3 };
|
enum { LEN_NETID = 3 };
|
||||||
@ -414,7 +421,6 @@ enum {
|
|||||||
HDR_FTYPE_DADN = 0x60, // data (unconfirmed) dn
|
HDR_FTYPE_DADN = 0x60, // data (unconfirmed) dn
|
||||||
HDR_FTYPE_DCUP = 0x80, // data confirmed up
|
HDR_FTYPE_DCUP = 0x80, // data confirmed up
|
||||||
HDR_FTYPE_DCDN = 0xA0, // data confirmed dn
|
HDR_FTYPE_DCDN = 0xA0, // data confirmed dn
|
||||||
HDR_FTYPE_REJOIN = 0xC0, // rejoin for roaming
|
|
||||||
HDR_FTYPE_PROP = 0xE0
|
HDR_FTYPE_PROP = 0xE0
|
||||||
};
|
};
|
||||||
enum {
|
enum {
|
||||||
@ -449,6 +455,7 @@ enum {
|
|||||||
MCMD_RXTimingSetupAns = 0x08, // : -
|
MCMD_RXTimingSetupAns = 0x08, // : -
|
||||||
MCMD_TxParamSetupAns = 0x09, // : -
|
MCMD_TxParamSetupAns = 0x09, // : -
|
||||||
MCMD_DIChannelAns = 0x0A, // : u1: [7-2]:RFU 1:exists 0:OK
|
MCMD_DIChannelAns = 0x0A, // : u1: [7-2]:RFU 1:exists 0:OK
|
||||||
|
MCMD_DeviceTimeReq = 0x0D,
|
||||||
|
|
||||||
// Class B
|
// Class B
|
||||||
MCMD_PING_IND = 0x10, // - pingability indic : u1: 7=RFU, 6-4:interval, 3-0:datarate
|
MCMD_PING_IND = 0x10, // - pingability indic : u1: 7=RFU, 6-4:interval, 3-0:datarate
|
||||||
@ -468,6 +475,7 @@ enum {
|
|||||||
MCMD_RXTimingSetupReq = 0x08, // : u1: [7-4]:RFU [3-0]: Delay 1-15s (0 => 1)
|
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_TxParamSetupReq = 0x09, // : u1: [7-6]:RFU [5:4]: dl dwell/ul dwell [3:0] max EIRP
|
||||||
MCMD_DIChannelReq = 0x0A, // : u1: channel, u3: frequency
|
MCMD_DIChannelReq = 0x0A, // : u1: channel, u3: frequency
|
||||||
|
MCMD_DeviceTimeAns = 0x0D,
|
||||||
|
|
||||||
// Class B
|
// Class B
|
||||||
MCMD_PING_SET = 0x11, // set ping freq : u3: freq
|
MCMD_PING_SET = 0x11, // set ping freq : u3: freq
|
||||||
|
42
src/lmic/oslmic.c
Normal file → Executable file
42
src/lmic/oslmic.c
Normal file → Executable file
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016 IBM Corporation.
|
* Copyright (c) 2014-2016 IBM Corporation.
|
||||||
* Copyright (c) 2016-2017 MCCI Corporation.
|
* Copyright (c) 2016-2017, 2019 MCCI Corporation.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -68,13 +68,15 @@ static int unlinkjob (osjob_t** pnext, osjob_t* job) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static osjob_t** getJobQueue(osjob_t* job) {
|
||||||
|
return os_jobIsTimed(job) ? &OS.scheduledjobs : &OS.runnablejobs;
|
||||||
|
}
|
||||||
|
|
||||||
// clear scheduled job
|
// clear scheduled job
|
||||||
void os_clearCallback (osjob_t* job) {
|
void os_clearCallback (osjob_t* job) {
|
||||||
hal_disableIRQs();
|
hal_disableIRQs();
|
||||||
|
|
||||||
// if it's not in the scheduled jobs, look in the runnable...
|
unlinkjob(getJobQueue(job), job);
|
||||||
if (! unlinkjob(&OS.scheduledjobs, job))
|
|
||||||
unlinkjob(&OS.runnablejobs, job);
|
|
||||||
|
|
||||||
hal_enableIRQs();
|
hal_enableIRQs();
|
||||||
}
|
}
|
||||||
@ -83,11 +85,15 @@ void os_clearCallback (osjob_t* job) {
|
|||||||
void os_setCallback (osjob_t* job, osjobcb_t cb) {
|
void os_setCallback (osjob_t* job, osjobcb_t cb) {
|
||||||
osjob_t** pnext;
|
osjob_t** pnext;
|
||||||
hal_disableIRQs();
|
hal_disableIRQs();
|
||||||
|
|
||||||
// remove if job was already queued
|
// remove if job was already queued
|
||||||
unlinkjob(&OS.runnablejobs, job);
|
unlinkjob(getJobQueue(job), job);
|
||||||
// fill-in job
|
|
||||||
job->func = cb;
|
// fill-in job. Ascending memory order is write-queue friendly
|
||||||
job->next = NULL;
|
job->next = NULL;
|
||||||
|
job->deadline = 0;
|
||||||
|
job->func = cb;
|
||||||
|
|
||||||
// add to end of run queue
|
// add to end of run queue
|
||||||
for(pnext=&OS.runnablejobs; *pnext; pnext=&((*pnext)->next));
|
for(pnext=&OS.runnablejobs; *pnext; pnext=&((*pnext)->next));
|
||||||
*pnext = job;
|
*pnext = job;
|
||||||
@ -97,13 +103,21 @@ void os_setCallback (osjob_t* job, osjobcb_t cb) {
|
|||||||
// schedule timed job
|
// schedule timed job
|
||||||
void os_setTimedCallback (osjob_t* job, ostime_t time, osjobcb_t cb) {
|
void os_setTimedCallback (osjob_t* job, ostime_t time, osjobcb_t cb) {
|
||||||
osjob_t** pnext;
|
osjob_t** pnext;
|
||||||
|
|
||||||
|
// special case time 0 -- it will be one tick late.
|
||||||
|
if (time == 0)
|
||||||
|
time = 1;
|
||||||
|
|
||||||
hal_disableIRQs();
|
hal_disableIRQs();
|
||||||
|
|
||||||
// remove if job was already queued
|
// remove if job was already queued
|
||||||
unlinkjob(&OS.scheduledjobs, job);
|
unlinkjob(getJobQueue(job), job);
|
||||||
|
|
||||||
// fill-in job
|
// fill-in job
|
||||||
|
job->next = NULL;
|
||||||
job->deadline = time;
|
job->deadline = time;
|
||||||
job->func = cb;
|
job->func = cb;
|
||||||
job->next = NULL;
|
|
||||||
// insert into schedule
|
// insert into schedule
|
||||||
for(pnext=&OS.scheduledjobs; *pnext; pnext=&((*pnext)->next)) {
|
for(pnext=&OS.scheduledjobs; *pnext; pnext=&((*pnext)->next)) {
|
||||||
if((*pnext)->deadline - time > 0) { // (cmp diff, not abs!)
|
if((*pnext)->deadline - time > 0) { // (cmp diff, not abs!)
|
||||||
@ -141,3 +155,13 @@ void os_runloop_once() {
|
|||||||
j->func(j);
|
j->func(j);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return true if there are any jobs scheduled within time ticks from now.
|
||||||
|
// return false if any jobs scheduled are at least time ticks in the future.
|
||||||
|
bit_t os_queryTimeCriticalJobs(ostime_t time) {
|
||||||
|
if (OS.scheduledjobs &&
|
||||||
|
OS.scheduledjobs->deadline - os_getTime() < time)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
152
src/lmic/oslmic.h
Normal file → Executable file
152
src/lmic/oslmic.h
Normal file → Executable file
@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016 IBM Corporation.
|
* Copyright (c) 2014-2016 IBM Corporation.
|
||||||
|
* Copyright (c) 2018, 2019 MCCI Corporation
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -29,29 +30,22 @@
|
|||||||
#ifndef _oslmic_h_
|
#ifndef _oslmic_h_
|
||||||
#define _oslmic_h_
|
#define _oslmic_h_
|
||||||
|
|
||||||
// Dependencies required for the LoRa MAC in C to run.
|
// Dependencies required for the LMIC to run.
|
||||||
// These settings can be adapted to the underlying system.
|
// These settings can be adapted to the underlying system.
|
||||||
// You should not, however, change the lmic.[hc]
|
// You should not, however, change the lmic merely for porting purposes.[hc]
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifndef _lmic_env_h_
|
||||||
extern "C"{
|
# include "lmic_env.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//================================================================================
|
#ifndef _oslmic_types_h_
|
||||||
//================================================================================
|
# include "oslmic_types.h"
|
||||||
// Target platform as C library
|
#endif
|
||||||
typedef uint8_t bit_t;
|
|
||||||
typedef uint8_t u1_t;
|
LMIC_BEGIN_DECLS
|
||||||
typedef int8_t s1_t;
|
|
||||||
typedef uint16_t u2_t;
|
|
||||||
typedef int16_t s2_t;
|
|
||||||
typedef uint32_t u4_t;
|
|
||||||
typedef int32_t s4_t;
|
|
||||||
typedef unsigned int uint;
|
|
||||||
typedef const char* str_t;
|
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "hal.h"
|
#include "hal.h"
|
||||||
@ -73,7 +67,6 @@ typedef struct rxsched_t rxsched_t;
|
|||||||
typedef struct bcninfo_t bcninfo_t;
|
typedef struct bcninfo_t bcninfo_t;
|
||||||
typedef const u1_t* xref2cu1_t;
|
typedef const u1_t* xref2cu1_t;
|
||||||
typedef u1_t* xref2u1_t;
|
typedef u1_t* xref2u1_t;
|
||||||
typedef s4_t ostime_t;
|
|
||||||
|
|
||||||
// int32_t == s4_t is long on some platforms; and someday
|
// int32_t == s4_t is long on some platforms; and someday
|
||||||
// we will want 64-bit ostime_t. So, we will use a macro for the
|
// we will want 64-bit ostime_t. So, we will use a macro for the
|
||||||
@ -91,107 +84,7 @@ typedef s4_t ostime_t;
|
|||||||
|
|
||||||
#define SIZEOFEXPR(x) sizeof(x)
|
#define SIZEOFEXPR(x) sizeof(x)
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
#define DECL_ON_LMIC_EVENT LMIC_DECLARE_FUNCTION_WEAK(void, onEvent, (ev_t e))
|
||||||
// Annotations to avoid various "unused" warnings. These must appear as a
|
|
||||||
// statement in the function body; the macro annotates the variable to quiet
|
|
||||||
// compiler warnings. The way this is done is compiler-specific, and so these
|
|
||||||
// definitions are fall-backs, which might be overridden.
|
|
||||||
//
|
|
||||||
// Although these are all similar, we don't want extra macro expansions,
|
|
||||||
// so we define each one explicitly rather than relying on a common macro.
|
|
||||||
//----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// signal that a parameter is intentionally unused.
|
|
||||||
#ifndef LMIC_UNREFERENCED_PARAMETER
|
|
||||||
# define LMIC_UNREFERENCED_PARAMETER(v) do { (void) (v); } while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// an API parameter is a parameter that is required by an API definition, but
|
|
||||||
// happens to be unreferenced in this implementation. This is a stronger
|
|
||||||
// assertion than LMIC_UNREFERENCED_PARAMETER(): this parameter is here
|
|
||||||
// becuase of an API contract, but we have no use for it in this function.
|
|
||||||
#ifndef LMIC_API_PARAMETER
|
|
||||||
# define LMIC_API_PARAMETER(v) do { (void) (v); } while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// an intentionally-unreferenced variable.
|
|
||||||
#ifndef LMIC_UNREFERENCED_VARIABLE
|
|
||||||
# define LMIC_UNREFERENCED_VARIABLE(v) do { (void) (v); } while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// we have three (!) debug levels (LMIC_DEBUG_LEVEL > 0, LMIC_DEBUG_LEVEL > 1,
|
|
||||||
// and LMIC_X_DEBUG_LEVEL > 0. In each case we might have parameters or
|
|
||||||
// or varables that are only refereneced at the target debug level.
|
|
||||||
|
|
||||||
// Parameter referenced only if debugging at level > 0.
|
|
||||||
#ifndef LMIC_DEBUG1_PARAMETER
|
|
||||||
# if LMIC_DEBUG_LEVEL > 0
|
|
||||||
# define LMIC_DEBUG1_PARAMETER(v) do { ; } while (0)
|
|
||||||
# else
|
|
||||||
# define LMIC_DEBUG1_PARAMETER(v) do { (void) (v); } while (0)
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// variable referenced only if debugging at level > 0
|
|
||||||
#ifndef LMIC_DEBUG1_VARIABLE
|
|
||||||
# if LMIC_DEBUG_LEVEL > 0
|
|
||||||
# define LMIC_DEBUG1_VARIABLE(v) do { ; } while (0)
|
|
||||||
# else
|
|
||||||
# define LMIC_DEBUG1_VARIABLE(v) do { (void) (v); } while (0)
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// parameter referenced only if debugging at level > 1
|
|
||||||
#ifndef LMIC_DEBUG2_PARAMETER
|
|
||||||
# if LMIC_DEBUG_LEVEL > 1
|
|
||||||
# define LMIC_DEBUG2_PARAMETER(v) do { ; } while (0)
|
|
||||||
# else
|
|
||||||
# define LMIC_DEBUG2_PARAMETER(v) do { (void) (v); } while (0)
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// variable referenced only if debugging at level > 1
|
|
||||||
#ifndef LMIC_DEBUG2_VARIABLE
|
|
||||||
# if LMIC_DEBUG_LEVEL > 1
|
|
||||||
# define LMIC_DEBUG2_VARIABLE(v) do { ; } while (0)
|
|
||||||
# else
|
|
||||||
# define LMIC_DEBUG2_VARIABLE(v) do { (void) (v); } while (0)
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// parameter referenced only if LMIC_X_DEBUG_LEVEL > 0
|
|
||||||
#ifndef LMIC_X_DEBUG_PARAMETER
|
|
||||||
# if LMIC_X_DEBUG_LEVEL > 0
|
|
||||||
# define LMIC_X_DEBUG_PARAMETER(v) do { ; } while (0)
|
|
||||||
# else
|
|
||||||
# define LMIC_X_DEBUG_PARAMETER(v) do { (void) (v); } while (0)
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// variable referenced only if LMIC_X_DEBUG_LEVEL > 0
|
|
||||||
#ifndef LMIC_X_DEBUG_VARIABLE
|
|
||||||
# if LMIC_X_DEBUG_LEVEL > 0
|
|
||||||
# define LMIC_X_DEBUG_VARIABLE(v) do { ; } while (0)
|
|
||||||
# else
|
|
||||||
# define LMIC_X_DEBUG_VARIABLE(v) do { (void) (v); } while (0)
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// parameter referenced only if EV() macro is enabled (which it never is)
|
|
||||||
// TODO(tmm@mcci.com) take out the EV() framework as it reuqires C++, and
|
|
||||||
// this code is really C-99 to its bones.
|
|
||||||
#ifndef LMIC_EV_PARAMETER
|
|
||||||
# define LMIC_EV_PARAMETER(v) do { (void) (v); } while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// variable referenced only if EV() macro is defined.
|
|
||||||
#ifndef LMIC_EV_VARIABLE
|
|
||||||
# define LMIC_EV_VARIABLE(v) do { (void) (v); } while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#define ON_LMIC_EVENT(ev) onEvent(ev)
|
|
||||||
#define DECL_ON_LMIC_EVENT void onEvent(ev_t e)
|
|
||||||
|
|
||||||
extern u4_t AESAUX[];
|
extern u4_t AESAUX[];
|
||||||
extern u4_t AESKEY[];
|
extern u4_t AESKEY[];
|
||||||
@ -255,7 +148,13 @@ void radio_monitor_rssi(ostime_t n, oslmic_radio_rssi_t *pRssi);
|
|||||||
|
|
||||||
|
|
||||||
struct osjob_t; // fwd decl.
|
struct osjob_t; // fwd decl.
|
||||||
typedef void (*osjobcb_t) (struct osjob_t*);
|
|
||||||
|
//! the function type for osjob_t callbacks
|
||||||
|
typedef void (osjobcbfn_t)(struct osjob_t*);
|
||||||
|
|
||||||
|
//! the pointer-to-function for osjob_t callbacks
|
||||||
|
typedef osjobcbfn_t *osjobcb_t;
|
||||||
|
|
||||||
struct osjob_t {
|
struct osjob_t {
|
||||||
struct osjob_t* next;
|
struct osjob_t* next;
|
||||||
ostime_t deadline;
|
ostime_t deadline;
|
||||||
@ -263,6 +162,11 @@ struct osjob_t {
|
|||||||
};
|
};
|
||||||
TYPEDEF_xref2osjob_t;
|
TYPEDEF_xref2osjob_t;
|
||||||
|
|
||||||
|
//! determine whether a job is timed or immediate. os_setTimedCallback()
|
||||||
|
// must treat incoming == 0 as being 1 instead.
|
||||||
|
static inline int os_jobIsTimed(xref2osjob_t job) {
|
||||||
|
return (job->deadline != 0);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef HAS_os_calls
|
#ifndef HAS_os_calls
|
||||||
|
|
||||||
@ -296,6 +200,10 @@ void os_radio (u1_t mode);
|
|||||||
#ifndef os_getBattLevel
|
#ifndef os_getBattLevel
|
||||||
u1_t os_getBattLevel (void);
|
u1_t os_getBattLevel (void);
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef os_queryTimeCriticalJobs
|
||||||
|
//! Return non-zero if any jobs are scheduled between now and now+time.
|
||||||
|
bit_t os_queryTimeCriticalJobs(ostime_t time);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef os_rlsbf4
|
#ifndef os_rlsbf4
|
||||||
//! Read 32-bit quantity from given pointer in little endian byte order.
|
//! Read 32-bit quantity from given pointer in little endian byte order.
|
||||||
@ -416,8 +324,6 @@ extern xref2u1_t AESaux;
|
|||||||
u4_t os_aes (u1_t mode, xref2u1_t buf, u2_t len);
|
u4_t os_aes (u1_t mode, xref2u1_t buf, u2_t len);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
LMIC_END_DECLS
|
||||||
} // extern "C"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // _oslmic_h_
|
#endif // _oslmic_h_
|
||||||
|
47
src/lmic/oslmic_types.h
Executable file
47
src/lmic/oslmic_types.h
Executable file
@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
Module: oslmic_types.h
|
||||||
|
|
||||||
|
Function:
|
||||||
|
Basic types from oslmic.h, shared by all layers.
|
||||||
|
|
||||||
|
Copyright & License:
|
||||||
|
See accompanying LICENSE file.
|
||||||
|
|
||||||
|
Author:
|
||||||
|
Terry Moore, MCCI November 2018
|
||||||
|
(based on oslmic.h from IBM).
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _oslmic_types_h_
|
||||||
|
# define _oslmic_types_h_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//================================================================================
|
||||||
|
//================================================================================
|
||||||
|
// Target platform as C library
|
||||||
|
typedef uint8_t bit_t;
|
||||||
|
typedef uint8_t u1_t;
|
||||||
|
typedef int8_t s1_t;
|
||||||
|
typedef uint16_t u2_t;
|
||||||
|
typedef int16_t s2_t;
|
||||||
|
typedef uint32_t u4_t;
|
||||||
|
typedef int32_t s4_t;
|
||||||
|
typedef unsigned int uint;
|
||||||
|
typedef const char* str_t;
|
||||||
|
|
||||||
|
// the HAL needs to give us ticks, so it ought to know the right type.
|
||||||
|
typedef s4_t ostime_t;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* end of oslmic_types.h */
|
||||||
|
#endif /* _oslmic_types_h_ */
|
98
src/lmic/radio.c
Normal file → Executable file
98
src/lmic/radio.c
Normal file → Executable file
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016 IBM Corporation.
|
* Copyright (c) 2014-2016 IBM Corporation.
|
||||||
* Copyright (c) 2016-2018 MCCI Corporation.
|
* Copyright (c) 2016-2019 MCCI Corporation.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
@ -135,13 +135,22 @@
|
|||||||
// #define RegAgcThresh2 0x45 // common
|
// #define RegAgcThresh2 0x45 // common
|
||||||
// #define RegAgcThresh3 0x46 // common
|
// #define RegAgcThresh3 0x46 // common
|
||||||
// #define RegPllHop 0x4B // common
|
// #define RegPllHop 0x4B // common
|
||||||
#define RegPaDac 0x4D // common
|
|
||||||
// #define RegTcxo 0x58 // common
|
// #define RegTcxo 0x58 // common
|
||||||
// #define RegPll 0x5C // common
|
// #define RegPll 0x5C // common
|
||||||
// #define RegPllLowPn 0x5E // common
|
// #define RegPllLowPn 0x5E // common
|
||||||
// #define RegFormerTemp 0x6C // common
|
// #define RegFormerTemp 0x6C // common
|
||||||
// #define RegBitRateFrac 0x70 // common
|
// #define RegBitRateFrac 0x70 // common
|
||||||
|
|
||||||
|
#if defined(CFG_sx1276_radio)
|
||||||
|
#define RegTcxo 0x4B // common
|
||||||
|
#define RegPaDac 0x4D // common
|
||||||
|
#elif defined(CFG_sx1272_radio)
|
||||||
|
#define RegTcxo 0x58 // common
|
||||||
|
#define RegPaDac 0x5A // common
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define RegTcxo_TcxoInputOn (1u << 4)
|
||||||
|
|
||||||
// ----------------------------------------
|
// ----------------------------------------
|
||||||
// spread factors and mode for RegModemConfig2
|
// spread factors and mode for RegModemConfig2
|
||||||
#define SX1272_MC2_FSK 0x00
|
#define SX1272_MC2_FSK 0x00
|
||||||
@ -179,6 +188,12 @@
|
|||||||
|
|
||||||
#define SX1276_MC1_IMPLICIT_HEADER_MODE_ON 0x01
|
#define SX1276_MC1_IMPLICIT_HEADER_MODE_ON 0x01
|
||||||
|
|
||||||
|
#ifdef CFG_sx1276_radio
|
||||||
|
# define SX127X_MC1_IMPLICIT_HEADER_MODE_ON SX1276_MC1_IMPLICIT_HEADER_MODE_ON
|
||||||
|
#else
|
||||||
|
# define SX127X_MC1_IMPLICIT_HEADER_MODE_ON SX1272_MC1_IMPLICIT_HEADER_MODE_ON
|
||||||
|
#endif
|
||||||
|
|
||||||
// sx1276 RegModemConfig2
|
// sx1276 RegModemConfig2
|
||||||
#define SX1276_MC2_RX_PAYLOAD_CRCON 0x04
|
#define SX1276_MC2_RX_PAYLOAD_CRCON 0x04
|
||||||
|
|
||||||
@ -255,7 +270,7 @@
|
|||||||
#define MAP_DIO0_LORA_TXDONE 0x40 // 01------
|
#define MAP_DIO0_LORA_TXDONE 0x40 // 01------
|
||||||
#define MAP_DIO1_LORA_RXTOUT 0x00 // --00----
|
#define MAP_DIO1_LORA_RXTOUT 0x00 // --00----
|
||||||
#define MAP_DIO1_LORA_NOP 0x30 // --11----
|
#define MAP_DIO1_LORA_NOP 0x30 // --11----
|
||||||
#define MAP_DIO2_LORA_NOP 0xC0 // ----11--
|
#define MAP_DIO2_LORA_NOP 0x0C // ----11--
|
||||||
|
|
||||||
#define MAP_DIO0_FSK_READY 0x00 // 00------ (packet sent / payload ready)
|
#define MAP_DIO0_FSK_READY 0x00 // 00------ (packet sent / payload ready)
|
||||||
#define MAP_DIO1_FSK_NOP 0x30 // --11----
|
#define MAP_DIO1_FSK_NOP 0x30 // --11----
|
||||||
@ -290,58 +305,41 @@ static u1_t randbuf[16];
|
|||||||
|
|
||||||
|
|
||||||
static void writeReg (u1_t addr, u1_t data ) {
|
static void writeReg (u1_t addr, u1_t data ) {
|
||||||
// ttn-esp32 change: higher level SPI interface
|
|
||||||
hal_spi_write(addr | 0x80, &data, 1);
|
hal_spi_write(addr | 0x80, &data, 1);
|
||||||
/*
|
|
||||||
hal_pin_nss(0);
|
|
||||||
hal_spi(addr | 0x80);
|
|
||||||
hal_spi(data);
|
|
||||||
hal_pin_nss(1);
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static u1_t readReg (u1_t addr) {
|
static u1_t readReg (u1_t addr) {
|
||||||
// ttn-esp32 change: higher level SPI interface
|
|
||||||
u1_t buf[1];
|
u1_t buf[1];
|
||||||
hal_spi_read(addr & 0x7f, buf, 1);
|
hal_spi_read(addr & 0x7f, buf, 1);
|
||||||
return buf[0];
|
return buf[0];
|
||||||
/*
|
|
||||||
hal_pin_nss(0);
|
|
||||||
hal_spi(addr & 0x7F);
|
|
||||||
u1_t val = hal_spi(0x00);
|
|
||||||
hal_pin_nss(1);
|
|
||||||
return val;
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void writeBuf (u1_t addr, xref2u1_t buf, u1_t len) {
|
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_spi_write(addr | 0x80, buf, len);
|
||||||
/*
|
|
||||||
hal_pin_nss(0);
|
|
||||||
hal_spi(addr | 0x80);
|
|
||||||
for (u1_t i=0; i<len; i++) {
|
|
||||||
hal_spi(buf[i]);
|
|
||||||
}
|
|
||||||
hal_pin_nss(1);
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void readBuf (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_spi_read(addr & 0x7f, buf, len);
|
||||||
/*
|
}
|
||||||
hal_pin_nss(0);
|
|
||||||
hal_spi(addr & 0x7F);
|
static void requestModuleActive(bit_t state) {
|
||||||
for (u1_t i=0; i<len; i++) {
|
ostime_t const ticks = hal_setModuleActive(state);
|
||||||
buf[i] = hal_spi(0x00);
|
|
||||||
}
|
if (ticks)
|
||||||
hal_pin_nss(1);
|
hal_waitUntil(os_getTime() + ticks);;
|
||||||
*/
|
}
|
||||||
|
|
||||||
|
static void writeOpmode(u1_t mode) {
|
||||||
|
u1_t const maskedMode = mode & OPMODE_MASK;
|
||||||
|
if (maskedMode != OPMODE_SLEEP)
|
||||||
|
requestModuleActive(1);
|
||||||
|
writeReg(RegOpMode, mode);
|
||||||
|
if (maskedMode == OPMODE_SLEEP)
|
||||||
|
requestModuleActive(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void opmode (u1_t mode) {
|
static void opmode (u1_t mode) {
|
||||||
writeReg(RegOpMode, (readReg(RegOpMode) & ~OPMODE_MASK) | mode);
|
writeOpmode((readReg(RegOpMode) & ~OPMODE_MASK) | mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void opmodeLora() {
|
static void opmodeLora() {
|
||||||
@ -349,7 +347,7 @@ static void opmodeLora() {
|
|||||||
#ifdef CFG_sx1276_radio
|
#ifdef CFG_sx1276_radio
|
||||||
u |= 0x8; // TBD: sx1276 high freq
|
u |= 0x8; // TBD: sx1276 high freq
|
||||||
#endif
|
#endif
|
||||||
writeReg(RegOpMode, u);
|
writeOpmode(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void opmodeFSK() {
|
static void opmodeFSK() {
|
||||||
@ -357,7 +355,7 @@ static void opmodeFSK() {
|
|||||||
#ifdef CFG_sx1276_radio
|
#ifdef CFG_sx1276_radio
|
||||||
u |= 0x8; // TBD: sx1276 high freq
|
u |= 0x8; // TBD: sx1276 high freq
|
||||||
#endif
|
#endif
|
||||||
writeReg(RegOpMode, u);
|
writeOpmode(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
// configure LoRa modem (cfg1, cfg2)
|
// configure LoRa modem (cfg1, cfg2)
|
||||||
@ -453,7 +451,7 @@ static void configChannel () {
|
|||||||
static void configPower () {
|
static void configPower () {
|
||||||
#ifdef CFG_sx1276_radio
|
#ifdef CFG_sx1276_radio
|
||||||
// PA_BOOST output is assumed but not 20 dBm.
|
// PA_BOOST output is assumed but not 20 dBm.
|
||||||
s1_t pw = (s1_t)LMIC.txpow;
|
s1_t pw = (s1_t)LMIC.radio_txpow;
|
||||||
if(pw > 17) {
|
if(pw > 17) {
|
||||||
pw = 17;
|
pw = 17;
|
||||||
} else if(pw < 2) {
|
} else if(pw < 2) {
|
||||||
@ -469,7 +467,7 @@ static void configPower () {
|
|||||||
|
|
||||||
#elif CFG_sx1272_radio
|
#elif CFG_sx1272_radio
|
||||||
// set PA config (2-17 dBm using PA_BOOST)
|
// set PA config (2-17 dBm using PA_BOOST)
|
||||||
s1_t pw = (s1_t)LMIC.txpow;
|
s1_t pw = (s1_t)LMIC.radio_txpow;
|
||||||
if(pw > 17) {
|
if(pw > 17) {
|
||||||
pw = 17;
|
pw = 17;
|
||||||
} else if(pw < 2) {
|
} else if(pw < 2) {
|
||||||
@ -483,7 +481,7 @@ static void configPower () {
|
|||||||
|
|
||||||
static void txfsk () {
|
static void txfsk () {
|
||||||
// select FSK modem (from sleep mode)
|
// select FSK modem (from sleep mode)
|
||||||
writeReg(RegOpMode, 0x10); // FSK, BT=0.5
|
writeOpmode(0x10); // FSK, BT=0.5
|
||||||
ASSERT(readReg(RegOpMode) == 0x10);
|
ASSERT(readReg(RegOpMode) == 0x10);
|
||||||
// enter standby mode (required for FIFO loading))
|
// enter standby mode (required for FIFO loading))
|
||||||
opmode(OPMODE_STANDBY);
|
opmode(OPMODE_STANDBY);
|
||||||
@ -642,8 +640,8 @@ static void rxlora (u1_t rxmode) {
|
|||||||
// set LNA gain
|
// set LNA gain
|
||||||
writeReg(RegLna, LNA_RX_GAIN);
|
writeReg(RegLna, LNA_RX_GAIN);
|
||||||
// set max payload size
|
// set max payload size
|
||||||
writeReg(LORARegPayloadMaxLength, 64);
|
writeReg(LORARegPayloadMaxLength, MAX_LEN_FRAME);
|
||||||
#if !defined(DISABLE_INVERT_IQ_ON_RX)
|
#if !defined(DISABLE_INVERT_IQ_ON_RX) /* DEPRECATED(tmm@mcci.com); #250. remove test, always include code in V3 */
|
||||||
// use inverted I/Q signal (prevent mote-to-mote communication)
|
// use inverted I/Q signal (prevent mote-to-mote communication)
|
||||||
|
|
||||||
// XXX: use flag to switch on/off inversion
|
// XXX: use flag to switch on/off inversion
|
||||||
@ -668,6 +666,9 @@ static void rxlora (u1_t rxmode) {
|
|||||||
// enable antenna switch for RX
|
// enable antenna switch for RX
|
||||||
hal_pin_rxtx(0);
|
hal_pin_rxtx(0);
|
||||||
|
|
||||||
|
writeReg(LORARegFifoAddrPtr, 0);
|
||||||
|
writeReg(LORARegFifoRxBaseAddr, 0);
|
||||||
|
|
||||||
// now instruct the radio to receive
|
// now instruct the radio to receive
|
||||||
if (rxmode == RXMODE_SINGLE) { // single rx
|
if (rxmode == RXMODE_SINGLE) { // single rx
|
||||||
hal_waitUntil(LMIC.rxtime); // busy wait until exact rx time
|
hal_waitUntil(LMIC.rxtime); // busy wait until exact rx time
|
||||||
@ -765,6 +766,8 @@ static void startrx (u1_t rxmode) {
|
|||||||
int radio_init () {
|
int radio_init () {
|
||||||
hal_disableIRQs();
|
hal_disableIRQs();
|
||||||
|
|
||||||
|
requestModuleActive(1);
|
||||||
|
|
||||||
// manually reset radio
|
// manually reset radio
|
||||||
#ifdef CFG_sx1276_radio
|
#ifdef CFG_sx1276_radio
|
||||||
hal_pin_rst(0); // drive RST pin low
|
hal_pin_rst(0); // drive RST pin low
|
||||||
@ -788,6 +791,10 @@ int radio_init () {
|
|||||||
#else
|
#else
|
||||||
#error Missing CFG_sx1272_radio/CFG_sx1276_radio
|
#error Missing CFG_sx1272_radio/CFG_sx1276_radio
|
||||||
#endif
|
#endif
|
||||||
|
// set the tcxo input, if needed
|
||||||
|
if (hal_queryUsingTcxo())
|
||||||
|
writeReg(RegTcxo, readReg(RegTcxo) | RegTcxo_TcxoInputOn);
|
||||||
|
|
||||||
// seed 15-byte randomness via noise rssi
|
// seed 15-byte randomness via noise rssi
|
||||||
rxlora(RXMODE_RSSI);
|
rxlora(RXMODE_RSSI);
|
||||||
while( (readReg(RegOpMode) & OPMODE_MASK) != OPMODE_RX ); // continuous rx
|
while( (readReg(RegOpMode) & OPMODE_MASK) != OPMODE_RX ); // continuous rx
|
||||||
@ -960,6 +967,7 @@ void radio_irq_handler_v2 (u1_t dio, ostime_t now) {
|
|||||||
#endif
|
#endif
|
||||||
if( (readReg(RegOpMode) & OPMODE_LORA) != 0) { // LORA modem
|
if( (readReg(RegOpMode) & OPMODE_LORA) != 0) { // LORA modem
|
||||||
u1_t flags = readReg(LORARegIrqFlags);
|
u1_t flags = readReg(LORARegIrqFlags);
|
||||||
|
LMIC.saveIrqFlags = flags;
|
||||||
LMIC_X_DEBUG_PRINTF("IRQ=%02x\n", flags);
|
LMIC_X_DEBUG_PRINTF("IRQ=%02x\n", flags);
|
||||||
if( flags & IRQ_LORA_TXDONE_MASK ) {
|
if( flags & IRQ_LORA_TXDONE_MASK ) {
|
||||||
// save exact tx time
|
// save exact tx time
|
||||||
@ -971,7 +979,7 @@ void radio_irq_handler_v2 (u1_t dio, ostime_t now) {
|
|||||||
}
|
}
|
||||||
LMIC.rxtime = now;
|
LMIC.rxtime = now;
|
||||||
// read the PDU and inform the MAC that we received something
|
// read the PDU and inform the MAC that we received something
|
||||||
LMIC.dataLen = (readReg(LORARegModemConfig1) & SX1272_MC1_IMPLICIT_HEADER_MODE_ON) ?
|
LMIC.dataLen = (readReg(LORARegModemConfig1) & SX127X_MC1_IMPLICIT_HEADER_MODE_ON) ?
|
||||||
readReg(LORARegPayloadLength) : readReg(LORARegRxNbBytes);
|
readReg(LORARegPayloadLength) : readReg(LORARegRxNbBytes);
|
||||||
// set FIFO read address pointer
|
// set FIFO read address pointer
|
||||||
writeReg(LORARegFifoAddrPtr, readReg(LORARegFifoRxCurrentAddr));
|
writeReg(LORARegFifoAddrPtr, readReg(LORARegFifoRxCurrentAddr));
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
*
|
|
||||||
* 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
|
|
||||||
*
|
|
||||||
* Task listening on a UART port for provisioning commands.
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
#ifndef _provision_task_h_
|
|
||||||
#define _provision_task_h_
|
|
||||||
|
|
||||||
#include "lmic/oslmic.h"
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
void provisioning_start_task();
|
|
||||||
bool provisioning_have_keys();
|
|
||||||
bool provisioning_decode_keys(const char *dev_eui, const char *app_eui, const char *app_key);
|
|
||||||
bool provisioning_from_mac(const char *app_eui, const char *app_key);
|
|
||||||
bool provisioning_save_keys();
|
|
||||||
bool provisioning_restore_keys(bool silent);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
Reference in New Issue
Block a user