This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC1350: Contiki-ng Web demo, add I2C process

Expert 1600 points

Part Number: CC1350
Other Parts Discussed in Thread: TMP006, HDC1000

Hello, 

- I'm using CC26x0 Web demo example in contiki-ng, pn CC1350 launchpad.

- The launchpad is connected to HTU21D Humidity and Temperature sensor which uses I2C to trigger and read measurements.

The objective is to have a Process that opens the I2C communication, send commands to the sensor, then read the measurements, and publish it as sensor reading.

- I'm wondering where in the code should I add the I2C process? Is there an example of an I2C process in Contiki-ng for the launchpad which I can append to the web-demo example?

Thanks

  • cc26xx-web-demo contains I2C tmp006 example and you can refer to it to do porting accordingly.

  • Could you please detail?

    In arch/platform/cc26x0-cc13x0/sensortag, I see:

    - board-i2c.c
    - board-i2c.h
    - tmp-007.c
    - tmp-007.h
    - sensor-common.c
    - sensor-common.h

    which are not found under the launchpad directory arch/platform/cc26x0-cc13x0/launchpad, am should I copy them then replace tmp-007 by HTU?

    Could you please explain a simple case: how to use tmp-007 with the Launchpad (not the sensortag board) in  contiki-ng CC26x0-web-demo? 

  • You should copy the following four files:

    - board-i2c.c

    - board-i2c.h

    - sensor-common.c

    - sensor-common.h

    And clone the following two files

    - tmp-007.c

    - tmp-007.h

    to

    - HTU21D.c

    - HTU21D.h

    Then, revise the register value in HTU21D.c/HTU21D.h according to HTU21D data sheet to make it work.

  • Thanks I did that, for hdc_1000_Sensor (because it's very similar to htu21d) and I'm getting this error when I build:

    undefined reference to `hdc_1000_sensor'  in the following function:

    static void
    init_hdc_reading(void *data)
    {
      if(hdc_hum_reading.publish || hdc_temp_reading.publish) {
        SENSORS_ACTIVATE(hdc_1000_sensor);
      } else {
        ctimer_set(&hdc_timer, CLOCK_SECOND, init_hdc_reading, NULL);
      }
    }

    Attached is my cc26xx-web-demo.c

    /*
     * Copyright (c) 2014, Texas Instruments Incorporated - http://www.ti.com/
     * 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 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 the copyright holder nor the names of its
     *    contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
     * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
     * COPYRIGHT HOLDER 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.
     */
    /**
     * \addtogroup cc26x0-web-demo
     * @{
     *
     * \file
     *   Main module for the CC26XX web demo. Activates on-device resources,
     *   takes sensor readings periodically and caches them for all other modules
     *   to use.
     */
    /*---------------------------------------------------------------------------*/
    #include "contiki.h"
    #include "contiki-net.h"
    #include "coap-engine.h"
    #include "board-peripherals.h"
    #include "lib/sensors.h"
    #include "lib/list.h"
    #include "sys/process.h"
    #include "sys/energest.h"
    #include "net/ipv6/sicslowpan.h"
    #include "dev/button-hal.h"
    #include "batmon-sensor.h"
    #include "httpd-simple.h"
    #include "mqtt-client.h"
    #include "coap-server.h"
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <strings.h>
    
    #include "cc26x0-web-demo-extended.h"
    #include "ti-lib.h"
    #if 1
    #include "hdc-1000-sensor.h"
    #endif
    /*---------------------------------------------------------------------------*/
    PROCESS_NAME(cetic_6lbr_client_process);
    PROCESS(cc26xx_web_demo_process, "CC26XX Web Demo");
    /*---------------------------------------------------------------------------*/
    /*
     * Update sensor readings in a staggered fashion every SENSOR_READING_PERIOD
     * ticks + a random interval between 0 and SENSOR_READING_RANDOM ticks
     */
    #define SENSOR_READING_PERIOD (CLOCK_SECOND * 20)
    #define SENSOR_READING_RANDOM (CLOCK_SECOND << 4)
    
    struct ctimer batmon_timer;
    
    #if 1
    struct ctimer hdc_timer;
    #endif
    #if BOARD_SENSORTAG
    struct ctimer bmp_timer, hdc_timer, tmp_timer, opt_timer, mpu_timer;
    #endif
    /*---------------------------------------------------------------------------*/
    /* Provide visible feedback via LEDS while searching for a network */
    #define NO_NET_LED_DURATION        (CC26XX_WEB_DEMO_NET_CONNECT_PERIODIC >> 1)
    
    static struct etimer et;
    static struct ctimer ct;
    /*---------------------------------------------------------------------------*/
    /* Parent RSSI functionality */
    #if CC26XX_WEB_DEMO_READ_PARENT_RSSI
    static struct uip_icmp6_echo_reply_notification echo_reply_notification;
    static struct etimer echo_request_timer;
    int def_rt_rssi = 0;
    #endif
    /*---------------------------------------------------------------------------*/
    #if CC26XX_WEB_DEMO_CONF_ADC_DEMO
    PROCESS(adc_process, "ADC process");
    static struct etimer et_adc;
    #if CC26XX_WEB_DEMO_ADC_DEMO_0
    static uint16_t single_adc_sample_0;
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_1
    static uint16_t single_adc_sample_1;
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_2
    static uint16_t single_adc_sample_2;
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_3
    static uint16_t single_adc_sample_3;
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_4
    static uint16_t single_adc_sample_4;
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_5
    static uint16_t single_adc_sample_5;
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_6
    static uint16_t single_adc_sample_6;
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_7
    static uint16_t single_adc_sample_7;
    #endif
    #endif
    
    #if CC26XX_WEB_DEMO_GPIO_READ
    PROCESS(gpio_read_process, "GPIO_read process");
    static gpio_hal_pin_mask_t gpio_reading;
    static struct etimer et_gpio_read;
    #endif
    
    #if ENERGEST_CONF_ON
    PROCESS(energest_process, "ENERGEST process");
    static struct etimer et_energest;
    #endif
    
    /*---------------------------------------------------------------------------*/
    process_event_t cc26xx_web_demo_publish_event;
    process_event_t cc26xx_web_demo_config_loaded_event;
    process_event_t cc26xx_web_demo_load_config_defaults;
    /*---------------------------------------------------------------------------*/
    /* Saved settings on flash: store, offset, magic */
    #define CONFIG_FLASH_OFFSET        0
    #define CONFIG_MAGIC      0xCC265002
    
    cc26xx_web_demo_config_t cc26xx_web_demo_config;
    /*---------------------------------------------------------------------------*/
    /* A cache of sensor values. Updated periodically or upon key press */
    LIST(sensor_list);
    /*---------------------------------------------------------------------------*/
    /* The objects representing sensors used in this demo */
    #define DEMO_SENSOR(name, type, descr, xml_element, form_field, units) \
      cc26xx_web_demo_sensor_reading_t name##_reading = \
      { NULL, 0, 0, descr, xml_element, form_field, units, type, 1, 1 }
    
    /* CC26xx sensors */
    DEMO_SENSOR(batmon_temp, CC26XX_WEB_DEMO_SENSOR_BATMON_TEMP,
                "Battery Temp", "battery-temp", "batmon_temp",
                CC26XX_WEB_DEMO_UNIT_TEMP);
    DEMO_SENSOR(batmon_volt, CC26XX_WEB_DEMO_SENSOR_BATMON_VOLT,
                "Battery Volt", "battery-volt", "batmon_volt",
                CC26XX_WEB_DEMO_UNIT_VOLT);
    
    #if CC26XX_WEB_DEMO_ADC_DEMO_0
    DEMO_SENSOR(adc_dio23, CC26XX_WEB_DEMO_SENSOR_ADC_DIO23,
                "ADC DIO23", "adc-dio23", "adc_dio23",
                CC26XX_WEB_DEMO_UNIT_VOLT);
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_1
    DEMO_SENSOR(adc_dio24, CC26XX_WEB_DEMO_SENSOR_ADC_DIO24,
                "ADC DIO24", "adc-dio24", "adc_dio24",
                CC26XX_WEB_DEMO_UNIT_VOLT);
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_2
    DEMO_SENSOR(adc_dio25, CC26XX_WEB_DEMO_SENSOR_ADC_DIO25,
                "ADC DIO25", "adc-dio25", "adc_dio25",
                CC26XX_WEB_DEMO_UNIT_VOLT);
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_3
    DEMO_SENSOR(adc_dio26, CC26XX_WEB_DEMO_SENSOR_ADC_DIO26,
                "ADC DIO26", "adc-dio26", "adc_dio26",
                CC26XX_WEB_DEMO_UNIT_VOLT);
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_4
    DEMO_SENSOR(adc_dio27, CC26XX_WEB_DEMO_SENSOR_ADC_DIO27,
                "ADC DIO27", "adc-dio27", "adc_dio27",
                CC26XX_WEB_DEMO_UNIT_VOLT);
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_5
    DEMO_SENSOR(adc_dio28, CC26XX_WEB_DEMO_SENSOR_ADC_DIO28,
                "ADC DIO28", "adc-dio28", "adc_dio28",
                CC26XX_WEB_DEMO_UNIT_VOLT);
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_6
    DEMO_SENSOR(adc_dio29, CC26XX_WEB_DEMO_SENSOR_ADC_DIO29,
                "ADC DIO29", "adc-dio29", "adc_dio29",
                CC26XX_WEB_DEMO_UNIT_VOLT);
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_7
    DEMO_SENSOR(adc_dio30, CC26XX_WEB_DEMO_SENSOR_ADC_DIO30,
                "ADC DIO30", "adc-dio30", "adc_dio30",
                CC26XX_WEB_DEMO_UNIT_VOLT);
    #endif
    
    #if CC26XX_WEB_DEMO_GPIO_READ
    DEMO_SENSOR(gpio_read, CC26XX_WEB_DEMO_SENSOR_GPIO_READ,
                "GPIO Read", "gpio-read", "gpio_read",
                "");
    #endif
    
    /* Sensortag sensors */
    #if 1
    DEMO_SENSOR(hdc_temp, CC26XX_WEB_DEMO_SENSOR_HDC_TEMP,
                "HDC Temp", "hdc-temp", "hdc_temp",
                CC26XX_WEB_DEMO_UNIT_TEMP);
    DEMO_SENSOR(hdc_hum, CC26XX_WEB_DEMO_SENSOR_HDC_HUMIDITY,
                "HDC Humidity", "hdc-humidity", "hdc_hum",
                CC26XX_WEB_DEMO_UNIT_HUMIDITY);
    #endif
    #if BOARD_SENSORTAG
    DEMO_SENSOR(bmp_pres, CC26XX_WEB_DEMO_SENSOR_BMP_PRES,
                "Air Pressure", "air-pressure", "bmp_pres",
                CC26XX_WEB_DEMO_UNIT_PRES);
    DEMO_SENSOR(bmp_temp, CC26XX_WEB_DEMO_SENSOR_BMP_TEMP,
                "Air Temp", "air-temp", "bmp_temp",
                CC26XX_WEB_DEMO_UNIT_TEMP);
    DEMO_SENSOR(hdc_temp, CC26XX_WEB_DEMO_SENSOR_HDC_TEMP,
                "HDC Temp", "hdc-temp", "hdc_temp",
                CC26XX_WEB_DEMO_UNIT_TEMP);
    DEMO_SENSOR(hdc_hum, CC26XX_WEB_DEMO_SENSOR_HDC_HUMIDITY,
                "HDC Humidity", "hdc-humidity", "hdc_hum",
                CC26XX_WEB_DEMO_UNIT_HUMIDITY);
    DEMO_SENSOR(tmp_amb, CC26XX_WEB_DEMO_SENSOR_TMP_AMBIENT,
                "Ambient Temp", "ambient-temp", "tmp_amb",
                CC26XX_WEB_DEMO_UNIT_TEMP);
    DEMO_SENSOR(tmp_obj, CC26XX_WEB_DEMO_SENSOR_TMP_OBJECT,
                "Object Temp", "object-temp", "tmp_obj",
                CC26XX_WEB_DEMO_UNIT_TEMP);
    DEMO_SENSOR(opt, CC26XX_WEB_DEMO_SENSOR_OPT_LIGHT,
                "Light", "light", "light",
                CC26XX_WEB_DEMO_UNIT_LIGHT);
    
    /* MPU Readings */
    DEMO_SENSOR(mpu_acc_x, CC26XX_WEB_DEMO_SENSOR_MPU_ACC_X,
                "Acc X", "acc-x", "acc_x",
                CC26XX_WEB_DEMO_UNIT_ACC);
    DEMO_SENSOR(mpu_acc_y, CC26XX_WEB_DEMO_SENSOR_MPU_ACC_Y,
                "Acc Y", "acc-y", "acc_y",
                CC26XX_WEB_DEMO_UNIT_ACC);
    DEMO_SENSOR(mpu_acc_z, CC26XX_WEB_DEMO_SENSOR_MPU_ACC_Z,
                "Acc Z", "acc-z", "acc_z",
                CC26XX_WEB_DEMO_UNIT_ACC);
    
    DEMO_SENSOR(mpu_gyro_x, CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_X,
                "Gyro X", "gyro-x", "gyro_x",
                CC26XX_WEB_DEMO_UNIT_GYRO);
    DEMO_SENSOR(mpu_gyro_y, CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_Y,
                "Gyro Y", "gyro-y", "gyro_y",
                CC26XX_WEB_DEMO_UNIT_GYRO);
    DEMO_SENSOR(mpu_gyro_z, CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_Z,
                "Gyro Z", "gyro-z", "gyro_Z",
                CC26XX_WEB_DEMO_UNIT_GYRO);
    #endif
    /*---------------------------------------------------------------------------*/
    #if 1
    static void init_hdc_reading(void *data);
    #endif
    #if BOARD_SENSORTAG
    static void init_bmp_reading(void *data);
    static void init_light_reading(void *data);
    static void init_hdc_reading(void *data);
    static void init_tmp_reading(void *data);
    static void init_mpu_reading(void *data);
    #endif
    /*---------------------------------------------------------------------------*/
    static void
    publish_led_off(void *d)
    {
      leds_off(CC26XX_WEB_DEMO_STATUS_LED);
    }
    /*---------------------------------------------------------------------------*/
    static void
    save_config()
    {
      /* Dump current running config to flash */
    #if BOARD_SENSORTAG || BOARD_LAUNCHPAD
      int rv;
      cc26xx_web_demo_sensor_reading_t *reading = NULL;
    
      rv = ext_flash_open(NULL);
    
      if(!rv) {
        printf("Could not open flash to save config\n");
        ext_flash_close(NULL);
        return;
      }
    
      rv = ext_flash_erase(NULL, CONFIG_FLASH_OFFSET, sizeof(cc26xx_web_demo_config_t));
    
      if(!rv) {
        printf("Error erasing flash\n");
      } else {
        cc26xx_web_demo_config.magic = CONFIG_MAGIC;
        cc26xx_web_demo_config.len = sizeof(cc26xx_web_demo_config_t);
        cc26xx_web_demo_config.sensors_bitmap = 0;
    
        for(reading = list_head(sensor_list);
            reading != NULL;
            reading = list_item_next(reading)) {
          if(reading->publish) {
            cc26xx_web_demo_config.sensors_bitmap |= (1 << reading->type);
          }
        }
    
        rv = ext_flash_write(NULL, CONFIG_FLASH_OFFSET, sizeof(cc26xx_web_demo_config_t),
                             (uint8_t *)&cc26xx_web_demo_config);
        if(!rv) {
          printf("Error saving config\n");
        }
      }
    
      ext_flash_close(NULL);
    #endif
    }
    /*---------------------------------------------------------------------------*/
    static void
    load_config()
    {
    #if BOARD_SENSORTAG || BOARD_LAUNCHPAD
      /* Read from flash into a temp buffer */
      cc26xx_web_demo_config_t tmp_cfg;
      cc26xx_web_demo_sensor_reading_t *reading = NULL;
    
      int rv = ext_flash_open(NULL);
    
      if(!rv) {
        printf("Could not open flash to load config\n");
        ext_flash_close(NULL);
        return;
      }
    
      rv = ext_flash_read(NULL, CONFIG_FLASH_OFFSET, sizeof(tmp_cfg),
                          (uint8_t *)&tmp_cfg);
    
      ext_flash_close(NULL);
    
      if(!rv) {
        printf("Error loading config\n");
        return;
      }
    
      if(tmp_cfg.magic == CONFIG_MAGIC && tmp_cfg.len == sizeof(tmp_cfg)) {
        memcpy(&cc26xx_web_demo_config, &tmp_cfg, sizeof(cc26xx_web_demo_config));
      }
    
      for(reading = list_head(sensor_list);
          reading != NULL;
          reading = list_item_next(reading)) {
        if(cc26xx_web_demo_config.sensors_bitmap & (1 << reading->type)) {
          reading->publish = 1;
        } else {
          reading->publish = 0;
          snprintf(reading->converted, CC26XX_WEB_DEMO_CONVERTED_LEN, "\"N/A\"");
        }
      }
    #endif
    }
    /*---------------------------------------------------------------------------*/
    /* Don't start everything here, we need to dictate order of initialisation */
    AUTOSTART_PROCESSES(&cc26xx_web_demo_process);
    /*---------------------------------------------------------------------------*/
    int
    cc26xx_web_demo_ipaddr_sprintf(char *buf, uint8_t buf_len,
                                   const uip_ipaddr_t *addr)
    {
      uint16_t a;
      uint8_t len = 0;
      int i, f;
      for(i = 0, f = 0; i < sizeof(uip_ipaddr_t); i += 2) {
        a = (addr->u8[i] << 8) + addr->u8[i + 1];
        if(a == 0 && f >= 0) {
          if(f++ == 0) {
            len += snprintf(&buf[len], buf_len - len, "::");
          }
        } else {
          if(f > 0) {
            f = -1;
          } else if(i > 0) {
            len += snprintf(&buf[len], buf_len - len, ":");
          }
          len += snprintf(&buf[len], buf_len - len, "%x", a);
        }
      }
    
      return len;
    }
    /*---------------------------------------------------------------------------*/
    const cc26xx_web_demo_sensor_reading_t *
    cc26xx_web_demo_sensor_lookup(int sens_type)
    {
      cc26xx_web_demo_sensor_reading_t *reading = NULL;
    
      for(reading = list_head(sensor_list);
          reading != NULL;
          reading = list_item_next(reading)) {
        if(reading->type == sens_type) {
          return reading;
        }
      }
    
      return NULL;
    }
    /*---------------------------------------------------------------------------*/
    const cc26xx_web_demo_sensor_reading_t *
    cc26xx_web_demo_sensor_first()
    {
      return list_head(sensor_list);
    }
    /*---------------------------------------------------------------------------*/
    void
    cc26xx_web_demo_restore_defaults(void)
    {
      cc26xx_web_demo_sensor_reading_t *reading = NULL;
    
      leds_on(LEDS_ALL);
    
      for(reading = list_head(sensor_list);
          reading != NULL;
          reading = list_item_next(reading)) {
        reading->publish = 1;
      }
    
    #if CC26XX_WEB_DEMO_MQTT_CLIENT
      process_post_synch(&mqtt_client_process,
                         cc26xx_web_demo_load_config_defaults, NULL);
    #endif
    
    #if CC26XX_WEB_DEMO_NET_UART
      process_post_synch(&net_uart_process, cc26xx_web_demo_load_config_defaults,
                         NULL);
    #endif
    
      save_config();
    
      leds_off(LEDS_ALL);
    }
    /*---------------------------------------------------------------------------*/
    static int
    defaults_post_handler(char *key, int key_len, char *val, int val_len)
    {
      if(key_len != strlen("defaults") ||
         strncasecmp(key, "defaults", strlen("defaults")) != 0) {
        /* Not ours */
        return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN;
      }
    
      cc26xx_web_demo_restore_defaults();
    
      return HTTPD_SIMPLE_POST_HANDLER_OK;
    }
    /*---------------------------------------------------------------------------*/
    static int
    sensor_readings_handler(char *key, int key_len, char *val, int val_len)
    {
      cc26xx_web_demo_sensor_reading_t *reading = NULL;
      int rv;
    
      for(reading = list_head(sensor_list);
          reading != NULL;
          reading = list_item_next(reading)) {
        if(key_len == strlen(reading->form_field) &&
           strncmp(reading->form_field, key, strlen(key)) == 0) {
    
          rv = atoi(val);
    
          /* Be pedantic: only accept 0 and 1, not just any non-zero value */
          if(rv == 0) {
            reading->publish = 0;
            snprintf(reading->converted, CC26XX_WEB_DEMO_CONVERTED_LEN, "\"N/A\"");
          } else if(rv == 1) {
            reading->publish = 1;
          } else {
            return HTTPD_SIMPLE_POST_HANDLER_ERROR;
          }
    
          return HTTPD_SIMPLE_POST_HANDLER_OK;
        }
      }
    
      return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN;
    }
    /*---------------------------------------------------------------------------*/
    #if CC26XX_WEB_DEMO_READ_PARENT_RSSI
    static int
    ping_interval_post_handler(char *key, int key_len, char *val, int val_len)
    {
      int rv = 0;
    
      if(key_len != strlen("ping_interval") ||
         strncasecmp(key, "ping_interval", strlen("ping_interval")) != 0) {
        /* Not ours */
        return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN;
      }
    
      rv = atoi(val);
    
      if(rv < CC26XX_WEB_DEMO_RSSI_MEASURE_INTERVAL_MIN ||
         rv > CC26XX_WEB_DEMO_RSSI_MEASURE_INTERVAL_MAX) {
        return HTTPD_SIMPLE_POST_HANDLER_ERROR;
      }
    
      cc26xx_web_demo_config.def_rt_ping_interval = rv * CLOCK_SECOND;
    
      return HTTPD_SIMPLE_POST_HANDLER_OK;
    }
    #endif
    /*---------------------------------------------------------------------------*/
    HTTPD_SIMPLE_POST_HANDLER(sensor, sensor_readings_handler);
    HTTPD_SIMPLE_POST_HANDLER(defaults, defaults_post_handler);
    
    #if CC26XX_WEB_DEMO_READ_PARENT_RSSI
    HTTPD_SIMPLE_POST_HANDLER(ping_interval, ping_interval_post_handler);
    /*---------------------------------------------------------------------------*/
    static void
    echo_reply_handler(uip_ipaddr_t *source, uint8_t ttl, uint8_t *data,
                       uint16_t datalen)
    {
      if(uip_ip6addr_cmp(source, uip_ds6_defrt_choose())) {
        def_rt_rssi = sicslowpan_get_last_rssi();
      }
    }
    /*---------------------------------------------------------------------------*/
    static void
    ping_parent(void)
    {
      if(uip_ds6_get_global(ADDR_PREFERRED) == NULL) {
        return;
      }
    
      uip_icmp6_send(uip_ds6_defrt_choose(), ICMP6_ECHO_REQUEST, 0,
                     CC26XX_WEB_DEMO_ECHO_REQ_PAYLOAD_LEN);
    }
    #endif
    /*---------------------------------------------------------------------------*/
    
    /* ========================================================================= */
    /*---------------------------------------------------------------------------*/
    /*--- SENSORS VALES: START --------------------------------------------------*/
    /*---------------------------------------------------------------------------*/
    static void
    get_batmon_reading(void *data)
    {
      int value;
      char *buf;
      clock_time_t next = SENSOR_READING_PERIOD +
        (random_rand() % SENSOR_READING_RANDOM);
    
      if(batmon_temp_reading.publish) {
        value = batmon_sensor.value(BATMON_SENSOR_TYPE_TEMP);
        if(value != CC26XX_SENSOR_READING_ERROR) {
          batmon_temp_reading.raw = value;
    
          buf = batmon_temp_reading.converted;
          memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
          snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d", value);
        }
      }
    
      if(batmon_volt_reading.publish) {
        value = batmon_sensor.value(BATMON_SENSOR_TYPE_VOLT);
        if(value != CC26XX_SENSOR_READING_ERROR) {
          batmon_volt_reading.raw = value;
    
          buf = batmon_volt_reading.converted;
          memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
          snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d", (value * 125) >> 5);
        }
      }
    
      ctimer_set(&batmon_timer, next, get_batmon_reading, NULL);
    }
    /*---------------------------------------------------------------------------*/
    #if CC26XX_WEB_DEMO_CONF_ADC_DEMO
    static void
    get_adc_reading(void *data)
    {
        int value;
        char *buf;
    
    #if CC26XX_WEB_DEMO_ADC_DEMO_0
      if(adc_dio23_reading.publish) {
        value = single_adc_sample_0;
        buf = adc_dio23_reading.converted;
        memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
        snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d", (value * 4300) >> 12);
      }
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_1
      if(adc_dio24_reading.publish) {
        value = single_adc_sample_1;
        buf = adc_dio24_reading.converted;
        memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
        snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d", (value * 4300) >> 12);
      }
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_2
      if(adc_dio25_reading.publish) {
        value = single_adc_sample_2;
        buf = adc_dio25_reading.converted;
        memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
        snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d", (value * 4300) >> 12);
      }
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_3
      if(adc_dio26_reading.publish) {
        value = single_adc_sample_3;
        buf = adc_dio26_reading.converted;
        memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
        snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d", (value * 4300) >> 12);
      }
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_4
      if(adc_dio27_reading.publish) {
        value = single_adc_sample_4;
        buf = adc_dio27_reading.converted;
        memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
        snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d", (value * 4300) >> 12);
      }
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_5
      if(adc_dio28_reading.publish) {
        value = single_adc_sample_5;
        buf = adc_dio28_reading.converted;
        memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
        snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d", (value * 4300) >> 12);
      }
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_6
      if(adc_dio29_reading.publish) {
        value = single_adc_sample_6;
        buf = adc_dio29_reading.converted;
        memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
        snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d", (value * 4300) >> 12);
      }
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_7
      if(adc_dio30_reading.publish) {
        value = single_adc_sample_7;
        buf = adc_dio30_reading.converted;
        memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
        snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d", (value * 4300) >> 12);
      }
    #endif
    }
    #endif
    
    #if CC26XX_WEB_DEMO_GPIO_READ
    static void
    get_gpio_reading(void *data)
    {
      int value;
      char *buf;
    
      if(gpio_read_reading.publish) {
        value = gpio_reading;
        buf = gpio_read_reading.converted;
        memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
        snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "0x%08X", (value));
      }
    }
    #endif
    
    /*---------------------------------------------------------------------------*/
    #if 1
    static void
    compare_and_update(cc26xx_web_demo_sensor_reading_t *reading)
    {
      if(reading->last == reading->raw) {
        reading->changed = 0;
      } else {
        reading->last = reading->raw;
        reading->changed = 1;
      }
    }
    /*---------------------------------------------------------------------------*/
    static void
    get_hdc_reading()
    {
      int value;
      char *buf;
      clock_time_t next = SENSOR_READING_PERIOD +
        (random_rand() % SENSOR_READING_RANDOM);
    
      if(hdc_temp_reading.publish) {
        value = hdc_1000_sensor.value(HDC_1000_SENSOR_TYPE_TEMP);
        if(value != CC26XX_SENSOR_READING_ERROR) {
          hdc_temp_reading.raw = value;
    
          compare_and_update(&hdc_temp_reading);
    
          buf = hdc_temp_reading.converted;
          memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
          snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100,
                   value % 100);
        }
      }
    
      if(hdc_hum_reading.publish) {
        value = hdc_1000_sensor.value(HDC_1000_SENSOR_TYPE_HUMID);
        if(value != CC26XX_SENSOR_READING_ERROR) {
          hdc_hum_reading.raw = value;
    
          compare_and_update(&hdc_hum_reading);
    
          buf = hdc_hum_reading.converted;
          memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
          snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100,
                   value % 100);
        }
      }
    
      ctimer_set(&hdc_timer, next, init_hdc_reading, NULL);
    }
    /*---------------------------------------------------------------------------*/
    static void
    init_hdc_reading(void *data)
    {
      if(hdc_hum_reading.publish || hdc_temp_reading.publish) {
        SENSORS_ACTIVATE(hdc_1000_sensor);
      } else {
        ctimer_set(&hdc_timer, CLOCK_SECOND, init_hdc_reading, NULL);
      }
    }
    /*---------------------------------------------------------------------------*/
    #endif
    #if BOARD_SENSORTAG
    /*---------------------------------------------------------------------------*/
    static void
    compare_and_update(cc26xx_web_demo_sensor_reading_t *reading)
    {
      if(reading->last == reading->raw) {
        reading->changed = 0;
      } else {
        reading->last = reading->raw;
        reading->changed = 1;
      }
    }
    /*---------------------------------------------------------------------------*/
    static void
    print_mpu_reading(int reading, char *buf)
    {
      char *loc_buf = buf;
    
      if(reading < 0) {
        sprintf(loc_buf, "-");
        reading = -reading;
        loc_buf++;
      }
    
      sprintf(loc_buf, "%d.%02d", reading / 100, reading % 100);
    }
    /*---------------------------------------------------------------------------*/
    static void
    get_bmp_reading()
    {
      int value;
      char *buf;
      clock_time_t next = SENSOR_READING_PERIOD +
        (random_rand() % SENSOR_READING_RANDOM);
    
      if(bmp_pres_reading.publish) {
        value = bmp_280_sensor.value(BMP_280_SENSOR_TYPE_PRESS);
        if(value != CC26XX_SENSOR_READING_ERROR) {
          bmp_pres_reading.raw = value;
    
          compare_and_update(&bmp_pres_reading);
    
          buf = bmp_pres_reading.converted;
          memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
          snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100,
                   value % 100);
        }
      }
    
      if(bmp_temp_reading.publish) {
        value = bmp_280_sensor.value(BMP_280_SENSOR_TYPE_TEMP);
        if(value != CC26XX_SENSOR_READING_ERROR) {
          bmp_temp_reading.raw = value;
    
          compare_and_update(&bmp_temp_reading);
    
          buf = bmp_temp_reading.converted;
          memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
          snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100,
                   value % 100);
        }
      }
    
      SENSORS_DEACTIVATE(bmp_280_sensor);
    
      ctimer_set(&bmp_timer, next, init_bmp_reading, NULL);
    }
    /*---------------------------------------------------------------------------*/
    static void
    get_tmp_reading()
    {
      int value;
      char *buf;
      clock_time_t next = SENSOR_READING_PERIOD +
        (random_rand() % SENSOR_READING_RANDOM);
    
      if(tmp_amb_reading.publish || tmp_obj_reading.publish) {
        if(tmp_007_sensor.value(TMP_007_SENSOR_TYPE_ALL) ==
           CC26XX_SENSOR_READING_ERROR) {
    
          SENSORS_DEACTIVATE(tmp_007_sensor);
          ctimer_set(&tmp_timer, next, init_tmp_reading, NULL);
        }
      }
    
      if(tmp_amb_reading.publish) {
        value = tmp_007_sensor.value(TMP_007_SENSOR_TYPE_AMBIENT);
        tmp_amb_reading.raw = value;
    
        compare_and_update(&tmp_amb_reading);
    
        buf = tmp_amb_reading.converted;
        memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
        snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%03d", value / 1000,
                 value % 1000);
      }
    
      if(tmp_obj_reading.publish) {
        value = tmp_007_sensor.value(TMP_007_SENSOR_TYPE_OBJECT);
        tmp_obj_reading.raw = value;
    
        compare_and_update(&tmp_obj_reading);
    
        buf = tmp_obj_reading.converted;
        memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
        snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%03d", value / 1000,
                 value % 1000);
      }
    
      SENSORS_DEACTIVATE(tmp_007_sensor);
    
      ctimer_set(&tmp_timer, next, init_tmp_reading, NULL);
    }
    /*---------------------------------------------------------------------------*/
    static void
    get_hdc_reading()
    {
      int value;
      char *buf;
      clock_time_t next = SENSOR_READING_PERIOD +
        (random_rand() % SENSOR_READING_RANDOM);
    
      if(hdc_temp_reading.publish) {
        value = hdc_1000_sensor.value(HDC_1000_SENSOR_TYPE_TEMP);
        if(value != CC26XX_SENSOR_READING_ERROR) {
          hdc_temp_reading.raw = value;
    
          compare_and_update(&hdc_temp_reading);
    
          buf = hdc_temp_reading.converted;
          memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
          snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100,
                   value % 100);
        }
      }
    
      if(hdc_hum_reading.publish) {
        value = hdc_1000_sensor.value(HDC_1000_SENSOR_TYPE_HUMID);
        if(value != CC26XX_SENSOR_READING_ERROR) {
          hdc_hum_reading.raw = value;
    
          compare_and_update(&hdc_hum_reading);
    
          buf = hdc_hum_reading.converted;
          memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
          snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100,
                   value % 100);
        }
      }
    
      ctimer_set(&hdc_timer, next, init_hdc_reading, NULL);
    }
    /*---------------------------------------------------------------------------*/
    static void
    get_light_reading()
    {
      int value;
      char *buf;
      clock_time_t next = SENSOR_READING_PERIOD +
        (random_rand() % SENSOR_READING_RANDOM);
    
      value = opt_3001_sensor.value(0);
    
      if(value != CC26XX_SENSOR_READING_ERROR) {
        opt_reading.raw = value;
    
        compare_and_update(&opt_reading);
    
        buf = opt_reading.converted;
        memset(buf, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
        snprintf(buf, CC26XX_WEB_DEMO_CONVERTED_LEN, "%d.%02d", value / 100,
                 value % 100);
      }
    
      /* The OPT will turn itself off, so we don't need to call its DEACTIVATE */
      ctimer_set(&opt_timer, next, init_light_reading, NULL);
    }
    /*---------------------------------------------------------------------------*/
    static void
    get_mpu_reading()
    {
      clock_time_t next = SENSOR_READING_PERIOD +
        (random_rand() % SENSOR_READING_RANDOM);
      int raw;
    
      if(mpu_gyro_x_reading.publish) {
        raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_GYRO_X);
        if(raw != CC26XX_SENSOR_READING_ERROR) {
          mpu_gyro_x_reading.raw = raw;
        }
      }
    
      if(mpu_gyro_y_reading.publish) {
        raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_GYRO_Y);
        if(raw != CC26XX_SENSOR_READING_ERROR) {
          mpu_gyro_y_reading.raw = raw;
        }
      }
    
      if(mpu_gyro_z_reading.publish) {
        raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_GYRO_Z);
        if(raw != CC26XX_SENSOR_READING_ERROR) {
          mpu_gyro_z_reading.raw = raw;
        }
      }
    
      if(mpu_acc_x_reading.publish) {
        raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_ACC_X);
        if(raw != CC26XX_SENSOR_READING_ERROR) {
          mpu_acc_x_reading.raw = raw;
        }
      }
    
      if(mpu_acc_y_reading.publish) {
        raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_ACC_Y);
        if(raw != CC26XX_SENSOR_READING_ERROR) {
          mpu_acc_y_reading.raw = raw;
        }
      }
    
      if(mpu_acc_z_reading.publish) {
        raw = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_ACC_Z);
        if(raw != CC26XX_SENSOR_READING_ERROR) {
          mpu_acc_z_reading.raw = raw;
        }
      }
    
      SENSORS_DEACTIVATE(mpu_9250_sensor);
    
      if(mpu_gyro_x_reading.publish) {
        compare_and_update(&mpu_gyro_x_reading);
        memset(mpu_gyro_x_reading.converted, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
        print_mpu_reading(mpu_gyro_x_reading.raw, mpu_gyro_x_reading.converted);
      }
    
      if(mpu_gyro_y_reading.publish) {
        compare_and_update(&mpu_gyro_y_reading);
        memset(mpu_gyro_y_reading.converted, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
        print_mpu_reading(mpu_gyro_y_reading.raw, mpu_gyro_y_reading.converted);
      }
    
      if(mpu_gyro_z_reading.publish) {
        compare_and_update(&mpu_gyro_z_reading);
        memset(mpu_gyro_z_reading.converted, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
        print_mpu_reading(mpu_gyro_z_reading.raw, mpu_gyro_z_reading.converted);
      }
    
      if(mpu_acc_x_reading.publish) {
        compare_and_update(&mpu_acc_x_reading);
        memset(mpu_acc_x_reading.converted, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
        print_mpu_reading(mpu_acc_x_reading.raw, mpu_acc_x_reading.converted);
      }
    
      if(mpu_acc_y_reading.publish) {
        compare_and_update(&mpu_acc_y_reading);
        memset(mpu_acc_y_reading.converted, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
        print_mpu_reading(mpu_acc_y_reading.raw, mpu_acc_y_reading.converted);
      }
    
      if(mpu_acc_z_reading.publish) {
        compare_and_update(&mpu_acc_z_reading);
        memset(mpu_acc_z_reading.converted, 0, CC26XX_WEB_DEMO_CONVERTED_LEN);
        print_mpu_reading(mpu_acc_z_reading.raw, mpu_acc_z_reading.converted);
      }
    
      /* We only use the single timer */
      ctimer_set(&mpu_timer, next, init_mpu_reading, NULL);
    }
    /*---------------------------------------------------------------------------*/
    static void
    init_tmp_reading(void *data)
    {
      if(tmp_amb_reading.publish || tmp_obj_reading.publish) {
        SENSORS_ACTIVATE(tmp_007_sensor);
      } else {
        ctimer_set(&tmp_timer, CLOCK_SECOND, init_tmp_reading, NULL);
      }
    }
    /*---------------------------------------------------------------------------*/
    static void
    init_bmp_reading(void *data)
    {
      if(bmp_pres_reading.publish || bmp_temp_reading.publish) {
        SENSORS_ACTIVATE(bmp_280_sensor);
      } else {
        ctimer_set(&bmp_timer, CLOCK_SECOND, init_bmp_reading, NULL);
      }
    }
    /*---------------------------------------------------------------------------*/
    static void
    init_hdc_reading(void *data)
    {
      if(hdc_hum_reading.publish || hdc_temp_reading.publish) {
        SENSORS_ACTIVATE(hdc_1000_sensor);
      } else {
        ctimer_set(&hdc_timer, CLOCK_SECOND, init_hdc_reading, NULL);
      }
    }
    /*---------------------------------------------------------------------------*/
    static void
    init_light_reading(void *data)
    {
      if(opt_reading.publish) {
        SENSORS_ACTIVATE(opt_3001_sensor);
      } else {
        ctimer_set(&opt_timer, CLOCK_SECOND, init_light_reading, NULL);
      }
    }
    /*---------------------------------------------------------------------------*/
    static void
    init_mpu_reading(void *data)
    {
      int readings_bitmap = 0;
    
      if(mpu_acc_x_reading.publish || mpu_acc_y_reading.publish ||
         mpu_acc_z_reading.publish) {
        readings_bitmap |= MPU_9250_SENSOR_TYPE_ACC;
      }
    
      if(mpu_gyro_x_reading.publish || mpu_gyro_y_reading.publish ||
         mpu_gyro_z_reading.publish) {
        readings_bitmap |= MPU_9250_SENSOR_TYPE_GYRO;
      }
    
      if(readings_bitmap) {
        mpu_9250_sensor.configure(SENSORS_ACTIVE, readings_bitmap);
      } else {
        ctimer_set(&mpu_timer, CLOCK_SECOND, init_mpu_reading, NULL);
      }
    }
    #endif
    /*---------------------------------------------------------------------------*/
    static void
    init_sensor_readings(void)
    {
      /*
       * Make a first pass and get all initial sensor readings. This will also
       * trigger periodic value updates
       */
      get_batmon_reading(NULL);
    
    #if 1
      init_hdc_reading(NULL);
    #endif
    #if BOARD_SENSORTAG
      init_bmp_reading(NULL);
      init_light_reading(NULL);
      init_hdc_reading(NULL);
      init_tmp_reading(NULL);
      init_mpu_reading(NULL);
    #endif /* BOARD_SENSORTAG */
    
      return;
    }
    /*---------------------------------------------------------------------------*/
    static void
    init_sensors(void)
    {
    
      list_add(sensor_list, &batmon_temp_reading);
      list_add(sensor_list, &batmon_volt_reading);
    
    #if CC26XX_WEB_DEMO_ADC_DEMO_0
      list_add(sensor_list, &adc_dio23_reading);
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_1
      list_add(sensor_list, &adc_dio24_reading);
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_2
      list_add(sensor_list, &adc_dio25_reading);
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_3
      list_add(sensor_list, &adc_dio26_reading);
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_4
      list_add(sensor_list, &adc_dio27_reading);
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_5
      list_add(sensor_list, &adc_dio28_reading);
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_6
      list_add(sensor_list, &adc_dio29_reading);
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_7
      list_add(sensor_list, &adc_dio30_reading);
    #endif
    
    #if CC26XX_WEB_DEMO_GPIO_READ
      list_add(sensor_list, &gpio_read_reading);
    #endif
    
      SENSORS_ACTIVATE(batmon_sensor);
    
    #if 1
      list_add(sensor_list, &hdc_hum_reading);
      list_add(sensor_list, &hdc_temp_reading);
    #endif
    #if BOARD_SENSORTAG
      list_add(sensor_list, &bmp_pres_reading);
      list_add(sensor_list, &bmp_temp_reading);
    
      list_add(sensor_list, &tmp_obj_reading);
      list_add(sensor_list, &tmp_amb_reading);
    
      list_add(sensor_list, &opt_reading);
    
      list_add(sensor_list, &hdc_hum_reading);
      list_add(sensor_list, &hdc_temp_reading);
    
      list_add(sensor_list, &mpu_acc_x_reading);
      list_add(sensor_list, &mpu_acc_y_reading);
      list_add(sensor_list, &mpu_acc_z_reading);
      list_add(sensor_list, &mpu_gyro_x_reading);
      list_add(sensor_list, &mpu_gyro_y_reading);
      list_add(sensor_list, &mpu_gyro_z_reading);
    #endif
    }
    /*---------------------------------------------------------------------------*/
    /*--- SENSORS FUNCTIONS: END ------------------------------------------------*/
    /*---------------------------------------------------------------------------*/
    /* ========================================================================= */
    
    /* ========================== CONTIKI-NG PROCESSES ========================= */
    /*---------------------------------------------------------------------------*/
    /*---MAIN PROCESS: START ----------------------------------------------------*/
    /*---------------------------------------------------------------------------*/
    PROCESS_THREAD(cc26xx_web_demo_process, ev, data)
    {
      PROCESS_BEGIN();
    
      printf("CC26XX Web Demo Process\n");
    
      init_sensors();
    
      cc26xx_web_demo_publish_event = process_alloc_event();
      cc26xx_web_demo_config_loaded_event = process_alloc_event();
      cc26xx_web_demo_load_config_defaults = process_alloc_event();
    
      /* Start all other (enabled) processes first */
      process_start(&httpd_simple_process, NULL);
    
    #if CC26XX_WEB_DEMO_COAP_SERVER
      process_start(&coap_server_process, NULL);
    #endif
    
    #if CC26XX_WEB_DEMO_6LBR_CLIENT
      process_start(&cetic_6lbr_client_process, NULL);
    #endif
    
    #if CC26XX_WEB_DEMO_MQTT_CLIENT
      process_start(&mqtt_client_process, NULL);
    #endif
    
    #if CC26XX_WEB_DEMO_NET_UART
      process_start(&net_uart_process, NULL);
    #endif
    
    #if CC26XX_WEB_DEMO_CONF_ADC_DEMO
      process_start(&adc_process, NULL);
    #endif
    
    #if CC26XX_WEB_DEMO_GPIO_READ
      process_start(&gpio_read_process, NULL);
    #endif
    
    #if ENERGEST_CONF_ON
      process_start(&energest_process, NULL);
    #endif
      /*
       * Now that processes have set their own config default values, set our
       * own defaults and restore saved config from flash...
       */
      cc26xx_web_demo_config.sensors_bitmap = 0xFFFFFFFF; /* all on by default */
      cc26xx_web_demo_config.def_rt_ping_interval =
        CC26XX_WEB_DEMO_DEFAULT_RSSI_MEAS_INTERVAL;
      load_config();
    
      /*
       * Notify all other processes (basically the ones in this demo) that the
       * configuration has been loaded from flash, in case they care
       */
      process_post(PROCESS_BROADCAST, cc26xx_web_demo_config_loaded_event, NULL);
    
      init_sensor_readings();
    
      httpd_simple_register_post_handler(&sensor_handler);
      httpd_simple_register_post_handler(&defaults_handler);
    
    #if CC26XX_WEB_DEMO_READ_PARENT_RSSI
      httpd_simple_register_post_handler(&ping_interval_handler);
    
      def_rt_rssi = 0x8000000;
      uip_icmp6_echo_reply_callback_add(&echo_reply_notification,
                                        echo_reply_handler);
      etimer_set(&echo_request_timer, CC26XX_WEB_DEMO_NET_CONNECT_PERIODIC);
    #endif
    
      etimer_set(&et, CC26XX_WEB_DEMO_NET_CONNECT_PERIODIC);
    
      /*
       * Update all sensor readings on a configurable sensors_event
       * (e.g a button press / or reed trigger)
       */
      while(1) {
        if(ev == PROCESS_EVENT_TIMER && etimer_expired(&et)) {
          if(uip_ds6_get_global(ADDR_PREFERRED) == NULL) {
            leds_on(CC26XX_WEB_DEMO_STATUS_LED);
            ctimer_set(&ct, NO_NET_LED_DURATION, publish_led_off, NULL);
            etimer_set(&et, CC26XX_WEB_DEMO_NET_CONNECT_PERIODIC);
          }
        }
    
    #if CC26XX_WEB_DEMO_READ_PARENT_RSSI
        if(ev == PROCESS_EVENT_TIMER && etimer_expired(&echo_request_timer)) {
          if(uip_ds6_get_global(ADDR_PREFERRED) == NULL) {
            etimer_set(&echo_request_timer, CC26XX_WEB_DEMO_NET_CONNECT_PERIODIC);
          } else {
            ping_parent();
            etimer_set(&echo_request_timer, cc26xx_web_demo_config.def_rt_ping_interval);
          }
        }
    #endif
    
        if(ev == button_hal_release_event &&
           ((button_hal_button_t *)data)->unique_id ==
           CC26XX_WEB_DEMO_SENSOR_READING_TRIGGER) {
          init_sensor_readings();
          process_post(PROCESS_BROADCAST, cc26xx_web_demo_publish_event, NULL);
        } else if(ev == button_hal_periodic_event &&
                  ((button_hal_button_t *)data)->unique_id ==
                  CC26XX_WEB_DEMO_SENSOR_READING_TRIGGER) {
          printf("Restoring defaults!\n");
          cc26xx_web_demo_restore_defaults();
        } else if(ev == httpd_simple_event_new_config) {
          save_config();
    #if 1
        } else if(ev == sensors_event && data == &hdc_1000_sensor) {
          get_hdc_reading();
    #endif
    #if BOARD_SENSORTAG
        } else if(ev == sensors_event && data == &bmp_280_sensor) {
          get_bmp_reading();
        } else if(ev == sensors_event && data == &opt_3001_sensor) {
          get_light_reading();
        } else if(ev == sensors_event && data == &hdc_1000_sensor) {
          get_hdc_reading();
        } else if(ev == sensors_event && data == &tmp_007_sensor) {
          get_tmp_reading();
        } else if(ev == sensors_event && data == &mpu_9250_sensor) {
          get_mpu_reading();
    #endif
        }
    
        PROCESS_YIELD();
      }
    
      PROCESS_END();
    }
    /*---------------------------------------------------------------------------*/
    /*--- MAIN PROCESS: END -----------------------------------------------------*/
    /*---------------------------------------------------------------------------*/
    
    /*---------------------------------------------------------------------------*/
    /*--- SUB PROCESSES: START --------------------------------------------------*/
    /*---------------------------------------------------------------------------*/
    #if CC26XX_WEB_DEMO_CONF_ADC_DEMO
    PROCESS_THREAD(adc_process, ev, data)
    {
      PROCESS_BEGIN();
    
      etimer_set(&et_adc, CLOCK_SECOND * 5);
    
      while(1) {
    
        PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et_adc));
    
        /* intialisation of ADC */
        ti_lib_aon_wuc_aux_wakeup_event(AONWUC_AUX_WAKEUP);
        while(!(ti_lib_aon_wuc_power_status_get() & AONWUC_AUX_POWER_ON));
    
        /*
         * Enable clock for ADC digital and analog interface (not currently enabled
         * in driver)
         */
        ti_lib_aux_wuc_clock_enable(AUX_WUC_ADI_CLOCK | AUX_WUC_ANAIF_CLOCK |
                                    AUX_WUC_SMPH_CLOCK);
    
        while(ti_lib_aux_wuc_clock_status(AUX_WUC_ADI_CLOCK | AUX_WUC_ANAIF_CLOCK |
                                          AUX_WUC_SMPH_CLOCK)
              != AUX_WUC_CLOCK_READY);
    
    #if CC26XX_WEB_DEMO_ADC_DEMO_0
        /* Connect AUX IO7 (DIO23, but also DP2 on XDS110) as analog input. */
        ti_lib_aux_adc_select_input(ADC_COMPB_IN_AUXIO7);
        /* Set up ADC range, AUXADC_REF_FIXED = nominally 4.3 V */
        ti_lib_aux_adc_enable_sync(AUXADC_REF_FIXED, AUXADC_SAMPLE_TIME_2P7_US,
                                   AUXADC_TRIGGER_MANUAL);
        /* Trigger ADC converting */
        ti_lib_aux_adc_gen_manual_trigger();
        /* Read value */
        single_adc_sample_0 = ti_lib_aux_adc_read_fifo();
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_1
        /* Connect AUX IO7 (DIO24, but also DP2 on XDS110) as analog input. */
        ti_lib_aux_adc_select_input(ADC_COMPB_IN_AUXIO6);
        /* Set up ADC range, AUXADC_REF_FIXED = nominally 4.3 V */
        ti_lib_aux_adc_enable_sync(AUXADC_REF_FIXED, AUXADC_SAMPLE_TIME_2P7_US,
                                   AUXADC_TRIGGER_MANUAL);
        /* Trigger ADC converting */
        ti_lib_aux_adc_gen_manual_trigger();
        /* Read value */
        single_adc_sample_1 = ti_lib_aux_adc_read_fifo();
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_2
        /* Connect AUX IO7 (DIO25, but also DP2 on XDS110) as analog input. */
        ti_lib_aux_adc_select_input(ADC_COMPB_IN_AUXIO5);
        /* Set up ADC range, AUXADC_REF_FIXED = nominally 4.3 V */
        ti_lib_aux_adc_enable_sync(AUXADC_REF_FIXED, AUXADC_SAMPLE_TIME_2P7_US,
                                   AUXADC_TRIGGER_MANUAL);
        /* Trigger ADC converting */
        ti_lib_aux_adc_gen_manual_trigger();
        /* Read value */
        single_adc_sample_2 = ti_lib_aux_adc_read_fifo();
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_3
        /* Connect AUX IO7 (DIO26, but also DP2 on XDS110) as analog input. */
        ti_lib_aux_adc_select_input(ADC_COMPB_IN_AUXIO4);
        /* Set up ADC range, AUXADC_REF_FIXED = nominally 4.3 V */
        ti_lib_aux_adc_enable_sync(AUXADC_REF_FIXED, AUXADC_SAMPLE_TIME_2P7_US,
                                   AUXADC_TRIGGER_MANUAL);
        /* Trigger ADC converting */
        ti_lib_aux_adc_gen_manual_trigger();
        /* Read value */
        single_adc_sample_3 = ti_lib_aux_adc_read_fifo();
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_4
        /* Connect AUX IO7 (DIO27, but also DP2 on XDS110) as analog input. */
        ti_lib_aux_adc_select_input(ADC_COMPB_IN_AUXIO3);
        /* Set up ADC range, AUXADC_REF_FIXED = nominally 4.3 V */
        ti_lib_aux_adc_enable_sync(AUXADC_REF_FIXED, AUXADC_SAMPLE_TIME_2P7_US,
                                   AUXADC_TRIGGER_MANUAL);
        /* Trigger ADC converting */
        ti_lib_aux_adc_gen_manual_trigger();
        /* Read value */
        single_adc_sample_4 = ti_lib_aux_adc_read_fifo();
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_5
        /* Connect AUX IO7 (DIO28, but also DP2 on XDS110) as analog input. */
        ti_lib_aux_adc_select_input(ADC_COMPB_IN_AUXIO2);
        /* Set up ADC range, AUXADC_REF_FIXED = nominally 4.3 V */
        ti_lib_aux_adc_enable_sync(AUXADC_REF_FIXED, AUXADC_SAMPLE_TIME_2P7_US,
                                   AUXADC_TRIGGER_MANUAL);
        /* Trigger ADC converting */
        ti_lib_aux_adc_gen_manual_trigger();
        /* Read value */
        single_adc_sample_5 = ti_lib_aux_adc_read_fifo();
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_6
        /* Connect AUX IO7 (DIO29, but also DP2 on XDS110) as analog input. */
        ti_lib_aux_adc_select_input(ADC_COMPB_IN_AUXIO1);
        /* Set up ADC range, AUXADC_REF_FIXED = nominally 4.3 V */
        ti_lib_aux_adc_enable_sync(AUXADC_REF_FIXED, AUXADC_SAMPLE_TIME_2P7_US,
                                   AUXADC_TRIGGER_MANUAL);
        /* Trigger ADC converting */
        ti_lib_aux_adc_gen_manual_trigger();
        /* Read value */
        single_adc_sample_6 = ti_lib_aux_adc_read_fifo();
    #endif
    #if CC26XX_WEB_DEMO_ADC_DEMO_7
        /* Connect AUX IO7 (DIO30, but also DP2 on XDS110) as analog input. */
        ti_lib_aux_adc_select_input(ADC_COMPB_IN_AUXIO0);
        /* Set up ADC range, AUXADC_REF_FIXED = nominally 4.3 V */
        ti_lib_aux_adc_enable_sync(AUXADC_REF_FIXED, AUXADC_SAMPLE_TIME_2P7_US,
                                   AUXADC_TRIGGER_MANUAL);
        /* Trigger ADC converting */
        ti_lib_aux_adc_gen_manual_trigger();
        /* Read value */
        single_adc_sample_7 = ti_lib_aux_adc_read_fifo();
    #endif
    
        /* Shut the adc down */
        ti_lib_aux_adc_disable();
    
        get_adc_reading(NULL);
    
        etimer_reset(&et_adc);
      }
    
      PROCESS_END();
    }
    #endif
    
    #if CC26XX_WEB_DEMO_GPIO_READ
    PROCESS_THREAD(gpio_read_process, ev, data)
    {
      PROCESS_BEGIN();
    
      etimer_set(&et_gpio_read, CLOCK_SECOND * 5);
    
      while(1) {
    
          PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et_gpio_read));
    
          /* read the logical state of all GPIO */
          gpio_reading = gpio_hal_arch_read_pins(0xFFFFFFFF);
    
          get_gpio_reading(NULL);
    
          etimer_reset(&et_gpio_read);
      }
    
      PROCESS_END();
    }
    #endif
    
    #if ENERGEST_CONF_ON
    static unsigned long
    to_seconds(uint64_t time)
    {
      return (unsigned long)(time / ENERGEST_SECOND);
    }
    
    PROCESS_THREAD(energest_process, ev, data)
    {
      PROCESS_BEGIN();
    
      etimer_set(&et_energest, CLOCK_SECOND * 10);
      while(1) {
        PROCESS_WAIT_EVENT_UNTIL(etimer_expired(&et_energest));
        etimer_reset(&et_energest);
    
        /* Update all energest times. */
        energest_flush();
    
        printf("\nEnergest:\n");
        printf(" CPU          %4lus LPM      %4lus DEEP LPM %4lus  Total time %lus\n",
               to_seconds(energest_type_time(ENERGEST_TYPE_CPU)),
               to_seconds(energest_type_time(ENERGEST_TYPE_LPM)),
               to_seconds(energest_type_time(ENERGEST_TYPE_DEEP_LPM)),
               to_seconds(ENERGEST_GET_TOTAL_TIME()));
        printf(" Radio LISTEN %4lus TRANSMIT %4lus OFF      %4lus\n",
               to_seconds(energest_type_time(ENERGEST_TYPE_LISTEN)),
               to_seconds(energest_type_time(ENERGEST_TYPE_TRANSMIT)),
               to_seconds(ENERGEST_GET_TOTAL_TIME()
                          - energest_type_time(ENERGEST_TYPE_TRANSMIT)
                          - energest_type_time(ENERGEST_TYPE_LISTEN)));
      }
      PROCESS_END();
    }
    #endif
    
    /*---------------------------------------------------------------------------*/
    /*--- SUB PROCESSES: END ----------------------------------------------------*/
    /*---------------------------------------------------------------------------*/
    /* ========================================================================= */
    

  • hdc_1000_sensor is a sensors_sensor structure defined in hdc-1000-Sensor.h. You have to include the header file to solve this build error.

  • I did include it in board-peripherals.h and the problem still persists ... 

    It built successfully when I added:

    const struct sensors_sensor hdc_1000_sensor;

    at the top of cc26xx-web-demo.c, which means for some reason the data structure is not getting defined, although I see it's declaration in hdc-1000-Sensor.h. Please note the all other definitions in hdc_1000_sensor.h are imported successfully in the program

    By the way, in board-peripgerals.h, should I set #define BOARD_CONF_HAS_SENSORS to 1 or keep it as it was (0) ?

  • Since you would connect humidity/temperature sensor to your board, you should set #define BOARD_CONF_HAS_SENSORS to 1

  • Tried setting it to 1 and got more errors ... 

    undefined reference to sensors_flags

    undefined reference to sensors ...

    I wonder if there is an example of how to port a new sensor?

  • There is no document or guild to show you this step by step. You have to study the code by yourself.

  • Hi Abhed,

    Contiki-NG related questions should be directed to the Contiki forums.

    Regards,
    Fredrik

  • Hi  YK, 

    I think there is a problem with the build / makefiles that shows up whenever the code uses the sensors_sensor data structure defined in os/dev/sensors.h. I tried a very simple example like the following and it gave the same error "undefined reference to button_sensor":

    #include "contiki.h"
    #include "dev/leds.h"
    #include "dev/button-sensor.h"
    #include <stdio.h>
    
    PROCESS(led_button_process, "Leds & Buttons process");
    
    AUTOSTART_PROCESSES(&led_button_process);
    
    PROCESS_THREAD(led_button_process, ev, data)
    
    {
      PROCESS_BEGIN();
    
      SENSORS_ACTIVATE(button_sensor);
    
      while(1) {
        printf("Press the user button\n");
        PROCESS_WAIT_EVENT_UNTIL(ev == sensors_event && data == &button_sensor);
        leds_toggle(LEDS_GREEN);
        printf("The sensor is: %u\n", leds_get());
      }
      PROCESS_END();
    }

    My make file is:

    CONTIKI_PROJECT = button_sensing
    TARGET=cc26x0-cc13x0
    BOARD=launchpad/cc1350
    
    CFLAGS += -g
    all: $(CONTIKI_PROJECT)
    
    CONTIKI = ../..
    include $(CONTIKI)/Makefile.include

    Could you please help me with this issue? Should I add any other file to the PROJECTFILES in the make file?

  • Yes, you also need to revise makefile. You can refer to Makefile.sensortag (contiki-ng\arch\platform\cc26x0-cc13x0\sensortag) and revise Makefile.launchpad (under contiki-ng\arch\platform\cc26x0-cc13x0\launchpad) accordingly.

  • This simple code in the latest post does not work on sensortag or even TARGET=native. I tried it on two computers.

  • Button and LED are default included in sensortag example. You don't need to add code for them.

  • Yes I know, I just want to demonstrate the error ...

  • I try to add HTU21D into sensortag configuration and I can build it without problem. I attach my revised files for your reference. You can put those four files under contiki-ng\arch\platform\cc26x0-cc13x0\sensortag to rebuild your CC26x0-web-demo.

    HTU21D.zip

  • Thanks, so as a work around, I can just build my project with BOARD=sensortag instead of the launchpad.

    But were you able to get it working with the Launchpad?

  • Yes, I can get it working on LaunchPad. It's just some copy and past.

  • My files are identical to yours and it doesn't work on the launchpad...

    I'll try to re-clone the repository again and post another update with the results tomorrow.

    Thank you for your support YK !

  • I just try this with some copy&paste and revision and I can confirm it can build successful on LaunchPad.

  • Thanks I got it working, I was missing: BOARD_SOURCEFILES += launchpad-sensors.c

    Below is a summary for the porting:

    In cc26x0-web-demo.c, I copied all hdc1000 sensor functions & definitions out of the #if BOARDSENSORTAG macro:
    - struct ctimer opt_timer;
    - DEMO_SENSOR(hdc_temp, CC26XX_WEB_DEMO_SENSOR_HDC_TEMP,  "HDC Temp", "hdc-temp", "hdc_temp", CC26XX_WEB_DEMO_UNIT_TEMP);
    - DEMO_SENSOR(hdc_hum, CC26XX_WEB_DEMO_SENSOR_HDC_HUMIDITY, "HDC Humidity", "hdc-humidity", "hdc_hum", CC26XX_WEB_DEMO_UNIT_HUMIDITY);
    - static void init_hdc_reading(void *data);
    - static void compare_and_update(cc26xx_web_demo_sensor_reading_t *reading)
    - static void get_hdc_reading()
    - call for init_hdc_reading(NULL); in static void init_sensor_readings(void)
    - call for list_add(sensor_list, &hdc_reading); in static void init_sensors(void)
    - call for get_hdc_reading() in PROCESS_THREAD(cc26xx_web_demo_process, ev, data)

    In launchpad/board_peripherals.h, I added:
    - #include "hdc-1000-sensor.h"

    In the same launchpad folder, I copied hdc-1000-sensor.c/h, sensor-common.c/h, and board-i2c.c/h from the sensortag folder, then I added:
    - BOARD_SOURCEFILES += hdc-1000-sensor.c sensor-common.c board-i2c.c
    to the Makefile.launchpad

    I also copied sensortag-sensors.c to the launchpad folder and renamed it to launchpad-sensors.c, and add:
    - BOARD_SOURCEFILES += launchpad-sensors.c
    to the Makefile.launchpad

    In launchpad/Board.c, I added i2c functions:
    - #include "lib/sensors.h"
    - #include "board-i2c.h"
    - static void shutdown_handler(uint8_t mode)     
    - LPM_MODULE(launchpad_module, NULL, shutdown_handler, wakeup_handler, LPM_DOMAIN_NONE);
    and in board_init():
    - board_i2c_wakeup(); 

    In Launchpad/cc1350/board.h, I added:
    - #define BOARD_IOID_SDA_HP IOID_UNUSED /**< Interface 1 SDA: MPU */ 
    - #define BOARD_IOID_SCL_HP IOID_UNUSED /**< Interface 1 SCL: MPU */ 

    and it compiled successfully, I didn't test the I2C operation of the sensor yet, I'll post an update once I get it working !