diff --git a/examples/provisioning/Makefile b/examples/provisioning/Makefile new file mode 100644 index 0000000..5866668 --- /dev/null +++ b/examples/provisioning/Makefile @@ -0,0 +1,3 @@ +PROJECT_NAME := provisioning + +include $(IDF_PATH)/make/project.mk diff --git a/examples/provisioning/main/component.mk b/examples/provisioning/main/component.mk new file mode 100644 index 0000000..e69de29 diff --git a/examples/provisioning/main/main.cpp b/examples/provisioning/main/main.cpp new file mode 100644 index 0000000..9c1cad9 --- /dev/null +++ b/examples/provisioning/main/main.cpp @@ -0,0 +1,91 @@ +/******************************************************************************* + * + * 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 + * + * Sample program showing how to provision the keys via the console. + *******************************************************************************/ + +#include "freertos/FreeRTOS.h" +#include "esp_event.h" +#include "nvs_flash.h" + +#include "TheThingsNetwork.h" + +// NOTE: +// The LoRaWAN frequency and the radio chip must be configured by running 'make menuconfig'. +// Go to Components / The Things Network, select the appropriate values and save. + +// Pins and other resources +#define TTN_SPI_HOST HSPI_HOST +#define TTN_SPI_DMA_CHAN 1 +#define TTN_PIN_SPI_SCLK 5 +#define TTN_PIN_SPI_MOSI 27 +#define TTN_PIN_SPI_MISO 19 +#define TTN_PIN_NSS 18 +#define TTN_PIN_RXTX TTN_NOT_CONNECTED +#define TTN_PIN_RST 14 +#define TTN_PIN_DIO0 26 +#define TTN_PIN_DIO1 33 + +static TheThingsNetwork ttn; + +const unsigned TX_INTERVAL = 30; +static uint8_t msgData[] = "Hello, world"; + + +void sendMessages(void* pvParameter) +{ + while (1) { + printf("Sending message...\n"); + TTNResponseCode res = ttn.transmitMessage(msgData, sizeof(msgData) - 1); + printf(res == kTTNSuccessfulTransmission ? "Message sent.\n" : "Transmission failed.\n"); + + vTaskDelay(TX_INTERVAL * 1000 / portTICK_PERIOD_MS); + } +} + +extern "C" void app_main(void) +{ + esp_err_t err; + // Initialize the GPIO ISR handler service + err = gpio_install_isr_service(ESP_INTR_FLAG_IRAM); + ESP_ERROR_CHECK(err); + + // Initialize the NVS (non-volatile storage) for saving and restoring the keys + err = nvs_flash_init(); + ESP_ERROR_CHECK(err); + + // Initialize SPI bus + spi_bus_config_t spi_bus_config; + spi_bus_config.miso_io_num = TTN_PIN_SPI_MISO; + spi_bus_config.mosi_io_num = TTN_PIN_SPI_MOSI; + spi_bus_config.sclk_io_num = TTN_PIN_SPI_SCLK; + spi_bus_config.quadwp_io_num = -1; + spi_bus_config.quadhd_io_num = -1; + spi_bus_config.max_transfer_sz = 0; + err = spi_bus_initialize(TTN_SPI_HOST, &spi_bus_config, TTN_SPI_DMA_CHAN); + ESP_ERROR_CHECK(err); + + // Configure the SX127x pins + ttn.configurePins(TTN_SPI_HOST, TTN_PIN_NSS, TTN_PIN_RXTX, TTN_PIN_RST, TTN_PIN_DIO0, TTN_PIN_DIO1); + + ttn.startProvisioningTask(); + + ttn.waitForProvisioning(); + + printf("Joining...\n"); + if (ttn.join()) + { + printf("Joined.\n"); + xTaskCreate(sendMessages, "send_messages", 1024 * 4, (void* )0, 3, NULL); + } + else + { + printf("Join failed. Goodbye\n"); + } +} diff --git a/include/TheThingsNetwork.h b/include/TheThingsNetwork.h index 99c040e..39e57c6 100644 --- a/include/TheThingsNetwork.h +++ b/include/TheThingsNetwork.h @@ -111,6 +111,16 @@ public: */ void startProvisioningTask(); + /** + * @brief Wait until the device EUI, app EUI and app key have been provisioned + * via the provisioning task. + * + * If device is already provisioned (stored data in NVS, call to 'provision()' + * or call to 'join(const char*, const char*, const char*)', this function + * immediately returns. + */ + void waitForProvisioning(); + /** * @brief Activate the device via OTAA. * diff --git a/src/TheThingsNetwork.cpp b/src/TheThingsNetwork.cpp index 21b9a7f..cab4f41 100644 --- a/src/TheThingsNetwork.cpp +++ b/src/TheThingsNetwork.cpp @@ -87,6 +87,21 @@ void TheThingsNetwork::startProvisioningTask() #endif } +void TheThingsNetwork::waitForProvisioning() +{ +#if !defined(CONFIG_TTN_PROVISION_UART_NONE) + if (isProvisioned()) + { + ESP_LOGI(TAG, "Device is already provisioned"); + return; + } + + while (!provisioning_have_keys()) + vTaskDelay(1000 / portTICK_PERIOD_MS); + + ESP_LOGI(TAG, "Device successfully provisioned"); +#endif +} bool TheThingsNetwork::join(const char *devEui, const char *appEui, const char *appKey) { diff --git a/src/provisioning.c b/src/provisioning.c index e0879e2..2c02fa6 100644 --- a/src/provisioning.c +++ b/src/provisioning.c @@ -245,32 +245,38 @@ bool provisioning_have_keys() bool provisioning_decode_keys(const char *dev_eui, const char *app_eui, const char *app_key) { - have_keys = false; + uint8_t buf_dev_eui[8]; + uint8_t buf_app_eui[8]; + uint8_t buf_app_key[16]; - if (strlen(dev_eui) != 16 || !hex_str_to_bin(dev_eui, global_dev_eui, 8)) + if (strlen(dev_eui) != 16 || !hex_str_to_bin(dev_eui, buf_dev_eui, 8)) { ESP_LOGW(TAG, "Invalid device EUI: %s", dev_eui); return false; } - swap_bytes(global_dev_eui, 8); + swap_bytes(buf_dev_eui, 8); - if (strlen(app_eui) != 16 || !hex_str_to_bin(app_eui, global_app_eui, 8)) + if (strlen(app_eui) != 16 || !hex_str_to_bin(app_eui, buf_app_eui, 8)) { ESP_LOGW(TAG, "Invalid application EUI: %s", app_eui); return false; } - swap_bytes(global_app_eui, 8); + swap_bytes(buf_app_eui, 8); - if (strlen(app_key) != 32 || !hex_str_to_bin(app_key, global_app_key, 16)) + if (strlen(app_key) != 32 || !hex_str_to_bin(app_key, buf_app_key, 16)) { ESP_LOGW(TAG, "Invalid application key: %s", app_key); return false; } - have_keys = true; - return true; + 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_key, buf_app_key, sizeof(global_app_key)); + + have_keys = provisioning_save_keys(); + return have_keys; } @@ -313,7 +319,9 @@ done: bool provisioning_restore_keys(bool silent) { - have_keys = false; + uint8_t buf_dev_eui[8]; + uint8_t buf_app_eui[8]; + uint8_t buf_app_key[16]; nvs_handle handle = 0; esp_err_t res = nvs_open(NVS_FLASH_PARTITION, NVS_READONLY, &handle); @@ -328,15 +336,18 @@ bool provisioning_restore_keys(bool silent) if (res != ESP_OK) goto done; - if (!read_nvs_value(handle, NVS_FLASH_KEY_DEV_EUI, global_dev_eui, sizeof(global_dev_eui), silent)) + if (!read_nvs_value(handle, NVS_FLASH_KEY_DEV_EUI, buf_dev_eui, sizeof(global_dev_eui), silent)) goto done; - if (!read_nvs_value(handle, NVS_FLASH_KEY_APP_EUI, global_app_eui, sizeof(global_app_eui), silent)) + if (!read_nvs_value(handle, NVS_FLASH_KEY_APP_EUI, buf_app_eui, sizeof(global_app_eui), silent)) goto done; - if (!read_nvs_value(handle, NVS_FLASH_KEY_APP_KEY, global_app_key, sizeof(global_app_key), silent)) + if (!read_nvs_value(handle, NVS_FLASH_KEY_APP_KEY, buf_app_key, sizeof(global_app_key), silent)) goto done; + 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_key, buf_app_key, sizeof(global_app_key)); have_keys = true; ESP_LOGI(TAG, "Dev and app EUI and app key have been restored from NVS storage");