Hi,
I'm testing the MQTT implementation integrated in the NRF5 SDK.
This is my test environment:
- A nRF52840 board with the MQTT publisher example from the SDK.
- A Raspberry Pi 3 B+, with Ubuntu MATE (18.04.2 LTS (Bionic Beaver) kernel 4.15.0-1032-raspi2)
- Mosquitto Broker installed in the Raspberry Pi.
When no security is enabled (port 1883) all works fine, but when the security (tls-psk in port 8883) is enabled the connection process doesn't work (Only tls-psk is used and no certificates are used/configured). This is what happen:
- I successfully create the interface between the nRF52 and the Raspberry (bt0).
- Then I press the button 1 to connect to the MQTT broker.
- It takes like 1 minute and 30 seconds to the handler to respond with a MQTT_EVT_CONNACK event with result in "0" (ok), but immediately the handler generate a disconnect event (MQTT_EVT_DISCONNECT event).
- If I retry the process the same happens again.
This is the output log:
<info> app_timer: RTC: initialized.
<info> app: Physical layer in connectable mode.
<info> app: Application started.
<info> app: Physical layer: connected.
<info> app: IPv6 Interface Up.
<info> app: >> MQTT_EVT_CONNACK, result 00000000
<info> app: >> MQTT_EVT_DISCONNECT
So I did some debug and research:
- The TSL debug say: "TLS: mbedtls_ssl_handshake result -29312"
- This code (from mbedtls) equals to -0x7280 and means "SSL - The connection indicated an EOF", and it's defined as MBEDTLS_ERR_SSL_CONN_EOF.
- The function "interface_ssl_context_setup" found in the source "tls_interface.c" is the only place where the above message is coded, and also it checks if the result is equal to MBEDTLS_ERR_SSL_CONN_EOF. If so it will return 0 anyway, so it is not treated as an error (if I'm not mistaken).
Only for additional information, when I enable the mbedtls debug (in nrf_tls_config.h file, with define MBEDTLS_DEBUG_C):
- The mbedtls debug say (repeatly): "<info> TLS: [ry/ssl_tls.c]:[3734]: mbedtls_ssl_read_record_layer() returned -29312 (-0x7280)"
- But this tells me the same as above.
In the Mosquitto Broker side, the log say:
1589922007: New connection from fd00:a::XX:XXXX:XXXX:XXXX on port 8883.
1589922008: New client connected from fd00:a::XX:XXXX:XXXX:XXXX as nrfPublisher (c1, k60).
1589922008: Sending CONNACK to nrfPublisher (0, 0)
...
1589922098: Client nrfPublisher has exceeded timeout, disconnecting.
1589922098: Socket error on client nrfPublisher, disconnecting.
So, the connection ACK was sent by the broker, and then it disconnect the client because a timeout after 90 seconds (the same 1 min 30 sec of the MQTT_EVT_CONNACK and MQTT_EVT_DISCONNECT event in the nRF52 board).
I also made a wireshark capture in the bt0 interface of the Raspberry. It shows a normal (I believe) tls handshake that ends with a MQTT message with a "Connect Ack" from the broker to the nRF52 board (publisher example). The next picture shows this:
(note: I included in wireshark the psk in order to view the data decrypted)
So, I'm stuck with my research, I'm not an expert in ssl/tls and either with mbedtls.
The problem seems to be that after a normal handshake between the broker and the client, at the end, the broker send a "Connect Ack" but the publisher client example halts for some reason and it doesn't generate the MQTT_EVT_CONNACK event. It's only generated when the broker disconnects after the 90 seconds. It's like the event is queued and only gets "unqueued" when happen the disconnection.
Aditional info of my setup, and my sdk_config.h file and the main.c source:
- nRF52840-MDK board by Makerdiary.com
- Mosquitto v1.4.15
- NRF5 SDK v16.0.0.
- Softdevice s140 v7.0.1
- Visual Studio Code / gcc
Best Regards,
José Forno
/** * Copyright (c) 2013 - 2019, Nordic Semiconductor ASA * * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form, except as embedded into a Nordic * Semiconductor ASA integrated circuit in a product or a software update for * such product, must reproduce the above copyright notice, this list of * conditions and the following disclaimer in the documentation and/or other * materials provided with the distribution. * * 3. Neither the name of Nordic Semiconductor ASA nor the names of its * contributors may be used to endorse or promote products derived from this * software without specific prior written permission. * * 4. This software, with or without modification, must only be used with a * Nordic Semiconductor ASA integrated circuit. * * 5. Any software provided in binary form under this license must not be reverse * engineered, decompiled, modified and/or disassembled. * * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /** @file * * @defgroup iot_sdk_app_mqtt_client main.c * @{ * @ingroup iot_sdk_app_lwip * * @brief This file contains the source code for LwIP based MQTT Client sample application. * This example publishes the topic "led/state" on button press. * Value of 0 or 1 is published as data for the topic based on LED is turned ON or OFF * on button press. */ #include <stdbool.h> #include <stdint.h> #include "boards.h" #include "nordic_common.h" #include "sdk_config.h" #include "nrf_sdm.h" #include "app_scheduler.h" #include "app_timer.h" #include "app_button.h" #include "lwip/init.h" #include "lwip/inet6.h" #include "lwip/ip6.h" #include "lwip/ip6_addr.h" #include "lwip/netif.h" #include "mqtt.h" #include "lwip/timers.h" #include "nrf_platform_port.h" #include "app_util_platform.h" #include "iot_timer.h" #include "ipv6_medium.h" #include "nrf_log.h" #include "nrf_log_ctrl.h" #include "nrf_log_default_backends.h" #include "mbedtls/error.h" /** Modify m_broker_addr according to your setup. * The address provided below is a place holder. */ static const ipv6_addr_t m_broker_addr = { .u8 = {0xFD, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01} }; #define SCHED_MAX_EVENT_DATA_SIZE 16 /**< Maximum size of scheduler events. */ #define SCHED_QUEUE_SIZE 192 /**< Maximum number of events in the scheduler queue. */ #define LED_ONE BSP_LED_0_MASK #define LED_TWO BSP_LED_1_MASK #define LED_THREE BSP_LED_2_MASK #define LED_FOUR BSP_LED_3_MASK #define ALL_APP_LED (BSP_LED_0_MASK | BSP_LED_1_MASK | \ BSP_LED_2_MASK | BSP_LED_3_MASK) /**< Define used for simultaneous operation of all application LEDs. */ #ifdef COMMISSIONING_ENABLED #define ERASE_BUTTON_PIN_NO BSP_BUTTON_3 /**< Button used to erase commissioning settings. */ #endif // COMMISSIONING_ENABLED #define LWIP_SYS_TICK_MS 10 /**< Interval for timer used as trigger to send. */ #define LED_BLINK_INTERVAL_MS 300 /**< LED blinking interval. */ #define DEAD_BEEF 0xDEADBEEF /**< Value used as error code on stack dump, can be used to identify stack location on stack unwind. */ #define APP_ENABLE_LOGS 1 /**< Enable logs in the application. */ #if (APP_ENABLE_LOGS == 1) #define APPL_LOG NRF_LOG_INFO #define APPL_DUMP NRF_LOG_RAW_HEXDUMP_INFO #define APPL_ADDR IPV6_ADDRESS_LOG #else // APP_ENABLE_LOGS #define APPL_LOG(...) #define APPL_DUMP(...) #define APPL_ADDR(...) #endif // APP_ENABLE_LOGS #define APP_MQTT_BROKER_PORT 8883 /**< Port number of MQTT Broker being used. */ #define APP_MQTT_PUBLISH_TOPIC "led/state" /**< MQTT topic to which this application publishes. */ /**@brief Application state with respect to MQTT. */ typedef enum { APP_MQTT_STATE_IDLE, /**< Indicates no MQTT connection exists. */ APP_MQTT_STATE_CONNECTED /**< Indicates MQTT connection is established. */ } app_mqtt_state_t; typedef enum { LEDS_INACTIVE = 0, LEDS_CONNECTABLE_MODE, LEDS_IPV6_IF_DOWN, LEDS_IPV6_IF_UP, LEDS_CONNECTED_TO_BROKER } display_state_t; APP_TIMER_DEF(m_iot_timer_tick_src_id); /**< System Timer used to service CoAP and LWIP periodically. */ eui64_t eui64_local_iid; /**< Local EUI64 value that is used as the IID for*/ static ipv6_medium_instance_t m_ipv6_medium; static mqtt_client_t m_app_mqtt_client; /**< MQTT Client instance reference provided by the MQTT module. */ static const char m_client_id[] = "nrfPublisher"; /**< Unique MQTT client identifier. */ static display_state_t m_display_state = LEDS_INACTIVE; /**< Board LED display state. */ static bool m_led_state = false; /**< LED state. This is the topic being published by the example MQTT client. */ static app_mqtt_state_t m_connection_state = APP_MQTT_STATE_IDLE; /**< MQTT Connection state. */ static bool m_do_ind_err = false; static uint8_t m_ind_err_count = 0; static uint16_t m_message_counter = 1; /**< Message counter used to generated message ids for MQTT messages. */ static const uint8_t identity[] = {0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79}; static const uint8_t shared_secret[] = {0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x50, 0x53, 0x4b}; static nrf_tls_preshared_key_t m_preshared_key = { .p_identity = &identity[0], .p_secret_key = &shared_secret[0], .identity_len = 15, .secret_key_len = 9 }; static nrf_tls_key_settings_t m_tls_keys = { .p_psk = &m_preshared_key //.p_own_certificate = NULL }; #ifdef COMMISSIONING_ENABLED static bool m_power_off_on_failure = false; static bool m_identity_mode_active; #endif // COMMISSIONING_ENABLED /**@brief Forward declarations. */ void app_mqtt_evt_handler(mqtt_client_t * const p_client, const mqtt_evt_t * p_evt); /**@brief Callback function for asserts in the SoftDevice. * * @details This function will be called in case of an assert in the SoftDevice. * * @warning This handler is an example only and does not fit a final product. You need to analyze * how your product is supposed to react in case of Assert. * @warning On assert from the SoftDevice, the system can only recover on reset. * * @param[in] line_num Line number of the failing ASSERT call. * @param[in] file_name File name of the failing ASSERT call. */ void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name) { app_error_handler(DEAD_BEEF, line_num, p_file_name); } /**@brief Function for the Event Scheduler initialization. */ static void scheduler_init(void) { APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE); } /**@brief Function for the LEDs initialization. * * @details Initializes all LEDs used by this application. */ static void leds_init(void) { // Configure application LED pins. LEDS_CONFIGURE(ALL_APP_LED); // Turn off all LED on initialization. LEDS_OFF(ALL_APP_LED); } /**@brief Timer callback used for controlling board LEDs to represent application state. * * @param[in] wall_clock_value The value of the wall clock that triggered the callback. */ static void blink_timeout_handler(iot_timer_time_in_ms_t wall_clock_value) { UNUSED_PARAMETER(wall_clock_value); #ifdef COMMISSIONING_ENABLED static bool id_mode_previously_enabled; #endif // COMMISSIONING_ENABLED if (m_do_ind_err == true) { // Flash LED_THREE for three periods if error occurs. if (m_ind_err_count < 3) { ++m_ind_err_count; } else { LEDS_OFF(LED_THREE); m_do_ind_err = false; m_ind_err_count = 0; } } switch (m_display_state) { case LEDS_INACTIVE: { LEDS_OFF(ALL_APP_LED); break; } case LEDS_CONNECTABLE_MODE: { LEDS_INVERT(LED_ONE); LEDS_OFF(LED_TWO); break; } case LEDS_IPV6_IF_DOWN: { LEDS_INVERT(LED_TWO); LEDS_OFF(LED_ONE); break; } case LEDS_IPV6_IF_UP: { LEDS_ON(LED_ONE); LEDS_OFF(LED_TWO); break; } case LEDS_CONNECTED_TO_BROKER: { LEDS_ON(LED_TWO); LEDS_OFF(LED_ONE); break; } default: { break; } } #ifdef COMMISSIONING_ENABLED if ((id_mode_previously_enabled == false) && (m_identity_mode_active == true)) { LEDS_OFF(LED_THREE | LED_FOUR); } if ((id_mode_previously_enabled == true) && (m_identity_mode_active == true)) { LEDS_INVERT(LED_THREE | LED_FOUR); } if ((id_mode_previously_enabled == true) && (m_identity_mode_active == false)) { LEDS_OFF(LED_THREE | LED_FOUR); } id_mode_previously_enabled = m_identity_mode_active; #endif // COMMISSIONING_ENABLED } /**@brief Connect to MQTT broker. */ static void app_mqtt_connect(void) { mqtt_client_init(&m_app_mqtt_client); memcpy(m_app_mqtt_client.broker_addr.u8, m_broker_addr.u8, IPV6_ADDR_SIZE); m_app_mqtt_client.broker_port = APP_MQTT_BROKER_PORT; m_app_mqtt_client.evt_cb = app_mqtt_evt_handler; m_app_mqtt_client.client_id.p_utf_str = (uint8_t *)m_client_id; m_app_mqtt_client.client_id.utf_strlen = strlen(m_client_id); m_app_mqtt_client.p_password = NULL; m_app_mqtt_client.p_user_name = NULL; m_app_mqtt_client.transport_type = MQTT_TRANSPORT_SECURE; m_app_mqtt_client.p_security_settings = &m_tls_keys; //m_app_mqtt_client.protocol_version = MQTT_VERSION_3_1_1; UNUSED_VARIABLE(mqtt_connect(&m_app_mqtt_client)); } /**@brief Publishes LED state to MQTT broker. * * @param[in] led_state LED state being published. */ static void app_mqtt_publish(bool led_state) { // Set topic to be published. const char * topic_str = APP_MQTT_PUBLISH_TOPIC; mqtt_publish_param_t param; param.message.topic.qos = MQTT_QoS_1_ATLEAST_ONCE; param.message.topic.topic.p_utf_str = (uint8_t *)topic_str; param.message.topic.topic.utf_strlen = strlen(topic_str); param.message.payload.p_bin_str = (uint8_t *)&led_state, param.message.payload.bin_strlen = 1; param.message_id = m_message_counter; param.dup_flag = 0; param.retain_flag = 0; uint32_t err_code = mqtt_publish(&m_app_mqtt_client, ¶m); APPL_LOG("mqtt_publish result 0x%08lx", err_code); if (err_code == NRF_SUCCESS) { LEDS_INVERT(LED_FOUR); m_led_state = !m_led_state; // Avoid ever sending invalid message id 0. m_message_counter+= 2; } else { // Flash LED_THREE if error occurs. LEDS_ON(LED_THREE); m_do_ind_err = true; } } static void button_event_handler(uint8_t pin_no, uint8_t button_action) { #ifdef COMMISSIONING_ENABLED if ((button_action == APP_BUTTON_PUSH) && (pin_no == ERASE_BUTTON_PIN_NO)) { APPL_LOG("Erasing all commissioning settings from persistent storage..."); commissioning_settings_clear(); return; } #endif // COMMISSIONING_ENABLED if (button_action == APP_BUTTON_PUSH) { switch (pin_no) { case BSP_BUTTON_0: { APPL_LOG("B0 Press"); if (m_connection_state == APP_MQTT_STATE_IDLE) { app_mqtt_connect(); APPL_LOG("JOE-Trying to connect..."); } break; } case BSP_BUTTON_1: { APPL_LOG("B1 Press"); if (m_connection_state == APP_MQTT_STATE_CONNECTED) { app_mqtt_publish(!m_led_state); } break; } case BSP_BUTTON_2: { APPL_LOG("B2 Press"); if (m_connection_state == APP_MQTT_STATE_CONNECTED) { UNUSED_VARIABLE(mqtt_disconnect(&m_app_mqtt_client)); } break; } default: break; } } } static void button_init(void) { uint32_t err_code; static app_button_cfg_t buttons[] = { {BSP_BUTTON_0, false, BUTTON_PULL, button_event_handler}, {BSP_BUTTON_1, false, BUTTON_PULL, button_event_handler}, {BSP_BUTTON_2, false, BUTTON_PULL, button_event_handler}, #ifdef COMMISSIONING_ENABLED {ERASE_BUTTON_PIN_NO, false, BUTTON_PULL, button_event_handler} #endif // COMMISSIONING_ENABLED }; #define BUTTON_DETECTION_DELAY APP_TIMER_TICKS(50) err_code = app_button_init(buttons, ARRAY_SIZE(buttons), BUTTON_DETECTION_DELAY); APP_ERROR_CHECK(err_code); err_code = app_button_enable(); APP_ERROR_CHECK(err_code); } /**@brief Function for initializing IP stack. * * @details Initialize the IP Stack and its driver. */ static void ip_stack_init(void) { uint32_t err_code; err_code = ipv6_medium_eui64_get(m_ipv6_medium.ipv6_medium_instance_id, &eui64_local_iid); APP_ERROR_CHECK(err_code); err_code = nrf_mem_init(); APP_ERROR_CHECK(err_code); // Initialize LwIP stack. lwip_init(); // Initialize LwIP stack driver. err_code = nrf_driver_init(); APP_ERROR_CHECK(err_code); err_code = mqtt_init(); APP_ERROR_CHECK(err_code); } /**@brief Timer callback used for periodic servicing of LwIP protocol timers. * This trigger is also used in the example to trigger sending TCP Connection. * * @details Timer callback used for periodic servicing of LwIP protocol timers. * * @param[in] wall_clock_value The value of the wall clock that triggered the callback. */ static void system_timer_callback(iot_timer_time_in_ms_t wall_clock_value) { UNUSED_VARIABLE(wall_clock_value); sys_check_timeouts(); UNUSED_VARIABLE(mqtt_live()); } /**@brief Function for updating the wall clock of the IoT Timer module. * * @param[in] p_context Pointer used for passing context. No context used in this application. */ static void iot_timer_tick_callback(void * p_context) { UNUSED_VARIABLE(p_context); uint32_t err_code = iot_timer_update(); APP_ERROR_CHECK(err_code); } /**@brief Function for the Timer initialization. * * @details Initializes the timer module. This creates and starts application timers. */ static void timers_init(void) { uint32_t err_code; // Initialize timer module. APP_ERROR_CHECK(app_timer_init()); // Create a sys timer. err_code = app_timer_create(&m_iot_timer_tick_src_id, APP_TIMER_MODE_REPEATED, iot_timer_tick_callback); APP_ERROR_CHECK(err_code); } /**@brief Function for initializing the IoT Timer. */ static void iot_timer_init(void) { uint32_t err_code; static const iot_timer_client_t list_of_clients[] = { {system_timer_callback, LWIP_SYS_TICK_MS}, {blink_timeout_handler, LED_BLINK_INTERVAL_MS}, #ifdef COMMISSIONING_ENABLED {commissioning_time_tick, SEC_TO_MILLISEC(COMMISSIONING_TICK_INTERVAL_SEC)} #endif // COMMISSIONING_ENABLED }; // The list of IoT Timer clients is declared as a constant. static const iot_timer_clients_list_t iot_timer_clients = { (sizeof(list_of_clients) / sizeof(iot_timer_client_t)), &(list_of_clients[0]), }; // Passing the list of clients to the IoT Timer module. err_code = iot_timer_client_list_set(&iot_timer_clients); APP_ERROR_CHECK(err_code); // Starting the app timer instance that is the tick source for the IoT Timer. err_code = app_timer_start(m_iot_timer_tick_src_id, APP_TIMER_TICKS(IOT_TIMER_RESOLUTION_IN_MS), NULL); APP_ERROR_CHECK(err_code); } /**@brief Function to handle interface up event. */ void nrf_driver_interface_up(iot_interface_t const * p_interface) { UNUSED_PARAMETER(p_interface); #ifdef COMMISSIONING_ENABLED commissioning_joining_mode_timer_ctrl(JOINING_MODE_TIMER_STOP_RESET); #endif // COMMISSIONING_ENABLED APPL_LOG ("IPv6 Interface Up."); sys_check_timeouts(); m_display_state = LEDS_IPV6_IF_UP; } /**@brief Function to handle interface down event. */ void nrf_driver_interface_down(iot_interface_t const * p_interface) { UNUSED_PARAMETER(p_interface); #ifdef COMMISSIONING_ENABLED commissioning_joining_mode_timer_ctrl(JOINING_MODE_TIMER_START); #endif // COMMISSIONING_ENABLED APPL_LOG ("IPv6 Interface Down."); m_display_state = LEDS_IPV6_IF_DOWN; } void app_mqtt_evt_handler(mqtt_client_t * const p_client, const mqtt_evt_t * p_evt) { switch (p_evt->id) { case MQTT_EVT_CONNACK: { APPL_LOG (">> MQTT_EVT_CONNACK, result %08lx", p_evt->result); if (p_evt->result == NRF_SUCCESS) { m_connection_state = APP_MQTT_STATE_CONNECTED; m_display_state = LEDS_CONNECTED_TO_BROKER; } else { m_connection_state = APP_MQTT_STATE_IDLE; m_display_state = LEDS_IPV6_IF_UP; } break; } case MQTT_EVT_PUBACK: { APPL_LOG (">> MQTT_EVT_PUBACK"); break; } case MQTT_EVT_DISCONNECT: { APPL_LOG (">> MQTT_EVT_DISCONNECT"); m_connection_state = APP_MQTT_STATE_IDLE; m_display_state = LEDS_IPV6_IF_UP; break; } default: break; } } /**@brief Function for starting connectable mode. */ static void connectable_mode_enter(void) { uint32_t err_code = ipv6_medium_connectable_mode_enter(m_ipv6_medium.ipv6_medium_instance_id); APP_ERROR_CHECK(err_code); APPL_LOG("Physical layer in connectable mode."); m_display_state = LEDS_CONNECTABLE_MODE; } static void on_ipv6_medium_evt(ipv6_medium_evt_t * p_ipv6_medium_evt) { switch (p_ipv6_medium_evt->ipv6_medium_evt_id) { case IPV6_MEDIUM_EVT_CONN_UP: { APPL_LOG("Physical layer: connected."); m_display_state = LEDS_IPV6_IF_DOWN; break; } case IPV6_MEDIUM_EVT_CONN_DOWN: { APPL_LOG("Physical layer: disconnected."); connectable_mode_enter(); break; } default: { break; } } } static void on_ipv6_medium_error(ipv6_medium_error_t * p_ipv6_medium_error) { // Do something. } #ifdef COMMISSIONING_ENABLED void commissioning_id_mode_cb(mode_control_cmd_t control_command) { switch (control_command) { case CMD_IDENTITY_MODE_ENTER: { LEDS_OFF(LED_THREE | LED_FOUR); m_identity_mode_active = true; break; } case CMD_IDENTITY_MODE_EXIT: { m_identity_mode_active = false; LEDS_OFF((LED_THREE | LED_FOUR)); break; } default: { break; } } } void commissioning_power_off_cb(bool power_off_on_failure) { m_power_off_on_failure = power_off_on_failure; APPL_LOG("Commissioning: do power_off on failure: %s.", m_power_off_on_failure ? "true" : "false"); } #endif // COMMISSIONING_ENABLED /**@brief Function for initializing the nrf log module. */ static void log_init(void) { ret_code_t err_code = NRF_LOG_INIT(NULL); APP_ERROR_CHECK(err_code); NRF_LOG_DEFAULT_BACKENDS_INIT(); } /** * @brief Function for application main entry. */ int main(void) { uint32_t err_code; // Initialize. log_init(); scheduler_init(); leds_init(); timers_init(); iot_timer_init(); button_init(); static ipv6_medium_init_params_t ipv6_medium_init_params; memset(&ipv6_medium_init_params, 0x00, sizeof(ipv6_medium_init_params)); ipv6_medium_init_params.ipv6_medium_evt_handler = on_ipv6_medium_evt; ipv6_medium_init_params.ipv6_medium_error_handler = on_ipv6_medium_error; #ifdef COMMISSIONING_ENABLED ipv6_medium_init_params.commissioning_id_mode_cb = commissioning_id_mode_cb; ipv6_medium_init_params.commissioning_power_off_cb = commissioning_power_off_cb; #endif // COMMISSIONING_ENABLED err_code = ipv6_medium_init(&ipv6_medium_init_params, IPV6_MEDIUM_ID_BLE, &m_ipv6_medium); APP_ERROR_CHECK(err_code); eui48_t ipv6_medium_eui48; err_code = ipv6_medium_eui48_get(m_ipv6_medium.ipv6_medium_instance_id, &ipv6_medium_eui48); ipv6_medium_eui48.identifier[EUI_48_SIZE - 1] = 0x00; err_code = ipv6_medium_eui48_set(m_ipv6_medium.ipv6_medium_instance_id, &ipv6_medium_eui48); APP_ERROR_CHECK(err_code); ip_stack_init(); // Start execution. connectable_mode_enter(); APPL_LOG("Application started."); char buffTmp[50]; buffTmp[0] = 0; int fake_ret = -29312; mbedtls_strerror(fake_ret, buffTmp, 50); APPL_LOG("Msg %d, %X: %s", fake_ret, fake_ret, buffTmp); // Enter main loop. for (;;) { app_sched_execute(); if (NRF_LOG_PROCESS() == false) { // Sleep waiting for an application event. err_code = sd_app_evt_wait(); APP_ERROR_CHECK(err_code); } } } /** * @} */