diff --git a/examples/lora/lorawan-set-keys/.gitignore b/examples/lora/lorawan-set-keys/.gitignore new file mode 100644 index 000000000..9029eada1 --- /dev/null +++ b/examples/lora/lorawan-set-keys/.gitignore @@ -0,0 +1 @@ +radioConfig.h diff --git a/examples/lora/lorawan-set-keys/Makefile b/examples/lora/lorawan-set-keys/Makefile new file mode 100644 index 000000000..df16e43e1 --- /dev/null +++ b/examples/lora/lorawan-set-keys/Makefile @@ -0,0 +1,40 @@ +# Makefile for user application + +# Specify this directory relative to the current application. +TOCK_USERLAND_BASE_DIR = ../../.. + +STACK_SIZE = 4096 + +# Which files to compile. +CXX_SRCS := $(wildcard *.cc) + +override CPPFLAGS += -DRADIOLIB_CLOCK_DRIFT_MS=9 + +# If we are building for a testing configuration (e.g. CI) then it's okay to +# use the example config header. However, if someone is doing local testing, +# especially of a different thing, we don't want to accidentally overwrite +# the build obeject here with the example config when a real one exists. +ifneq ($(TOCK_BUILDALL),) +ifeq ($(wildcard radioConfig.h),) +override CPPFLAGS += "-DRADIO_CONFIG_CI=radioConfig_example.h" +endif +endif + +# The app ID ends up being 2903764429, so we need to give ourselves +# permission to read/write that +# If the name changes these will need to be updated +ELF2TAB_ARGS += --write_id 2903764429 --read_ids 2903764429 --access_ids 2903764429 + +# Use the libtock-c Make system +EXTERN_LIBS += $(TOCK_USERLAND_BASE_DIR)/RadioLib + +include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk + +# Protect from the (unlikely) case where the app happens to have been +# built from an unrelated `build all` event, but now the user is trying +# to flash the app with an invalid configuration. +flash: radioConfig.h + +program: radioConfig.h + +install: radioConfig.h diff --git a/examples/lora/lorawan-set-keys/README.md b/examples/lora/lorawan-set-keys/README.md new file mode 100644 index 000000000..bbadeefec --- /dev/null +++ b/examples/lora/lorawan-set-keys/README.md @@ -0,0 +1,8 @@ +LoRaWAN Set Keys +================ + +This will set the keys and secrets for LoRaWAN. Copy the `radioConfig_example.h` +and call it `radioConfig.h`. Set the values based on the values from your LoRaWAN +gateway. Then flash this application. That will set the keys in flash on the board. + +After that the keys will be retrieved when running the LoRaWAN examples. diff --git a/examples/lora/lorawan-set-keys/main.cc b/examples/lora/lorawan-set-keys/main.cc new file mode 100644 index 000000000..b63c119a8 --- /dev/null +++ b/examples/lora/lorawan-set-keys/main.cc @@ -0,0 +1,160 @@ +/* + RadioLib Non-Arduino Tock Library LoRaWAN test application + + Licensed under the MIT or Apache License + + Copyright (c) 2023 Alistair Francis + */ + +#include +#include + +// include the library +#include + +// Include some libtock-c helpers +#include + +// To get this working copy radioConfig_example.h to radioConfig.h +// and then modify it to match the LoRaWAN gateway settings. +#ifdef RADIO_CONFIG_CI +#include "radioConfig_example.h" +#else +#include "radioConfig.h" +#endif + +#define JOIN_EUI_KEY_LEN 8 +uint8_t join_eui_key_buf[JOIN_EUI_KEY_LEN] = "joinEUI"; + +#define DEV_EUI_KEY_LEN 7 +uint8_t dev_eui_key_buf[DEV_EUI_KEY_LEN] = "devEUI"; + +#define NWK_KEY_KEY_LEN 7 +uint8_t nwk_key_key_buf[NWK_KEY_KEY_LEN] = "nwkKey"; + +#define APP_KEY_KEY_LEN 7 +uint8_t app_key_key_buf[APP_KEY_KEY_LEN] = "appKey"; + +#define KV_DATA_LEN 8 +uint8_t kv_data_buf[KV_DATA_LEN]; + +// Store the joinEUI to the Tock K/V store +static int set_join_eui(void) { + returncode_t ret; + + if (!libtock_kv_exists()) { + return 1; + } + + kv_data_buf[0] = joinEUI & 0xFF; + kv_data_buf[1] = (joinEUI >> 8) & 0xFF; + kv_data_buf[2] = (joinEUI >> 16) & 0xFF; + kv_data_buf[3] = (joinEUI >> 24) & 0xFF; + kv_data_buf[4] = (joinEUI >> 32) & 0xFF; + kv_data_buf[5] = (joinEUI >> 40) & 0xFF; + kv_data_buf[6] = (joinEUI >> 48) & 0xFF; + kv_data_buf[7] = (joinEUI >> 56) & 0xFF; + + ret = libtocksync_kv_set(join_eui_key_buf, JOIN_EUI_KEY_LEN, kv_data_buf, KV_DATA_LEN); + + if (ret == RETURNCODE_SUCCESS) { + return 0; + } else { + return 1; + } +} + +// Store the devEUI to the Tock K/V store +static int set_dev_eui(void) { + returncode_t ret; + + if (!libtock_kv_exists()) { + return 1; + } + + kv_data_buf[0] = devEUI & 0xFF; + kv_data_buf[1] = (devEUI >> 8) & 0xFF; + kv_data_buf[2] = (devEUI >> 16) & 0xFF; + kv_data_buf[3] = (devEUI >> 24) & 0xFF; + kv_data_buf[4] = (devEUI >> 32) & 0xFF; + kv_data_buf[5] = (devEUI >> 40) & 0xFF; + kv_data_buf[6] = (devEUI >> 48) & 0xFF; + kv_data_buf[7] = (devEUI >> 56) & 0xFF; + + ret = libtocksync_kv_set(dev_eui_key_buf, DEV_EUI_KEY_LEN, kv_data_buf, KV_DATA_LEN); + + if (ret == RETURNCODE_SUCCESS) { + return 0; + } else { + return 1; + } +} + +// Store the nwkKey to the Tock K/V store +static int set_nwk_key(void) { + returncode_t ret; + + if (!libtock_kv_exists()) { + return 1; + } + + ret = libtocksync_kv_set(nwk_key_key_buf, NWK_KEY_KEY_LEN, nwkKey, 16); + + if (ret == RETURNCODE_SUCCESS) { + return 0; + } else { + return 1; + } +} + +// Store the appKey to the Tock K/V store +static int set_app_key(void) { + returncode_t ret; + + if (!libtock_kv_exists()) { + return 1; + } + + ret = libtocksync_kv_set(app_key_key_buf, APP_KEY_KEY_LEN, appKey, 16); + + if (ret == RETURNCODE_SUCCESS) { + return 0; + } else { + return 1; + } +} + +// the entry point for the program +int main(void) { + if (set_join_eui() == 0) { + printf("Set joinEUI key to storage: 0x%lx%lx\r\n", + (uint32_t)(joinEUI >> 32), (uint32_t)joinEUI); + } else { + printf("Unable to store joinEUI key to storage\r\n"); + return 1; + } + + if (set_dev_eui() == 0) { + printf("Set devEUI key to storage: 0x%lx%lx\r\n", + (uint32_t)(devEUI >> 32), (uint32_t)devEUI); + } else { + printf("Unable to store devEUI key to storage\r\n"); + return 1; + } + + if (set_nwk_key() == 0) { + printf("Set nwkKey key to storage\r\n"); + } else { + printf("Unable to store nwkKey to storage\r\n"); + return 1; + } + + if (set_app_key() == 0) { + printf("Set appKey key to storage\r\n"); + } else { + printf("Unable to store appKey to storage\r\n"); + return 1; + } + + return 0; +} diff --git a/examples/lora/sensor-lorawan/radioConfig_example.h b/examples/lora/lorawan-set-keys/radioConfig_example.h similarity index 79% rename from examples/lora/sensor-lorawan/radioConfig_example.h rename to examples/lora/lorawan-set-keys/radioConfig_example.h index c18b4685a..6a662b322 100644 --- a/examples/lora/sensor-lorawan/radioConfig_example.h +++ b/examples/lora/lorawan-set-keys/radioConfig_example.h @@ -11,7 +11,3 @@ uint64_t joinEUI = 0x0000000000000000; uint64_t devEUI = 0x0000000000000000; uint8_t appKey[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t nwkKey[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - -// regional choices: EU868, US915, AU915, AS923, IN865, KR920, CN780, CN500 -const LoRaWANBand_t* Region = &AU915; -const uint8_t subBand = 2; diff --git a/examples/lora/sensor-lorawan/Makefile b/examples/lora/sensor-lorawan/Makefile index b63b807e0..0054cf6bc 100644 --- a/examples/lora/sensor-lorawan/Makefile +++ b/examples/lora/sensor-lorawan/Makefile @@ -20,6 +20,8 @@ override CPPFLAGS += "-DRADIO_CONFIG_CI=radioConfig_example.h" endif endif +ELF2TAB_ARGS += --read_ids 2903764429 + # Use the libtock-c Make system EXTERN_LIBS += $(TOCK_USERLAND_BASE_DIR)/RadioLib diff --git a/examples/lora/sensor-lorawan/README.md b/examples/lora/sensor-lorawan/README.md index 9e65ffcfe..befcb14d9 100644 --- a/examples/lora/sensor-lorawan/README.md +++ b/examples/lora/sensor-lorawan/README.md @@ -6,9 +6,12 @@ This example builds an application to transmit sensor data via LoRaWAN. See https://github.com/jgromes/RadioLib/blob/master/examples/LoRaWAN/LoRaWAN_Starter/notes.md for notes on setting up the LoRaWAN device. -The most important part is creating a radioConfig.h file with the secrets -from your LoRaWAN server and any country specific settings. There is an -existing radioConfig_example.h which can be used as a useful starting point. +The most important part is setting the secrets from your LoRaWAN server +and any country specific settings. + +To set the secrets first run the `lorawan-set-keys` example. That will set +the keys in flash. Then everytime you run the sensor-lorwan application +it will use those secrets. This has been tested against The Things Network. Before changing settings make sure you consider regulatory duty cycles and TTN's Fair Usage Policy, diff --git a/examples/lora/sensor-lorawan/main.cc b/examples/lora/sensor-lorawan/main.cc index c1e19af47..a3ac29026 100644 --- a/examples/lora/sensor-lorawan/main.cc +++ b/examples/lora/sensor-lorawan/main.cc @@ -15,22 +15,170 @@ // Include some libtock-c helpers #include #include +#include #include "CayenneLPP.h" -// To get this working copy radioConfig_example.h to radioConfig.h -// and then modify it to match the LoRaWAN gateway settings. -#ifdef RADIO_CONFIG_CI -#include "radioConfig_example.h" -#else -#include "radioConfig.h" -#endif +/* These need to be updated to use values from your LoRaWAN server */ +uint64_t joinEUI = 0x0000000000000000; +uint64_t devEUI = 0x0000000000000000; +uint8_t appKey[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; +uint8_t nwkKey[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -#define MAX_SIZE 10 +// regional choices: EU868, US915, AU915, AS923, IN865, KR920, CN780, CN500 +const LoRaWANBand_t* Region = &AU915; +const uint8_t subBand = 2; + +#define MAX_PAYLOAD_SIZE 10 + +#define JOIN_EUI_KEY_LEN 8 +uint8_t join_eui_key_buf[JOIN_EUI_KEY_LEN] = "joinEUI"; + +#define DEV_EUI_KEY_LEN 7 +uint8_t dev_eui_key_buf[DEV_EUI_KEY_LEN] = "devEUI"; + +#define NWK_KEY_KEY_LEN 7 +uint8_t nwk_key_key_buf[NWK_KEY_KEY_LEN] = "nwkKey"; + +#define APP_KEY_KEY_LEN 7 +uint8_t app_key_key_buf[APP_KEY_KEY_LEN] = "appKey"; + +#define KV_DATA_LEN 8 +uint8_t kv_data_buf[KV_DATA_LEN]; + +// Retrieve the joinEUI from the Tock K/V store +static int retrieve_join_eui(void) { + uint32_t value_len; + returncode_t ret; + + if (!libtock_kv_exists()) { + return 1; + } + + ret = libtocksync_kv_get(join_eui_key_buf, JOIN_EUI_KEY_LEN, kv_data_buf, KV_DATA_LEN, &value_len); + + if (ret == RETURNCODE_SUCCESS) { + // We found the key, set the global variable + joinEUI = (uint64_t) kv_data_buf[0] | + ((uint64_t) kv_data_buf[1] << 8) | + ((uint64_t) kv_data_buf[2] << 16) | + ((uint64_t) kv_data_buf[3] << 24) | + ((uint64_t) kv_data_buf[4] << 32) | + ((uint64_t) kv_data_buf[5] << 40) | + ((uint64_t) kv_data_buf[6] << 48) | + ((uint64_t) kv_data_buf[7] << 56); + return 0; + } else { + return 1; + } +} + +// Retrieve the devEUI from the Tock K/V store +static int retrieve_dev_eui(void) { + uint32_t value_len; + returncode_t ret; + + if (!libtock_kv_exists()) { + return 1; + } + + ret = libtocksync_kv_get(dev_eui_key_buf, DEV_EUI_KEY_LEN, kv_data_buf, KV_DATA_LEN, &value_len); + + if (ret == RETURNCODE_SUCCESS) { + // We found the key, set the global variable + devEUI = (uint64_t) kv_data_buf[0] | + ((uint64_t) kv_data_buf[1] << 8) | + ((uint64_t) kv_data_buf[2] << 16) | + ((uint64_t) kv_data_buf[3] << 24) | + ((uint64_t) kv_data_buf[4] << 32) | + ((uint64_t) kv_data_buf[5] << 40) | + ((uint64_t) kv_data_buf[6] << 48) | + ((uint64_t) kv_data_buf[7] << 56); + return 0; + } else { + return 1; + } +} + +// Retrieve the nwkKey from the Tock K/V store +static int retrieve_nwk_key(void) { + uint32_t value_len; + returncode_t ret; + + if (!libtock_kv_exists()) { + return 1; + } + + ret = libtocksync_kv_get(nwk_key_key_buf, NWK_KEY_KEY_LEN, nwkKey, 16, &value_len); + + if (ret == RETURNCODE_SUCCESS) { + return 0; + } else { + return 1; + } +} + +// Retrieve the appKey from the Tock K/V store +static int retrieve_app_key(void) { + uint32_t value_len; + returncode_t ret; + + if (!libtock_kv_exists()) { + return 1; + } + + ret = libtocksync_kv_get(app_key_key_buf, APP_KEY_KEY_LEN, appKey, 16, &value_len); + + if (ret == RETURNCODE_SUCCESS) { + return 0; + } else { + return 1; + } +} + +// Retrieve the LoRaWAN keys from the Tock K/V store +static int retrieve_keys(void) { + if (retrieve_join_eui() == 0) { + printf("Retrieve joinEUI key from storage: 0x%lx%lx\r\n", + (uint32_t)(joinEUI >> 32), (uint32_t)joinEUI); + } else { + printf("Unable to retrieve joinEUI key from storage\r\n"); + return 1; + } + + if (retrieve_dev_eui() == 0) { + printf("Retrieve devEUI key from storage: 0x%lx%lx\r\n", + (uint32_t)(devEUI >> 32), (uint32_t)devEUI); + } else { + printf("Unable to retrieve devEUI key from storage\r\n"); + return 1; + } + + if (retrieve_nwk_key() == 0) { + printf("Retrieve nwkKey key from storage\r\n"); + } else { + printf("Unable to retrieve nwkKey key from storage\r\n"); + return 1; + } + + if (retrieve_app_key() == 0) { + printf("Retrieve appKey key from storage\r\n"); + } else { + printf("Unable to retrieve appKey key from storage\r\n"); + return 1; + } + + return 0; +} // the entry point for the program int main(void) { - CayenneLPP Payload(MAX_SIZE); + CayenneLPP Payload(MAX_PAYLOAD_SIZE); + + // Retrieve the LoRaWAN keys from the Tock K/V store + if (retrieve_keys()) { + return 1; + } printf("[SX1261] Initialising Radio ... \r\n"); @@ -91,7 +239,7 @@ int main(void) { state = node.sendReceive(Payload.getBuffer(), Payload.getSize()); - if (state > 0) { + if (state >= 0) { // the packet was successfully transmitted printf("success!\r\n"); } else {