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

Problems on nrf52840 coap server to receive packages

Hi All, 
I want to implement a function to send data from the internet coap client to nrf52840 DK coap server. The nrf52840 runs .hex file which is one modified from Nordic Thread SDK example\thread\simple_coap_server, but I find that whether I use the otCoapAddResource registered function or the coap_default_handler function, neither received the coap data that internet coap client sent. I've caught coap message on the wpan0 interface of OTBR, but the function didn't work as if it hadn't received those package, that is the OTBR in wpan0 has received this package, but it doesn't deliver to nrf52840 DK coap sever. 
Therefore, how do I get the nrf52840 DK coap server to receive and process packages from coap client successfully?
I really appreciate any help you can provide. 
Best, 
Tao

Parents
  • Hi,

    Can you provide more details about the "internet coap client"? How are the packets addressed to the CoAP server node in the Thread network? Do you have global IPv6 connectivity to the border router?

    Can you post logs, packet captures, etc that can help with identifying where the packets stop? If you could also upload the modified CoAP server project to show the changes you made, that would also be helpful.

    Best regards,
    Jørgen

  • It looks from your sniffer logs that you do not have global IPv6 connectivity and/or the CoAP cloud server is running on a IPv4 interface. In order to send packets from IPv4 cloud service to the nodes in the network, you either need to use global IPv6 addresses (2000::/3 prefix), or you need to setup a translation method on the border router to forward the packets to the correct node (for instance NAT46). The border router image provided by Nordic only enables NAT64, which can send packets from the IPv6 based Thread network, to global IPv4 internet. It does not provide any mechanisms for packets going from global IPv4 internet to the IPv6 based Thread network.

  • The sniffer trace does confirm that the CoAP PUT request is being sent over the air and received by the intended recipient. So,NAT64 can be deliver packets going from global IPv4 internet to the IPv6 based Thread network.The problem should be with my source code caused the error.

    /**
     * Copyright (c) 2017 - 2020, 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 simple_coap_client_example_main main.c
     * @{
     * @ingroup simple_coap_client_example_example
     * @brief Simple CoAP Client Example Application main file.
     *
     * @details This example demonstrates a CoAP client application that enables to control BSP_LED_0
     *          on a board with related Simple CoAP Server application via CoAP messages.
     *
     */
    #include "mbedtls/base64.h"
    #include "mbedtls/md.h"
    #include "app_scheduler.h"
    #include "app_timer.h"
    #include "bsp_thread.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log.h"
    #include "nrf_log_default_backends.h"
    
    #include "thread_coap_utils.h"
    #include "thread_utils.h"
    
    #include <openthread/instance.h>
    #include <openthread/thread.h>
    
    #define SCHED_QUEUE_SIZE      32                                                      /**< Maximum number of events in the scheduler queue. */
    #define SCHED_EVENT_DATA_SIZE APP_TIMER_SCHED_EVENT_DATA_SIZE                         /**< Maximum app_scheduler event size. */
    
    static thread_coap_utils_light_command_t m_command = THREAD_COAP_UTILS_LIGHT_CMD_OFF; /**< This variable stores command that has been most recently used. */
    
    char *OneNetmethod  = "sha1";
    char *OneNetres     = "products/CxD2hb4NHT/devices/tttt";
    char *OneNetversion  = "2018-10-31";
    char *OneNetkey     = "WWtxWyeJ+wPB/08/6f3THe8rNSe5i1ubPyex+Qu7N08=";
    char *OneNetEndpoint = "183.230.102.116:5683";
    char *OneNetPathLogin    = "$sys/CxD2hb4NHT/tttt/log_in";
    char *OneNetPathLogout    = "$sys/CxD2hb4NHT/tttt/log_out";
    char *OneNetPathKeepAlive = "$sys/CxD2hb4NHT/tttt/keep_alive";
    char *OneNetPathPropertyPost   = "$sys/CxD2hb4NHT/tttt/thing/property/post";
    char *OneNetPathPropertyGet    = "$sys/CxD2hb4NHT/tttt/thing/property/get";
    char *OneNetPathPropertyDelete = "$sys/CxD2hb4NHT/tttt/thing/property/delete";
    char *OneNetPathPropertySet    = "$sys/CxD2hb4NHT/tttt/thing/property/set";
    /***************************************************************************************************
     * @section TheThings.io
     **************************************************************************************************/
    
    static unsigned char hexchars[] = "0123456789ABCDEF";
    char *url_encode(char const *s, int len, int *new_length)
    {
        register unsigned char c;
        unsigned char *to, *start;
        unsigned char const *from, *end;
        
        from = (unsigned char *)s;
        end  = (unsigned char *)s + len;
        start = to = (unsigned char *) nrf_malloc(1, 3*len+1);
    
        while (from < end) 
        {
            c = *from++;
    
            if (c == ' ') 
            {
                *to++ = '+';
            } 
            else if ((c < '0' && c != '-' && c != '.') ||
                     (c < 'A' && c > '9') ||
                     (c > 'Z' && c < 'a' && c != '_') ||
                     (c > 'z')) 
            {
                to[0] = '%';
                to[1] = hexchars[c >> 4];//��2����ת����16���Ʊ�ʾ
                to[2] = hexchars[c & 15];//��2����ת����16���Ʊ�ʾ
                to += 3;
            }
            else 
            {
                *to++ = c;
            }
        }
        *to = 0;
        if (new_length) 
        {
            *new_length = to - start;
        }
        return (char *) start;
    }
    
    char* OneNetLogInPayload()
    {
        char *OneNetet = "1600913071";
        uint8_t hash[20]={0};
    
        uint8_t content[100]={0};
        sprintf(content, "%s\n%s\n%s\n%s", OneNetet, OneNetmethod, OneNetres, OneNetversion);
    
        uint8_t key[100] = {0};
        size_t olen = strlen(OneNetkey);
        mbedtls_base64_decode(key, olen, &olen, (const unsigned char *)OneNetkey, olen);
    
        mbedtls_md_context_t ctx;
        const mbedtls_md_info_t *info;
        mbedtls_md_init(&ctx);
        info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
        mbedtls_md_setup(&ctx, info, 1);
        mbedtls_md_hmac_starts(&ctx, key, strlen( (const char *)key));
        mbedtls_md_hmac_update(&ctx, content, strlen( (const char *)content));
        mbedtls_md_hmac_finish(&ctx, hash);
        mbedtls_md_free(&ctx);
    
        uint8_t old_sign[100];
        size_t len = sizeof(hash);
        mbedtls_base64_encode(old_sign, sizeof(old_sign), &len, hash, len);
    //    printf("Old Sign:%s\n",old_sign);
    //    printf("Old Res:%s\n",OneNetres);
    
    
        char *new_sign = url_encode(old_sign,strlen(old_sign),NULL);
        char *new_res = url_encode(OneNetres,strlen(OneNetres),NULL);
    
    //    printf("New Sign:%s\n",new_sign);
    //    printf("New Res:%s\n",new_res);
        char token[300]={0};
        sprintf(token,"version=%s&res=%s&et=%s&method=%s&sign=%s",
                OneNetversion, new_res, OneNetet, OneNetmethod, new_sign);
    //    printf("Token:%s\n",token);
    
        char *payload = nrf_malloc(300);
        sprintf(payload,"{\"lt\":86400,\"st\":\"%s\"}",token);
    
        return payload;
    }
    
    #define TYZ
    #ifdef TYZ
    static uint16_t     m_counter       = 0;
    static int32_t      m_temperature   = 0;
    static otIp6Address m_cloud_address = {0};
    static bool         m_associated    = false;
    unsigned char m_ccode[8];
    #endif
    /***************************************************************************************************
     * @section Buttons
     **************************************************************************************************/
    
    
    
    #ifdef TYZ
    #define ONENET_COAP_IOT_CORE_SERVER_ADDRESS "64:FF9B::B7E6:6674"
    #define ONENET_URI_PATH_PROPERTY    "$sys/CxD2hb4NHT/tttt/thing/property/post"
    void my_otCoapResponseHandler(void *               aContext,
                                          otMessage *          aMessage,
                                          const otMessageInfo *aMessageInfo,
                                          otError              aResult); 
    static void coap_client_cloud_update_2(void)
    {
        char            payload_buffer[256];
        otError         error;
        otMessage     * p_request;
        otMessageInfo   message_info;
        otInstance    * p_instance = thread_ot_instance_get();
        char aValue;
        otCoapResponseHandler     aHandler;
        char  host[16];
        short port;
        if (m_associated == false)
        {
            return;
        }
        
        error = otIp6AddressFromString(ONENET_COAP_IOT_CORE_SERVER_ADDRESS, &m_cloud_address);
        ASSERT(error == OT_ERROR_NONE);
    
        snprintf(payload_buffer, sizeof(payload_buffer),
            "{\"id\":\"43725\",\"version\":\"1.0\",\"params\":{\"count\":{\"value\":%d},\"someString\":{\"value\":\"this is a string\"}}}",m_counter++);
    
        do
        {
            p_request = otCoapNewMessage(p_instance, NULL);
            if (p_request == NULL)
            {
                NRF_LOG_INFO("Failed to allocate message for CoAP Request\r\n");
                break;
            }
    
            otCoapMessageInit(p_request, OT_COAP_TYPE_CONFIRMABLE, OT_COAP_CODE_POST);
            otCoapMessageSetToken(p_request,m_ccode,8);
    
            error = otCoapMessageAppendUriPathOptions(p_request, ONENET_URI_PATH_PROPERTY);
            ASSERT(error == OT_ERROR_NONE);
    
            error = otCoapMessageAppendContentFormatOption(p_request, OT_COAP_OPTION_CONTENT_FORMAT_JSON);
            ASSERT(error == OT_ERROR_NONE);
    
            aValue=OT_COAP_OPTION_CONTENT_FORMAT_JSON;
            otCoapMessageAppendOption(p_request, OT_COAP_OPTION_ACCEPT, 1, (const void *)&aValue);
    
            error = otCoapMessageSetPayloadMarker(p_request);
            ASSERT(error == OT_ERROR_NONE);
    
            error = otMessageAppend(p_request, payload_buffer, strlen(payload_buffer));
            if (error != OT_ERROR_NONE)
            {
                break;
            }
    
            memset(&message_info, 0, sizeof(message_info));
            message_info.mPeerPort = OT_DEFAULT_COAP_PORT;
            message_info.mPeerAddr = m_cloud_address;
    
            error = otCoapSendRequest(p_instance, p_request, &message_info, my_otCoapResponseHandler, NULL);
    
        } while (false);
    
        if ((error != OT_ERROR_NONE) && (p_request != NULL))
        {
            NRF_LOG_INFO("Failed to send CoAP Request: %d\r\n", error);
            otMessageFree(p_request);
        }
    }
    
    static void coap_client_cloud_update(void)
    {
        char            payload_buffer[256];
        otError         error;
        otMessage     * p_request;
        otMessageInfo   message_info;
        otInstance    * p_instance = thread_ot_instance_get(); 
        otCoapResponseHandler     aHandler;
        printf("hello\n");
        if (m_associated == false)
        {
            return;
        }
        char *pl = OneNetLogInPayload();
        error = otIp6AddressFromString(ONENET_COAP_IOT_CORE_SERVER_ADDRESS, &m_cloud_address);
        ASSERT(error == OT_ERROR_NONE);
    
        // If IPv6 address of the cloud is unspecified try to resolve hostname.
        #if 0
        if (otIp6IsAddressUnspecified(&m_cloud_address))
        {
            error = thread_dns_utils_hostname_resolve(CLOUD_HOSTNAME,
                                                      dns_response_handler,
                                                      NULL);
            ASSERT(error == OT_ERROR_NONE);
            return;
        } 
        #endif
    
        snprintf(payload_buffer, sizeof(payload_buffer),
            "{\"lt\":36000,\"st\":\"version=2018-10-31&res=products/CxD2hb4NHT/devices/tttt&et=1607290563&method=md5&sign=N7wUQoYBamNqlkRwKpyRHQ%%3D%%3D\"}");
    
        do
        {
            p_request = otCoapNewMessage(p_instance, NULL);
            if (p_request == NULL)
            {
                NRF_LOG_INFO("Failed to allocate message for CoAP Request\r\n");
                break;
            }
    
            otCoapMessageInit(p_request, OT_COAP_TYPE_CONFIRMABLE, OT_COAP_CODE_POST);
            //otCoapMessageGenerateToken(p_request, 4);
    
    #define ONENET_URI_PATH    "$sys/CxD2hb4NHT/tttt/log_in"
    
            error = otCoapMessageAppendUriPathOptions(p_request, ONENET_URI_PATH);
            //error = otCoapMessageAppendUriPathOptions(p_request, CLOUD_URI_PATH);
            ASSERT(error == OT_ERROR_NONE);
    
            error = otCoapMessageAppendContentFormatOption(p_request, OT_COAP_OPTION_CONTENT_FORMAT_JSON);
            ASSERT(error == OT_ERROR_NONE);
    
            error = otCoapMessageSetPayloadMarker(p_request);
            ASSERT(error == OT_ERROR_NONE);
    
    
            //error = otMessageAppend(p_request, pl, strlen(pl));
            error = otMessageAppend(p_request, payload_buffer, strlen(payload_buffer));
            if (error != OT_ERROR_NONE)
            {
                break;
            }
    
            memset(&message_info, 0, sizeof(message_info));
            message_info.mPeerPort = OT_DEFAULT_COAP_PORT;
            message_info.mPeerAddr = m_cloud_address;
            printf("11111\n");
            error = otCoapSendRequest(p_instance, p_request, &message_info, my_otCoapResponseHandler, NULL);
    
        } while (false);
    
        if ((error != OT_ERROR_NONE) && (p_request != NULL))
        {
            NRF_LOG_INFO("Failed to send CoAP Request: %d\r\n", error);
            otMessageFree(p_request);
        }
    }
    
    void my_otCoapResponseHandler(void *               aContext,
                                          otMessage *          aMessage,
                                          const otMessageInfo *aMessageInfo,
                                          otError              aResult)
    {
        if (otCoapMessageGetType(aMessage) != OT_COAP_TYPE_CONFIRMABLE &&
            otCoapMessageGetType(aMessage) != OT_COAP_TYPE_NON_CONFIRMABLE)
        {
            printf("tyz=1\n");
        }
    
        if (otCoapMessageGetCode(aMessage) != OT_COAP_CODE_CREATED)
        {
            printf("tyz=2\n");
        }
    
        if (otMessageRead(aMessage, otMessageGetOffset(aMessage), m_ccode, 8) != 1)
        {
            NRF_LOG_INFO("light handler - missing command\r\n");
        }
    }
    
    static void bsp_event_handler(bsp_event_t event)
    {
        switch (event)
        {
            case BSP_EVENT_KEY_0:
                coap_client_cloud_update();
                break;
            case BSP_EVENT_KEY_1:
                coap_client_cloud_update_2();
                break;
            case BSP_EVENT_KEY_3:
                break;
    
            default:
                return; // no implementation needed
        }
    }
    #else
    static void bsp_event_handler(bsp_event_t event)
    {
        switch (event)
        {
            case BSP_EVENT_KEY_0:
                thread_coap_utils_unicast_light_request_send(THREAD_COAP_UTILS_LIGHT_CMD_TOGGLE);
                break;
    
            case BSP_EVENT_KEY_1:
            {
                m_command = ((m_command == THREAD_COAP_UTILS_LIGHT_CMD_OFF) ? THREAD_COAP_UTILS_LIGHT_CMD_ON :
                                                                              THREAD_COAP_UTILS_LIGHT_CMD_OFF);
    
                thread_coap_utils_multicast_light_request_send(m_command,
                                                               THREAD_COAP_UTILS_MULTICAST_REALM_LOCAL);
                break;
            }
    
            case BSP_EVENT_KEY_3:
                thread_coap_utils_provisioning_request_send();
                break;
    
            default:
                return; // no implementation needed
        }
    }
    #endif
    /***************************************************************************************************
     * @section Callbacks
     **************************************************************************************************/
    
    static void thread_state_changed_callback(uint32_t flags, void * p_context)
    {
        if (flags & OT_CHANGED_THREAD_ROLE)
        {
            switch (otThreadGetDeviceRole(p_context))
            {
                case OT_DEVICE_ROLE_CHILD:
                case OT_DEVICE_ROLE_ROUTER:
                case OT_DEVICE_ROLE_LEADER:
                    m_associated = true;
                    break;
    
                case OT_DEVICE_ROLE_DISABLED:
                case OT_DEVICE_ROLE_DETACHED:
                    m_associated = false;
                default:
                    thread_coap_utils_peer_addr_clear();
                    break;
            }
        }
    
        NRF_LOG_INFO("State changed! Flags: 0x%08x Current role: %d\r\n",
                     flags,
                     otThreadGetDeviceRole(p_context));
    }
    
    /***************************************************************************************************
     * @section Initialization
     **************************************************************************************************/
    
    /**@brief Function for initializing the Thread Board Support Package
     */
    static void thread_bsp_init(void)
    {
        uint32_t error_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_event_handler);
        APP_ERROR_CHECK(error_code);
    
        error_code = bsp_thread_init(thread_ot_instance_get());
        APP_ERROR_CHECK(error_code);
    }
    
    
    /**@brief Function for initializing the Application Timer Module
     */
    static void timer_init(void)
    {
        uint32_t error_code = app_timer_init();
        APP_ERROR_CHECK(error_code);
    }
    
    
    /**@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 initializing the Thread Stack
     */
    static void thread_instance_init(void)
    {
        thread_configuration_t thread_configuration =
        {
            .radio_mode        = THREAD_RADIO_MODE_RX_ON_WHEN_IDLE,
            .autocommissioning = true,
        };
    
        thread_init(&thread_configuration);
        thread_cli_init();
        thread_state_changed_callback_set(thread_state_changed_callback);
    }
    
    
    /**@brief Function for initializing the Constrained Application Protocol Module
     */
    
    static void thread_coap_init(void)
    {
        thread_coap_utils_configuration_t thread_coap_configuration =
        {
            .coap_server_enabled               = true,
            .coap_client_enabled               = true,
            .configurable_led_blinking_enabled = false,
        };
    
        thread_coap_utils_init(&thread_coap_configuration);
    }
    
    
    /**@brief Function for initializing scheduler module.
     */
    static void scheduler_init(void)
    {
        APP_SCHED_INIT(SCHED_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
    }
    
    
    /***************************************************************************************************
     * @section Main
     **************************************************************************************************/
    
    int main(int argc, char * argv[])
    {
        log_init();
        scheduler_init();
        timer_init();
    
        thread_instance_init();
        thread_coap_init();
        thread_bsp_init();
        while (true)
        {
            thread_process();
            app_sched_execute();
    
            if (NRF_LOG_PROCESS() == false)
            {
                thread_sleep();
            }
        }
    }
    
    /**
     *@}
     **/
    
    /**
     * Copyright (c) 2017-2019 - 2020, 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.
     *
     */
    
    #include "thread_coap_utils.h"
    
    #include "app_timer.h"
    #include "bsp_thread.h"
    #include "nrf_assert.h"
    #include "nrf_log.h"
    #include "sdk_config.h"
    #include "thread_utils.h"
    
    #include <openthread/ip6.h>
    #include <openthread/link.h>
    #include <openthread/thread.h>
    #include <openthread/platform/alarm-milli.h>
    
    #define RESPONSE_POLL_PERIOD     100
    #define PROVISIONING_EXPIRY_TIME 5000
    #define LED_INTERVAL             100
    
    APP_TIMER_DEF(m_provisioning_timer);
    APP_TIMER_DEF(m_led_timer);
    
    /**@brief Structure holding CoAP status information. */
    typedef struct
    {
        bool         provisioning_enabled; /**< Information if provisioning is enabled. */
        uint32_t     provisioning_expiry;  /**< Provisioning timeout time. */
        bool         led_blinking_is_on;   /**< Information if leds are blinking */
        otIp6Address peer_address;         /**< An address of a related server node. */
    } state_t;
    
    static uint32_t                                  m_poll_period;
    static state_t                                   m_state;
    static thread_coap_utils_configuration_t         m_config;
    static thread_coap_utils_light_command_handler_t m_light_command_handler;
    
    /**@brief Forward declarations of CoAP resources handlers. */
    static void provisioning_request_handler(void *, otMessage *, const otMessageInfo *);
    static void light_request_handler(void *, otMessage *, const otMessageInfo *);
    static void property_set_request_handler(void *, otMessage *, const otMessageInfo *);
    
    
    static otCoapResource m_property_set_request_resource =
    {
        .mUriPath = "/$sys/CxD2hb4NHT/tttt/thing/property/set",
        .mHandler = property_set_request_handler,
        .mContext = NULL,
        .mNext    = NULL
    };
    
    /**@brief Definition of CoAP resources for provisioning. */
    static otCoapResource m_provisioning_resource =
    {
        .mUriPath = "provisioning",
        .mHandler = provisioning_request_handler,
        .mContext = NULL,
        .mNext    = NULL
    };
    
    /**@brief Definition of CoAP resources for light. */
    static otCoapResource m_light_resource =
    {
        .mUriPath = "light",
        .mHandler = light_request_handler,
        .mContext = NULL,
        .mNext    = NULL
    };
    
    static void coap_default_handler(void                * p_context,
                                     otMessage           * p_message,
                                     const otMessageInfo * p_message_info)
    {
        printf("coap_default_handler\n");
        UNUSED_PARAMETER(p_context);
        UNUSED_PARAMETER(p_message);
        UNUSED_PARAMETER(p_message_info);
    
        
    
        NRF_LOG_INFO("Received CoAP message that does not match any request or resource\r\n");
    }
    
    static uint32_t poll_period_response_set(void)
    {
        uint32_t     error;
        otError      ot_error;
        otInstance * p_instance = thread_ot_instance_get();
    
        do
        {
            if (otThreadGetLinkMode(p_instance).mRxOnWhenIdle)
            {
                error = NRF_ERROR_INVALID_STATE;
                break;
            }
    
            if (!m_poll_period)
            {
                m_poll_period = otLinkGetPollPeriod(p_instance);
    
                NRF_LOG_INFO("Poll Period: %dms set\r\n", RESPONSE_POLL_PERIOD);
    
                ot_error = otLinkSetPollPeriod(p_instance, RESPONSE_POLL_PERIOD);
                ASSERT(ot_error == OT_ERROR_NONE);
    
                error =  NRF_SUCCESS;
            }
            else
            {
                error = NRF_ERROR_BUSY;
            }
        } while (false);
    
        return error;
    }
    
    static void poll_period_restore(void)
    {
        otError      error;
        otInstance * p_instance = thread_ot_instance_get();
    
        do
        {
            if (otThreadGetLinkMode(p_instance).mRxOnWhenIdle)
            {
                break;
            }
    
            if (m_poll_period)
            {
                error = otLinkSetPollPeriod(p_instance, m_poll_period);
                ASSERT(error == OT_ERROR_NONE);
    
                NRF_LOG_INFO("Poll Period: %dms restored\r\n", m_poll_period);
                m_poll_period = 0;
            }
        } while (false);
    }
    
    static void light_changed_default(thread_coap_utils_light_command_t light_command)
    {
        switch (light_command)
        {
            case THREAD_COAP_UTILS_LIGHT_CMD_ON:
                LEDS_ON(BSP_LED_3_MASK);
                break;
    
            case THREAD_COAP_UTILS_LIGHT_CMD_OFF:
                LEDS_OFF(BSP_LED_3_MASK);
                break;
    
            case THREAD_COAP_UTILS_LIGHT_CMD_TOGGLE:
                LEDS_INVERT(BSP_LED_3_MASK);
                break;
    
            default:
                break;
        }
    }
    
    static bool provisioning_is_enabled(void)
    {
        return m_state.provisioning_enabled;
    }
    
    static void provisioning_enable(bool enable)
    {
        uint32_t error;
    
        m_state.provisioning_enabled = enable;
    
        if (enable)
        {
            m_state.provisioning_expiry = otPlatAlarmMilliGetNow() + PROVISIONING_EXPIRY_TIME;
            error = app_timer_start(m_provisioning_timer,
                                    APP_TIMER_TICKS(PROVISIONING_EXPIRY_TIME),
                                    NULL);
            ASSERT(error == NRF_SUCCESS);
    
            error = app_timer_start(m_led_timer, APP_TIMER_TICKS(LED_INTERVAL), NULL);
            ASSERT(error == NRF_SUCCESS);
    
            if (m_config.configurable_led_blinking_enabled)
            {
                m_light_command_handler(THREAD_COAP_UTILS_LIGHT_CMD_ON);
            }
        }
        else
        {
            m_state.provisioning_expiry = 0;
    
            error = app_timer_stop(m_provisioning_timer);
            ASSERT(error == NRF_SUCCESS);
    
            error = app_timer_stop(m_led_timer);
            ASSERT(error == NRF_SUCCESS);
    
            LEDS_OFF(BSP_LED_2_MASK);
    
            if (m_config.configurable_led_blinking_enabled)
            {
                error = app_timer_stop(m_led_timer);
                ASSERT(error == NRF_SUCCESS);
    
                if (m_state.led_blinking_is_on)
                {
                    m_light_command_handler(THREAD_COAP_UTILS_LIGHT_CMD_ON);
                }
                else
                {
                    m_light_command_handler(THREAD_COAP_UTILS_LIGHT_CMD_OFF);
                }
            }
        }
    }
    
    static void provisioning_timer_handler(void * p_context)
    {
        provisioning_enable(false);
    }
    
    static otError provisioning_response_send(otMessage           * p_request_message,
                                              const otMessageInfo * p_message_info)
    {
        otError        error = OT_ERROR_NO_BUFS;
        otMessage    * p_response;
        otInstance   * p_instance = thread_ot_instance_get();
    
        do
        {
            p_response = otCoapNewMessage(p_instance, NULL);
            if (p_response == NULL)
            {
                break;
            }
    
            otCoapMessageInit(p_response, OT_COAP_TYPE_NON_CONFIRMABLE, OT_COAP_CODE_CONTENT);
    
            error = otCoapMessageSetToken(p_response,
                                          otCoapMessageGetToken(p_request_message),
                                          otCoapMessageGetTokenLength(p_request_message));
            if (error != OT_ERROR_NONE)
            {
                break;
            }
    
            error = otCoapMessageSetPayloadMarker(p_response);
            if (error != OT_ERROR_NONE)
            {
                break;
            }
    
            error = otMessageAppend(
                p_response, otThreadGetMeshLocalEid(p_instance), sizeof(otIp6Address));
            if (error != OT_ERROR_NONE)
            {
                break;
            }
    
            error = otCoapSendResponse(p_instance, p_response, p_message_info);
    
        } while (false);
    
        if (error != OT_ERROR_NONE && p_response != NULL)
        {
            otMessageFree(p_response);
        }
    
        return error;
    }
    
    static void provisioning_request_handler(void                * p_context,
                                             otMessage           * p_message,
                                             const otMessageInfo * p_message_info)
    {
        UNUSED_PARAMETER(p_message);
    
        otError       error;
        otMessageInfo message_info;
    
        if (!provisioning_is_enabled())
        {
            return;
        }
    
        if ((otCoapMessageGetType(p_message) == OT_COAP_TYPE_NON_CONFIRMABLE) &&
            (otCoapMessageGetCode(p_message) == OT_COAP_CODE_GET))
        {
            message_info = *p_message_info;
            memset(&message_info.mSockAddr, 0, sizeof(message_info.mSockAddr));
    
            error = provisioning_response_send(p_message, &message_info);
            if (error == OT_ERROR_NONE)
            {
                provisioning_enable(false);
            }
        }
    }
    
    static void property_set_request_handler(void                * p_context,
                                             otMessage           * p_message,
                                             const otMessageInfo * p_message_info)
    {
        printf("provisioning_request_handler\n");
        UNUSED_PARAMETER(p_message);
    
        otError       error;
        otMessageInfo message_info;
        
    
    #if 0
        if ((otCoapMessageGetType(p_message) == OT_COAP_TYPE_NON_CONFIRMABLE) &&
            (otCoapMessageGetCode(p_message) == OT_COAP_CODE_GET))
        {
            message_info = *p_message_info;
            memset(&message_info.mSockAddr, 0, sizeof(message_info.mSockAddr));
    
            error = provisioning_response_send(p_message, &message_info);
            if (error == OT_ERROR_NONE)
            {
                provisioning_enable(false);
            }
        }
    #endif
    }
    
    static void led_timer_handler(void * p_context)
    {
        // This handler may be called after app_timer_stop due to app_shceduler.
        if (m_state.provisioning_enabled)
        {
            LEDS_INVERT(BSP_LED_2_MASK);
        }
    }
    
    static void light_response_send(otMessage           * p_request_message,
                                    const otMessageInfo * p_message_info)
    {
        otError      error = OT_ERROR_NO_BUFS;
        otMessage  * p_response;
        otInstance * p_instance = thread_ot_instance_get();
    
        do
        {
            p_response = otCoapNewMessage(p_instance, NULL);
            if (p_response == NULL)
            {
                break;
            }
    
            error = otCoapMessageInitResponse(p_response,
                                              p_request_message,
                                              OT_COAP_TYPE_ACKNOWLEDGMENT,
                                              OT_COAP_CODE_CHANGED);
    
            if (error != OT_ERROR_NONE)
            {
                break;
            }
    
            error = otCoapSendResponse(p_instance, p_response, p_message_info);
    
        } while (false);
    
        if ((error != OT_ERROR_NONE) && (p_response != NULL))
        {
            otMessageFree(p_response);
        }
    }
    
    static void light_request_handler(void                * p_context,
                                      otMessage           * p_message,
                                      const otMessageInfo * p_message_info)
    {
        uint8_t command;
    
        do
        {
            if (otCoapMessageGetType(p_message) != OT_COAP_TYPE_CONFIRMABLE &&
                otCoapMessageGetType(p_message) != OT_COAP_TYPE_NON_CONFIRMABLE)
            {
                break;
            }
    
            if (otCoapMessageGetCode(p_message) != OT_COAP_CODE_PUT)
            {
                break;
            }
    
            if (otMessageRead(p_message, otMessageGetOffset(p_message), &command, 1) != 1)
            {
                NRF_LOG_INFO("light handler - missing command\r\n");
            }
    
            m_light_command_handler((thread_coap_utils_light_command_t)command);
    
            switch (command)
            {
                case THREAD_COAP_UTILS_LIGHT_CMD_ON:
                    if (m_config.configurable_led_blinking_enabled)
                    {
                        m_state.led_blinking_is_on = true;
                    }
                    break;
    
                case THREAD_COAP_UTILS_LIGHT_CMD_OFF:
                    if (m_config.configurable_led_blinking_enabled)
                    {
                        m_state.led_blinking_is_on = false;
                    }
                    break;
    
                case THREAD_COAP_UTILS_LIGHT_CMD_TOGGLE:
                    if (m_config.configurable_led_blinking_enabled)
                    {
                        m_state.led_blinking_is_on = !m_state.led_blinking_is_on;
                    }
                    break;
    
                default:
                    break;
            }
    
            if (otCoapMessageGetType(p_message) == OT_COAP_TYPE_CONFIRMABLE)
            {
                light_response_send(p_message, p_message_info);
            }
    
        } while (false);
    }
    
    void thread_coap_utils_init(const thread_coap_utils_configuration_t * p_config)
    {
        otInstance * p_instance = thread_ot_instance_get();
    
        otError error = otCoapStart(p_instance, OT_DEFAULT_COAP_PORT);
        ASSERT(error == OT_ERROR_NONE);
        printf("setDefaultHandler\n");
        otCoapSetDefaultHandler(p_instance, coap_default_handler, NULL);
    
        m_config = *p_config;
    
        m_light_command_handler = light_changed_default;
    
        if (m_config.coap_server_enabled)
        {
            LEDS_CONFIGURE(LEDS_MASK);
            LEDS_OFF(LEDS_MASK);
    
            uint32_t retval = app_timer_create(&m_led_timer,
                                               APP_TIMER_MODE_REPEATED,
                                               led_timer_handler);
            ASSERT(retval == NRF_SUCCESS);
    
            retval = app_timer_create(&m_provisioning_timer,
                                      APP_TIMER_MODE_SINGLE_SHOT,
                                      provisioning_timer_handler);
            ASSERT(retval == NRF_SUCCESS);
    
            m_light_resource.mContext        = p_instance;
            m_provisioning_resource.mContext = p_instance;
            m_property_set_request_resource.mContext  = p_instance;
    		
            error = otCoapAddResource(p_instance, &m_light_resource);
            ASSERT(error == OT_ERROR_NONE);
    
            error = otCoapAddResource(p_instance, &m_provisioning_resource);
            ASSERT(error == OT_ERROR_NONE);
    		
            error = otCoapAddResource(p_instance, &m_property_set_request_resource);
            ASSERT(error == OT_ERROR_NONE);
        }
    }
    
    void thread_coap_utils_deinit(void)
    {
        otInstance * p_instance = thread_ot_instance_get();
    
        otError error = otCoapStop(p_instance);
        ASSERT(error == OT_ERROR_NONE);
    
        otCoapSetDefaultHandler(p_instance, NULL, NULL);
    
        if (m_config.coap_server_enabled)
        {
            m_light_resource.mContext        = NULL;
            m_provisioning_resource.mContext = NULL;
    
            otCoapRemoveResource(p_instance, &m_light_resource);
            otCoapRemoveResource(p_instance, &m_provisioning_resource);
        }
    }
    
    void thread_coap_utils_peer_addr_clear(void)
    {
        memset(&m_state.peer_address, 0, sizeof(m_state.peer_address));
    }
    
    void thread_coap_utils_unicast_light_request_send(uint8_t command)
    {
        otError       error = OT_ERROR_NONE;
        otMessage   * p_request;
        otMessageInfo message_info;
        otInstance  * p_instance = thread_ot_instance_get();
    
        do
        {
            if (otIp6IsAddressUnspecified(&m_state.peer_address))
            {
                NRF_LOG_INFO("Failed to send the CoAP Request to the unspecified IPv6 address\r\n");
                break;
            }
    
            p_request = otCoapNewMessage(p_instance, NULL);
            if (p_request == NULL)
            {
                NRF_LOG_INFO("Failed to allocate message for CoAP Request\r\n");
                break;
            }
    
            otCoapMessageInit(p_request, OT_COAP_TYPE_NON_CONFIRMABLE, OT_COAP_CODE_PUT);
            otCoapMessageGenerateToken(p_request, 2);
    
            error = otCoapMessageAppendUriPathOptions(p_request, "light");
            ASSERT(error == OT_ERROR_NONE);
    
            error = otCoapMessageSetPayloadMarker(p_request);
            ASSERT(error == OT_ERROR_NONE);
    
            otCoapMessageInit(p_request, OT_COAP_TYPE_NON_CONFIRMABLE, OT_COAP_CODE_PUT);
            otCoapMessageGenerateToken(p_request, 2);
            UNUSED_VARIABLE(otCoapMessageAppendUriPathOptions(p_request, "light"));
            UNUSED_VARIABLE(otCoapMessageSetPayloadMarker(p_request));
    
            error = otMessageAppend(p_request, &command, sizeof(command));
            if (error != OT_ERROR_NONE)
            {
                break;
            }
    
            memset(&message_info, 0, sizeof(message_info));
            message_info.mPeerPort = OT_DEFAULT_COAP_PORT;
            memcpy(&message_info.mPeerAddr, &m_state.peer_address, sizeof(message_info.mPeerAddr));
    
            error = otCoapSendRequest(p_instance,
                                      p_request,
                                      &message_info,
                                      NULL,
                                      p_instance);
        } while (false);
    
        if (error != OT_ERROR_NONE && p_request != NULL)
        {
            NRF_LOG_INFO("Failed to send CoAP Request: %d\r\n", error);
            otMessageFree(p_request);
        }
    }
    
    void thread_coap_utils_multicast_light_request_send(uint8_t                             command,
                                                        thread_coap_utils_multicast_scope_t scope)
    {
        otError       error = OT_ERROR_NONE;
        otMessage   * p_request;
        otMessageInfo message_info;
        const char  * p_scope = NULL;
        otInstance  * p_instance = thread_ot_instance_get();
    
        do
        {
            p_request = otCoapNewMessage(p_instance, NULL);
            if (p_request == NULL)
            {
                NRF_LOG_INFO("Failed to allocate message for CoAP Request\r\n");
                break;
            }
    
            otCoapMessageInit(p_request, OT_COAP_TYPE_NON_CONFIRMABLE, OT_COAP_CODE_PUT);
    
            error = otCoapMessageAppendUriPathOptions(p_request, "light");
            ASSERT(error == OT_ERROR_NONE);
    
            error = otCoapMessageSetPayloadMarker(p_request);
            ASSERT(error == OT_ERROR_NONE);
    
            error = otMessageAppend(p_request, &command, sizeof(command));
            if (error != OT_ERROR_NONE)
            {
                break;
            }
    
            switch (scope)
            {
            case THREAD_COAP_UTILS_MULTICAST_LINK_LOCAL:
                p_scope = "ff02::1";
                break;
    
            case THREAD_COAP_UTILS_MULTICAST_REALM_LOCAL:
                p_scope = "ff03::1";
                break;
    
            default:
                ASSERT(false);
            }
    
            memset(&message_info, 0, sizeof(message_info));
            message_info.mPeerPort = OT_DEFAULT_COAP_PORT;
    
            error = otIp6AddressFromString(p_scope, &message_info.mPeerAddr);
            ASSERT(error == OT_ERROR_NONE);
    
            error = otCoapSendRequest(p_instance, p_request, &message_info, NULL, NULL);
        } while (false);
    
        if (error != OT_ERROR_NONE && p_request != NULL)
        {
            NRF_LOG_INFO("Failed to send CoAP Request: %d\r\n", error);
            otMessageFree(p_request);
        }
    }
    
    static void provisioning_response_handler(void                * p_context,
                                              otMessage           * p_message,
                                              const otMessageInfo * p_message_info,
                                              otError               result)
    {
        UNUSED_PARAMETER(p_context);
    
        // Restore the polling period back to initial slow value.
        poll_period_restore();
    
        if (result == OT_ERROR_NONE)
        {
            UNUSED_RETURN_VALUE(otMessageRead(p_message,
                                              otMessageGetOffset(p_message),
                                              &m_state.peer_address,
                                              sizeof(m_state.peer_address)));
        }
        else
        {
            NRF_LOG_INFO("Provisioning failed: %d\r\n", result);
        }
    }
    
    void thread_coap_utils_provisioning_request_send(void)
    {
        otError       error = OT_ERROR_NO_BUFS;
        otMessage   * p_request;
        otMessageInfo message_info;
        otInstance  * p_instance = thread_ot_instance_get();
    
        do
        {
            p_request = otCoapNewMessage(p_instance, NULL);
            if (p_request == NULL)
            {
                break;
            }
    
            otCoapMessageInit(p_request, OT_COAP_TYPE_NON_CONFIRMABLE, OT_COAP_CODE_GET);
            otCoapMessageGenerateToken(p_request, 2);
    
            error = otCoapMessageAppendUriPathOptions(p_request, "provisioning");
            ASSERT(error == OT_ERROR_NONE);
    
            // decrease the polling period for higher responsiveness
            uint32_t err_code = poll_period_response_set();
            if (err_code == NRF_ERROR_BUSY)
            {
                break;
            }
    
            memset(&message_info, 0, sizeof(message_info));
            message_info.mPeerPort = OT_DEFAULT_COAP_PORT;
    
            error = otIp6AddressFromString("ff03::1", &message_info.mPeerAddr);
            ASSERT(error == OT_ERROR_NONE);
    
            error = otCoapSendRequest(
                p_instance, p_request, &message_info, provisioning_response_handler, p_instance);
    
        } while (false);
    
        if (error != OT_ERROR_NONE && p_request != NULL)
        {
            otMessageFree(p_request);
        }
    
    }
    
    void thread_coap_utils_provisioning_enable_set(bool value)
    {
        provisioning_enable(value);
    }
    
    void thread_coap_utils_light_command_handler_set(thread_coap_utils_light_command_handler_t handler)
    {
        ASSERT(handler != NULL);
    
        m_light_command_handler = handler;
    }
    
    bool thread_coap_utils_light_is_led_blinking(void)
    {
        return m_state.led_blinking_is_on;
    }
    

Reply
  • The sniffer trace does confirm that the CoAP PUT request is being sent over the air and received by the intended recipient. So,NAT64 can be deliver packets going from global IPv4 internet to the IPv6 based Thread network.The problem should be with my source code caused the error.

    /**
     * Copyright (c) 2017 - 2020, 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 simple_coap_client_example_main main.c
     * @{
     * @ingroup simple_coap_client_example_example
     * @brief Simple CoAP Client Example Application main file.
     *
     * @details This example demonstrates a CoAP client application that enables to control BSP_LED_0
     *          on a board with related Simple CoAP Server application via CoAP messages.
     *
     */
    #include "mbedtls/base64.h"
    #include "mbedtls/md.h"
    #include "app_scheduler.h"
    #include "app_timer.h"
    #include "bsp_thread.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log.h"
    #include "nrf_log_default_backends.h"
    
    #include "thread_coap_utils.h"
    #include "thread_utils.h"
    
    #include <openthread/instance.h>
    #include <openthread/thread.h>
    
    #define SCHED_QUEUE_SIZE      32                                                      /**< Maximum number of events in the scheduler queue. */
    #define SCHED_EVENT_DATA_SIZE APP_TIMER_SCHED_EVENT_DATA_SIZE                         /**< Maximum app_scheduler event size. */
    
    static thread_coap_utils_light_command_t m_command = THREAD_COAP_UTILS_LIGHT_CMD_OFF; /**< This variable stores command that has been most recently used. */
    
    char *OneNetmethod  = "sha1";
    char *OneNetres     = "products/CxD2hb4NHT/devices/tttt";
    char *OneNetversion  = "2018-10-31";
    char *OneNetkey     = "WWtxWyeJ+wPB/08/6f3THe8rNSe5i1ubPyex+Qu7N08=";
    char *OneNetEndpoint = "183.230.102.116:5683";
    char *OneNetPathLogin    = "$sys/CxD2hb4NHT/tttt/log_in";
    char *OneNetPathLogout    = "$sys/CxD2hb4NHT/tttt/log_out";
    char *OneNetPathKeepAlive = "$sys/CxD2hb4NHT/tttt/keep_alive";
    char *OneNetPathPropertyPost   = "$sys/CxD2hb4NHT/tttt/thing/property/post";
    char *OneNetPathPropertyGet    = "$sys/CxD2hb4NHT/tttt/thing/property/get";
    char *OneNetPathPropertyDelete = "$sys/CxD2hb4NHT/tttt/thing/property/delete";
    char *OneNetPathPropertySet    = "$sys/CxD2hb4NHT/tttt/thing/property/set";
    /***************************************************************************************************
     * @section TheThings.io
     **************************************************************************************************/
    
    static unsigned char hexchars[] = "0123456789ABCDEF";
    char *url_encode(char const *s, int len, int *new_length)
    {
        register unsigned char c;
        unsigned char *to, *start;
        unsigned char const *from, *end;
        
        from = (unsigned char *)s;
        end  = (unsigned char *)s + len;
        start = to = (unsigned char *) nrf_malloc(1, 3*len+1);
    
        while (from < end) 
        {
            c = *from++;
    
            if (c == ' ') 
            {
                *to++ = '+';
            } 
            else if ((c < '0' && c != '-' && c != '.') ||
                     (c < 'A' && c > '9') ||
                     (c > 'Z' && c < 'a' && c != '_') ||
                     (c > 'z')) 
            {
                to[0] = '%';
                to[1] = hexchars[c >> 4];//��2����ת����16���Ʊ�ʾ
                to[2] = hexchars[c & 15];//��2����ת����16���Ʊ�ʾ
                to += 3;
            }
            else 
            {
                *to++ = c;
            }
        }
        *to = 0;
        if (new_length) 
        {
            *new_length = to - start;
        }
        return (char *) start;
    }
    
    char* OneNetLogInPayload()
    {
        char *OneNetet = "1600913071";
        uint8_t hash[20]={0};
    
        uint8_t content[100]={0};
        sprintf(content, "%s\n%s\n%s\n%s", OneNetet, OneNetmethod, OneNetres, OneNetversion);
    
        uint8_t key[100] = {0};
        size_t olen = strlen(OneNetkey);
        mbedtls_base64_decode(key, olen, &olen, (const unsigned char *)OneNetkey, olen);
    
        mbedtls_md_context_t ctx;
        const mbedtls_md_info_t *info;
        mbedtls_md_init(&ctx);
        info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
        mbedtls_md_setup(&ctx, info, 1);
        mbedtls_md_hmac_starts(&ctx, key, strlen( (const char *)key));
        mbedtls_md_hmac_update(&ctx, content, strlen( (const char *)content));
        mbedtls_md_hmac_finish(&ctx, hash);
        mbedtls_md_free(&ctx);
    
        uint8_t old_sign[100];
        size_t len = sizeof(hash);
        mbedtls_base64_encode(old_sign, sizeof(old_sign), &len, hash, len);
    //    printf("Old Sign:%s\n",old_sign);
    //    printf("Old Res:%s\n",OneNetres);
    
    
        char *new_sign = url_encode(old_sign,strlen(old_sign),NULL);
        char *new_res = url_encode(OneNetres,strlen(OneNetres),NULL);
    
    //    printf("New Sign:%s\n",new_sign);
    //    printf("New Res:%s\n",new_res);
        char token[300]={0};
        sprintf(token,"version=%s&res=%s&et=%s&method=%s&sign=%s",
                OneNetversion, new_res, OneNetet, OneNetmethod, new_sign);
    //    printf("Token:%s\n",token);
    
        char *payload = nrf_malloc(300);
        sprintf(payload,"{\"lt\":86400,\"st\":\"%s\"}",token);
    
        return payload;
    }
    
    #define TYZ
    #ifdef TYZ
    static uint16_t     m_counter       = 0;
    static int32_t      m_temperature   = 0;
    static otIp6Address m_cloud_address = {0};
    static bool         m_associated    = false;
    unsigned char m_ccode[8];
    #endif
    /***************************************************************************************************
     * @section Buttons
     **************************************************************************************************/
    
    
    
    #ifdef TYZ
    #define ONENET_COAP_IOT_CORE_SERVER_ADDRESS "64:FF9B::B7E6:6674"
    #define ONENET_URI_PATH_PROPERTY    "$sys/CxD2hb4NHT/tttt/thing/property/post"
    void my_otCoapResponseHandler(void *               aContext,
                                          otMessage *          aMessage,
                                          const otMessageInfo *aMessageInfo,
                                          otError              aResult); 
    static void coap_client_cloud_update_2(void)
    {
        char            payload_buffer[256];
        otError         error;
        otMessage     * p_request;
        otMessageInfo   message_info;
        otInstance    * p_instance = thread_ot_instance_get();
        char aValue;
        otCoapResponseHandler     aHandler;
        char  host[16];
        short port;
        if (m_associated == false)
        {
            return;
        }
        
        error = otIp6AddressFromString(ONENET_COAP_IOT_CORE_SERVER_ADDRESS, &m_cloud_address);
        ASSERT(error == OT_ERROR_NONE);
    
        snprintf(payload_buffer, sizeof(payload_buffer),
            "{\"id\":\"43725\",\"version\":\"1.0\",\"params\":{\"count\":{\"value\":%d},\"someString\":{\"value\":\"this is a string\"}}}",m_counter++);
    
        do
        {
            p_request = otCoapNewMessage(p_instance, NULL);
            if (p_request == NULL)
            {
                NRF_LOG_INFO("Failed to allocate message for CoAP Request\r\n");
                break;
            }
    
            otCoapMessageInit(p_request, OT_COAP_TYPE_CONFIRMABLE, OT_COAP_CODE_POST);
            otCoapMessageSetToken(p_request,m_ccode,8);
    
            error = otCoapMessageAppendUriPathOptions(p_request, ONENET_URI_PATH_PROPERTY);
            ASSERT(error == OT_ERROR_NONE);
    
            error = otCoapMessageAppendContentFormatOption(p_request, OT_COAP_OPTION_CONTENT_FORMAT_JSON);
            ASSERT(error == OT_ERROR_NONE);
    
            aValue=OT_COAP_OPTION_CONTENT_FORMAT_JSON;
            otCoapMessageAppendOption(p_request, OT_COAP_OPTION_ACCEPT, 1, (const void *)&aValue);
    
            error = otCoapMessageSetPayloadMarker(p_request);
            ASSERT(error == OT_ERROR_NONE);
    
            error = otMessageAppend(p_request, payload_buffer, strlen(payload_buffer));
            if (error != OT_ERROR_NONE)
            {
                break;
            }
    
            memset(&message_info, 0, sizeof(message_info));
            message_info.mPeerPort = OT_DEFAULT_COAP_PORT;
            message_info.mPeerAddr = m_cloud_address;
    
            error = otCoapSendRequest(p_instance, p_request, &message_info, my_otCoapResponseHandler, NULL);
    
        } while (false);
    
        if ((error != OT_ERROR_NONE) && (p_request != NULL))
        {
            NRF_LOG_INFO("Failed to send CoAP Request: %d\r\n", error);
            otMessageFree(p_request);
        }
    }
    
    static void coap_client_cloud_update(void)
    {
        char            payload_buffer[256];
        otError         error;
        otMessage     * p_request;
        otMessageInfo   message_info;
        otInstance    * p_instance = thread_ot_instance_get(); 
        otCoapResponseHandler     aHandler;
        printf("hello\n");
        if (m_associated == false)
        {
            return;
        }
        char *pl = OneNetLogInPayload();
        error = otIp6AddressFromString(ONENET_COAP_IOT_CORE_SERVER_ADDRESS, &m_cloud_address);
        ASSERT(error == OT_ERROR_NONE);
    
        // If IPv6 address of the cloud is unspecified try to resolve hostname.
        #if 0
        if (otIp6IsAddressUnspecified(&m_cloud_address))
        {
            error = thread_dns_utils_hostname_resolve(CLOUD_HOSTNAME,
                                                      dns_response_handler,
                                                      NULL);
            ASSERT(error == OT_ERROR_NONE);
            return;
        } 
        #endif
    
        snprintf(payload_buffer, sizeof(payload_buffer),
            "{\"lt\":36000,\"st\":\"version=2018-10-31&res=products/CxD2hb4NHT/devices/tttt&et=1607290563&method=md5&sign=N7wUQoYBamNqlkRwKpyRHQ%%3D%%3D\"}");
    
        do
        {
            p_request = otCoapNewMessage(p_instance, NULL);
            if (p_request == NULL)
            {
                NRF_LOG_INFO("Failed to allocate message for CoAP Request\r\n");
                break;
            }
    
            otCoapMessageInit(p_request, OT_COAP_TYPE_CONFIRMABLE, OT_COAP_CODE_POST);
            //otCoapMessageGenerateToken(p_request, 4);
    
    #define ONENET_URI_PATH    "$sys/CxD2hb4NHT/tttt/log_in"
    
            error = otCoapMessageAppendUriPathOptions(p_request, ONENET_URI_PATH);
            //error = otCoapMessageAppendUriPathOptions(p_request, CLOUD_URI_PATH);
            ASSERT(error == OT_ERROR_NONE);
    
            error = otCoapMessageAppendContentFormatOption(p_request, OT_COAP_OPTION_CONTENT_FORMAT_JSON);
            ASSERT(error == OT_ERROR_NONE);
    
            error = otCoapMessageSetPayloadMarker(p_request);
            ASSERT(error == OT_ERROR_NONE);
    
    
            //error = otMessageAppend(p_request, pl, strlen(pl));
            error = otMessageAppend(p_request, payload_buffer, strlen(payload_buffer));
            if (error != OT_ERROR_NONE)
            {
                break;
            }
    
            memset(&message_info, 0, sizeof(message_info));
            message_info.mPeerPort = OT_DEFAULT_COAP_PORT;
            message_info.mPeerAddr = m_cloud_address;
            printf("11111\n");
            error = otCoapSendRequest(p_instance, p_request, &message_info, my_otCoapResponseHandler, NULL);
    
        } while (false);
    
        if ((error != OT_ERROR_NONE) && (p_request != NULL))
        {
            NRF_LOG_INFO("Failed to send CoAP Request: %d\r\n", error);
            otMessageFree(p_request);
        }
    }
    
    void my_otCoapResponseHandler(void *               aContext,
                                          otMessage *          aMessage,
                                          const otMessageInfo *aMessageInfo,
                                          otError              aResult)
    {
        if (otCoapMessageGetType(aMessage) != OT_COAP_TYPE_CONFIRMABLE &&
            otCoapMessageGetType(aMessage) != OT_COAP_TYPE_NON_CONFIRMABLE)
        {
            printf("tyz=1\n");
        }
    
        if (otCoapMessageGetCode(aMessage) != OT_COAP_CODE_CREATED)
        {
            printf("tyz=2\n");
        }
    
        if (otMessageRead(aMessage, otMessageGetOffset(aMessage), m_ccode, 8) != 1)
        {
            NRF_LOG_INFO("light handler - missing command\r\n");
        }
    }
    
    static void bsp_event_handler(bsp_event_t event)
    {
        switch (event)
        {
            case BSP_EVENT_KEY_0:
                coap_client_cloud_update();
                break;
            case BSP_EVENT_KEY_1:
                coap_client_cloud_update_2();
                break;
            case BSP_EVENT_KEY_3:
                break;
    
            default:
                return; // no implementation needed
        }
    }
    #else
    static void bsp_event_handler(bsp_event_t event)
    {
        switch (event)
        {
            case BSP_EVENT_KEY_0:
                thread_coap_utils_unicast_light_request_send(THREAD_COAP_UTILS_LIGHT_CMD_TOGGLE);
                break;
    
            case BSP_EVENT_KEY_1:
            {
                m_command = ((m_command == THREAD_COAP_UTILS_LIGHT_CMD_OFF) ? THREAD_COAP_UTILS_LIGHT_CMD_ON :
                                                                              THREAD_COAP_UTILS_LIGHT_CMD_OFF);
    
                thread_coap_utils_multicast_light_request_send(m_command,
                                                               THREAD_COAP_UTILS_MULTICAST_REALM_LOCAL);
                break;
            }
    
            case BSP_EVENT_KEY_3:
                thread_coap_utils_provisioning_request_send();
                break;
    
            default:
                return; // no implementation needed
        }
    }
    #endif
    /***************************************************************************************************
     * @section Callbacks
     **************************************************************************************************/
    
    static void thread_state_changed_callback(uint32_t flags, void * p_context)
    {
        if (flags & OT_CHANGED_THREAD_ROLE)
        {
            switch (otThreadGetDeviceRole(p_context))
            {
                case OT_DEVICE_ROLE_CHILD:
                case OT_DEVICE_ROLE_ROUTER:
                case OT_DEVICE_ROLE_LEADER:
                    m_associated = true;
                    break;
    
                case OT_DEVICE_ROLE_DISABLED:
                case OT_DEVICE_ROLE_DETACHED:
                    m_associated = false;
                default:
                    thread_coap_utils_peer_addr_clear();
                    break;
            }
        }
    
        NRF_LOG_INFO("State changed! Flags: 0x%08x Current role: %d\r\n",
                     flags,
                     otThreadGetDeviceRole(p_context));
    }
    
    /***************************************************************************************************
     * @section Initialization
     **************************************************************************************************/
    
    /**@brief Function for initializing the Thread Board Support Package
     */
    static void thread_bsp_init(void)
    {
        uint32_t error_code = bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, bsp_event_handler);
        APP_ERROR_CHECK(error_code);
    
        error_code = bsp_thread_init(thread_ot_instance_get());
        APP_ERROR_CHECK(error_code);
    }
    
    
    /**@brief Function for initializing the Application Timer Module
     */
    static void timer_init(void)
    {
        uint32_t error_code = app_timer_init();
        APP_ERROR_CHECK(error_code);
    }
    
    
    /**@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 initializing the Thread Stack
     */
    static void thread_instance_init(void)
    {
        thread_configuration_t thread_configuration =
        {
            .radio_mode        = THREAD_RADIO_MODE_RX_ON_WHEN_IDLE,
            .autocommissioning = true,
        };
    
        thread_init(&thread_configuration);
        thread_cli_init();
        thread_state_changed_callback_set(thread_state_changed_callback);
    }
    
    
    /**@brief Function for initializing the Constrained Application Protocol Module
     */
    
    static void thread_coap_init(void)
    {
        thread_coap_utils_configuration_t thread_coap_configuration =
        {
            .coap_server_enabled               = true,
            .coap_client_enabled               = true,
            .configurable_led_blinking_enabled = false,
        };
    
        thread_coap_utils_init(&thread_coap_configuration);
    }
    
    
    /**@brief Function for initializing scheduler module.
     */
    static void scheduler_init(void)
    {
        APP_SCHED_INIT(SCHED_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
    }
    
    
    /***************************************************************************************************
     * @section Main
     **************************************************************************************************/
    
    int main(int argc, char * argv[])
    {
        log_init();
        scheduler_init();
        timer_init();
    
        thread_instance_init();
        thread_coap_init();
        thread_bsp_init();
        while (true)
        {
            thread_process();
            app_sched_execute();
    
            if (NRF_LOG_PROCESS() == false)
            {
                thread_sleep();
            }
        }
    }
    
    /**
     *@}
     **/
    
    /**
     * Copyright (c) 2017-2019 - 2020, 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.
     *
     */
    
    #include "thread_coap_utils.h"
    
    #include "app_timer.h"
    #include "bsp_thread.h"
    #include "nrf_assert.h"
    #include "nrf_log.h"
    #include "sdk_config.h"
    #include "thread_utils.h"
    
    #include <openthread/ip6.h>
    #include <openthread/link.h>
    #include <openthread/thread.h>
    #include <openthread/platform/alarm-milli.h>
    
    #define RESPONSE_POLL_PERIOD     100
    #define PROVISIONING_EXPIRY_TIME 5000
    #define LED_INTERVAL             100
    
    APP_TIMER_DEF(m_provisioning_timer);
    APP_TIMER_DEF(m_led_timer);
    
    /**@brief Structure holding CoAP status information. */
    typedef struct
    {
        bool         provisioning_enabled; /**< Information if provisioning is enabled. */
        uint32_t     provisioning_expiry;  /**< Provisioning timeout time. */
        bool         led_blinking_is_on;   /**< Information if leds are blinking */
        otIp6Address peer_address;         /**< An address of a related server node. */
    } state_t;
    
    static uint32_t                                  m_poll_period;
    static state_t                                   m_state;
    static thread_coap_utils_configuration_t         m_config;
    static thread_coap_utils_light_command_handler_t m_light_command_handler;
    
    /**@brief Forward declarations of CoAP resources handlers. */
    static void provisioning_request_handler(void *, otMessage *, const otMessageInfo *);
    static void light_request_handler(void *, otMessage *, const otMessageInfo *);
    static void property_set_request_handler(void *, otMessage *, const otMessageInfo *);
    
    
    static otCoapResource m_property_set_request_resource =
    {
        .mUriPath = "/$sys/CxD2hb4NHT/tttt/thing/property/set",
        .mHandler = property_set_request_handler,
        .mContext = NULL,
        .mNext    = NULL
    };
    
    /**@brief Definition of CoAP resources for provisioning. */
    static otCoapResource m_provisioning_resource =
    {
        .mUriPath = "provisioning",
        .mHandler = provisioning_request_handler,
        .mContext = NULL,
        .mNext    = NULL
    };
    
    /**@brief Definition of CoAP resources for light. */
    static otCoapResource m_light_resource =
    {
        .mUriPath = "light",
        .mHandler = light_request_handler,
        .mContext = NULL,
        .mNext    = NULL
    };
    
    static void coap_default_handler(void                * p_context,
                                     otMessage           * p_message,
                                     const otMessageInfo * p_message_info)
    {
        printf("coap_default_handler\n");
        UNUSED_PARAMETER(p_context);
        UNUSED_PARAMETER(p_message);
        UNUSED_PARAMETER(p_message_info);
    
        
    
        NRF_LOG_INFO("Received CoAP message that does not match any request or resource\r\n");
    }
    
    static uint32_t poll_period_response_set(void)
    {
        uint32_t     error;
        otError      ot_error;
        otInstance * p_instance = thread_ot_instance_get();
    
        do
        {
            if (otThreadGetLinkMode(p_instance).mRxOnWhenIdle)
            {
                error = NRF_ERROR_INVALID_STATE;
                break;
            }
    
            if (!m_poll_period)
            {
                m_poll_period = otLinkGetPollPeriod(p_instance);
    
                NRF_LOG_INFO("Poll Period: %dms set\r\n", RESPONSE_POLL_PERIOD);
    
                ot_error = otLinkSetPollPeriod(p_instance, RESPONSE_POLL_PERIOD);
                ASSERT(ot_error == OT_ERROR_NONE);
    
                error =  NRF_SUCCESS;
            }
            else
            {
                error = NRF_ERROR_BUSY;
            }
        } while (false);
    
        return error;
    }
    
    static void poll_period_restore(void)
    {
        otError      error;
        otInstance * p_instance = thread_ot_instance_get();
    
        do
        {
            if (otThreadGetLinkMode(p_instance).mRxOnWhenIdle)
            {
                break;
            }
    
            if (m_poll_period)
            {
                error = otLinkSetPollPeriod(p_instance, m_poll_period);
                ASSERT(error == OT_ERROR_NONE);
    
                NRF_LOG_INFO("Poll Period: %dms restored\r\n", m_poll_period);
                m_poll_period = 0;
            }
        } while (false);
    }
    
    static void light_changed_default(thread_coap_utils_light_command_t light_command)
    {
        switch (light_command)
        {
            case THREAD_COAP_UTILS_LIGHT_CMD_ON:
                LEDS_ON(BSP_LED_3_MASK);
                break;
    
            case THREAD_COAP_UTILS_LIGHT_CMD_OFF:
                LEDS_OFF(BSP_LED_3_MASK);
                break;
    
            case THREAD_COAP_UTILS_LIGHT_CMD_TOGGLE:
                LEDS_INVERT(BSP_LED_3_MASK);
                break;
    
            default:
                break;
        }
    }
    
    static bool provisioning_is_enabled(void)
    {
        return m_state.provisioning_enabled;
    }
    
    static void provisioning_enable(bool enable)
    {
        uint32_t error;
    
        m_state.provisioning_enabled = enable;
    
        if (enable)
        {
            m_state.provisioning_expiry = otPlatAlarmMilliGetNow() + PROVISIONING_EXPIRY_TIME;
            error = app_timer_start(m_provisioning_timer,
                                    APP_TIMER_TICKS(PROVISIONING_EXPIRY_TIME),
                                    NULL);
            ASSERT(error == NRF_SUCCESS);
    
            error = app_timer_start(m_led_timer, APP_TIMER_TICKS(LED_INTERVAL), NULL);
            ASSERT(error == NRF_SUCCESS);
    
            if (m_config.configurable_led_blinking_enabled)
            {
                m_light_command_handler(THREAD_COAP_UTILS_LIGHT_CMD_ON);
            }
        }
        else
        {
            m_state.provisioning_expiry = 0;
    
            error = app_timer_stop(m_provisioning_timer);
            ASSERT(error == NRF_SUCCESS);
    
            error = app_timer_stop(m_led_timer);
            ASSERT(error == NRF_SUCCESS);
    
            LEDS_OFF(BSP_LED_2_MASK);
    
            if (m_config.configurable_led_blinking_enabled)
            {
                error = app_timer_stop(m_led_timer);
                ASSERT(error == NRF_SUCCESS);
    
                if (m_state.led_blinking_is_on)
                {
                    m_light_command_handler(THREAD_COAP_UTILS_LIGHT_CMD_ON);
                }
                else
                {
                    m_light_command_handler(THREAD_COAP_UTILS_LIGHT_CMD_OFF);
                }
            }
        }
    }
    
    static void provisioning_timer_handler(void * p_context)
    {
        provisioning_enable(false);
    }
    
    static otError provisioning_response_send(otMessage           * p_request_message,
                                              const otMessageInfo * p_message_info)
    {
        otError        error = OT_ERROR_NO_BUFS;
        otMessage    * p_response;
        otInstance   * p_instance = thread_ot_instance_get();
    
        do
        {
            p_response = otCoapNewMessage(p_instance, NULL);
            if (p_response == NULL)
            {
                break;
            }
    
            otCoapMessageInit(p_response, OT_COAP_TYPE_NON_CONFIRMABLE, OT_COAP_CODE_CONTENT);
    
            error = otCoapMessageSetToken(p_response,
                                          otCoapMessageGetToken(p_request_message),
                                          otCoapMessageGetTokenLength(p_request_message));
            if (error != OT_ERROR_NONE)
            {
                break;
            }
    
            error = otCoapMessageSetPayloadMarker(p_response);
            if (error != OT_ERROR_NONE)
            {
                break;
            }
    
            error = otMessageAppend(
                p_response, otThreadGetMeshLocalEid(p_instance), sizeof(otIp6Address));
            if (error != OT_ERROR_NONE)
            {
                break;
            }
    
            error = otCoapSendResponse(p_instance, p_response, p_message_info);
    
        } while (false);
    
        if (error != OT_ERROR_NONE && p_response != NULL)
        {
            otMessageFree(p_response);
        }
    
        return error;
    }
    
    static void provisioning_request_handler(void                * p_context,
                                             otMessage           * p_message,
                                             const otMessageInfo * p_message_info)
    {
        UNUSED_PARAMETER(p_message);
    
        otError       error;
        otMessageInfo message_info;
    
        if (!provisioning_is_enabled())
        {
            return;
        }
    
        if ((otCoapMessageGetType(p_message) == OT_COAP_TYPE_NON_CONFIRMABLE) &&
            (otCoapMessageGetCode(p_message) == OT_COAP_CODE_GET))
        {
            message_info = *p_message_info;
            memset(&message_info.mSockAddr, 0, sizeof(message_info.mSockAddr));
    
            error = provisioning_response_send(p_message, &message_info);
            if (error == OT_ERROR_NONE)
            {
                provisioning_enable(false);
            }
        }
    }
    
    static void property_set_request_handler(void                * p_context,
                                             otMessage           * p_message,
                                             const otMessageInfo * p_message_info)
    {
        printf("provisioning_request_handler\n");
        UNUSED_PARAMETER(p_message);
    
        otError       error;
        otMessageInfo message_info;
        
    
    #if 0
        if ((otCoapMessageGetType(p_message) == OT_COAP_TYPE_NON_CONFIRMABLE) &&
            (otCoapMessageGetCode(p_message) == OT_COAP_CODE_GET))
        {
            message_info = *p_message_info;
            memset(&message_info.mSockAddr, 0, sizeof(message_info.mSockAddr));
    
            error = provisioning_response_send(p_message, &message_info);
            if (error == OT_ERROR_NONE)
            {
                provisioning_enable(false);
            }
        }
    #endif
    }
    
    static void led_timer_handler(void * p_context)
    {
        // This handler may be called after app_timer_stop due to app_shceduler.
        if (m_state.provisioning_enabled)
        {
            LEDS_INVERT(BSP_LED_2_MASK);
        }
    }
    
    static void light_response_send(otMessage           * p_request_message,
                                    const otMessageInfo * p_message_info)
    {
        otError      error = OT_ERROR_NO_BUFS;
        otMessage  * p_response;
        otInstance * p_instance = thread_ot_instance_get();
    
        do
        {
            p_response = otCoapNewMessage(p_instance, NULL);
            if (p_response == NULL)
            {
                break;
            }
    
            error = otCoapMessageInitResponse(p_response,
                                              p_request_message,
                                              OT_COAP_TYPE_ACKNOWLEDGMENT,
                                              OT_COAP_CODE_CHANGED);
    
            if (error != OT_ERROR_NONE)
            {
                break;
            }
    
            error = otCoapSendResponse(p_instance, p_response, p_message_info);
    
        } while (false);
    
        if ((error != OT_ERROR_NONE) && (p_response != NULL))
        {
            otMessageFree(p_response);
        }
    }
    
    static void light_request_handler(void                * p_context,
                                      otMessage           * p_message,
                                      const otMessageInfo * p_message_info)
    {
        uint8_t command;
    
        do
        {
            if (otCoapMessageGetType(p_message) != OT_COAP_TYPE_CONFIRMABLE &&
                otCoapMessageGetType(p_message) != OT_COAP_TYPE_NON_CONFIRMABLE)
            {
                break;
            }
    
            if (otCoapMessageGetCode(p_message) != OT_COAP_CODE_PUT)
            {
                break;
            }
    
            if (otMessageRead(p_message, otMessageGetOffset(p_message), &command, 1) != 1)
            {
                NRF_LOG_INFO("light handler - missing command\r\n");
            }
    
            m_light_command_handler((thread_coap_utils_light_command_t)command);
    
            switch (command)
            {
                case THREAD_COAP_UTILS_LIGHT_CMD_ON:
                    if (m_config.configurable_led_blinking_enabled)
                    {
                        m_state.led_blinking_is_on = true;
                    }
                    break;
    
                case THREAD_COAP_UTILS_LIGHT_CMD_OFF:
                    if (m_config.configurable_led_blinking_enabled)
                    {
                        m_state.led_blinking_is_on = false;
                    }
                    break;
    
                case THREAD_COAP_UTILS_LIGHT_CMD_TOGGLE:
                    if (m_config.configurable_led_blinking_enabled)
                    {
                        m_state.led_blinking_is_on = !m_state.led_blinking_is_on;
                    }
                    break;
    
                default:
                    break;
            }
    
            if (otCoapMessageGetType(p_message) == OT_COAP_TYPE_CONFIRMABLE)
            {
                light_response_send(p_message, p_message_info);
            }
    
        } while (false);
    }
    
    void thread_coap_utils_init(const thread_coap_utils_configuration_t * p_config)
    {
        otInstance * p_instance = thread_ot_instance_get();
    
        otError error = otCoapStart(p_instance, OT_DEFAULT_COAP_PORT);
        ASSERT(error == OT_ERROR_NONE);
        printf("setDefaultHandler\n");
        otCoapSetDefaultHandler(p_instance, coap_default_handler, NULL);
    
        m_config = *p_config;
    
        m_light_command_handler = light_changed_default;
    
        if (m_config.coap_server_enabled)
        {
            LEDS_CONFIGURE(LEDS_MASK);
            LEDS_OFF(LEDS_MASK);
    
            uint32_t retval = app_timer_create(&m_led_timer,
                                               APP_TIMER_MODE_REPEATED,
                                               led_timer_handler);
            ASSERT(retval == NRF_SUCCESS);
    
            retval = app_timer_create(&m_provisioning_timer,
                                      APP_TIMER_MODE_SINGLE_SHOT,
                                      provisioning_timer_handler);
            ASSERT(retval == NRF_SUCCESS);
    
            m_light_resource.mContext        = p_instance;
            m_provisioning_resource.mContext = p_instance;
            m_property_set_request_resource.mContext  = p_instance;
    		
            error = otCoapAddResource(p_instance, &m_light_resource);
            ASSERT(error == OT_ERROR_NONE);
    
            error = otCoapAddResource(p_instance, &m_provisioning_resource);
            ASSERT(error == OT_ERROR_NONE);
    		
            error = otCoapAddResource(p_instance, &m_property_set_request_resource);
            ASSERT(error == OT_ERROR_NONE);
        }
    }
    
    void thread_coap_utils_deinit(void)
    {
        otInstance * p_instance = thread_ot_instance_get();
    
        otError error = otCoapStop(p_instance);
        ASSERT(error == OT_ERROR_NONE);
    
        otCoapSetDefaultHandler(p_instance, NULL, NULL);
    
        if (m_config.coap_server_enabled)
        {
            m_light_resource.mContext        = NULL;
            m_provisioning_resource.mContext = NULL;
    
            otCoapRemoveResource(p_instance, &m_light_resource);
            otCoapRemoveResource(p_instance, &m_provisioning_resource);
        }
    }
    
    void thread_coap_utils_peer_addr_clear(void)
    {
        memset(&m_state.peer_address, 0, sizeof(m_state.peer_address));
    }
    
    void thread_coap_utils_unicast_light_request_send(uint8_t command)
    {
        otError       error = OT_ERROR_NONE;
        otMessage   * p_request;
        otMessageInfo message_info;
        otInstance  * p_instance = thread_ot_instance_get();
    
        do
        {
            if (otIp6IsAddressUnspecified(&m_state.peer_address))
            {
                NRF_LOG_INFO("Failed to send the CoAP Request to the unspecified IPv6 address\r\n");
                break;
            }
    
            p_request = otCoapNewMessage(p_instance, NULL);
            if (p_request == NULL)
            {
                NRF_LOG_INFO("Failed to allocate message for CoAP Request\r\n");
                break;
            }
    
            otCoapMessageInit(p_request, OT_COAP_TYPE_NON_CONFIRMABLE, OT_COAP_CODE_PUT);
            otCoapMessageGenerateToken(p_request, 2);
    
            error = otCoapMessageAppendUriPathOptions(p_request, "light");
            ASSERT(error == OT_ERROR_NONE);
    
            error = otCoapMessageSetPayloadMarker(p_request);
            ASSERT(error == OT_ERROR_NONE);
    
            otCoapMessageInit(p_request, OT_COAP_TYPE_NON_CONFIRMABLE, OT_COAP_CODE_PUT);
            otCoapMessageGenerateToken(p_request, 2);
            UNUSED_VARIABLE(otCoapMessageAppendUriPathOptions(p_request, "light"));
            UNUSED_VARIABLE(otCoapMessageSetPayloadMarker(p_request));
    
            error = otMessageAppend(p_request, &command, sizeof(command));
            if (error != OT_ERROR_NONE)
            {
                break;
            }
    
            memset(&message_info, 0, sizeof(message_info));
            message_info.mPeerPort = OT_DEFAULT_COAP_PORT;
            memcpy(&message_info.mPeerAddr, &m_state.peer_address, sizeof(message_info.mPeerAddr));
    
            error = otCoapSendRequest(p_instance,
                                      p_request,
                                      &message_info,
                                      NULL,
                                      p_instance);
        } while (false);
    
        if (error != OT_ERROR_NONE && p_request != NULL)
        {
            NRF_LOG_INFO("Failed to send CoAP Request: %d\r\n", error);
            otMessageFree(p_request);
        }
    }
    
    void thread_coap_utils_multicast_light_request_send(uint8_t                             command,
                                                        thread_coap_utils_multicast_scope_t scope)
    {
        otError       error = OT_ERROR_NONE;
        otMessage   * p_request;
        otMessageInfo message_info;
        const char  * p_scope = NULL;
        otInstance  * p_instance = thread_ot_instance_get();
    
        do
        {
            p_request = otCoapNewMessage(p_instance, NULL);
            if (p_request == NULL)
            {
                NRF_LOG_INFO("Failed to allocate message for CoAP Request\r\n");
                break;
            }
    
            otCoapMessageInit(p_request, OT_COAP_TYPE_NON_CONFIRMABLE, OT_COAP_CODE_PUT);
    
            error = otCoapMessageAppendUriPathOptions(p_request, "light");
            ASSERT(error == OT_ERROR_NONE);
    
            error = otCoapMessageSetPayloadMarker(p_request);
            ASSERT(error == OT_ERROR_NONE);
    
            error = otMessageAppend(p_request, &command, sizeof(command));
            if (error != OT_ERROR_NONE)
            {
                break;
            }
    
            switch (scope)
            {
            case THREAD_COAP_UTILS_MULTICAST_LINK_LOCAL:
                p_scope = "ff02::1";
                break;
    
            case THREAD_COAP_UTILS_MULTICAST_REALM_LOCAL:
                p_scope = "ff03::1";
                break;
    
            default:
                ASSERT(false);
            }
    
            memset(&message_info, 0, sizeof(message_info));
            message_info.mPeerPort = OT_DEFAULT_COAP_PORT;
    
            error = otIp6AddressFromString(p_scope, &message_info.mPeerAddr);
            ASSERT(error == OT_ERROR_NONE);
    
            error = otCoapSendRequest(p_instance, p_request, &message_info, NULL, NULL);
        } while (false);
    
        if (error != OT_ERROR_NONE && p_request != NULL)
        {
            NRF_LOG_INFO("Failed to send CoAP Request: %d\r\n", error);
            otMessageFree(p_request);
        }
    }
    
    static void provisioning_response_handler(void                * p_context,
                                              otMessage           * p_message,
                                              const otMessageInfo * p_message_info,
                                              otError               result)
    {
        UNUSED_PARAMETER(p_context);
    
        // Restore the polling period back to initial slow value.
        poll_period_restore();
    
        if (result == OT_ERROR_NONE)
        {
            UNUSED_RETURN_VALUE(otMessageRead(p_message,
                                              otMessageGetOffset(p_message),
                                              &m_state.peer_address,
                                              sizeof(m_state.peer_address)));
        }
        else
        {
            NRF_LOG_INFO("Provisioning failed: %d\r\n", result);
        }
    }
    
    void thread_coap_utils_provisioning_request_send(void)
    {
        otError       error = OT_ERROR_NO_BUFS;
        otMessage   * p_request;
        otMessageInfo message_info;
        otInstance  * p_instance = thread_ot_instance_get();
    
        do
        {
            p_request = otCoapNewMessage(p_instance, NULL);
            if (p_request == NULL)
            {
                break;
            }
    
            otCoapMessageInit(p_request, OT_COAP_TYPE_NON_CONFIRMABLE, OT_COAP_CODE_GET);
            otCoapMessageGenerateToken(p_request, 2);
    
            error = otCoapMessageAppendUriPathOptions(p_request, "provisioning");
            ASSERT(error == OT_ERROR_NONE);
    
            // decrease the polling period for higher responsiveness
            uint32_t err_code = poll_period_response_set();
            if (err_code == NRF_ERROR_BUSY)
            {
                break;
            }
    
            memset(&message_info, 0, sizeof(message_info));
            message_info.mPeerPort = OT_DEFAULT_COAP_PORT;
    
            error = otIp6AddressFromString("ff03::1", &message_info.mPeerAddr);
            ASSERT(error == OT_ERROR_NONE);
    
            error = otCoapSendRequest(
                p_instance, p_request, &message_info, provisioning_response_handler, p_instance);
    
        } while (false);
    
        if (error != OT_ERROR_NONE && p_request != NULL)
        {
            otMessageFree(p_request);
        }
    
    }
    
    void thread_coap_utils_provisioning_enable_set(bool value)
    {
        provisioning_enable(value);
    }
    
    void thread_coap_utils_light_command_handler_set(thread_coap_utils_light_command_handler_t handler)
    {
        ASSERT(handler != NULL);
    
        m_light_command_handler = handler;
    }
    
    bool thread_coap_utils_light_is_led_blinking(void)
    {
        return m_state.led_blinking_is_on;
    }
    

Children
No Data
Related