This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Subscribing to different topic while publishing on another topic

Hi everyone,

I am using nRF52 which has 52832 on it. Currently, I am working on 2 nRFs and one RPi with MQTT on the softdevice 132. One nRF is the publisher, another one is a sub and RPi is a router. Publisher senses the temperature and publish this data to subscriber. Router is recording data to Sql database. What I want to do is to make subscribed my publisher nRF to the topic that is managed by broker/router. For example, when the sensed data is recorded to database it is first checked that temperature does not exceed the critical value. If exceeds broker sends turn on the led on the publisher nRF. I can do these actions seperately, however, when try to integrate both of them into one application, the first happening operation works but second does not. At the same time, I am using ADC in publisher. Actually, I have searched related questions and found the below but I could not get any result. Additionally, I changed the max number of clients setting from 1 to 2 in sdk_config but I do not think it is the point. What should be done to integrate my scenario? Thank you in advance. 

devzone.nordicsemi.com/.../57469

Parents
  • I started with the mqtt publisher example from SDK 15.2.0 and added the subscriber part to the main.c file. I'm able to both subscribe and publish at the same time.

    Please note that m_connection_state changes from APP_MQTT_STATE_CONNECED to APP_MQTT_STATE_SUBSCRIBED in the subscriber example, so make sure that button 2 is checking for both states when you want to publish while subscribing.

    Attaching the main.c file for the modified mqtt publisher example. This is set up to subscribe to temp/state and publish on led/state. LED4 will toggle when a node publishes on temp/state.

    /**
     * Copyright (c) 2013 - 2018, 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"
    
    /** 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 =
        {0x20, 0x01, 0x0D, 0xB8,
         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                1883                                                    /**< Port number of MQTT Broker being used. */
    #define APP_MQTT_PUBLISH_TOPIC              "led/state"                                             /**< MQTT topic to which this application publishes. */
    #define APP_MQTT_SUBSCRIPTION_PKT_ID        11                                                      /**< Unique identification of subscription, can be any unsigned 16 bit integer value. */
    #define APP_MQTT_SUBSCRIPTION_TOPIC         "temp/state"                                             /**< MQTT topic to which this application subscribes. */
    
    /**@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_SUBSCRIBED                                                                       /**< Indicates application is subscribed for MQTT topic on the connection. */
    } app_mqtt_state_t;
    
    typedef enum
    {
        LEDS_INACTIVE = 0,
        LEDS_CONNECTABLE_MODE,
        LEDS_IPV6_IF_DOWN,
        LEDS_IPV6_IF_UP,
        LEDS_CONNECTED_TO_BROKER,
        LEDS_SUBSCRIBED_TO_TOPIC
    } 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
    };
    
    #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;
            }
            case LEDS_SUBSCRIBED_TO_TOPIC:
            {
                //LEDS_ON(LED_TWO);
                //LEDS_ON(LED_THREE);
                //LEDS_OFF(LED_ONE);
                //LEDS_ON(LED_FOUR);
                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_NON_SECURE;
        m_app_mqtt_client.p_security_settings  = &m_tls_keys;
    
        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, &param);
        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;
        }
    }
    
    /**@brief Subscribe with the broker. */
    static void app_mqtt_subscribe(void)
    {
        const char * topic_str = APP_MQTT_SUBSCRIPTION_TOPIC;
    
        mqtt_topic_t topic =
        {
            .topic =
            {
                .p_utf_str  = (uint8_t *)topic_str,
                .utf_strlen = strlen(topic_str)
            },
            .qos = MQTT_QoS_1_ATLEAST_ONCE
        };
    
        const mqtt_subscription_list_t subscription_list =
        {
            .p_list     = &topic,
            .list_count = 1,
            .message_id = APP_MQTT_SUBSCRIPTION_PKT_ID
        };
    
        uint32_t err_code = mqtt_subscribe(&m_app_mqtt_client, &subscription_list);
    
        if (err_code == NRF_SUCCESS)
        {
            m_connection_state = APP_MQTT_STATE_SUBSCRIBED;
            m_display_state = LEDS_SUBSCRIBED_TO_TOPIC;
        }
    }
    
    
    /**@brief Unsubscribe with the broker. */
    static void app_mqtt_unsubscribe(void)
    {
        const char * topic_str = APP_MQTT_SUBSCRIPTION_TOPIC;
    
        mqtt_topic_t topic =
        {
            .topic =
            {
                .p_utf_str  = (uint8_t *)topic_str,
                .utf_strlen = strlen(topic_str)
            },
            .qos = MQTT_QoS_0_AT_MOST_ONCE
        };
    
        const mqtt_subscription_list_t subscription_list =
        {
            .p_list     = &topic,
            .list_count = 1,
            .message_id = APP_MQTT_SUBSCRIPTION_PKT_ID
        };
    
        uint32_t err_code = mqtt_unsubscribe(&m_app_mqtt_client, &subscription_list);
    
        if (err_code == NRF_SUCCESS)
        {
            m_connection_state = APP_MQTT_STATE_CONNECTED;
            m_display_state = LEDS_CONNECTED_TO_BROKER;
        }
    }
    
    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:
                {
                    if (m_connection_state == APP_MQTT_STATE_IDLE)
                    {
                        app_mqtt_connect();
                    }
                    break;
                }
                case BSP_BUTTON_1:
                {
                    if (m_connection_state == APP_MQTT_STATE_CONNECTED || m_connection_state == APP_MQTT_STATE_SUBSCRIBED)
                    {
                        app_mqtt_publish(!m_led_state);
                    }
                    break;
                }
                case BSP_BUTTON_2:
                {
                    if (m_connection_state == APP_MQTT_STATE_CONNECTED)
                    {
                        UNUSED_VARIABLE(mqtt_disconnect(&m_app_mqtt_client));
                    }
                    break;
                }
                case BSP_BUTTON_3:
                {
                    if (m_connection_state == APP_MQTT_STATE_CONNECTED)
                    {
                        app_mqtt_subscribe();
                    }
                    else if (m_connection_state == APP_MQTT_STATE_SUBSCRIBED)
                    {
                        app_mqtt_unsubscribe();
                    }
                    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},
            {BSP_BUTTON_3,        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;
            }
            case MQTT_EVT_PUBLISH:
            {
                APPL_LOG (">> Data length 0x%04lX", p_evt->param.publish.message.payload.bin_strlen);
                APPL_LOG (">> Topic length 0x%04lX", p_evt->param.publish.message.topic.topic.utf_strlen);
    
                if (p_evt->param.publish.message.payload.bin_strlen == 1)
                {
                    // Accept binary or ASCII 0 and 1.
                    if ((p_evt->param.publish.message.payload.p_bin_str[0] == 0) ||
                        (p_evt->param.publish.message.payload.p_bin_str[0] == 0x30))
                    {
                        LEDS_OFF(LED_FOUR);
                    }
                    else if ((p_evt->param.publish.message.payload.p_bin_str[0] == 1) ||
                             (p_evt->param.publish.message.payload.p_bin_str[0] == 0x31))
                    {
                        LEDS_ON(LED_FOUR);
                    }
                }
                if (p_evt->param.publish.message.topic.qos == MQTT_QoS_1_ATLEAST_ONCE)
                {
                    const mqtt_puback_param_t ack_param = {
                        .message_id = p_evt->param.publish.message_id
                    };
    
                    // Send acknowledgment.
                    uint32_t err_code = mqtt_publish_ack(p_client, &ack_param);
    
                    APPL_LOG (">> mqtt_publish_ack message id 0x%04x, result 0x%08lx",
                              p_evt->param.publish.message_id,
                              err_code);
                    UNUSED_VARIABLE(err_code);
                }
    
                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.");
    
        // 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);
            }
        }
    }
    
    /**
     * @}
     */
    

Reply
  • I started with the mqtt publisher example from SDK 15.2.0 and added the subscriber part to the main.c file. I'm able to both subscribe and publish at the same time.

    Please note that m_connection_state changes from APP_MQTT_STATE_CONNECED to APP_MQTT_STATE_SUBSCRIBED in the subscriber example, so make sure that button 2 is checking for both states when you want to publish while subscribing.

    Attaching the main.c file for the modified mqtt publisher example. This is set up to subscribe to temp/state and publish on led/state. LED4 will toggle when a node publishes on temp/state.

    /**
     * Copyright (c) 2013 - 2018, 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"
    
    /** 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 =
        {0x20, 0x01, 0x0D, 0xB8,
         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                1883                                                    /**< Port number of MQTT Broker being used. */
    #define APP_MQTT_PUBLISH_TOPIC              "led/state"                                             /**< MQTT topic to which this application publishes. */
    #define APP_MQTT_SUBSCRIPTION_PKT_ID        11                                                      /**< Unique identification of subscription, can be any unsigned 16 bit integer value. */
    #define APP_MQTT_SUBSCRIPTION_TOPIC         "temp/state"                                             /**< MQTT topic to which this application subscribes. */
    
    /**@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_SUBSCRIBED                                                                       /**< Indicates application is subscribed for MQTT topic on the connection. */
    } app_mqtt_state_t;
    
    typedef enum
    {
        LEDS_INACTIVE = 0,
        LEDS_CONNECTABLE_MODE,
        LEDS_IPV6_IF_DOWN,
        LEDS_IPV6_IF_UP,
        LEDS_CONNECTED_TO_BROKER,
        LEDS_SUBSCRIBED_TO_TOPIC
    } 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
    };
    
    #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;
            }
            case LEDS_SUBSCRIBED_TO_TOPIC:
            {
                //LEDS_ON(LED_TWO);
                //LEDS_ON(LED_THREE);
                //LEDS_OFF(LED_ONE);
                //LEDS_ON(LED_FOUR);
                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_NON_SECURE;
        m_app_mqtt_client.p_security_settings  = &m_tls_keys;
    
        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, &param);
        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;
        }
    }
    
    /**@brief Subscribe with the broker. */
    static void app_mqtt_subscribe(void)
    {
        const char * topic_str = APP_MQTT_SUBSCRIPTION_TOPIC;
    
        mqtt_topic_t topic =
        {
            .topic =
            {
                .p_utf_str  = (uint8_t *)topic_str,
                .utf_strlen = strlen(topic_str)
            },
            .qos = MQTT_QoS_1_ATLEAST_ONCE
        };
    
        const mqtt_subscription_list_t subscription_list =
        {
            .p_list     = &topic,
            .list_count = 1,
            .message_id = APP_MQTT_SUBSCRIPTION_PKT_ID
        };
    
        uint32_t err_code = mqtt_subscribe(&m_app_mqtt_client, &subscription_list);
    
        if (err_code == NRF_SUCCESS)
        {
            m_connection_state = APP_MQTT_STATE_SUBSCRIBED;
            m_display_state = LEDS_SUBSCRIBED_TO_TOPIC;
        }
    }
    
    
    /**@brief Unsubscribe with the broker. */
    static void app_mqtt_unsubscribe(void)
    {
        const char * topic_str = APP_MQTT_SUBSCRIPTION_TOPIC;
    
        mqtt_topic_t topic =
        {
            .topic =
            {
                .p_utf_str  = (uint8_t *)topic_str,
                .utf_strlen = strlen(topic_str)
            },
            .qos = MQTT_QoS_0_AT_MOST_ONCE
        };
    
        const mqtt_subscription_list_t subscription_list =
        {
            .p_list     = &topic,
            .list_count = 1,
            .message_id = APP_MQTT_SUBSCRIPTION_PKT_ID
        };
    
        uint32_t err_code = mqtt_unsubscribe(&m_app_mqtt_client, &subscription_list);
    
        if (err_code == NRF_SUCCESS)
        {
            m_connection_state = APP_MQTT_STATE_CONNECTED;
            m_display_state = LEDS_CONNECTED_TO_BROKER;
        }
    }
    
    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:
                {
                    if (m_connection_state == APP_MQTT_STATE_IDLE)
                    {
                        app_mqtt_connect();
                    }
                    break;
                }
                case BSP_BUTTON_1:
                {
                    if (m_connection_state == APP_MQTT_STATE_CONNECTED || m_connection_state == APP_MQTT_STATE_SUBSCRIBED)
                    {
                        app_mqtt_publish(!m_led_state);
                    }
                    break;
                }
                case BSP_BUTTON_2:
                {
                    if (m_connection_state == APP_MQTT_STATE_CONNECTED)
                    {
                        UNUSED_VARIABLE(mqtt_disconnect(&m_app_mqtt_client));
                    }
                    break;
                }
                case BSP_BUTTON_3:
                {
                    if (m_connection_state == APP_MQTT_STATE_CONNECTED)
                    {
                        app_mqtt_subscribe();
                    }
                    else if (m_connection_state == APP_MQTT_STATE_SUBSCRIBED)
                    {
                        app_mqtt_unsubscribe();
                    }
                    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},
            {BSP_BUTTON_3,        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;
            }
            case MQTT_EVT_PUBLISH:
            {
                APPL_LOG (">> Data length 0x%04lX", p_evt->param.publish.message.payload.bin_strlen);
                APPL_LOG (">> Topic length 0x%04lX", p_evt->param.publish.message.topic.topic.utf_strlen);
    
                if (p_evt->param.publish.message.payload.bin_strlen == 1)
                {
                    // Accept binary or ASCII 0 and 1.
                    if ((p_evt->param.publish.message.payload.p_bin_str[0] == 0) ||
                        (p_evt->param.publish.message.payload.p_bin_str[0] == 0x30))
                    {
                        LEDS_OFF(LED_FOUR);
                    }
                    else if ((p_evt->param.publish.message.payload.p_bin_str[0] == 1) ||
                             (p_evt->param.publish.message.payload.p_bin_str[0] == 0x31))
                    {
                        LEDS_ON(LED_FOUR);
                    }
                }
                if (p_evt->param.publish.message.topic.qos == MQTT_QoS_1_ATLEAST_ONCE)
                {
                    const mqtt_puback_param_t ack_param = {
                        .message_id = p_evt->param.publish.message_id
                    };
    
                    // Send acknowledgment.
                    uint32_t err_code = mqtt_publish_ack(p_client, &ack_param);
    
                    APPL_LOG (">> mqtt_publish_ack message id 0x%04x, result 0x%08lx",
                              p_evt->param.publish.message_id,
                              err_code);
                    UNUSED_VARIABLE(err_code);
                }
    
                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.");
    
        // 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);
            }
        }
    }
    
    /**
     * @}
     */
    

Children
No Data
Related