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

Openthread COAP Client Server device reconnection failure

Hello,

I am having hard time using openthread NCS examples. Recently I was handed over a project based on NCS COAP client server example to resolve a issue but I am not able solve the issue.

Issue: We have 2 FTD device one running COAP client example which is basically reading data from sensor and sending values to COAP server. The sensor update is basically automated using zephyr kwork with delay so we don't have to press button instead it will submit kwork at fixed intervals. Now COAP server is just receiving data and printing data on terminal. 

That's it. Nothing new has been done if I compare with Nordic demo examples. At the start everything works fine. Both server and client are able to communicate with eachother but after say nealry 30-35 hours my COAP client device gets disconnected and not able to reconnect to my COAP server. And if I restart my COAP client device it gets connected. So what's really the issue here ? When I ask the same question on Google Open Thread group they advised me this could be possible issue with radio drivers. So I would like to know what's really the issue here ? And how to resolve this issue ?

When we started developing at my company, we decided to select openthread as mesh communication protocols because of it's benefits over other protocols and Nordic SOC because of it's production ready examples. But it's seems both selection are letting me down.

Also I would like to ask in COAP examples I have seen this lights, provisioning on which we are COAP client is sending turn on off commands. So in this examples does this light act as topic or what ? Also suppose if I have 2 COAP Clients interfaced with different sensors, now if I have to send data to server should I use 2 different topics (something like light1, light2 or sensor 1 and sensor2) instead of sending data on the same light services ? 

Parents
No Data
Reply
  • Hey Charlie,

    Thanks for quick reply again. I will try to keep my queries as precise as possible.

    I have a setup running around 48 hours now, and there is no issue so I do not know your problem. I can share my codes with you so you can check if there is anything different or repeat the experiment.

    I will checkout the example that you have provided and compare it with my COAP sensor client examples and revert back.

    Anyway, the codes shows you have an understanding on how to use coap URI now,

    Okay that suggest, i should use multiple URI paths to update different sensor/devcie data.

    Here is my understanding:

    1. Client1 runs coap_client, it has Sensor1, Sensor1 control resource Led1 on Server1 to turn on and off.

    2. Client2 runs coap_client, it has Sensor2, Sensor2, control resource Led2 on Server1 to turn on and off.

    3. Server1 runs coap_server, it has Led1 and Led2 as resources. 

    Your understanding is right. But before we proceed forward, i just want to once again make sure whether i should use single URI path for different sensor nodes/devices or multiple URI paths (one for each sensor node/devices).

    Scenario 1:

    sensor 1 will update data on SENSOR1 URI path, sensor 2 will update on SENSOR 2 URI path.

    Scenario 2:

    Or I should just use one URI path called SENSORS and all client sensor device (2 or more) sends data on single topic.

    Which scenario will be right to update sensor data ? I have worked with MQTT more and not COAP as such And if i compare COAP URI paths with MQTT Topics, than definitely Scenario 1 is the right way to go, were i have multiple URI paths for different sensor nodes. But what's your thoughts regarding the same ?

    Final Objective of Application and COAP Client Code

    I just want to receive sensor data on my COAP server from different sensor nodes attached to different machines. Than on my COAP server i will be just printing out the sensor data on USB CDC.

    Here is my sensor application code files till now  but i have considered Scenario 2 (although i think it's not the right way):

    /*
     * Copyright (c) 2020 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    #include <zephyr.h>
    #include <dk_buttons_and_leds.h>
    #include <logging/log.h>
    #include <ram_pwrdn.h>
    #include <device.h>
    
    #include "coap_client_utils.h"
    
    #if CONFIG_BT_NUS
    #include "ble_utils.h"
    #endif
    #include <net/openthread.h>
    #include <openthread/thread.h>
    #if CONFIG_USB
    #include <drivers/uart.h>
    #include <usb/usb_device.h>
    #endif
    
    
    #if CONFIG_NFC_T4T_NRFXLIB
    #include <nfc_t4t_lib.h>
    #include <nfc/ndef/text_rec.h>
    #include "ndef_file_m.h"
    #include <nfc/ndef/msg.h>
    #include "nfc_Parser.h"
    #endif
    #include <devicetree.h>
    #include <drivers/gpio.h>
    #include "sensor.h"
    #include "pmic.h"
    #include <stdio.h>
    
    LOG_MODULE_REGISTER(coap_client, CONFIG_COAP_CLIENT_LOG_LEVEL);
    
    #define CONSOLE_LABEL DT_LABEL(DT_CHOSEN(zephyr_console))
    
    
    volatile bool is_connected;
    
    #define OT_CONNECTION_LED DK_LED3
    #define BLE_CONNECTION_LED DK_LED4
    #define MTD_SED_LED DK_LED3
    #define LIGHT_LED DK_LED1
    #define SENSOR_UPDATE_INTERVAL K_MSEC(200)   //K_MSEC(50)    //K_SECONDS(10) 
    bool         SHT_Enable      = false;
    bool         BME_Enable      = false;
    bool         LPS22H1B_Enable = false;
    bool         SI1151_Enable   = false;
    bool         LSM6DSOX_Enable = false;
    //bool         MP34DT05_Enable = false;
    unsigned long     m_counter       = 0;
    
    struct device *i2c_dev;
    struct device *i2c_dev1;
    //float features[210];
    static struct k_delayed_work coapcloud_work;
    
    
    /**
     * @brief   Function for enable MOSFET Trigger for sensor.
     * @return Nothing
     */
    void MOSFET_ENABLE()
    {
    	const struct device *gpio_dev1;
    
    		gpio_dev1 = device_get_binding("GPIO_1");
    
           if (gpio_dev1 == NULL) {
    		return;
    	   }
    
          gpio_pin_configure(gpio_dev1, 8, GPIO_OUTPUT_INACTIVE| 1);
          gpio_pin_set(gpio_dev1, 8,0); //0 --on
    }
    
    /**
     * @brief   Function for disable MOSFET Trigger for sensor.
       @return Nothing
     */
    void MOSFET_DISABLE()
    {
    	const struct device *gpio_dev1;
    
    		gpio_dev1 = device_get_binding("GPIO_1");
    
           if (gpio_dev1 == NULL) {
    		return;
    	    }
    
          gpio_pin_configure(gpio_dev1, 8, GPIO_OUTPUT_INACTIVE| 1);
          gpio_pin_set(gpio_dev1, 8,1); //      1--- off
    }
    
    #if CONFIG_NFC_T4T_NRFXLIB
    
    static struct k_delayed_work update_flash;
    
    #define NFC_FIELD_LED		DK_LED3
    #define NFC_WRITE_LED		DK_LED3
    #define NFC_READ_LED		DK_LED3
    
    #define NDEF_MSG_BUF_SIZE	128
    
    static uint8_t ndef_msg_buf[CONFIG_NDEF_FILE_SIZE]; /**< Buffer for NDEF file. */
    
    uint32_t len = sizeof(ndef_msg_buf);
    
    enum {
    	FLASH_WRITE_FINISHED,
    	FLASH_BUF_PREP_STARTED,
    	FLASH_BUF_PREP_FINISHED,
    	FLASH_WRITE_STARTED,
    };
    
    static atomic_t op_flags;
    static uint8_t flash_buf[40]; /**< Buffer for flash update. */
    static uint8_t flash_buf_len; /**< Length of the flash buffer. */
    
    static void flash_buffer_prepare(size_t data_length)
    {
    	if (atomic_cas(&op_flags, FLASH_WRITE_FINISHED,
    			FLASH_BUF_PREP_STARTED)) {
    		flash_buf_len = data_length + NLEN_FIELD_SIZE;
    		memcpy(flash_buf, ndef_msg_buf, sizeof(flash_buf));
    
    		atomic_set(&op_flags, FLASH_BUF_PREP_FINISHED);
    	} else {
    		LOG_INF("Flash update pending. Discarding new data...\n");
    	}
    
    }
    
    /**
     * @brief   Function for update  channel and panid  .
       @return Nothing
     */
    static void flash_update(struct k_work *item)
    {
    	if (atomic_cas(&op_flags, FLASH_BUF_PREP_FINISHED,
    				FLASH_WRITE_STARTED)) {
    			if (ndef_file_update(flash_buf, flash_buf_len) < 0) {
    				LOG_INF("Cannot flash NDEF message!\n");
    			} else {
    		    nfcParser(ndef_msg_buf+2);
    			LOG_INF("NDEF message successfully flashed \n");
    			}
    
    			atomic_set(&op_flags, FLASH_WRITE_FINISHED);
    		}
    	 k_delayed_work_submit(&update_flash, K_SECONDS(1));
    }
    /**
     * @brief Callback function for handling NFC events.
     */
    static void nfc_callback(void *context,
    			 enum nfc_t4t_event event,
    			 const uint8_t *data,
    			 size_t data_length,
    			 uint32_t flags)
    {
    	ARG_UNUSED(context);
    	ARG_UNUSED(data);
    	ARG_UNUSED(flags);
    
    	switch (event) {
    	case NFC_T4T_EVENT_FIELD_ON:
    		dk_set_led_on(NFC_FIELD_LED);
    		break;
    
    	case NFC_T4T_EVENT_FIELD_OFF:
    		dk_set_leds(NFC_FIELD_LED);
    		break;
    
    	case NFC_T4T_EVENT_NDEF_READ:
    		dk_set_led_on(NFC_FIELD_LED);
    		break;
    
    	case NFC_T4T_EVENT_NDEF_UPDATED:
    		if (data_length > 0) {
    			dk_set_led_on(NFC_READ_LED);
    			flash_buffer_prepare(data_length);
    		}
    		break;
    
    	default:
    		break;
    	}
    }
    #endif /*CONFIG_NFC_T4T_NRFXLIB*/
    
    #if defined (CONFIG_SENSOR_BME680)
    struct bme680_dev gas_sensor;
    struct bme680_field_data data;
    void user_delay_ms(uint32_t period)
    {
       k_msleep(period);
    }
    
    void IO_init()
    {
      i2c_init();
      gas_sensor.dev_id = BME680_I2C_ADDR_SECONDARY;
      gas_sensor.intf = BME680_I2C_INTF;
      gas_sensor.read = user_i2c_read;
      gas_sensor.write = user_i2c_write;
      gas_sensor.delay_ms = user_delay_ms;
      gas_sensor.amb_temp = 25;
       bme680_init(&gas_sensor);
        /* Set the temperature, pressure and humidity settings */
        gas_sensor.tph_sett.os_hum = BME680_OS_2X;
        gas_sensor.tph_sett.os_pres = BME680_OS_4X;
        gas_sensor.tph_sett.os_temp = BME680_OS_8X;
        gas_sensor.tph_sett.filter = BME680_FILTER_SIZE_3;
    
        /* Set the remaining gas sensor settings and link the heating profile */
        gas_sensor.gas_sett.run_gas = BME680_ENABLE_GAS_MEAS;
        /* Create a ramp heat waveform in 3 steps */
        gas_sensor.gas_sett.heatr_temp = 320; /* degree Celsius */
        gas_sensor.gas_sett.heatr_dur = 150; /* milliseconds */
    
        /* Select the power mode */
        /* Must be set before writing the sensor configuration */
        gas_sensor.power_mode = BME680_FORCED_MODE; 
    }
    #endif /*CONFIG_SENSOR_BME680*/
    
     
    int32_t i2c_init()
    {
      i2c_dev = device_get_binding("I2C_1");
        if (!i2c_dev) {
                printk("I2C: Device driver not found.\n");
    
        }
      i2c_configure(i2c_dev, I2C_SPEED_SET(I2C_SPEED_STANDARD)| I2C_MODE_MASTER);
        return 0;
    
    }
    
    #if defined (CONFIG_SENSOR_BME680)
    int8_t user_i2c_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len)
    {
        int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */
        if(i2c_burst_read(i2c_dev,dev_id,reg_addr,reg_data,len) < 0)   
        {
          LOG_INF("error_bme_read\r\n");
          return -1;
        }
        return rslt;
    }
    
    int8_t user_i2c_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *reg_data, uint16_t len)
    {
        int8_t rslt = 0; /* Return 0 for Success, non-zero for failure */
        if(i2c_burst_write(i2c_dev,dev_id,reg_addr,reg_data,len) < 0)   
        {
          LOG_INF("error_bme_read\r\n");
          return -1;
        }
        return rslt;
    }
    #endif /*CONFIG_SENSOR_BME680*/
    
    #if defined (CONFIG_SENSOR_LSM6DSOX)
    static stmdev_ctx_t dev_ctx;
    static int32_t platform_write(void *handle, uint8_t reg, uint8_t *bufp,
                                  uint16_t len)
    {
        i2c_burst_write(i2c_dev,LSM6DSOX_I2C_ADD_L,reg,bufp,len);
        return 0;
    }
    
    static int32_t platform_read(void *handle, uint8_t reg, uint8_t *bufp,
                                 uint16_t len)
    {
        i2c_burst_read(i2c_dev,LSM6DSOX_I2C_ADD_L,reg,bufp,len);
        return 0;
    }
    
    void LSM6DSOX_init()
    {
    
         i2c_init();
         dev_ctx.write_reg = platform_write;
         dev_ctx.read_reg = platform_read;
    
         k_msleep(BOOT_TIME);
         lsm6dsox_device_id_get(&dev_ctx, &whoamI);
    
        
    
         lsm6dsox_reset_set(&dev_ctx, PROPERTY_ENABLE);
         do {
          lsm6dsox_reset_get(&dev_ctx, &rst);
         }while (rst);
      
         /* Disable I3C interface */
         lsm6dsox_i3c_disable_set(&dev_ctx, LSM6DSOX_I3C_DISABLE);
           /* Enable Block Data Update */
         lsm6dsox_block_data_update_set(&dev_ctx, PROPERTY_ENABLE);
         /* Set Output Data Rate */
         lsm6dsox_xl_data_rate_set(&dev_ctx, LSM6DSOX_XL_ODR_104Hz);
         lsm6dsox_gy_data_rate_set(&dev_ctx, LSM6DSOX_GY_ODR_104Hz);
         /* Set full scale */
         lsm6dsox_xl_full_scale_set(&dev_ctx, LSM6DSOX_16g);
         lsm6dsox_gy_full_scale_set(&dev_ctx, LSM6DSOX_2000dps);
    }
    
    void lsm6dsox_data_read()
    {
     
      /* Read acceleration field data */
      memset(data_raw_acceleration.u8bit, 0x00, 3 * sizeof(int16_t));
      lsm6dsox_acceleration_raw_get(&dev_ctx, data_raw_acceleration.u8bit);
      acceleration_mg[0] =
        lsm6dsox_from_fs2_to_mg(data_raw_acceleration.i16bit[0]);
      acceleration_mg[1] =
        lsm6dsox_from_fs2_to_mg(data_raw_acceleration.i16bit[1]);
      acceleration_mg[2] =
        lsm6dsox_from_fs2_to_mg(data_raw_acceleration.i16bit[2]);
       printf("%i %i %i\r\n",data_raw_acceleration.i16bit[0],
                                           data_raw_acceleration.i16bit[1],
                                           data_raw_acceleration.i16bit[2]);
    
    		SENSOR_X=data_raw_acceleration.i16bit[0];
            SENSOR_Y=data_raw_acceleration.i16bit[1];
            SENSOR_Z=data_raw_acceleration.i16bit[2];
    
      /* Read angular rate field data */
      memset(data_raw_angular_rate.u8bit, 0x00, 3 * sizeof(int16_t));
      lsm6dsox_angular_rate_raw_get(&dev_ctx, data_raw_angular_rate.u8bit);
      angular_rate_mdps[0] =
        lsm6dsox_from_fs2000_to_mdps(data_raw_angular_rate.i16bit[0]);
      angular_rate_mdps[1] =
        lsm6dsox_from_fs2000_to_mdps(data_raw_angular_rate.i16bit[1]);
      angular_rate_mdps[2] =
        lsm6dsox_from_fs2000_to_mdps(data_raw_angular_rate.i16bit[2]);
        /*printf("angular rate : %i %i %i \r\n",data_raw_angular_rate.i16bit[0],
                                            data_raw_angular_rate.i16bit[1],
                                            data_raw_angular_rate.i16bit[2]);*/
    
        printf("\r\n");
    }
    #endif /*CONFIG_SENSOR_LSM6DSOX*/
    
    
    #if defined(CONFIG_SENSOR_SI1151)
    
    void getSensorData(void)
    {
    	// Start next measurement
    	Si115xForce(&i2c_dev);
    	Si115xHandler(&i2c_dev, &samples);
    }
    
    void proximityDemo(void)
    {
       // i2c_init();
        static uint8_t proximityOrAls = SI1153_AA00_PROX_ALS;			//Chooses which demo to run
    	char * demoName = "Proximity Demo";
    	char ch0Str[17];
    	int32_t lux;
    	int32_t result;
    	uint32_t mag;
    
    	//Initialize the demo
    		if(proximityOrAls == SI1153_AA00_PROX_ALS){
    			Si115xInitProxAls(&i2c_dev, false);
    			initialized = SI1153_AA00_PROX_ALS;
    		}else if(proximityOrAls == SI1153_AA00_PROX){
    			Si115xInitProxAls(&i2c_dev, true);
    			initialized = SI1153_AA00_PROX;
    		}
    
    	if (proximityOrAls == SI1153_AA00_PROX)
    	{
    		result = (int32_t) samples.ch0;
    
    		if(result < 0){
    			result = 0;
    		}
    
    
    		if (result >= SENSOR_OVERFLOW_VALUE)
    		{
    			// Overflow occurred
    			sprintf(ch0Str, "PROX OVERFLOW");
    			mag = 1; // Use 1 because we want to draw a very small square
    		}
    		else
    		{
    			//Update display every 10 readings
    			if(countsDisplayCounter%10 == 0)
    				countsDisplay = (int32_t) result;
    			// Display counts
    			mag = (uint16_t) result;
    			sprintf(ch0Str, "PROX %d COUNTS", (int)countsDisplay);
    		}
    
    		//Scale the reading and display a square
    		mag /= 5;
    		//GRAPHICS_DrawScreenSquare(mag);//, border);
    	}
    	else if(proximityOrAls == SI1153_AA00_PROX_ALS)// demo Ambient Light Sensing
    	{
    		// Calculate lux values
          
    		lux = (uint32_t)Si1153_getLuxReading(0, &samples);
    		demoName = "Ambient Light";
    		//GRAPHICS_DrawLightbulb(lux);
    		printf("ALS %d LUX\n", (int)lux);
    		SENSOR_lux=(int)lux;
    	}
    }
    
    #endif /*CONFIG_SENSOR_SI1151*/
    
    int32_t i2c_dinit()
    {
      return 0;
    }
    
    
    #if (CONFIG_SENSOR_SHT35||CONFIG_SENSOR_LPS22HH1B)
    
    int32_t i2c_write_data(uint16_t adress,uint16_t reg, uint8_t *cmd, uint16_t len)
    {
    	#if (CONFIG_SENSOR_SHT35)
          i2c_write(i2c_dev,cmd,len,SHT35_I2C_ADDRESS_L);
      	#else
          i2c_burst_write(i2c_dev,ADC_SLAVE_ADDR,reg,cmd,len);
    	#endif
    
       return 0; 
    }
    
    int32_t i2c_read_data(uint16_t adress, uint16_t reg, uint8_t *cmd, uint16_t len)
    {
    	 #if defined(CONFIG_SENSOR_SHT35)
           i2c_read(i2c_dev,cmd,len,SHT35_I2C_ADDRESS_L);
    	  #else
           i2c_burst_read(i2c_dev,ADC_SLAVE_ADDR,reg,cmd,len);
         #endif
    
       return 0;
    }
    
    int32_t SHT35_GetTick()
    {
      return k_uptime_get();
    }
    
    void IO_init()
    {
       IO.Init =  i2c_init;  
       IO.DeInit = i2c_dinit;   
       IO.Address = SENSOR_I2C_ADDRESS_L;   
       IO.BusType = SENSOR_I2C_BUS;
       IO.WriteReg =  i2c_write_data; 
       IO.ReadReg =   i2c_read_data;
       #if defined(CONFIG_SENSOR_SHT35)
       IO.GetTick =  SHT35_GetTick ;
       #endif
    }
    #endif 
    
    /*
    *@brief Sensor init function.
    *
    */
    void  Sensor_init()
    {
            
    #if (CONFIG_SENSOR_SHT35||CONFIG_SENSOR_LPS22HH1B||CONFIG_SENSOR_BME680)
        IO_init(); 
    #endif /*CONFIG_SENSOR_SHT35||CONFIG_SENSOR_LPS22HH1B||CONFIG_SENSOR_BME680*/
    
    #if defined(CONFIG_SENSOR_SHT35)
            LOG_INF("*****Start SHT35_SENSOR Temperature AND HUMIDITY *****");
            SHT_Enable=true;
            SHT35_RegisterBusIO(&Obj, &IO);
    #endif /*CONFIG_SENSOR_SHT35*/
    
    #if defined(CONFIG_SENSOR_LPS22HH1B)
       LOG_INF("*****Start LPS22HH1B_SENSOR Temperature AND Pressure*****");
       LPS22H1B_Enable=true;
       LPS22HB_RegisterBusIO(&Obj, &IO);
       LPS22HB_Init(&Obj);
       LPS22HB_TEMP_Enable(&Obj);
       LPS22HB_PRESS_Enable(&Obj);
    #endif /* CONFIG_SENSOR_LPS22HH1B */
    
    #if defined(CONFIG_SENSOR_SI1151)
       LOG_INF("*****Start SI1151_SENSOR node  LIGHT AND UV *****");
       SI1151_Enable= true;
       i2c_init();
     
    #endif /*CONFIG_SENSOR_SI1151*/
    
    #if defined(CONFIG_SENSOR_BME680)
       LOG_INF("*****Start BME680_SENSOR node  Temperature  HUMIDITY Pressure AND GAS *****");
       BME_Enable=true;
       uint8_t set_required_settings;
        /* Set the required sensor settings needed */
        set_required_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_FILTER_SEL 
            | BME680_GAS_SENSOR_SEL;
        /* Set the desired sensor configuration */
        bme680_set_sensor_settings(set_required_settings,&gas_sensor);
       /* Set the power mode */
       bme680_set_sensor_mode(&gas_sensor);
       uint16_t meas_period = 2000;
      bme680_get_profile_dur(&meas_period, &gas_sensor);
     
    #endif	/*CONFIG_SENSOR_BME680*/
    
    #if defined (CONFIG_SENSOR_LSM6DSOX)
        LOG_INF("*****Start LSM6DSOX  node  ACC x y z *****");
    	LSM6DSOX_Enable=true;
        LSM6DSOX_init();
    #endif /*CONFIG_SENSOR_LSM6DSOX*/
    
    }
    /* 
    * @brief read  sensor value interval of SENSOR_UPDATE_INTERVAL
    */
    
    static void upload(struct k_work *item)
    {
    	ARG_UNUSED(item);
           
          if(is_connected)
    	   {		
    		 #if defined(CONFIG_SENSOR_SHT35)
    		   SHT35_getTemperature(&Obj,&SENSOR_TEMPRATURE);
               SHT35_getHumidity(&Obj,&SENSOR_HUMIDITY);
    		   printf(" tem : %.2f hum : %.2f\r\n",SENSOR_TEMPRATURE,SENSOR_HUMIDITY);
    		 #endif
    		
    		 #if defined(CONFIG_SENSOR_LPS22HH1B)
    		   LPS22HB_Get_Temp(&Obj,&SENSOR_TEMPRATURE);
               LPS22HB_PRESS_GetPressure(&Obj,&SENSOR_PRESSURE);
    		   printf(" tempratute : %.2f pressure : %.2f\r\n",SENSOR_TEMPRATURE,SENSOR_PRESSURE);
    
         	 #endif
    
    		 #if defined(CONFIG_SENSOR_SI1151)
    		   getSensorData();
    		   proximityDemo();
             #endif
           
             #if defined(CONFIG_SENSOR_BME680)
               bme680_get_sensor_data(&data, &gas_sensor);
    		   printf("T: %.2f degC, P: %.2f hPa, H %.2f %%rH\r\n ", data.temperature / 100.0f,
                 data.pressure / 100.0f, data.humidity / 1000.0f );
    		   if(data.status & BME680_GASM_VALID_MSK)
          		{
        			// printf(", G: %d ohms", data.gas_resistance);
    				SENSOR_GAS        =  data.gas_resistance;
       			}
    			SENSOR_TEMPRATURE =  data.temperature / 100.0f;
    			SENSOR_HUMIDITY   =  data.humidity / 1000.0f;
    			SENSOR_PRESSURE   =  data.pressure / 100.0f;
    		 #endif
    
    	     #if defined (CONFIG_SENSOR_LSM6DSOX)
    	   
                 lsm6dsox_data_read();
    		 #endif
    		}
           coap_client_toggle_mesh_lights();
           k_delayed_work_submit(&coapcloud_work, SENSOR_UPDATE_INTERVAL);
    	
    }
    
    
    /* 
    * @brief init  s_node peripheral
    *@return nothing
    */
    
    void S_node_peripheral_init()
    {
    MOSFET_ENABLE();
    Sensor_init();
    
    }
    
    #if CONFIG_BT_NUS
    
    #define COMMAND_REQUEST_UNICAST 'u'
    #define COMMAND_REQUEST_MULTICAST 'm'
    #define COMMAND_REQUEST_PROVISIONING 'p'
    
    
    
    static void on_nus_received(struct bt_conn *conn, const uint8_t *const data,
    			    uint16_t len)
    {
    	if (len != 1) {
    		LOG_WRN("Received invalid data length (%hd) from NUS", len);
    		return;
    	}
    
    	LOG_INF("Received data: %c", data[0]);
    
    	switch (*data) {
    	case COMMAND_REQUEST_UNICAST:
    		coap_client_toggle_one_light();
    		break;
    
    	case COMMAND_REQUEST_MULTICAST:
    		coap_client_toggle_mesh_lights();
    		break;
    
    	case COMMAND_REQUEST_PROVISIONING:
    		coap_client_send_provisioning_request();
    		break;
    
    	default:
    		LOG_WRN("Received invalid data from NUS");
    	}
    }
    
    
    static void on_ble_connect(struct k_work *item)
    {
    	ARG_UNUSED(item);
    
    	dk_set_led_on(BLE_CONNECTION_LED);
    }
    
    static void on_ble_disconnect(struct k_work *item)
    {
    	ARG_UNUSED(item);
    
    	dk_set_led_off(BLE_CONNECTION_LED);
    }
    
    #endif /* CONFIG_BT_NUS */
    
    static void on_ot_connect(struct k_work *item)
    {
    	ARG_UNUSED(item);
    
    	dk_set_led_on(OT_CONNECTION_LED);
    }
    
    static void on_ot_disconnect(struct k_work *item)
    {
    	ARG_UNUSED(item);
    
    	dk_set_led_off(OT_CONNECTION_LED);
    }
    
    static void on_mtd_mode_toggle(uint32_t med)
    {
    #if IS_ENABLED(CONFIG_DEVICE_POWER_MANAGEMENT)
    	const struct device *cons = device_get_binding(CONSOLE_LABEL);
    
    	if (med) {
    		device_set_power_state(cons, DEVICE_PM_ACTIVE_STATE,
    				       NULL, NULL);
    	} else {
    		device_set_power_state(cons, DEVICE_PM_OFF_STATE,
    				       NULL, NULL);
    	}
    #endif
    	dk_set_led(MTD_SED_LED, med);
    }
    
    static void on_button_changed(uint32_t button_state, uint32_t has_changed)
    {
    	uint32_t buttons = button_state & has_changed;
    
    	if (buttons & DK_BTN4_MSK) {
    		coap_client_toggle_one_light();
    	}
    
    	if (buttons & DK_BTN2_MSK) {
    		coap_client_toggle_mesh_lights();
    	}
    
    	if (buttons & DK_BTN3_MSK) {
    		coap_client_toggle_minimal_sleepy_end_device();
    	}
    
    	if (buttons & DK_BTN1_MSK) {
    		//printf("button press 4\r\n");
    		coap_client_send_provisioning_request();
    
    	}
    }
    
    
    void main(void)
    {
    	int ret;
    	/*USB enable */
    #if defined(CONFIG_USB)
    	const struct device *dev;
    	uint32_t baudrate = 0U;
    
    	dev = device_get_binding(
    		CONFIG_UART_CONSOLE_ON_DEV_NAME);
    	if (!dev) {
    		LOG_ERR("UART device not found");
    		return;
    	}
    
    	ret = usb_enable(NULL);
    	if (ret != 0) {
    		LOG_ERR("Failed to enable USB");
    		return;
    	}
        uart_line_ctrl_get(dev, UART_LINE_CTRL_BAUD_RATE, &baudrate);
    	
    	if (strlen(CONFIG_UART_CONSOLE_ON_DEV_NAME) !=
    	    strlen("CDC_ACM_0") ||
    	    strncmp(CONFIG_UART_CONSOLE_ON_DEV_NAME, "CDC_ACM_0",
    		    strlen(CONFIG_UART_CONSOLE_ON_DEV_NAME))) {
    		printk("Error: Console device name is not USB ACM\n");
    
    		return;
    	}
    #endif /*CONFIG_USB*/
    
    
        S_node_peripheral_init();
        k_delayed_work_init(&coapcloud_work, upload);
        k_delayed_work_submit(&coapcloud_work, K_NO_WAIT); //UPDATE SENSOR DATA INTERVAL
    	
    #if CONFIG_NFC_T4T_NRFXLIB   /* NFC Enable*/
    
    k_delayed_work_init(&update_flash, flash_update);
    k_delayed_work_submit(&update_flash, K_NO_WAIT); 
    	/* Initialize NVS. */
         ndef_file_setup();
    	 	/* Set up NFC */
         nfc_t4t_setup(nfc_callback, NULL);
    	 	/* Run Read-Write mode for Type 4 Tag platform */
    	 nfc_t4t_ndef_rwpayload_set(ndef_msg_buf,sizeof(ndef_msg_buf)) ;
    	 	/* Start sensing NFC field */
    	 nfc_t4t_emulation_start();
    #endif/*CONFIG_NFC_T4T_NRFXLIB*/
     
    	if (IS_ENABLED(CONFIG_RAM_POWER_DOWN_LIBRARY)) {
    		power_down_unused_ram();
    	}
    
    	ret = dk_buttons_init(on_button_changed);
    	if (ret) {
    		LOG_ERR("Cannot init buttons (error: %d)", ret);
    		return;
    	}
    
    	ret = dk_leds_init();
    	if (ret) {
    		LOG_ERR("Cannot init leds, (error: %d)", ret);
    		return;
    	}
    
    #if CONFIG_BT_NUS
    	struct bt_nus_cb nus_clbs = {
    		.received = on_nus_received,
    		.sent = NULL,
    	};
    
    	ret = ble_utils_init(&nus_clbs, on_ble_connect, on_ble_disconnect);
    	if (ret) {
    		LOG_ERR("Cannot init BLE utilities");
    		return;
    	}
    
    #endif /* CONFIG_BT_NUS */
    
    	coap_client_utils_init(on_ot_connect, on_ot_disconnect,
    			       on_mtd_mode_toggle);
    }
    

    /*
     * Copyright (c) 2020 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    #include <zephyr.h>
    #include <coap_server_client_interface.h>
    #include <net/coap_utils.h>
    #include <logging/log.h>
    #include <net/openthread.h>
    #include <net/socket.h>
    #include <openthread/thread.h>
    #include <stdio.h>
    #include "coap_client_utils.h"
    
    // #include "sensor.h"
    
    
    LOG_MODULE_REGISTER(coap_client_utils, CONFIG_COAP_CLIENT_UTILS_LOG_LEVEL);
    
    #define RESPONSE_POLL_PERIOD 100
    
    static uint32_t poll_period;
    
    
    static struct k_work unicast_light_work;
    static struct k_work multicast_light_work;
    static struct k_work toggle_MTD_SED_work;
    static struct k_work provisioning_work;
    static struct k_work on_connect_work;
    static struct k_work on_disconnect_work;
    
    mtd_mode_toggle_cb_t on_mtd_mode_toggle;
    
    /* Options supported by the server */
    static const char *const light_option[] = { LIGHT_URI_PATH, NULL };
    static const char *const provisioning_option[] = { PROVISIONING_URI_PATH,
    						   NULL };
    
    /* Thread multicast mesh local address */
    static struct sockaddr_in6 multicast_local_addr = {
    	.sin6_family = AF_INET6,
    	.sin6_port = htons(COAP_PORT),
    	.sin6_addr.s6_addr = { 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    			       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 },
    	.sin6_scope_id = 0U
    };
    
    /* Variable for storing server address acquiring in provisioning handshake */
    static char unique_local_addr_str[INET6_ADDRSTRLEN];
    static struct sockaddr_in6 unique_local_addr = {
    	.sin6_family = AF_INET6,
    	.sin6_port = htons(COAP_PORT),
    	.sin6_addr.s6_addr = {0, },
    	.sin6_scope_id = 0U
    };
    
    static bool is_mtd_in_med_mode(otInstance *instance)
    {
    	return otThreadGetLinkMode(instance).mRxOnWhenIdle;
    }
    
    static void poll_period_response_set(void)
    {
    	otError error;
    
    	otInstance *instance = openthread_get_default_instance();
    
    	if (is_mtd_in_med_mode(instance)) {
    		return;
    	}
    
    	if (!poll_period) {
    		poll_period = otLinkGetPollPeriod(instance);
    
    		error = otLinkSetPollPeriod(instance, RESPONSE_POLL_PERIOD);
    		__ASSERT(error == OT_ERROR_NONE, "Failed to set pool period");
    
    		LOG_INF("Poll Period: %dms set", RESPONSE_POLL_PERIOD);
    	}
    }
    
    static void poll_period_restore(void)
    {
    	otError error;
    	otInstance *instance = openthread_get_default_instance();
    
    	if (is_mtd_in_med_mode(instance)) {
    		return;
    	}
    
    	if (poll_period) {
    		error = otLinkSetPollPeriod(instance, poll_period);
    		__ASSERT_NO_MSG(error == OT_ERROR_NONE);
    
    		LOG_INF("Poll Period: %dms restored", poll_period);
    		poll_period = 0;
    	}
    }
    
    static int on_provisioning_reply(const struct coap_packet *response,
    				 struct coap_reply *reply,
    				 const struct sockaddr *from)
    {
    	int ret = 0;
    	const uint8_t *payload;
    	uint16_t payload_size = 0u;
    
    	ARG_UNUSED(reply);
    	ARG_UNUSED(from);
    
    	payload = coap_packet_get_payload(response, &payload_size);
    
    	if (payload == NULL ||
    	    payload_size != sizeof(unique_local_addr.sin6_addr)) {
    		LOG_ERR("Received data is invalid");
    		ret = -EINVAL;
    		goto exit;
    	}
    
    	memcpy(&unique_local_addr.sin6_addr, payload, payload_size);
    
    	if (!inet_ntop(AF_INET6, payload, unique_local_addr_str,
    		       INET6_ADDRSTRLEN)) {
    		LOG_ERR("Received data is not IPv6 address: %d", errno);
    		ret = -errno;
    		goto exit;
    	}
    
    	LOG_INF("Received peer address: %s", log_strdup(unique_local_addr_str));
    
    exit:
    	if (IS_ENABLED(CONFIG_OPENTHREAD_MTD_SED)) {
    		poll_period_restore();
    	}
    
    	return ret;
    }
    
    static void toggle_one_light(struct k_work *item)
    {
    	uint8_t payload = (uint8_t)THREAD_COAP_UTILS_LIGHT_CMD_TOGGLE;
    
    	ARG_UNUSED(item);
    
    	if (unique_local_addr.sin6_addr.s6_addr16[0] == 0) {
    		LOG_WRN("Peer address not set. Activate 'provisioning' option "
    			"on the server side");
    		return;
    	}
    
    	LOG_INF("Send 'light' request to: %s",
    		log_strdup(unique_local_addr_str));
    	coap_send_request(COAP_METHOD_PUT,
    			  (const struct sockaddr *)&unique_local_addr,
    			  light_option, &payload, sizeof(payload), NULL);
    }
    
    /*
    @brief send sensor data  on all CoAP servers in the network mesh.
     */
    
    static void toggle_mesh_lights(struct k_work *item)
    {
    	
        static char sensor_buffer[120];
        
    	ARG_UNUSED(item);
    	/* send sensor data */
    	#if defined (CONFIG_SENSOR_SHT35)
          sprintf(sensor_buffer,"%.2f,%.2f",SENSOR_TEMPRATURE,SENSOR_HUMIDITY);
    	#endif
    
    	#if defined (CONFIG_SENSOR_LSM6DSOX)
    	  sprintf(sensor_buffer,"%i %i %i",SENSOR_X,SENSOR_Y,SENSOR_Z);
    	#endif
    
    	#if defined (CONFIG_SENSOR_LPS22HH1B)
    	 sprintf(sensor_buffer,"%.2f %.2f",SENSOR_TEMPRATURE,SENSOR_PRESSURE);
        #endif
    
    	#if defined (CONFIG_SENSOR_BME680)
    	 sprintf(sensor_buffer,"%.2f %.2f %.2f",SENSOR_TEMPRATURE,SENSOR_PRESSURE,SENSOR_HUMIDITY);
        #endif
    
    	#if defined (CONFIG_SENSOR_SI1151)
    	sprintf(sensor_buffer,"ALS:%d",SENSOR_lux);
    	#endif		
                       
                coap_send_request(COAP_METHOD_PUT,
    			  (const struct sockaddr *)&multicast_local_addr,
    			  light_option, &sensor_buffer, sizeof(sensor_buffer), NULL);
                   
                memset(sensor_buffer,0x00,sizeof(sensor_buffer));
          	    // printk("data:%s\r\n",sensor_buffer);
    	
    }
    /*
    static void toggle_mesh_lights(struct k_work *item)
    {
    	static uint8_t command = (uint8_t)THREAD_COAP_UTILS_LIGHT_CMD_OFF;
    
    	ARG_UNUSED(item);
    
    	command = ((command == THREAD_COAP_UTILS_LIGHT_CMD_OFF) ?
    			   THREAD_COAP_UTILS_LIGHT_CMD_ON :
    			   THREAD_COAP_UTILS_LIGHT_CMD_OFF);
    
    	LOG_INF("Send multicast mesh 'light' request");
    	coap_send_request(COAP_METHOD_PUT,
    			  (const struct sockaddr *)&multicast_local_addr,
    			  light_option, &command, sizeof(command), NULL);
    }*/
    
    static void send_provisioning_request(struct k_work *item)
    {
    	ARG_UNUSED(item);
    
    	if (IS_ENABLED(CONFIG_OPENTHREAD_MTD_SED)) {
    		/* decrease the polling period for higher responsiveness */
    		poll_period_response_set();
    	}
    
    	LOG_INF("Send 'provisioning' request");
    	coap_send_request(COAP_METHOD_GET,
    			  (const struct sockaddr *)&multicast_local_addr,
    			  provisioning_option, NULL, 0u, on_provisioning_reply);
    }
    
    static void toggle_minimal_sleepy_end_device(struct k_work *item)
    {
    	otError error;
    	otLinkModeConfig mode;
    	struct openthread_context *context = openthread_get_default_context();
    
    	__ASSERT_NO_MSG(context != NULL);
    
    	openthread_api_mutex_lock(context);
    	mode = otThreadGetLinkMode(context->instance);
    	mode.mRxOnWhenIdle = !mode.mRxOnWhenIdle;
    	error = otThreadSetLinkMode(context->instance, mode);
    	openthread_api_mutex_unlock(context);
    
    	if (error != OT_ERROR_NONE) {
    		LOG_ERR("Failed to set MLE link mode configuration");
    	} else {
    		on_mtd_mode_toggle(mode.mRxOnWhenIdle);
    	}
    }
    
    static void update_device_state(void)
    {
    	struct otInstance *instance = openthread_get_default_instance();
    	otLinkModeConfig mode = otThreadGetLinkMode(instance);
    	on_mtd_mode_toggle(mode.mRxOnWhenIdle);
    }
    
    static void on_thread_state_changed(uint32_t flags, void *context)
    {
    	struct openthread_context *ot_context = context;
    
    	if (flags & OT_CHANGED_THREAD_ROLE) {
    		switch (otThreadGetDeviceRole(ot_context->instance)) {
    		case OT_DEVICE_ROLE_CHILD:
    		case OT_DEVICE_ROLE_ROUTER:
    		case OT_DEVICE_ROLE_LEADER:
    			k_work_submit(&on_connect_work);
    			is_connected = true;
    			break;
    
    		case OT_DEVICE_ROLE_DISABLED:
    		case OT_DEVICE_ROLE_DETACHED:
    		 default:
    			k_work_submit(&on_disconnect_work);
    			is_connected = false;
    			break;
    		}
    	}
    }
    
    static void submit_work_if_connected(struct k_work *work)
    {
    	if (is_connected) {
    		k_work_submit(work);
    	} else {
    		LOG_INF("Connection is broken");
    		// printk("Node DETACHED\r\n");
    	}
    }
    /*
    @brief coap_client initlize function 
    */
    void coap_client_utils_init(ot_connection_cb_t on_connect,
    			    ot_disconnection_cb_t on_disconnect,
    			    mtd_mode_toggle_cb_t on_toggle)
    {
    	on_mtd_mode_toggle = on_toggle;
    
    	coap_init(AF_INET6, NULL);
    
    	k_work_init(&on_connect_work, on_connect);
    	k_work_init(&on_disconnect_work, on_disconnect);
    	k_work_init(&unicast_light_work, toggle_one_light);
    	k_work_init(&multicast_light_work, toggle_mesh_lights);
    	k_work_init(&provisioning_work, send_provisioning_request);
    
    	openthread_set_state_changed_cb(on_thread_state_changed);
    	openthread_start(openthread_get_default_context());
    
    	if (IS_ENABLED(CONFIG_OPENTHREAD_MTD_SED)) {
    		k_work_init(&toggle_MTD_SED_work,
    			    toggle_minimal_sleepy_end_device);
    		update_device_state();
    	}
    }
    
    void coap_client_toggle_one_light(void)
    {
    	submit_work_if_connected(&unicast_light_work);
    }
    
    void coap_client_toggle_mesh_lights(void)
    {
    	submit_work_if_connected(&multicast_light_work);
    }
    
    void coap_client_send_provisioning_request(void)
    {
    	submit_work_if_connected(&provisioning_work);
    }
    
    void coap_client_toggle_minimal_sleepy_end_device(void)
    {
    	if (IS_ENABLED(CONFIG_OPENTHREAD_MTD_SED)) {
    		k_work_submit(&toggle_MTD_SED_work);
    	}
    }
    

    If Scenario 1 (different URI path for each sensor/device) is the right way to go, I would need the COAP Server implementation with multiple URI paths on which different sensor client nodes are updating data on different URI paths. Client side implementation seems easy as you can see in my recent post too.

Children
  • Hi McGregor,

    McGregor said:
    But before we proceed forward, i just want to once again make sure whether i should use single URI path for different sensor nodes/devices or multiple URI paths (one for each sensor node/devices).

     As I mentioned before, you have the freedom to define your communication protocol on top of CoAP. I think both of them are OK. I would prefer Scenario 1 as it can separate topics and values/commands properly, but this is only my personal taste. You can choose any of them that can solve your needs.

    Best regards,
    Charlie

Related