Convert provisioning code to C++

This commit is contained in:
Manuel Bleichenbacher 2018-10-27 14:45:55 +02:00
parent ee08d2a3c1
commit 47063256a3
9 changed files with 184 additions and 157 deletions

View File

@ -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"
} }
], ],

View File

@ -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
{ {

View File

@ -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
{ {

View File

@ -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
{ {

View File

@ -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
{ {

View File

@ -16,49 +16,26 @@
#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(CONFIG_TTN_PROVISION_UART_NONE)
#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* TAG = "ttn_prov";
static const char *NVS_FLASH_PARTITION = "ttn"; static const char* NVS_FLASH_PARTITION = "ttn";
static const char *NVS_FLASH_KEY_DEV_EUI = "devEui"; static const char* NVS_FLASH_KEY_DEV_EUI = "devEui";
static const char *NVS_FLASH_KEY_APP_EUI = "appEui"; static const char* NVS_FLASH_KEY_APP_EUI = "appEui";
static const char *NVS_FLASH_KEY_APP_KEY = "appKey"; static const char* 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;
void ttn_provisioning_task_caller(void* pvParameter);
#if defined(CONFIG_TTN_PROVISION_UART_CONFIG_YES)
static void provisioning_config_uart();
#endif
// --- LMIC callbacks // --- LMIC callbacks
@ -86,22 +63,38 @@ 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(CONFIG_TTN_PROVISION_UART_NONE)
, 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() void TTNProvisioning::startTask()
{ {
#if defined(CONFIG_TTN_PROVISION_UART_CONFIG_YES) #if defined(CONFIG_TTN_PROVISION_UART_CONFIG_YES)
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 +111,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 +127,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 +142,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 +151,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 +168,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 +184,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 +202,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 +221,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 +231,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 +243,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 +259,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)
@ -296,7 +289,7 @@ void provisioning_process_line()
#if defined(CONFIG_TTN_PROVISION_UART_CONFIG_YES) #if defined(CONFIG_TTN_PROVISION_UART_CONFIG_YES)
void provisioning_config_uart() void TTNProvisioning::configUART()
{ {
esp_err_t err; esp_err_t err;
@ -305,7 +298,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 +314,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 +339,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 +376,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 +389,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 +404,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 +424,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 +443,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 +474,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 +499,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 +514,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 +528,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 +550,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 +581,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)

67
src/TTNProvisioning.h Normal file
View File

@ -0,0 +1,67 @@
/*******************************************************************************
*
* 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();
void startTask();
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);
private:
void provisioningTask();
bool decode(bool incl_dev_eui, const char *dev_eui, const char *app_eui, const char *app_key);
void addLineData(int numBytes);
void detectLineEnd(int start_at);
void processLine();
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(CONFIG_TTN_PROVISION_UART_CONFIG_YES)
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(CONFIG_TTN_PROVISION_UART_NONE)
QueueHandle_t uart_queue;
char* line_buf;
int line_length;
uint8_t last_line_end_char;
bool quit_task;
#endif
friend void ttn_provisioning_task_caller(void* pvParameter);
};
#endif

View File

@ -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,7 +43,7 @@ TheThingsNetwork::TheThingsNetwork()
esp_restart(); esp_restart();
#endif #endif
ASSERT(ttnInstance == NULL); ASSERT(ttnInstance == nullptr);
ttnInstance = this; ttnInstance = this;
hal_initCriticalSection(); hal_initCriticalSection();
} }
@ -65,7 +66,7 @@ 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(); hal_startBgTask();
} }
@ -78,24 +79,24 @@ void TheThingsNetwork::reset()
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(CONFIG_TTN_PROVISION_UART_NONE)
provisioning_start_task(); provisioning.startTask();
#endif #endif
} }
@ -108,7 +109,7 @@ void TheThingsNetwork::waitForProvisioning()
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");
@ -117,7 +118,7 @@ void TheThingsNetwork::waitForProvisioning()
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 +126,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,7 +137,7 @@ 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;
@ -173,12 +174,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 +199,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 +212,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",

View File

@ -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