2018-07-23 09:46:45 +02:00
/*******************************************************************************
*
* ttn - esp32 - The Things Network device library for ESP - IDF / SX127x
*
2021-07-25 17:00:08 +02:00
* Copyright ( c ) 2018 - 2021 Manuel Bleichenbacher
2018-07-23 09:46:45 +02:00
*
* Licensed under MIT License
* https : //opensource.org/licenses/MIT
*
* Task listening on a UART port for provisioning commands .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2021-07-25 17:00:08 +02:00
# include "ttn_provisioning.h"
2018-07-23 09:46:45 +02:00
# include "freertos/FreeRTOS.h"
# include "driver/uart.h"
# include "esp_event.h"
# include "esp_log.h"
2018-09-17 22:50:15 +02:00
# include "esp_system.h"
2018-07-23 09:46:45 +02:00
# include "nvs_flash.h"
2018-10-02 20:25:40 +02:00
# include "lmic/lmic.h"
2021-07-25 20:03:16 +02:00
# include "hal/hal_esp32.h"
2018-07-23 09:46:45 +02:00
2018-10-27 19:19:55 +02:00
# if defined(TTN_HAS_AT_COMMANDS)
2021-07-25 17:00:08 +02:00
# define UART_NUM CONFIG_TTN_PROVISION_UART_NUM
# define MAX_LINE_LENGTH 128
2018-10-27 14:45:55 +02:00
# endif
2021-07-25 17:00:08 +02:00
# define TAG "ttn_prov"
# define NVS_FLASH_PARTITION "ttn"
# define NVS_FLASH_KEY_DEV_EUI "devEui"
# define NVS_FLASH_KEY_APP_EUI "appEui"
# define NVS_FLASH_KEY_APP_KEY "appKey"
# if defined(TTN_HAS_AT_COMMANDS)
static void provisioning_task ( void * pvParameter ) ;
static void add_line_data ( int num_bytes ) ;
static void detect_line_end ( int start_at ) ;
static void process_line ( void ) ;
# endif
# if defined(TTN_CONFIG_UART)
static void config_uart ( void ) ;
# endif
static bool decode ( bool incl_dev_eui , const char * dev_eui , const char * app_eui , const char * app_key ) ;
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_zeros ( const uint8_t * buf , int len ) ;
2018-10-27 14:45:55 +02:00
2018-07-23 09:46:45 +02:00
static uint8_t global_dev_eui [ 8 ] ;
static uint8_t global_app_eui [ 8 ] ;
static uint8_t global_app_key [ 16 ] ;
2021-07-25 17:00:08 +02:00
static bool have_keys = false ;
2018-10-27 19:19:55 +02:00
# if defined(TTN_HAS_AT_COMMANDS)
2021-07-25 17:00:08 +02:00
static QueueHandle_t uart_queue ;
static char * line_buf ;
static int line_length ;
static uint8_t last_line_end_char ;
static bool quit_task ;
2018-10-27 19:19:55 +02:00
# endif
2018-07-23 09:46:45 +02:00
// --- LMIC callbacks
// This EUI must be in little-endian format, so least-significant-byte first.
// When copying an EUI from ttnctl output, this means to reverse the bytes.
// For TTN issued EUIs the last bytes should be 0xD5, 0xB3, 0x70.
// The order is swapped in provisioning_decode_keys().
void os_getArtEui ( u1_t * buf )
{
memcpy ( buf , global_app_eui , 8 ) ;
}
// This should also be in little endian format, see above.
void os_getDevEui ( u1_t * buf )
{
memcpy ( buf , global_dev_eui , 8 ) ;
}
// This key should be in big endian format (or, since it is not really a number
// but a block of memory, endianness does not really apply). In practice, a key
// taken from ttnctl can be copied as-is.
void os_getDevKey ( u1_t * buf )
{
memcpy ( buf , global_app_key , 16 ) ;
}
2018-10-27 14:45:55 +02:00
// --- Constructor
2021-07-25 22:15:21 +02:00
void ttn_provisioning_init ( void )
2018-10-27 14:45:55 +02:00
{
}
2018-07-23 09:46:45 +02:00
// --- Provisioning task
2018-10-27 19:19:55 +02:00
# if defined(TTN_HAS_AT_COMMANDS)
2021-07-25 22:15:21 +02:00
void ttn_provisioning_start_task ( void )
2018-07-23 09:46:45 +02:00
{
2018-10-27 19:19:55 +02:00
# if defined(TTN_CONFIG_UART)
2021-07-25 17:00:08 +02:00
config_uart ( ) ;
2018-07-23 09:46:45 +02:00
# endif
esp_err_t err = uart_driver_install ( UART_NUM , 2048 , 2048 , 20 , & uart_queue , 0 ) ;
ESP_ERROR_CHECK ( err ) ;
2021-07-25 17:00:08 +02:00
xTaskCreate ( provisioning_task , " ttn_provision " , 2048 , NULL , 1 , NULL ) ;
2018-07-23 09:46:45 +02:00
}
2021-07-25 17:00:08 +02:00
void provisioning_task ( void * pvParameter )
2018-07-23 09:46:45 +02:00
{
line_buf = ( char * ) malloc ( MAX_LINE_LENGTH + 1 ) ;
line_length = 0 ;
uart_event_t event ;
ESP_LOGI ( TAG , " Provisioning task started " ) ;
2018-07-23 16:14:33 +02:00
while ( ! quit_task )
2018-07-23 09:46:45 +02:00
{
if ( ! xQueueReceive ( uart_queue , & event , portMAX_DELAY ) )
continue ;
switch ( event . type )
{
case UART_DATA :
2021-07-25 17:00:08 +02:00
add_line_data ( event . size ) ;
2018-07-23 09:46:45 +02:00
break ;
case UART_FIFO_OVF :
case UART_BUFFER_FULL :
uart_flush_input ( UART_NUM ) ;
xQueueReset ( uart_queue ) ;
break ;
default :
break ;
}
}
2018-07-23 16:14:33 +02:00
free ( line_buf ) ;
uart_driver_delete ( UART_NUM ) ;
2021-07-25 17:00:08 +02:00
vTaskDelete ( NULL ) ;
2018-07-23 09:46:45 +02:00
}
2021-07-25 17:00:08 +02:00
void add_line_data ( int num_bytes )
2018-07-23 09:46:45 +02:00
{
int n ;
top :
2021-07-25 17:00:08 +02:00
n = num_bytes ;
2018-07-23 09:46:45 +02:00
if ( line_length + n > MAX_LINE_LENGTH )
n = MAX_LINE_LENGTH - line_length ;
uart_read_bytes ( UART_NUM , ( uint8_t * ) line_buf + line_length , n , portMAX_DELAY ) ;
int start_at = line_length ;
line_length + = n ;
2021-07-25 17:00:08 +02:00
detect_line_end ( start_at ) ;
2018-07-23 09:46:45 +02:00
2021-07-25 17:00:08 +02:00
if ( n < num_bytes )
2018-07-23 09:46:45 +02:00
{
2021-07-25 17:00:08 +02:00
num_bytes - = n ;
2018-07-23 09:46:45 +02:00
goto top ;
}
}
2021-07-25 17:00:08 +02:00
void detect_line_end ( int start_at )
2018-07-23 09:46:45 +02:00
{
top :
for ( int p = start_at ; p < line_length ; p + + )
{
char ch = line_buf [ p ] ;
if ( ch = = 0x0d | | ch = = 0x0a )
{
if ( p > 0 )
uart_write_bytes ( UART_NUM , line_buf + start_at , line_length - start_at - 1 ) ;
if ( p > 0 | | ch = = 0x0d | | last_line_end_char = = 0x0a )
uart_write_bytes ( UART_NUM , " \r \n " , 2 ) ;
line_buf [ p ] = 0 ;
last_line_end_char = ch ;
if ( p > 0 )
2021-07-25 17:00:08 +02:00
process_line ( ) ;
2018-07-23 09:46:45 +02:00
memcpy ( line_buf , line_buf + p + 1 , line_length - p - 1 ) ;
line_length - = p + 1 ;
start_at = 0 ;
goto top ;
}
}
if ( line_length > 0 )
uart_write_bytes ( UART_NUM , line_buf + start_at , line_length - start_at ) ;
if ( line_length = = MAX_LINE_LENGTH )
line_length = 0 ; // Line too long; flush it
}
2021-07-25 17:00:08 +02:00
void process_line ( void )
2018-07-23 09:46:45 +02:00
{
bool is_ok = true ;
2018-09-30 13:56:04 +02:00
bool reset_needed = false ;
2018-07-23 09:46:45 +02:00
// Expected format:
// AT+PROV?
// AT+PROV=hex16-hex16-hex32
2018-09-30 13:56:04 +02:00
// AT+PROVM=hex16-hex32
2018-09-17 22:50:15 +02:00
// AT+MAC?
2018-09-30 13:56:04 +02:00
// AT+HWEUI?
2018-07-23 09:46:45 +02:00
if ( strcmp ( line_buf , " AT+PROV? " ) = = 0 )
{
uint8_t binbuf [ 8 ] ;
char hexbuf [ 16 ] ;
memcpy ( binbuf , global_dev_eui , 8 ) ;
2021-07-25 17:00:08 +02:00
swap_bytes ( binbuf , 8 ) ;
bin_to_hex_str ( binbuf , 8 , hexbuf ) ;
2018-07-23 09:46:45 +02:00
uart_write_bytes ( UART_NUM , hexbuf , 16 ) ;
uart_write_bytes ( UART_NUM , " - " , 1 ) ;
memcpy ( binbuf , global_app_eui , 8 ) ;
2021-07-25 17:00:08 +02:00
swap_bytes ( binbuf , 8 ) ;
bin_to_hex_str ( binbuf , 8 , hexbuf ) ;
2018-07-23 09:46:45 +02:00
uart_write_bytes ( UART_NUM , hexbuf , 16 ) ;
uart_write_bytes ( UART_NUM , " -00000000000000000000000000000000 \r \n " , 35 ) ;
}
else if ( strncmp ( line_buf , " AT+PROV= " , 8 ) = = 0 )
{
2018-09-30 13:56:04 +02:00
is_ok = strlen ( line_buf ) = = 74 & & line_buf [ 24 ] = = ' - ' & & line_buf [ 41 ] = = ' - ' ;
if ( is_ok )
2018-07-23 09:46:45 +02:00
{
line_buf [ 24 ] = 0 ;
line_buf [ 41 ] = 0 ;
2021-07-25 22:15:21 +02:00
is_ok = ttn_provisioning_decode_keys ( line_buf + 8 , line_buf + 25 , line_buf + 42 ) ;
2020-09-27 16:21:04 +02:00
if ( is_ok )
2021-07-25 22:15:21 +02:00
is_ok = ttn_provisioning_save_keys ( ) ;
2018-09-30 13:56:04 +02:00
reset_needed = is_ok ;
2018-09-27 16:56:14 +02:00
}
2018-09-30 13:56:04 +02:00
}
else if ( strncmp ( line_buf , " AT+PROVM= " , 8 ) = = 0 )
{
is_ok = strlen ( line_buf ) = = 58 & & line_buf [ 25 ] = = ' - ' ;
if ( is_ok )
2018-07-23 09:46:45 +02:00
{
2018-09-30 13:56:04 +02:00
line_buf [ 25 ] = 0 ;
2021-07-25 22:15:21 +02:00
is_ok = ttn_provisioning_from_mac ( line_buf + 9 , line_buf + 26 ) ;
2020-09-27 16:21:04 +02:00
if ( is_ok )
2021-07-25 22:15:21 +02:00
is_ok = ttn_provisioning_save_keys ( ) ;
2018-09-30 13:56:04 +02:00
reset_needed = is_ok ;
2018-07-23 09:46:45 +02:00
}
}
2018-09-17 22:50:15 +02:00
else if ( strcmp ( line_buf , " AT+MAC? " ) = = 0 )
{
uint8_t mac [ 6 ] ;
char hexbuf [ 12 ] ;
esp_err_t err = esp_efuse_mac_get_default ( mac ) ;
ESP_ERROR_CHECK ( err ) ;
2021-07-25 17:00:08 +02:00
bin_to_hex_str ( mac , 6 , hexbuf ) ;
2018-09-17 22:50:15 +02:00
for ( int i = 0 ; i < 12 ; i + = 2 ) {
if ( i > 0 )
uart_write_bytes ( UART_NUM , " : " , 1 ) ;
uart_write_bytes ( UART_NUM , hexbuf + i , 2 ) ;
}
uart_write_bytes ( UART_NUM , " \r \n " , 2 ) ;
}
2018-09-27 16:56:14 +02:00
else if ( strcmp ( line_buf , " AT+HWEUI? " ) = = 0 )
{
uint8_t mac [ 6 ] ;
char hexbuf [ 12 ] ;
esp_err_t err = esp_efuse_mac_get_default ( mac ) ;
ESP_ERROR_CHECK ( err ) ;
2021-07-25 17:00:08 +02:00
bin_to_hex_str ( mac , 6 , hexbuf ) ;
2018-09-27 16:56:14 +02:00
for ( int i = 0 ; i < 12 ; i + = 2 ) {
uart_write_bytes ( UART_NUM , hexbuf + i , 2 ) ;
2018-09-30 13:56:04 +02:00
if ( i = = 4 )
uart_write_bytes ( UART_NUM , " FFFE " , 4 ) ;
2018-09-27 16:56:14 +02:00
}
uart_write_bytes ( UART_NUM , " \r \n " , 2 ) ;
}
2018-07-23 16:14:33 +02:00
else if ( strcmp ( line_buf , " AT+PROVQ " ) = = 0 )
{
quit_task = true ;
}
2018-07-23 15:29:37 +02:00
else if ( strcmp ( line_buf , " AT " ) ! = 0 )
2018-07-23 09:46:45 +02:00
{
is_ok = false ;
}
2018-09-30 13:56:04 +02:00
if ( reset_needed )
{
2021-07-25 20:03:16 +02:00
hal_esp32_enter_critical_section ( ) ;
2018-09-30 13:56:04 +02:00
LMIC_reset ( ) ;
2021-07-25 20:03:16 +02:00
hal_esp32_leave_critical_section ( ) ;
2019-10-12 00:02:31 +02:00
LMIC . client . eventCb ( LMIC . client . eventUserData , EV_RESET ) ;
2018-09-30 13:56:04 +02:00
}
2018-07-23 09:46:45 +02:00
uart_write_bytes ( UART_NUM , is_ok ? " OK \r \n " : " ERROR \r \n " , is_ok ? 4 : 7 ) ;
}
2018-10-27 19:19:55 +02:00
# endif
# if defined(TTN_CONFIG_UART)
2018-07-23 09:46:45 +02:00
2021-07-25 17:00:08 +02:00
void config_uart ( void )
2018-07-23 09:46:45 +02:00
{
2018-07-23 16:59:38 +02:00
esp_err_t err ;
uart_config_t uart_config = {
. baud_rate = CONFIG_TTN_PROVISION_UART_BAUDRATE ,
. data_bits = UART_DATA_8_BITS ,
. parity = UART_PARITY_DISABLE ,
. stop_bits = UART_STOP_BITS_1 ,
2021-07-25 17:00:08 +02:00
. flow_ctrl = UART_HW_FLOWCTRL_DISABLE
2018-07-23 16:59:38 +02:00
} ;
err = uart_param_config ( UART_NUM , & uart_config ) ;
ESP_ERROR_CHECK ( err ) ;
2018-07-23 09:46:45 +02:00
2018-07-23 16:59:38 +02:00
err = uart_set_pin ( UART_NUM , CONFIG_TTN_PROVISION_UART_TX_GPIO , CONFIG_TTN_PROVISION_UART_RX_GPIO , UART_PIN_NO_CHANGE , UART_PIN_NO_CHANGE ) ;
ESP_ERROR_CHECK ( err ) ;
2018-07-23 09:46:45 +02:00
}
# endif
// --- Key handling
2021-07-25 22:15:21 +02:00
bool ttn_provisioning_have_keys ( void )
2018-07-23 09:46:45 +02:00
{
return have_keys ;
}
2021-07-25 22:15:21 +02:00
bool ttn_provisioning_decode_keys ( const char * dev_eui , const char * app_eui , const char * app_key )
2018-09-17 22:50:15 +02:00
{
2018-10-27 14:45:55 +02:00
return decode ( true , dev_eui , app_eui , app_key ) ;
2018-09-17 22:50:15 +02:00
}
2021-07-25 22:15:21 +02:00
bool ttn_provisioning_from_mac ( const char * app_eui , const char * app_key )
2018-09-17 22:50:15 +02:00
{
uint8_t mac [ 6 ] ;
esp_err_t err = esp_efuse_mac_get_default ( mac ) ;
ESP_ERROR_CHECK ( err ) ;
2018-09-27 16:56:14 +02:00
global_dev_eui [ 7 ] = mac [ 0 ] ;
global_dev_eui [ 6 ] = mac [ 1 ] ;
global_dev_eui [ 5 ] = mac [ 2 ] ;
global_dev_eui [ 4 ] = 0xff ;
global_dev_eui [ 3 ] = 0xfe ;
global_dev_eui [ 2 ] = mac [ 3 ] ;
global_dev_eui [ 1 ] = mac [ 4 ] ;
global_dev_eui [ 0 ] = mac [ 5 ] ;
2018-09-17 22:50:15 +02:00
2021-07-25 17:00:08 +02:00
return decode ( false , NULL , app_eui , app_key ) ;
2018-09-17 22:50:15 +02:00
}
2021-07-25 17:00:08 +02:00
bool decode ( bool incl_dev_eui , const char * dev_eui , const char * app_eui , const char * app_key )
2018-07-23 09:46:45 +02:00
{
2018-07-23 14:30:03 +02:00
uint8_t buf_dev_eui [ 8 ] ;
uint8_t buf_app_eui [ 8 ] ;
uint8_t buf_app_key [ 16 ] ;
2018-07-23 09:46:45 +02:00
2021-07-25 17:00:08 +02:00
if ( incl_dev_eui & & ( strlen ( dev_eui ) ! = 16 | | ! hex_str_to_bin ( dev_eui , buf_dev_eui , 8 ) ) )
2018-07-23 09:46:45 +02:00
{
2021-07-27 22:37:22 +02:00
ESP_LOGW ( TAG , " Invalid DevEUI: %s " , dev_eui ) ;
2018-07-23 09:46:45 +02:00
return false ;
}
2018-09-17 22:50:15 +02:00
if ( incl_dev_eui )
2021-07-25 17:00:08 +02:00
swap_bytes ( buf_dev_eui , 8 ) ;
2018-07-23 09:46:45 +02:00
2021-07-25 17:00:08 +02:00
if ( strlen ( app_eui ) ! = 16 | | ! hex_str_to_bin ( app_eui , buf_app_eui , 8 ) )
2018-07-23 09:46:45 +02:00
{
2021-07-27 22:37:22 +02:00
ESP_LOGW ( TAG , " Invalid AppEUI/JoinEUI: %s " , app_eui ) ;
2018-07-23 09:46:45 +02:00
return false ;
}
2021-07-25 17:00:08 +02:00
swap_bytes ( buf_app_eui , 8 ) ;
2018-07-23 09:46:45 +02:00
2021-07-25 17:00:08 +02:00
if ( strlen ( app_key ) ! = 32 | | ! hex_str_to_bin ( app_key , buf_app_key , 16 ) )
2018-07-23 09:46:45 +02:00
{
ESP_LOGW ( TAG , " Invalid application key: %s " , app_key ) ;
return false ;
}
2018-09-17 22:50:15 +02:00
if ( incl_dev_eui )
memcpy ( global_dev_eui , buf_dev_eui , sizeof ( global_dev_eui ) ) ;
2018-07-23 14:30:03 +02:00
memcpy ( global_app_eui , buf_app_eui , sizeof ( global_app_eui ) ) ;
memcpy ( global_app_key , buf_app_key , sizeof ( global_app_key ) ) ;
2021-07-25 17:00:08 +02:00
have_keys = ! is_all_zeros ( global_dev_eui , sizeof ( global_dev_eui ) )
& & ! is_all_zeros ( global_app_key , sizeof ( global_app_key ) ) ;
2018-07-28 22:13:59 +02:00
return true ;
2018-07-23 09:46:45 +02:00
}
// --- Non-volatile storage
2021-07-25 22:15:21 +02:00
bool ttn_provisioning_save_keys ( )
2018-07-23 09:46:45 +02:00
{
bool result = false ;
nvs_handle handle = 0 ;
esp_err_t res = nvs_open ( NVS_FLASH_PARTITION , NVS_READWRITE , & handle ) ;
if ( res = = ESP_ERR_NVS_NOT_INITIALIZED )
{
ESP_LOGW ( TAG , " NVS storage is not initialized. Call 'nvs_flash_init()' first. " ) ;
goto done ;
}
ESP_ERROR_CHECK ( res ) ;
if ( res ! = ESP_OK )
goto done ;
2021-07-25 17:00:08 +02:00
if ( ! write_nvs_value ( handle , NVS_FLASH_KEY_DEV_EUI , global_dev_eui , sizeof ( global_dev_eui ) ) )
2018-07-23 09:46:45 +02:00
goto done ;
2021-07-25 17:00:08 +02:00
if ( ! write_nvs_value ( handle , NVS_FLASH_KEY_APP_EUI , global_app_eui , sizeof ( global_app_eui ) ) )
2018-07-23 09:46:45 +02:00
goto done ;
2021-07-25 17:00:08 +02:00
if ( ! write_nvs_value ( handle , NVS_FLASH_KEY_APP_KEY , global_app_key , sizeof ( global_app_key ) ) )
2018-07-23 09:46:45 +02:00
goto done ;
res = nvs_commit ( handle ) ;
ESP_ERROR_CHECK ( res ) ;
result = true ;
2021-07-27 22:37:22 +02:00
ESP_LOGI ( TAG , " DevEUI, AppEUI/JoinEUI and AppKey saved in NVS storage " ) ;
2018-07-23 09:46:45 +02:00
done :
nvs_close ( handle ) ;
return result ;
}
2021-07-25 22:15:21 +02:00
bool ttn_provisioning_restore_keys ( bool silent )
2018-07-23 09:46:45 +02:00
{
2018-07-23 14:30:03 +02:00
uint8_t buf_dev_eui [ 8 ] ;
uint8_t buf_app_eui [ 8 ] ;
uint8_t buf_app_key [ 16 ] ;
2018-07-23 09:46:45 +02:00
nvs_handle handle = 0 ;
esp_err_t res = nvs_open ( NVS_FLASH_PARTITION , NVS_READONLY , & handle ) ;
if ( res = = ESP_ERR_NVS_NOT_FOUND )
return false ; // partition does not exist yet
if ( res = = ESP_ERR_NVS_NOT_INITIALIZED )
{
ESP_LOGW ( TAG , " NVS storage is not initialized. Call 'nvs_flash_init()' first. " ) ;
goto done ;
}
ESP_ERROR_CHECK ( res ) ;
if ( res ! = ESP_OK )
goto done ;
2021-07-25 17:00:08 +02:00
if ( ! read_nvs_value ( handle , NVS_FLASH_KEY_DEV_EUI , buf_dev_eui , sizeof ( global_dev_eui ) , silent ) )
2018-07-23 09:46:45 +02:00
goto done ;
2021-07-25 17:00:08 +02:00
if ( ! read_nvs_value ( handle , NVS_FLASH_KEY_APP_EUI , buf_app_eui , sizeof ( global_app_eui ) , silent ) )
2018-07-23 09:46:45 +02:00
goto done ;
2021-07-25 17:00:08 +02:00
if ( ! read_nvs_value ( handle , NVS_FLASH_KEY_APP_KEY , buf_app_key , sizeof ( global_app_key ) , silent ) )
2018-07-23 09:46:45 +02:00
goto done ;
2018-07-23 14:30:03 +02:00
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 ) ) ;
2018-07-28 22:13:59 +02:00
2021-07-25 17:00:08 +02:00
have_keys = ! is_all_zeros ( global_dev_eui , sizeof ( global_dev_eui ) )
& & ! is_all_zeros ( global_app_key , sizeof ( global_app_key ) ) ;
2018-07-28 22:13:59 +02:00
if ( have_keys )
{
2021-07-27 22:37:22 +02:00
ESP_LOGI ( TAG , " DevEUI, AppEUI/JoinEUI and AppKey have been restored from NVS storage " ) ;
2018-07-28 22:13:59 +02:00
}
else
{
2021-07-27 22:37:22 +02:00
ESP_LOGW ( TAG , " DevEUI or DevEUI is invalid (zeroes only) " ) ;
2018-07-28 22:13:59 +02:00
}
2018-07-23 09:46:45 +02:00
done :
nvs_close ( handle ) ;
2018-07-28 22:13:59 +02:00
return true ;
2018-07-23 09:46:45 +02:00
}
2021-07-25 17:00:08 +02:00
bool read_nvs_value ( nvs_handle handle , const char * key , uint8_t * data , size_t expected_length , bool silent )
2018-07-23 09:46:45 +02:00
{
size_t size = expected_length ;
esp_err_t res = nvs_get_blob ( handle , key , data , & size ) ;
if ( res = = ESP_OK & & size = = expected_length )
return true ;
if ( res = = ESP_OK & & size ! = expected_length )
{
if ( ! silent )
ESP_LOGW ( TAG , " Invalid size of NVS data for %s " , key ) ;
return false ;
}
if ( res = = ESP_ERR_NVS_NOT_FOUND )
{
if ( ! silent )
ESP_LOGW ( TAG , " No NVS data found for %s " , key ) ;
return false ;
}
ESP_ERROR_CHECK ( res ) ;
return false ;
}
2021-07-25 17:00:08 +02:00
bool write_nvs_value ( nvs_handle handle , const char * key , const uint8_t * data , size_t len )
2018-07-23 09:46:45 +02:00
{
uint8_t buf [ 16 ] ;
2021-07-25 17:00:08 +02:00
if ( read_nvs_value ( handle , key , buf , len , true ) & & memcmp ( buf , data , len ) = = 0 )
2018-07-23 09:46:45 +02:00
return true ; // unchanged
esp_err_t res = nvs_set_blob ( handle , key , data , len ) ;
ESP_ERROR_CHECK ( res ) ;
return res = = ESP_OK ;
}
// --- Helper functions ---
2021-07-25 17:00:08 +02:00
bool hex_str_to_bin ( const char * hex , uint8_t * buf , int len )
2018-07-23 09:46:45 +02:00
{
const char * ptr = hex ;
for ( int i = 0 ; i < len ; i + + )
{
2021-07-25 17:00:08 +02:00
int val = hex_tuple_to_byte ( ptr ) ;
2018-07-23 09:46:45 +02:00
if ( val < 0 )
return false ;
buf [ i ] = val ;
ptr + = 2 ;
}
return true ;
}
2021-07-25 17:00:08 +02:00
int hex_tuple_to_byte ( const char * hex )
2018-07-23 09:46:45 +02:00
{
2021-07-25 17:00:08 +02:00
int nibble1 = hex_digit_to_val ( hex [ 0 ] ) ;
2018-07-23 09:46:45 +02:00
if ( nibble1 < 0 )
return - 1 ;
2021-07-25 17:00:08 +02:00
int nibble2 = hex_digit_to_val ( hex [ 1 ] ) ;
2018-07-23 09:46:45 +02:00
if ( nibble2 < 0 )
return - 1 ;
return ( nibble1 < < 4 ) | nibble2 ;
}
2021-07-25 17:00:08 +02:00
int hex_digit_to_val ( char ch )
2018-07-23 09:46:45 +02:00
{
if ( ch > = ' 0 ' & & ch < = ' 9 ' )
return ch - ' 0 ' ;
if ( ch > = ' A ' & & ch < = ' F ' )
return ch + 10 - ' A ' ;
if ( ch > = ' a ' & & ch < = ' f ' )
return ch + 10 - ' a ' ;
return - 1 ;
}
2021-07-25 17:00:08 +02:00
void bin_to_hex_str ( const uint8_t * buf , int len , char * hex )
2018-07-23 09:46:45 +02:00
{
for ( int i = 0 ; i < len ; i + + )
{
uint8_t b = buf [ i ] ;
2021-07-25 17:00:08 +02:00
* hex = val_to_hex_digit ( ( b & 0xf0 ) > > 4 ) ;
2018-07-23 09:46:45 +02:00
hex + + ;
2021-07-25 17:00:08 +02:00
* hex = val_to_hex_digit ( b & 0x0f ) ;
2018-07-23 09:46:45 +02:00
hex + + ;
}
}
2021-07-25 17:00:08 +02:00
char val_to_hex_digit ( int val )
2018-07-23 09:46:45 +02:00
{
return " 0123456789ABCDEF " [ val ] ;
}
2021-07-25 17:00:08 +02:00
void swap_bytes ( uint8_t * buf , int len )
2018-07-23 09:46:45 +02:00
{
uint8_t * p1 = buf ;
uint8_t * p2 = buf + len - 1 ;
while ( p1 < p2 )
{
uint8_t t = * p1 ;
* p1 = * p2 ;
* p2 = t ;
p1 + + ;
p2 - - ;
}
}
2018-07-28 22:13:59 +02:00
2021-07-25 17:00:08 +02:00
bool is_all_zeros ( const uint8_t * buf , int len )
2018-07-28 22:13:59 +02:00
{
for ( int i = 0 ; i < len ; i + + )
if ( buf [ i ] ! = 0 )
return false ;
return true ;
}