Add CC26xx examples

This commit is contained in:
Jonas Olsson 2015-02-25 13:15:35 +01:00
parent c9071b6952
commit 0f567e499f
30 changed files with 5928 additions and 0 deletions

9
examples/cc26xx/Makefile Normal file
View file

@ -0,0 +1,9 @@
DEFINES+=PROJECT_CONF_H=\"project-conf.h\"
CONTIKI_PROJECT = cc26xx-demo
all: $(CONTIKI_PROJECT)
CONTIKI_WITH_IPV6 = 1
CONTIKI = ../..
include $(CONTIKI)/Makefile.include

View file

@ -0,0 +1 @@
TARGET = srf06-cc26xx

15
examples/cc26xx/README.md Normal file
View file

@ -0,0 +1,15 @@
CC26xx Demo
===========
This example demonstrates basic functionality for the two supported CC26xx
boards. More specifically, the example demonstrates:
* How to take sensor readings
* How to use buttons and the reed relay (triggered by holding a magnet near S3
on the SensorTag).
* How to keep a power domain powered and a peripheral clocked under low power
operation
* How to send out BLE advertisements. The device will periodically send out BLE
beacons with the platform name as payload. Those beacons/BLE ADV packets can
be captured with any BLE capable device. Two such applications for iOS are the
TI Multitool and the TI Sensortag app. They can be found in the Apple App
Store. If you have a BLE-capable Mac, you can also use LightBlue for OS X.

View file

@ -0,0 +1,477 @@
/*
* 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 cc26xx-platforms
* @{
*
* \defgroup cc26xx-examples CC26xx Example Projects
*
* Example projects for CC26xx-based platforms.
* @{
*
* \defgroup cc26xx-demo CC26xx Demo Project
*
* Example project demonstrating the CC26xx platforms
*
* This example will work for the following boards:
* - srf06-cc26xx: SmartRF06EB + CC26XX EM
* - sensortag-cc26xx: CC26XX sensortag
*
* By default, the example will build for the srf06-cc26xx board. To switch
* between platforms:
* - make clean
* - make BOARD=sensortag-cc26xx savetarget
*
* or
*
* make BOARD=srf06-cc26xx savetarget
*
* This is an IPv6/RPL-enabled example. Thus, if you have a border router in
* your installation (same RDC layer, same PAN ID and RF channel), you should
* be able to ping6 this demo node.
*
* This example also demonstrates CC26xx BLE operation. The process starts
* the BLE beacon daemon (implemented in the RF driver). The daemon will
* send out a BLE beacon periodically. Use any BLE-enabled application (e.g.
* LightBlue on OS X or the TI BLE Multitool smartphone app) and after a few
* seconds the cc26xx device will be discovered.
*
* - etimer/clock : Every CC26XX_DEMO_LOOP_INTERVAL clock ticks the LED defined
* as CC26XX_DEMO_LEDS_PERIODIC will toggle and the device
* will print out readings from some supported sensors
* - sensors : Some sensortag sensors are read asynchronously (see sensor
* documentation). For those, this example will print out
* readings in a staggered fashion at a random interval
* - Buttons : CC26XX_DEMO_SENSOR_1 button will toggle CC26XX_DEMO_LEDS_BUTTON
* - CC26XX_DEMO_SENSOR_2 turns on LEDS_REBOOT and causes a
* watchdog reboot
* - The remaining buttons will just print something
* - The example also shows how to retrieve the duration of a
* button press (in ticks). The driver will generate a
* sensors_changed event upon button release
* - UART : Receiving an entire line of text over UART (ending
* in \\r) will cause CC26XX_DEMO_LEDS_SERIAL_IN to toggle
* This also demonstrates how a code module can influence
* low-power operation: In this example we keep the UART on
* and capable to RX even with the chip in deep sleep.
* see keep_uart_on() and the UART driver
* - Reed Relay : Will toggle the sensortag buzzer on/off
*
* @{
*
* \file
* Example demonstrating the cc26xx platforms
*/
#include "contiki.h"
#include "sys/etimer.h"
#include "sys/ctimer.h"
#include "dev/leds.h"
#include "dev/serial-line.h"
#include "dev/watchdog.h"
#include "random.h"
#include "button-sensor.h"
#include "batmon-sensor.h"
#include "board-peripherals.h"
#include "lpm.h"
#include "cc26xx-rf.h"
#include "ti-lib.h"
#include <stdio.h>
#include <stdint.h>
/*---------------------------------------------------------------------------*/
#define CC26XX_DEMO_LOOP_INTERVAL (CLOCK_SECOND * 20)
#define CC26XX_DEMO_LEDS_PERIODIC LEDS_YELLOW
#define CC26XX_DEMO_LEDS_BUTTON LEDS_RED
#define CC26XX_DEMO_LEDS_SERIAL_IN LEDS_ORANGE
#define CC26XX_DEMO_LEDS_REBOOT LEDS_ALL
/*---------------------------------------------------------------------------*/
#define CC26XX_DEMO_SENSOR_NONE (void *)0xFFFFFFFF
#define CC26XX_DEMO_SENSOR_1 &button_left_sensor
#define CC26XX_DEMO_SENSOR_2 &button_right_sensor
#if BOARD_SENSORTAG
#define CC26XX_DEMO_SENSOR_3 CC26XX_DEMO_SENSOR_NONE
#define CC26XX_DEMO_SENSOR_4 CC26XX_DEMO_SENSOR_NONE
#define CC26XX_DEMO_SENSOR_5 &reed_relay_sensor
#else
#define CC26XX_DEMO_SENSOR_3 &button_up_sensor
#define CC26XX_DEMO_SENSOR_4 &button_down_sensor
#define CC26XX_DEMO_SENSOR_5 &button_select_sensor
#endif
/*---------------------------------------------------------------------------*/
static struct etimer et;
/*---------------------------------------------------------------------------*/
PROCESS(cc26xx_demo_process, "cc26xx demo process");
AUTOSTART_PROCESSES(&cc26xx_demo_process);
/*---------------------------------------------------------------------------*/
#if BOARD_SENSORTAG
/*---------------------------------------------------------------------------*/
/*
* 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)
static struct ctimer bmp_timer, opt_timer, sht_timer, tmp_timer, mpu_timer;
/*---------------------------------------------------------------------------*/
static void init_bmp_reading(void *not_used);
static void init_opt_reading(void *not_used);
static void init_sht_reading(void *not_used);
static void init_tmp_reading(void *not_used);
static void init_mpu_reading(void *not_used);
/*---------------------------------------------------------------------------*/
static void
print_mpu_reading(int reading)
{
if(reading < 0) {
printf("-");
reading = -reading;
}
printf("%d.%02d", reading / 100, reading % 100);
}
/*---------------------------------------------------------------------------*/
static void
get_bmp_reading()
{
int value;
clock_time_t next = SENSOR_READING_PERIOD +
(random_rand() % SENSOR_READING_RANDOM);
value = bmp_280_sensor.value(BMP_280_SENSOR_TYPE_PRESS);
if(value != CC26XX_SENSOR_READING_ERROR) {
printf("BAR: Pressure=%d.%02d hPa\n", value / 100, value % 100);
} else {
printf("BAR: Pressure Read Error\n");
}
value = bmp_280_sensor.value(BMP_280_SENSOR_TYPE_TEMP);
if(value != CC26XX_SENSOR_READING_ERROR) {
printf("BAR: Temp=%d.%02d C\n", value / 100, value % 100);
} else {
printf("BAR: Temperature Read Error\n");
}
SENSORS_DEACTIVATE(bmp_280_sensor);
ctimer_set(&bmp_timer, next, init_bmp_reading, NULL);
}
/*---------------------------------------------------------------------------*/
static void
get_tmp_reading()
{
int value;
clock_time_t next = SENSOR_READING_PERIOD +
(random_rand() % SENSOR_READING_RANDOM);
value = tmp_007_sensor.value(TMP_007_SENSOR_TYPE_ALL);
if(value == CC26XX_SENSOR_READING_ERROR) {
printf("TMP: Ambient Read Error\n");
return;
}
value = tmp_007_sensor.value(TMP_007_SENSOR_TYPE_AMBIENT);
printf("TMP: Ambient=%d.%03d C\n", value / 1000, value % 1000);
value = tmp_007_sensor.value(TMP_007_SENSOR_TYPE_OBJECT);
printf("TMP: Object=%d.%03d C\n", value / 1000, value % 1000);
SENSORS_DEACTIVATE(tmp_007_sensor);
ctimer_set(&tmp_timer, next, init_tmp_reading, NULL);
}
/*---------------------------------------------------------------------------*/
static void
get_sht_reading()
{
int value;
clock_time_t next = SENSOR_READING_PERIOD +
(random_rand() % SENSOR_READING_RANDOM);
value = sht_21_sensor.value(SHT_21_SENSOR_TYPE_TEMP);
if(value != CC26XX_SENSOR_READING_ERROR) {
printf("SHT: Temp=%d.%02d C\n", value / 100, value % 100);
} else {
printf("SHT: Temp Read Error\n");
}
value = sht_21_sensor.value(SHT_21_SENSOR_TYPE_HUMIDITY);
if(value != CC26XX_SENSOR_READING_ERROR) {
printf("SHT: Humidity=%d.%02d %%RH\n", value / 100, value % 100);
} else {
printf("SHT: Humidity Read Error\n");
}
ctimer_set(&sht_timer, next, init_sht_reading, NULL);
}
/*---------------------------------------------------------------------------*/
static void
get_light_reading()
{
int value;
clock_time_t next = SENSOR_READING_PERIOD +
(random_rand() % SENSOR_READING_RANDOM);
value = opt_3001_sensor.value(0);
if(value != CC26XX_SENSOR_READING_ERROR) {
printf("OPT: Light=%d.%02d lux\n", value / 100, value % 100);
} else {
printf("OPT: Light Read Error\n");
}
SENSORS_DEACTIVATE(opt_3001_sensor);
ctimer_set(&opt_timer, next, init_opt_reading, NULL);
}
/*---------------------------------------------------------------------------*/
static void
get_mpu_reading()
{
int value;
clock_time_t next = SENSOR_READING_PERIOD +
(random_rand() % SENSOR_READING_RANDOM);
printf("MPU Gyro: X=");
value = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_GYRO_X);
print_mpu_reading(value);
printf(" deg/sec\n");
printf("MPU Gyro: Y=");
value = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_GYRO_Y);
print_mpu_reading(value);
printf(" deg/sec\n");
printf("MPU Gyro: Z=");
value = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_GYRO_Z);
print_mpu_reading(value);
printf(" deg/sec\n");
printf("MPU Acc: X=");
value = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_ACC_X);
print_mpu_reading(value);
printf(" G\n");
printf("MPU Acc: Y=");
value = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_ACC_Y);
print_mpu_reading(value);
printf(" G\n");
printf("MPU Acc: Z=");
value = mpu_9250_sensor.value(MPU_9250_SENSOR_TYPE_ACC_Z);
print_mpu_reading(value);
printf(" G\n");
SENSORS_DEACTIVATE(mpu_9250_sensor);
ctimer_set(&mpu_timer, next, init_mpu_reading, NULL);
}
/*---------------------------------------------------------------------------*/
static void
init_bmp_reading(void *not_used)
{
SENSORS_ACTIVATE(bmp_280_sensor);
}
/*---------------------------------------------------------------------------*/
static void
init_opt_reading(void *not_used)
{
SENSORS_ACTIVATE(opt_3001_sensor);
}
/*---------------------------------------------------------------------------*/
static void
init_sht_reading(void *not_used)
{
SENSORS_ACTIVATE(sht_21_sensor);
}
/*---------------------------------------------------------------------------*/
static void
init_tmp_reading(void *not_used)
{
SENSORS_ACTIVATE(tmp_007_sensor);
}
/*---------------------------------------------------------------------------*/
static void
init_mpu_reading(void *not_used)
{
mpu_9250_sensor.configure(SENSORS_ACTIVE, MPU_9250_SENSOR_TYPE_ALL);
}
#endif
/*---------------------------------------------------------------------------*/
static void
get_sync_sensor_readings(void)
{
int value;
printf("-----------------------------------------\n");
value = batmon_sensor.value(BATMON_SENSOR_TYPE_TEMP);
printf("Bat: Temp=%d.%02d C (%08x)\n", value >> 2,
(value & 0x00000003) * 25, value);
value = batmon_sensor.value(BATMON_SENSOR_TYPE_VOLT);
printf("Bat: Volt=%d mV\n", (value * 125) >> 5);
return;
}
/*---------------------------------------------------------------------------*/
static void
init_sensors(void)
{
#if BOARD_SENSORTAG
SENSORS_ACTIVATE(reed_relay_sensor);
#endif
SENSORS_ACTIVATE(batmon_sensor);
}
/*---------------------------------------------------------------------------*/
static void
init_sensor_readings(void)
{
#if BOARD_SENSORTAG
SENSORS_ACTIVATE(sht_21_sensor);
SENSORS_ACTIVATE(tmp_007_sensor);
SENSORS_ACTIVATE(opt_3001_sensor);
SENSORS_ACTIVATE(bmp_280_sensor);
init_mpu_reading(NULL);
#endif
}
/*---------------------------------------------------------------------------*/
static lpm_power_domain_lock_t lock;
/*---------------------------------------------------------------------------*/
/*
* In order to maintain UART input operation:
* - Keep the uart clocked in sleep and deep sleep
* - Keep the serial PD on in deep sleep
*/
static void
keep_uart_on(void)
{
/* Keep the serial PD on */
lpm_pd_lock_obtain(&lock, PRCM_DOMAIN_SERIAL);
/* Keep the UART clock on during Sleep and Deep Sleep */
ti_lib_prcm_peripheral_sleep_enable(PRCM_PERIPH_UART0);
ti_lib_prcm_peripheral_deep_sleep_enable(PRCM_PERIPH_UART0);
ti_lib_prcm_load_set();
while(!ti_lib_prcm_load_get());
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(cc26xx_demo_process, ev, data)
{
PROCESS_BEGIN();
printf("CC26XX demo\n");
init_sensors();
/* Init the BLE advertisement daemon */
cc26xx_rf_ble_beacond_config(0, BOARD_STRING);
cc26xx_rf_ble_beacond_start();
etimer_set(&et, CC26XX_DEMO_LOOP_INTERVAL);
get_sync_sensor_readings();
init_sensor_readings();
keep_uart_on();
while(1) {
PROCESS_YIELD();
if(ev == PROCESS_EVENT_TIMER) {
if(data == &et) {
leds_toggle(CC26XX_DEMO_LEDS_PERIODIC);
get_sync_sensor_readings();
etimer_set(&et, CC26XX_DEMO_LOOP_INTERVAL);
}
} else if(ev == sensors_event) {
if(data == CC26XX_DEMO_SENSOR_1) {
printf("Left: Pin %d, press duration %d clock ticks\n",
(CC26XX_DEMO_SENSOR_1)->value(BUTTON_SENSOR_VALUE_STATE),
(CC26XX_DEMO_SENSOR_1)->value(BUTTON_SENSOR_VALUE_DURATION));
if((CC26XX_DEMO_SENSOR_1)->value(BUTTON_SENSOR_VALUE_DURATION) >
CLOCK_SECOND) {
printf("Long button press!\n");
}
leds_toggle(CC26XX_DEMO_LEDS_BUTTON);
} else if(data == CC26XX_DEMO_SENSOR_2) {
leds_on(CC26XX_DEMO_LEDS_REBOOT);
watchdog_reboot();
} else if(data == CC26XX_DEMO_SENSOR_3) {
printf("Up\n");
} else if(data == CC26XX_DEMO_SENSOR_4) {
printf("Down\n");
} else if(data == CC26XX_DEMO_SENSOR_5) {
#if BOARD_SENSORTAG
if(buzzer_state()) {
buzzer_stop();
} else {
buzzer_start(1000);
}
} 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 == &sht_21_sensor) {
get_sht_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();
#else
printf("Sel: Pin %d, press duration %d clock ticks\n",
button_select_sensor.value(BUTTON_SENSOR_VALUE_STATE),
button_select_sensor.value(BUTTON_SENSOR_VALUE_DURATION));
#endif
}
} else if(ev == serial_line_event_message) {
leds_toggle(CC26XX_DEMO_LEDS_SERIAL_IN);
}
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
/**
* @}
* @}
* @}
*/

View file

@ -0,0 +1,24 @@
DEFINES+=PROJECT_CONF_H=\"project-conf.h\"
all: cc26xx-web-demo
REST_RESOURCES_DIR = ./resources
REST_RESOURCES_FILES += res-leds.c res-toggle-leds.c res-device.c
REST_RESOURCES_FILES += res-sensors.c res-ble-advd.c
PROJECTDIRS += $(REST_RESOURCES_DIR)
PROJECT_SOURCEFILES += $(REST_RESOURCES_FILES)
PROJECT_SOURCEFILES += cetic-6lbr-client.c coap-server.c net-uart.c mqtt-client.c
PROJECT_SOURCEFILES += httpd-simple.c
CONTIKI_WITH_IPV6 = 1
# REST Engine shall use Erbium CoAP implementation
APPS += er-coap
APPS += rest-engine
APPS += mqtt
CONTIKI=../../..
include $(CONTIKI)/Makefile.include

View file

@ -0,0 +1 @@
TARGET = srf06-cc26xx

View file

@ -0,0 +1,169 @@
CC26xx Web Demo Readme
======================
This demo project combines a number of web-based applications aiming to
demonstrate the CC26xx capability. The applications are:
* A network-based UART
* A client for [6lbr](http://cetic.github.io/6lbr/)
* A CoAP server
* An MQTT client
* A web server which can be used to display sensor readings but also to
configure MQTT functionality
The example has been configured to run for both CC26xx-based boards: i) The
SensorTag 2.0 and ii) The Srf06EB with a CC26xx EM mounted on it.
To build the example for the Srf, simply run `make`. To build for the tag,
run `make BOARD=sensortag`. Do not forget to `make clean` when switching
between the two platforms.
You can disable some of those individual components by changing the respective
defines in `project-conf.h`. For instance, to disable the CoAP functionality,
set `#define CC26XX_WEB_DEMO_CONF_COAP_SERVER 0`. The web server cannot be
disabled, all other aforementioned applications can.
Network UART (net-uart)
-----------------------
This example only makes sense if you are using the Srf or if you have taken
the sensortag out of its case and you have it connected over JTAG to the Srf.
The net-uart does two things:
* When you type a string to the UART console, the string will be sent verbatim
to a remote UDP port 7777 listener. This can be for example a netcat listener
on a linux or OS X PC:
`nc -6ulkw 1 7777`
* The net-uart also listens to UDP port 7777 and when it receives a string over
UDP, it will print it verbatim over UART.
The example will initially send packets to a hard-coded IPv6 address. This can
be changed very easily by entering a different IPv6 address to the console.
Thus, when the serial input string is an IPv6 address, it will not be sent as
any other string would, but instead it will configure the example to send to a
different remote address. This new IPv6 address is not persistent across
device reboots.
6lbr Client
-----------
This will periodically send a UDP packet to your 6lbr, containing network
information, which will be used by 6lbr to construct a network graph. To see
this in action, fire up a browser and navigate to the 6lbr web page. The
default address is http://[bbbb::100]. Once the page loads, click the 'sensors'
tab, as per the image below.
![6lbr](img/6lbr-web.png)
CoAP Server
-----------
For this functionality to work, you will need to install the
[Copper (Cu)](https://addons.mozilla.org/en-US/firefox/addon/copper-270430/)
addon to your browser.
From the sensors tab in the 6lbr web page, click the 'coap' link in the line
corresponding to your CC26xx device. Once the addon fires up, select
".well-known/core" in the left pane and then hit the 'Get' button at the top.
![CoAP Resources](img/coap-resources.png)
The Device will respond with a list of all available CoAP resources. This list
will be different between the Srf and the SensorTag. The screenshot below shows
a (partial) list of resources exported by the SensorTag CoAP server. Select
a resource on the left pane and hit 'Get' to retrieve its value. Select
`lt/g` and hit 'Post' to toggle the green LED, `lt/r` for the red one.
You can also use CoAP to enable/disable BLE advertisements! Select
`dev/ble_advd` and then hit the "Outgoing" button in the payload panel. Type in
the desired payload, which can be:
* `mode=on|off`
* `name=<name>`
* `interval=<secs>`
or a combination of both delimited with an amp. For example, you can set as
payload `mode=on&name=My CC26xx Device 4&interval=5`. Once you have set the
payload, hit either the POST or PUT button.
Bear in mind that you must set `name` at least once before enabling BLE
advertisements. If you fail to do so, the RF will refuse to enter BLE mode and
the CoAP engine will return 4.03 forbidden. The values of `name` and `interval`
persist across BLE on/off cycles, so you only have to set them once. The values
do _not_ persist through device powercycles.
HTTPD
-----
Back on the 6lbr page, hit the 'web' link corresponding to your device. This
will take you to a web page served by the CC26xx. The HTTPD serves two pages:
* index.html: Provides sensor readings and network information
* config.html: Can be used to configure the MQTT client (more below)
In the navigation bar at the top there is also a third link, which will take
you directly to your device's page on IBM's quickstart service.
IBM Quickstart / MQTT Client
----------------------------
The MQTT client can be used to:
* Publish sensor readings to an MQTT broker.
* Subscribe to a topic and as a result receive commands from an MQTT broker
The device will try to connect to IBM's quickstart over NAT64, so you will
need a NAT64 gateway in your network to make this work. A guide on how to
setup NAT64 is out of scope here. If this is not an option for you, you can
configure the device to publish to a local MQTT broker over end-to-end IPv6.
See below on how to change the destination broker's address.
By default the device will publish readings to IBM's quickstart service. The
publish messages include sensor readings but also some other information such
as device uptime in seconds and a message sequence number. Click the "IBM
Quickstart" link in the web page to go directly to your device's page
on Quickstart. After a few seconds, you will see something like this:
![A SensorTag on IBM Quickstart](img/quickstart-sensortag.png)
Sensor readings are only published if they have changed since the previous
reading (BatMon is an exception and always gets published). Additionally, you
can turn on/off individual readings from the config.html web page, as per the
figure below.
![Sensor Readings Configuration](img/sensor-readings-config.png)
Some of the MQTT client functionality can be configured even further:
* You can change the broker IP and port. This is useful if you want to use your
own MQTT broker instead of IBM's quickstart. The example has been tested
successfully with [mosquitto](http://mosquitto.org/)
* You can change the publish interval. Recommended values are 10secs or higher.
You will not be allowed to set this to anything less than 5 seconds.
* If you want to use IBM's cloud service with a registered device, change
'Org ID' and provide an 'Auth Token', which acts as a 'password', but bear in
mind that it gets transported in clear text, both over the web configuration
page as well as inside MQTT messages.
* The remaining configuration options are related to the content of MQTT
messages and in general you won't have to modify them.
For the SensorTag, changes to the MQTT configuration get saved in external
flash and persist across device restarts. The same does not hold true for
Srf+EM builds.
You can also subscribe to topics and receive commands, but this will only
work if you use "Org ID" != 'quickstart'. Thus, if you provide a different
Org ID (do not forget the auth token!), the device will subscribe to:
`iot-2/cmd/+/fmt/json`
You can then use this to toggle LEDs or to turn the buzzer on and off.
The buzzer is only available on the SensorTag. To do this, you can for example
use mosquitto client to publish to `iot-2/cmd/leds/fmt/json`. So, to turn
the buzzer on, you would do this:
`mosquitto_pub -h <broker IP> -m "1" -t iot-2/cmd/buzz/fmt/json`
Where `broker IP` should be replaced with the IP address of your mosquitto
broker (the one where you device has subscribed). Replace `-m "1'` with `-m "0"`
to turn the buzzer back off. Replace `buzz` with `leds` in the topic to change
the state of the LED.
Bear in mind that, even though the topic suggests that messages are of json
format, they are in fact not. This was done in order to avoid linking a json
parser into the firmware.

View file

@ -0,0 +1,893 @@
/*
* 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 cc26xx-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 "rest-engine.h"
#include "board-peripherals.h"
#include "lib/sensors.h"
#include "lib/list.h"
#include "sys/process.h"
#include "button-sensor.h"
#include "batmon-sensor.h"
#include "httpd-simple.h"
#include "cc26xx-web-demo.h"
#include "mqtt-client.h"
#include "coap-server.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*---------------------------------------------------------------------------*/
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 BOARD_SENSORTAG
struct ctimer bmp_timer, sht_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;
/*---------------------------------------------------------------------------*/
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 0xCC265001
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);
/* Sensortag sensors */
#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(sht_temp, CC26XX_WEB_DEMO_SENSOR_SHT_TEMP,
"SHT Temp", "sht-temp", "sht_temp",
CC26XX_WEB_DEMO_UNIT_TEMP);
DEMO_SENSOR(sht_hum, CC26XX_WEB_DEMO_SENSOR_SHT_HUMIDITY,
"SHT Humidity", "sht-humidity", "sht_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 BOARD_SENSORTAG
static void init_bmp_reading(void *data);
static void init_light_reading(void *data);
static void init_sht_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
int rv;
cc26xx_web_demo_sensor_reading_t *reading = NULL;
rv = ext_flash_open();
if(!rv) {
printf("Could not open flash to save config\n");
ext_flash_close();
return;
}
rv = ext_flash_erase(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(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();
#endif
}
/*---------------------------------------------------------------------------*/
static void
load_config()
{
#if BOARD_SENSORTAG
/* 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();
if(!rv) {
printf("Could not open flash to load config\n");
ext_flash_close();
return;
}
rv = ext_flash_read(CONFIG_FLASH_OFFSET, sizeof(tmp_cfg),
(uint8_t *)&tmp_cfg);
ext_flash_close();
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;
}
/*---------------------------------------------------------------------------*/
HTTPD_SIMPLE_POST_HANDLER(sensor, sensor_readings_handler);
HTTPD_SIMPLE_POST_HANDLER(defaults, defaults_post_handler);
/*---------------------------------------------------------------------------*/
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.%02d", value >> 2,
(value & 0x00000003) * 25);
}
}
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 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_sht_reading()
{
int value;
char *buf;
clock_time_t next = SENSOR_READING_PERIOD +
(random_rand() % SENSOR_READING_RANDOM);
if(sht_temp_reading.publish) {
value = sht_21_sensor.value(SHT_21_SENSOR_TYPE_TEMP);
if(value != CC26XX_SENSOR_READING_ERROR) {
sht_temp_reading.raw = value;
compare_and_update(&sht_temp_reading);
buf = sht_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(sht_hum_reading.publish) {
value = sht_21_sensor.value(SHT_21_SENSOR_TYPE_HUMIDITY);
if(value != CC26XX_SENSOR_READING_ERROR) {
sht_hum_reading.raw = value;
compare_and_update(&sht_hum_reading);
buf = sht_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(&sht_timer, next, init_sht_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);
SENSORS_DEACTIVATE(opt_3001_sensor);
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);
}
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_sht_reading(void *data)
{
if(sht_hum_reading.publish || sht_temp_reading.publish) {
SENSORS_ACTIVATE(sht_21_sensor);
} else {
ctimer_set(&sht_timer, CLOCK_SECOND, init_sht_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 BOARD_SENSORTAG
init_bmp_reading(NULL);
init_light_reading(NULL);
init_sht_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);
SENSORS_ACTIVATE(batmon_sensor);
#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, &sht_hum_reading);
list_add(sensor_list, &sht_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);
SENSORS_ACTIVATE(reed_relay_sensor);
#endif
}
/*---------------------------------------------------------------------------*/
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
/*
* 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 */
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);
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 == sensors_event && data == CC26XX_WEB_DEMO_SENSOR_READING_TRIGGER) {
if((CC26XX_WEB_DEMO_SENSOR_READING_TRIGGER)->value(
BUTTON_SENSOR_VALUE_DURATION) > CLOCK_SECOND * 5) {
printf("Restoring defaults!\n");
cc26xx_web_demo_restore_defaults();
} else {
init_sensor_readings();
process_post(PROCESS_BROADCAST, cc26xx_web_demo_publish_event, NULL);
}
} else 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);
}
} else if(ev == httpd_simple_event_new_config) {
save_config();
#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 == &sht_21_sensor) {
get_sht_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();
}
/*---------------------------------------------------------------------------*/
/**
* @}
*/

View file

@ -0,0 +1,210 @@
/*
* 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 cc26xx-examples
* @{
*
* \defgroup cc26xx-web-demo CC26xx Web Demo
* @{
*
* An example demonstrating:
* * how to use a CC26XX-powered node in a deployment driven by a 6LBR
* * how to expose on-device sensors as CoAP resources
* * how to build a small web page which reports networking and sensory data
* * how to configure functionality through the aforementioned web page using
* HTTP POST requests
* * a network-based UART
*
* \file
* Main header file for the CC26XX web demo.
*/
/*---------------------------------------------------------------------------*/
#ifndef CC26XX_WEB_DEMO_H_
#define CC26XX_WEB_DEMO_H_
/*---------------------------------------------------------------------------*/
#include "dev/leds.h"
#include "sys/process.h"
#include "mqtt-client.h"
#include "net-uart.h"
#include <stdint.h>
/*---------------------------------------------------------------------------*/
#ifdef CC26XX_WEB_DEMO_CONF_MQTT_CLIENT
#define CC26XX_WEB_DEMO_MQTT_CLIENT CC26XX_WEB_DEMO_CONF_MQTT_CLIENT
#else
#define CC26XX_WEB_DEMO_MQTT_CLIENT 1
#endif
#ifdef CC26XX_WEB_DEMO_CONF_6LBR_CLIENT
#define CC26XX_WEB_DEMO_6LBR_CLIENT CC26XX_WEB_DEMO_CONF_6LBR_CLIENT
#else
#define CC26XX_WEB_DEMO_6LBR_CLIENT 1
#endif
#ifdef CC26XX_WEB_DEMO_CONF_COAP_SERVER
#define CC26XX_WEB_DEMO_COAP_SERVER CC26XX_WEB_DEMO_CONF_COAP_SERVER
#else
#define CC26XX_WEB_DEMO_COAP_SERVER 1
#endif
#ifdef CC26XX_WEB_DEMO_CONF_NET_UART
#define CC26XX_WEB_DEMO_NET_UART CC26XX_WEB_DEMO_CONF_NET_UART
#else
#define CC26XX_WEB_DEMO_NET_UART 1
#endif
/*---------------------------------------------------------------------------*/
/* User configuration */
/* Take a sensor reading on button press */
#define CC26XX_WEB_DEMO_SENSOR_READING_TRIGGER &button_left_sensor
/* Payload length of ICMPv6 echo requests used to measure RSSI with def rt */
#define CC26XX_WEB_DEMO_ECHO_REQ_PAYLOAD_LEN 20
#if BOARD_SENSORTAG
/* Force an MQTT publish on sensor event */
#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER &reed_relay_sensor
#else
#define CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER &button_right_sensor
#endif
#define CC26XX_WEB_DEMO_STATUS_LED LEDS_GREEN
/*---------------------------------------------------------------------------*/
/* A timeout used when waiting to connect to a network */
#define CC26XX_WEB_DEMO_NET_CONNECT_PERIODIC (CLOCK_SECOND >> 3)
/*---------------------------------------------------------------------------*/
/* Default configuration values */
#define CC26XX_WEB_DEMO_DEFAULT_ORG_ID "quickstart"
#define CC26XX_WEB_DEMO_DEFAULT_TYPE_ID "cc26xx"
#define CC26XX_WEB_DEMO_DEFAULT_EVENT_TYPE_ID "status"
#define CC26XX_WEB_DEMO_DEFAULT_SUBSCRIBE_CMD_TYPE "+"
#define CC26XX_WEB_DEMO_DEFAULT_BROKER_PORT 1883
#define CC26XX_WEB_DEMO_DEFAULT_PUBLISH_INTERVAL (30 * CLOCK_SECOND)
#define CC26XX_WEB_DEMO_DEFAULT_KEEP_ALIVE_TIMER 60
#define CC26XX_WEB_DEMO_DEFAULT_RSSI_MEAS_INTERVAL (CLOCK_SECOND * 30)
/*---------------------------------------------------------------------------*/
/*
* You normally won't have to change anything from here onwards unless you are
* extending the example
*/
/*---------------------------------------------------------------------------*/
/* Sensor types */
#define CC26XX_WEB_DEMO_SENSOR_BATMON_TEMP 0
#define CC26XX_WEB_DEMO_SENSOR_BATMON_VOLT 1
#define CC26XX_WEB_DEMO_SENSOR_BMP_PRES 2
#define CC26XX_WEB_DEMO_SENSOR_BMP_TEMP 3
#define CC26XX_WEB_DEMO_SENSOR_TMP_AMBIENT 4
#define CC26XX_WEB_DEMO_SENSOR_TMP_OBJECT 5
#define CC26XX_WEB_DEMO_SENSOR_SHT_TEMP 6
#define CC26XX_WEB_DEMO_SENSOR_SHT_HUMIDITY 7
#define CC26XX_WEB_DEMO_SENSOR_OPT_LIGHT 8
#define CC26XX_WEB_DEMO_SENSOR_MPU_ACC_X 9
#define CC26XX_WEB_DEMO_SENSOR_MPU_ACC_Y 10
#define CC26XX_WEB_DEMO_SENSOR_MPU_ACC_Z 11
#define CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_X 12
#define CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_Y 13
#define CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_Z 14
/*---------------------------------------------------------------------------*/
extern process_event_t cc26xx_web_demo_publish_event;
extern process_event_t cc26xx_web_demo_config_loaded_event;
extern process_event_t cc26xx_web_demo_load_config_defaults;
/*---------------------------------------------------------------------------*/
#define CC26XX_WEB_DEMO_UNIT_TEMP "C"
#define CC26XX_WEB_DEMO_UNIT_VOLT "mV"
#define CC26XX_WEB_DEMO_UNIT_PRES "hPa"
#define CC26XX_WEB_DEMO_UNIT_HUMIDITY "%RH"
#define CC26XX_WEB_DEMO_UNIT_LIGHT "lux"
#define CC26XX_WEB_DEMO_UNIT_ACC "G"
#define CC26XX_WEB_DEMO_UNIT_GYRO "deg per sec"
/*---------------------------------------------------------------------------*/
/* A data type for sensor readings, internally stored in a linked list */
#define CC26XX_WEB_DEMO_CONVERTED_LEN 12
typedef struct cc26xx_web_demo_sensor_reading {
struct cc26xx_web_demo_sensor_reading *next;
int raw;
int last;
const char *descr;
const char *xml_element;
const char *form_field;
char *units;
uint8_t type;
uint8_t publish;
uint8_t changed;
char converted[CC26XX_WEB_DEMO_CONVERTED_LEN];
} cc26xx_web_demo_sensor_reading_t;
/*---------------------------------------------------------------------------*/
/* Global configuration */
typedef struct cc26xx_web_demo_config_s {
uint32_t magic;
int len;
uint32_t sensors_bitmap;
mqtt_client_config_t mqtt_config;
net_uart_config_t net_uart;
} cc26xx_web_demo_config_t;
extern cc26xx_web_demo_config_t cc26xx_web_demo_config;
/*---------------------------------------------------------------------------*/
/**
* \brief Performs a lookup for a reading of a specific type of sensor
* \param sens_type CC26XX_WEB_DEMO_SENSOR_BATMON_TEMP...
* \return A pointer to the reading data structure or NULL
*/
const cc26xx_web_demo_sensor_reading_t *cc26xx_web_demo_sensor_lookup(int sens_type);
/**
* \brief Returns the first available sensor reading
* \return A pointer to the reading data structure or NULL
*/
const cc26xx_web_demo_sensor_reading_t *cc26xx_web_demo_sensor_first(void);
/**
* \brief Print an IPv6 address into a buffer
* \param buf A pointer to the buffer where this function will print the IPv6
* address
* \param buf_len the length of the buffer
* \param addr A pointer to the IPv6 address
* \return The number of bytes written to the buffer
*
* It is the caller's responsibility to allocate enough space for buf
*/
int cc26xx_web_demo_ipaddr_sprintf(char *buf, uint8_t buf_len,
const uip_ipaddr_t *addr);
/**
* \brief Resets the example to a default configuration
*/
void cc26xx_web_demo_restore_defaults(void);
/*---------------------------------------------------------------------------*/
#endif /* CC26XX_WEB_DEMO_H_ */
/*---------------------------------------------------------------------------*/
/**
* @}
* @}
*/

View file

@ -0,0 +1,197 @@
/*
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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 cc26xx-web-demo
* @{
*
* \file
* An implementation of a 6LBR UDP client. Is used to populate the 6LBR
* web server's 'sensors' tab
*/
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include "contiki-lib.h"
#include "contiki-net.h"
#include "net/rpl/rpl.h"
#include "net/ip/uip.h"
#include <string.h>
#include <stdio.h>
/*---------------------------------------------------------------------------*/
#define DEBUG 0
#include "net/ip/uip-debug.h"
/*---------------------------------------------------------------------------*/
#ifndef CETIC_6LBR_NODE_INFO_PORT
#define CETIC_6LBR_NODE_INFO_PORT 3000
#endif
#define MAX_PAYLOAD_LEN 40
#define MSG_INTERVAL (60 * CLOCK_SECOND)
/*---------------------------------------------------------------------------*/
static struct uip_udp_conn *client_conn = NULL;
static struct etimer et;
static uip_ip6addr_t dest_addr;
/*---------------------------------------------------------------------------*/
PROCESS(cetic_6lbr_client_process, "6LBR Client Process");
/*---------------------------------------------------------------------------*/
static void
tcpip_handler(void)
{
char *str;
if(uip_newdata()) {
str = uip_appdata;
str[uip_datalen()] = '\0';
PRINTF("Response from the server: '%s'\n", str);
}
}
/*---------------------------------------------------------------------------*/
static char *
add_ipaddr(char *buf, const uip_ipaddr_t *addr)
{
uint16_t a;
unsigned int i;
int f;
char *p = buf;
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) {
p += sprintf(p, "::");
}
} else {
if(f > 0) {
f = -1;
} else if(i > 0) {
p += sprintf(p, ":");
}
p += sprintf(p, "%04x", a);
}
}
return p;
}
/*---------------------------------------------------------------------------*/
static void
timeout_handler(void)
{
static int seq_id;
char buf[MAX_PAYLOAD_LEN];
int i;
uip_ip6addr_t *globaladdr = NULL;
uint16_t dest_port = CETIC_6LBR_NODE_INFO_PORT;
int has_dest = 0;
rpl_dag_t *dag;
uip_ds6_addr_t *addr_desc = uip_ds6_get_global(ADDR_PREFERRED);
if(addr_desc != NULL) {
globaladdr = &addr_desc->ipaddr;
dag = rpl_get_any_dag();
if(dag) {
uip_ipaddr_copy(&dest_addr, globaladdr);
memcpy(&dest_addr.u8[8], &dag->dag_id.u8[8], sizeof(uip_ipaddr_t) / 2);
has_dest = 1;
}
}
if(has_dest) {
if(client_conn == NULL) {
PRINTF("UDP-CLIENT: address destination: ");
PRINT6ADDR(&dest_addr);
PRINTF("\n");
client_conn = udp_new(&dest_addr, UIP_HTONS(dest_port), NULL);
if(client_conn != NULL) {
PRINTF("Created a connection with the server ");
PRINT6ADDR(&client_conn->ripaddr);
PRINTF(" local/remote port %u/%u\n",
UIP_HTONS(client_conn->lport), UIP_HTONS(client_conn->rport));
} else {
PRINTF("Could not open connection\n");
}
} else {
if(memcmp(&client_conn->ripaddr, &dest_addr, sizeof(uip_ipaddr_t)) != 0) {
PRINTF("UDP-CLIENT: new address destination: ");
PRINT6ADDR(&dest_addr);
PRINTF("\n");
uip_udp_remove(client_conn);
client_conn = udp_new(&dest_addr, UIP_HTONS(dest_port), NULL);
if(client_conn != NULL) {
PRINTF("Created a connection with the server ");
PRINT6ADDR(&client_conn->ripaddr);
PRINTF(" local/remote port %u/%u\n",
UIP_HTONS(client_conn->lport), UIP_HTONS(client_conn->rport));
} else {
PRINTF("Could not open connection\n");
}
}
}
if(client_conn != NULL) {
PRINTF("Client sending to: ");
PRINT6ADDR(&client_conn->ripaddr);
i = sprintf(buf, "%d | ", ++seq_id);
dag = rpl_get_any_dag();
if(dag && dag->instance->def_route) {
add_ipaddr(buf + i, &dag->instance->def_route->ipaddr);
} else {
sprintf(buf + i, "(null)");
}
PRINTF(" (msg: %s)\n", buf);
uip_udp_packet_send(client_conn, buf, strlen(buf));
} else {
PRINTF("No connection created\n");
}
} else {
PRINTF("No address configured\n");
}
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(cetic_6lbr_client_process, ev, data)
{
PROCESS_BEGIN();
printf("6LBR Client Process\n");
memset(&dest_addr, 0, sizeof(uip_ipaddr_t));
etimer_set(&et, MSG_INTERVAL);
while(1) {
PROCESS_YIELD();
if(etimer_expired(&et)) {
timeout_handler();
etimer_set(&et, MSG_INTERVAL);
} else if(ev == tcpip_event) {
tcpip_handler();
}
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
/**
* @}
*/

View file

@ -0,0 +1,157 @@
/*
* 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 cc26xx-web-demo
* @{
*
* \file
* A CC26XX-specific CoAP server
*/
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include "contiki-net.h"
#include "rest-engine.h"
#include "board-peripherals.h"
#include "dev/cc26xx-rf.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*---------------------------------------------------------------------------*/
/* Common resources */
extern resource_t res_leds;
extern resource_t res_batmon_temp;
extern resource_t res_batmon_volt;
extern resource_t res_device_sw;
extern resource_t res_device_hw;
extern resource_t res_device_uptime;
extern resource_t res_device_cfg_reset;
#if CC26XX_RF_BLE_SUPPORT
extern resource_t res_ble_advd;
#endif
/* Board-specific resources */
#if BOARD_SENSORTAG
extern resource_t res_bmp280_temp;
extern resource_t res_bmp280_press;
extern resource_t res_tmp007_amb;
extern resource_t res_tmp007_obj;
extern resource_t res_sht21_temp;
extern resource_t res_sht21_hum;
extern resource_t res_opt3001_light;
extern resource_t res_mpu_acc_x;
extern resource_t res_mpu_acc_y;
extern resource_t res_mpu_acc_z;
extern resource_t res_mpu_gyro_x;
extern resource_t res_mpu_gyro_y;
extern resource_t res_mpu_gyro_z;
extern resource_t res_toggle_red;
extern resource_t res_toggle_green;
#else
extern resource_t res_toggle_red;
extern resource_t res_toggle_green;
extern resource_t res_toggle_orange;
extern resource_t res_toggle_yellow;
#endif
/*---------------------------------------------------------------------------*/
const char *coap_server_not_found_msg = "Resource not found";
const char *coap_server_supported_msg = "Supported:"
"text/plain,"
"application/json,"
"application/xml";
/*---------------------------------------------------------------------------*/
static void
start_board_resources(void)
{
#if BOARD_SENSORTAG
rest_activate_resource(&res_bmp280_temp, "sen/bar/temp");
rest_activate_resource(&res_bmp280_press, "sen/bar/pres");
rest_activate_resource(&res_tmp007_amb, "sen/tmp/amb");
rest_activate_resource(&res_tmp007_obj, "sen/tmp/obj");
rest_activate_resource(&res_sht21_temp, "sen/sht/t");
rest_activate_resource(&res_sht21_hum, "sen/sht/h");
rest_activate_resource(&res_opt3001_light, "sen/opt/light");
rest_activate_resource(&res_mpu_acc_x, "sen/mpu/acc/x");
rest_activate_resource(&res_mpu_acc_y, "sen/mpu/acc/y");
rest_activate_resource(&res_mpu_acc_z, "sen/mpu/acc/z");
rest_activate_resource(&res_mpu_gyro_x, "sen/mpu/gyro/x");
rest_activate_resource(&res_mpu_gyro_y, "sen/mpu/gyro/y");
rest_activate_resource(&res_mpu_gyro_z, "sen/mpu/gyro/z");
rest_activate_resource(&res_leds, "lt");
rest_activate_resource(&res_toggle_green, "lt/g");
rest_activate_resource(&res_toggle_red, "lt/r");
#elif BOARD_SMARTRF06EB
rest_activate_resource(&res_leds, "lt");
rest_activate_resource(&res_toggle_red, "lt/r");
rest_activate_resource(&res_toggle_yellow, "lt/y");
rest_activate_resource(&res_toggle_green, "lt/g");
rest_activate_resource(&res_toggle_orange, "lt/o");
#endif
}
/*---------------------------------------------------------------------------*/
PROCESS(coap_server_process, "CC26XX CoAP Server");
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(coap_server_process, ev, data)
{
PROCESS_BEGIN();
printf("CC26XX CoAP Server\n");
/* Initialize the REST engine. */
rest_init_engine();
rest_activate_resource(&res_batmon_temp, "sen/batmon/temp");
rest_activate_resource(&res_batmon_volt, "sen/batmon/voltage");
rest_activate_resource(&res_device_hw, "dev/mdl/hw");
rest_activate_resource(&res_device_sw, "dev/mdl/sw");
rest_activate_resource(&res_device_uptime, "dev/uptime");
rest_activate_resource(&res_device_cfg_reset, "dev/cfg_reset");
#if CC26XX_RF_BLE_SUPPORT
rest_activate_resource(&res_ble_advd, "dev/ble_advd");
#endif
start_board_resources();
/* Define application-specific events here. */
while(1) {
PROCESS_WAIT_EVENT();
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
/**
* @}
*/

View file

@ -0,0 +1,52 @@
/*
* 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 cc26xx-web-demo
* @{
*
* \file
* Header file for the CC26xx web demo CoAP functionality
*/
/*---------------------------------------------------------------------------*/
#include "sys/process.h"
/*---------------------------------------------------------------------------*/
#ifndef COAP_SERVER_H_
#define COAP_SERVER_H_
/*---------------------------------------------------------------------------*/
extern const char *coap_server_not_found_msg;
extern const char *coap_server_supported_msg;
/*---------------------------------------------------------------------------*/
PROCESS_NAME(coap_server_process);
/*---------------------------------------------------------------------------*/
#endif /* COAP_SERVER_H_ */
/*---------------------------------------------------------------------------*/
/**
* @}
*/

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,101 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* 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 Institute 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 INSTITUTE 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 INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/*---------------------------------------------------------------------------*/
/**
* \file
* Header file for the HTTPD of the cc26xx web demo example.
* \author
* Adam Dunkels <adam@sics.se>
* Niclas Finne <nfi@sics.se>
* Joakim Eriksson <joakime@sics.se>
* Texas Instruments Incorporated - http://www.ti.com/
*/
/*---------------------------------------------------------------------------*/
#ifndef HTTPD_SIMPLE_H_
#define HTTPD_SIMPLE_H_
/*---------------------------------------------------------------------------*/
#include "contiki-net.h"
#include "sys/process.h"
#include "cc26xx-web-demo.h"
/*---------------------------------------------------------------------------*/
/* Ideally a multiple of TCP_MSS */
#ifdef HTTPD_SIMPLE_CONF_MAIN_BUF_SIZE
#define HTTPD_SIMPLE_MAIN_BUF_SIZE HTTPD_SIMPLE_CONF_BUF_SIZE
#else
#define HTTPD_SIMPLE_MAIN_BUF_SIZE UIP_TCP_MSS
#endif
/*---------------------------------------------------------------------------*/
#define HTTPD_PATHLEN 16
#define HTTPD_INBUF_LEN (HTTPD_PATHLEN + 10)
#define TMP_BUF_SIZE (UIP_TCP_MSS + 1)
/*---------------------------------------------------------------------------*/
/* POST request handlers */
#define HTTPD_SIMPLE_POST_HANDLER_OK 1
#define HTTPD_SIMPLE_POST_HANDLER_UNKNOWN 0
#define HTTPD_SIMPLE_POST_HANDLER_ERROR 0xFFFFFFFF
/**
* \brief Datatype for a handler which can process incoming POST requests
* \param key The configuration key to be updated
* \param key_len The length of the key argument
* \param val The new configuration value for key
* \param val_len The length of the value argument
*
* \return 1: HTTPD_SIMPLE_POST_HANDLER_OK if the function can handle the
* request, HTTPD_SIMPLE_POST_HANDLER_UNKNOWN if it does not know how to handle
* it. HTTPD_SIMPLE_POST_HANDLER_ERROR if it does know how to handle it but
* the request was malformed.
*/
typedef struct httpd_simple_post_handler {
struct httpd_simple_post_handler *next;
int (*handler)(char *key, int key_len, char *val, int val_len);
} httpd_simple_post_handler_t;
/* Declare a handler */
#define HTTPD_SIMPLE_POST_HANDLER(name, fp) \
httpd_simple_post_handler_t name##_handler = { NULL, fp }
/**
* \brief Register a handler for POST requests
* \param h A pointer to the handler structure
*/
void httpd_simple_register_post_handler(httpd_simple_post_handler_t *h);
/*---------------------------------------------------------------------------*/
/*
* An event generated by the HTTPD when a new configuration request has been
* received
*/
extern process_event_t httpd_simple_event_new_config;
/*---------------------------------------------------------------------------*/
PROCESS_NAME(httpd_simple_process);
/*---------------------------------------------------------------------------*/
#endif /* HTTPD_SIMPLE_H_ */

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

View file

@ -0,0 +1,975 @@
/*
* 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 cc26xx-web-demo
* @{
*
* \file
* MQTT/IBM cloud service client for the CC26XX web demo.
*/
/*---------------------------------------------------------------------------*/
#include "contiki-conf.h"
#include "rpl/rpl-private.h"
#include "mqtt.h"
#include "net/rpl/rpl.h"
#include "net/ip/uip.h"
#include "net/ipv6/uip-icmp6.h"
#include "net/ipv6/sicslowpan.h"
#include "sys/etimer.h"
#include "sys/ctimer.h"
#include "lib/sensors.h"
#include "button-sensor.h"
#include "board-peripherals.h"
#include "cc26xx-web-demo.h"
#include "dev/leds.h"
#include "mqtt-client.h"
#include "httpd-simple.h"
#include <string.h>
#include <strings.h>
/*---------------------------------------------------------------------------*/
/*
* IBM server: messaging.quickstart.internetofthings.ibmcloud.com
* (184.172.124.189) mapped in an NAT64 (prefix 64:ff9b::/96) IPv6 address
* Note: If not able to connect; lookup the IP address again as it may change.
*
* If the node has a broker IP setting saved on flash, this value here will
* get ignored
*/
static const char *broker_ip = "0064:ff9b:0000:0000:0000:0000:b8ac:7cbd";
/*---------------------------------------------------------------------------*/
/*
* A timeout used when waiting for something to happen (e.g. to connect or to
* disconnect)
*/
#define STATE_MACHINE_PERIODIC (CLOCK_SECOND >> 1)
/*---------------------------------------------------------------------------*/
/* Provide visible feedback via LEDS during various states */
/* When connecting to broker */
#define CONNECTING_LED_DURATION (CLOCK_SECOND >> 3)
/* Each time we try to publish */
#define PUBLISH_LED_ON_DURATION (CLOCK_SECOND)
/*---------------------------------------------------------------------------*/
/* Connections and reconnections */
#define RETRY_FOREVER 0xFF
#define RECONNECT_INTERVAL (CLOCK_SECOND * 2)
/*
* Number of times to try reconnecting to the broker.
* Can be a limited number (e.g. 3, 10 etc) or can be set to RETRY_FOREVER
*/
#define RECONNECT_ATTEMPTS RETRY_FOREVER
#define CONNECTION_STABLE_TIME (CLOCK_SECOND * 5)
#define NEW_CONFIG_WAIT_INTERVAL (CLOCK_SECOND * 20)
static struct timer connection_life;
static uint8_t connect_attempt;
/*---------------------------------------------------------------------------*/
/* Various states */
static uint8_t state;
#define MQTT_CLIENT_STATE_INIT 0
#define MQTT_CLIENT_STATE_REGISTERED 1
#define MQTT_CLIENT_STATE_CONNECTING 2
#define MQTT_CLIENT_STATE_CONNECTED 3
#define MQTT_CLIENT_STATE_PUBLISHING 4
#define MQTT_CLIENT_STATE_DISCONNECTED 5
#define MQTT_CLIENT_STATE_NEWCONFIG 6
#define MQTT_CLIENT_STATE_CONFIG_ERROR 0xFE
#define MQTT_CLIENT_STATE_ERROR 0xFF
/*---------------------------------------------------------------------------*/
/* Maximum TCP segment size for outgoing segments of our socket */
#define MQTT_CLIENT_MAX_SEGMENT_SIZE 32
/*---------------------------------------------------------------------------*/
/*
* Buffers for Client ID and Topic.
* Make sure they are large enough to hold the entire respective string
*
* d:quickstart:status:EUI64 is 32 bytes long
* iot-2/evt/status/fmt/json is 25 bytes
* We also need space for the null termination
*/
#define BUFFER_SIZE 64
static char client_id[BUFFER_SIZE];
static char pub_topic[BUFFER_SIZE];
static char sub_topic[BUFFER_SIZE];
/*---------------------------------------------------------------------------*/
/*
* The main MQTT buffers.
* We will need to increase if we start publishing more data.
*/
#define APP_BUFFER_SIZE 512
static struct mqtt_connection conn;
static char app_buffer[APP_BUFFER_SIZE];
/*---------------------------------------------------------------------------*/
#define QUICKSTART "quickstart"
/*---------------------------------------------------------------------------*/
static struct mqtt_message *msg_ptr = 0;
static struct etimer publish_periodic_timer;
static struct ctimer ct;
static char *buf_ptr;
static uint16_t seq_nr_value = 0;
/*---------------------------------------------------------------------------*/
static uip_ip6addr_t def_route;
/*---------------------------------------------------------------------------*/
/* Parent RSSI functionality */
static struct uip_icmp6_echo_reply_notification echo_reply_notification;
static struct etimer echo_request_timer;
int def_rt_rssi = 0;
/*---------------------------------------------------------------------------*/
const static cc26xx_web_demo_sensor_reading_t *reading;
/*---------------------------------------------------------------------------*/
mqtt_client_config_t *conf;
/*---------------------------------------------------------------------------*/
PROCESS(mqtt_client_process, "CC26XX MQTT Client");
/*---------------------------------------------------------------------------*/
static void
publish_led_off(void *d)
{
leds_off(CC26XX_WEB_DEMO_STATUS_LED);
}
/*---------------------------------------------------------------------------*/
static void
new_net_config(void)
{
/*
* We got a new configuration over the net.
*
* Disconnect from the current broker and stop the periodic timer.
*
* When the source of the new configuration is done, we will get notified
* via an event.
*/
if(state == MQTT_CLIENT_STATE_NEWCONFIG) {
return;
}
state = MQTT_CLIENT_STATE_NEWCONFIG;
etimer_stop(&publish_periodic_timer);
mqtt_disconnect(&conn);
}
/*---------------------------------------------------------------------------*/
static int
org_id_post_handler(char *key, int key_len, char *val, int val_len)
{
int rv = HTTPD_SIMPLE_POST_HANDLER_UNKNOWN;
if(key_len != strlen("org_id") ||
strncasecmp(key, "org_id", strlen("org_id")) != 0) {
/* Not ours */
return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN;
}
if(val_len > MQTT_CLIENT_CONFIG_ORG_ID_LEN) {
/* Ours but bad value */
rv = HTTPD_SIMPLE_POST_HANDLER_ERROR;
} else {
memset(conf->org_id, 0, MQTT_CLIENT_CONFIG_ORG_ID_LEN);
memcpy(conf->org_id, val, val_len);
rv = HTTPD_SIMPLE_POST_HANDLER_OK;
}
new_net_config();
return rv;
}
/*---------------------------------------------------------------------------*/
static int
type_id_post_handler(char *key, int key_len, char *val, int val_len)
{
int rv = HTTPD_SIMPLE_POST_HANDLER_UNKNOWN;
if(key_len != strlen("type_id") ||
strncasecmp(key, "type_id", strlen("type_id")) != 0) {
/* Not ours */
return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN;
}
if(val_len > MQTT_CLIENT_CONFIG_TYPE_ID_LEN) {
/* Ours but bad value */
rv = HTTPD_SIMPLE_POST_HANDLER_ERROR;
} else {
memset(conf->type_id, 0, MQTT_CLIENT_CONFIG_TYPE_ID_LEN);
memcpy(conf->type_id, val, val_len);
rv = HTTPD_SIMPLE_POST_HANDLER_OK;
}
new_net_config();
return rv;
}
/*---------------------------------------------------------------------------*/
static int
event_type_id_post_handler(char *key, int key_len, char *val, int val_len)
{
int rv = HTTPD_SIMPLE_POST_HANDLER_UNKNOWN;
if(key_len != strlen("event_type_id") ||
strncasecmp(key, "event_type_id", strlen("event_type_id")) != 0) {
/* Not ours */
return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN;
}
if(val_len > MQTT_CLIENT_CONFIG_EVENT_TYPE_ID_LEN) {
/* Ours but bad value */
rv = HTTPD_SIMPLE_POST_HANDLER_ERROR;
} else {
memset(conf->event_type_id, 0, MQTT_CLIENT_CONFIG_EVENT_TYPE_ID_LEN);
memcpy(conf->event_type_id, val, val_len);
rv = HTTPD_SIMPLE_POST_HANDLER_OK;
}
new_net_config();
return rv;
}
/*---------------------------------------------------------------------------*/
static int
cmd_type_post_handler(char *key, int key_len, char *val, int val_len)
{
int rv = HTTPD_SIMPLE_POST_HANDLER_UNKNOWN;
if(key_len != strlen("cmd_type") ||
strncasecmp(key, "cmd_type", strlen("cmd_type")) != 0) {
/* Not ours */
return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN;
}
if(val_len > MQTT_CLIENT_CONFIG_CMD_TYPE_LEN) {
/* Ours but bad value */
rv = HTTPD_SIMPLE_POST_HANDLER_ERROR;
} else {
memset(conf->cmd_type, 0, MQTT_CLIENT_CONFIG_CMD_TYPE_LEN);
memcpy(conf->cmd_type, val, val_len);
rv = HTTPD_SIMPLE_POST_HANDLER_OK;
}
new_net_config();
return rv;
}
/*---------------------------------------------------------------------------*/
static int
auth_token_post_handler(char *key, int key_len, char *val, int val_len)
{
int rv = HTTPD_SIMPLE_POST_HANDLER_UNKNOWN;
if(key_len != strlen("auth_token") ||
strncasecmp(key, "auth_token", strlen("auth_token")) != 0) {
/* Not ours */
return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN;
}
if(val_len > MQTT_CLIENT_CONFIG_AUTH_TOKEN_LEN) {
/* Ours but bad value */
rv = HTTPD_SIMPLE_POST_HANDLER_ERROR;
} else {
memset(conf->auth_token, 0, MQTT_CLIENT_CONFIG_AUTH_TOKEN_LEN);
memcpy(conf->auth_token, val, val_len);
rv = HTTPD_SIMPLE_POST_HANDLER_OK;
}
new_net_config();
return rv;
}
/*---------------------------------------------------------------------------*/
static int
interval_post_handler(char *key, int key_len, char *val, int val_len)
{
int rv = 0;
if(key_len != strlen("interval") ||
strncasecmp(key, "interval", strlen("interval")) != 0) {
/* Not ours */
return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN;
}
rv = atoi(val);
if(rv < MQTT_CLIENT_PUBLISH_INTERVAL_MIN ||
rv > MQTT_CLIENT_PUBLISH_INTERVAL_MAX) {
return HTTPD_SIMPLE_POST_HANDLER_ERROR;
}
conf->pub_interval = rv * CLOCK_SECOND;
return HTTPD_SIMPLE_POST_HANDLER_OK;
}
/*---------------------------------------------------------------------------*/
static int
port_post_handler(char *key, int key_len, char *val, int val_len)
{
int rv = 0;
if(key_len != strlen("broker_port") ||
strncasecmp(key, "broker_port", strlen("broker_port")) != 0) {
/* Not ours */
return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN;
}
rv = atoi(val);
if(rv <= 65535 && rv > 0) {
conf->broker_port = rv;
} else {
return HTTPD_SIMPLE_POST_HANDLER_ERROR;
}
new_net_config();
return HTTPD_SIMPLE_POST_HANDLER_OK;
}
/*---------------------------------------------------------------------------*/
static int
ip_addr_post_handler(char *key, int key_len, char *val, int val_len)
{
int rv = HTTPD_SIMPLE_POST_HANDLER_UNKNOWN;
if(key_len != strlen("broker_ip") ||
strncasecmp(key, "broker_ip", strlen("broker_ip")) != 0) {
/* Not ours */
return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN;
}
if(val_len > MQTT_CLIENT_CONFIG_IP_ADDR_STR_LEN) {
/* Ours but bad value */
rv = HTTPD_SIMPLE_POST_HANDLER_ERROR;
} else {
memset(conf->broker_ip, 0, MQTT_CLIENT_CONFIG_IP_ADDR_STR_LEN);
memcpy(conf->broker_ip, val, val_len);
rv = HTTPD_SIMPLE_POST_HANDLER_OK;
}
new_net_config();
return rv;
}
/*---------------------------------------------------------------------------*/
static int
reconnect_post_handler(char *key, int key_len, char *val, int val_len)
{
if(key_len != strlen("reconnect") ||
strncasecmp(key, "reconnect", strlen("reconnect")) != 0) {
/* Not ours */
return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN;
}
new_net_config();
return HTTPD_SIMPLE_POST_HANDLER_OK;
}
/*---------------------------------------------------------------------------*/
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 < MQTT_CLIENT_RSSI_MEASURE_INTERVAL_MIN ||
rv > MQTT_CLIENT_RSSI_MEASURE_INTERVAL_MAX) {
return HTTPD_SIMPLE_POST_HANDLER_ERROR;
}
conf->def_rt_ping_interval = rv * CLOCK_SECOND;
return HTTPD_SIMPLE_POST_HANDLER_OK;
}
/*---------------------------------------------------------------------------*/
HTTPD_SIMPLE_POST_HANDLER(org_id, org_id_post_handler);
HTTPD_SIMPLE_POST_HANDLER(type_id, type_id_post_handler);
HTTPD_SIMPLE_POST_HANDLER(event_type_id, event_type_id_post_handler);
HTTPD_SIMPLE_POST_HANDLER(cmd_type, cmd_type_post_handler);
HTTPD_SIMPLE_POST_HANDLER(auth_token, auth_token_post_handler);
HTTPD_SIMPLE_POST_HANDLER(ip_addr, ip_addr_post_handler);
HTTPD_SIMPLE_POST_HANDLER(port, port_post_handler);
HTTPD_SIMPLE_POST_HANDLER(interval, interval_post_handler);
HTTPD_SIMPLE_POST_HANDLER(reconnect, reconnect_post_handler);
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
pub_handler(const char *topic, uint16_t topic_len, const uint8_t *chunk,
uint16_t chunk_len)
{
DBG("Pub Handler: topic='%s' (len=%u), chunk_len=%u\n", topic, topic_len,
chunk_len);
/* If we don't like the length, ignore */
if(topic_len != 23 || chunk_len != 1) {
printf("Incorrect topic or chunk len. Ignored\n");
return;
}
/* If the format != json, ignore */
if(strncmp(&topic[topic_len - 4], "json", 4) != 0) {
printf("Incorrect format\n");
}
if(strncmp(&topic[10], "leds", 4) == 0) {
if(chunk[0] == '1') {
leds_on(LEDS_RED);
} else if(chunk[0] == '0') {
leds_off(LEDS_RED);
}
return;
}
#if BOARD_SENSORTAG
if(strncmp(&topic[10], "buzz", 4) == 0) {
if(chunk[0] == '1') {
buzzer_start(1000);
} else if(chunk[0] == '0') {
buzzer_stop();
}
return;
}
#endif
}
/*---------------------------------------------------------------------------*/
static void
mqtt_event(struct mqtt_connection *m, mqtt_event_t event, void *data)
{
switch(event) {
case MQTT_EVENT_CONNECTED: {
DBG("APP - Application has a MQTT connection\n");
timer_set(&connection_life, CONNECTION_STABLE_TIME);
state = MQTT_CLIENT_STATE_CONNECTED;
break;
}
case MQTT_EVENT_DISCONNECTED: {
DBG("APP - MQTT Disconnect. Reason %u\n", *((mqtt_event_t *)data));
/* Do nothing if the disconnect was the result of an incoming config */
if(state != MQTT_CLIENT_STATE_NEWCONFIG) {
state = MQTT_CLIENT_STATE_DISCONNECTED;
process_poll(&mqtt_client_process);
}
break;
}
case MQTT_EVENT_PUBLISH: {
msg_ptr = data;
/* Implement first_flag in publish message? */
if(msg_ptr->first_chunk) {
msg_ptr->first_chunk = 0;
DBG("APP - Application received a publish on topic '%s'. Payload "
"size is %i bytes. Content:\n\n",
msg_ptr->topic, msg_ptr->payload_length);
}
pub_handler(msg_ptr->topic, strlen(msg_ptr->topic), msg_ptr->payload_chunk,
msg_ptr->payload_length);
break;
}
case MQTT_EVENT_SUBACK: {
DBG("APP - Application is subscribed to topic successfully\n");
break;
}
case MQTT_EVENT_UNSUBACK: {
DBG("APP - Application is unsubscribed to topic successfully\n");
break;
}
case MQTT_EVENT_PUBACK: {
DBG("APP - Publishing complete.\n");
break;
}
default:
DBG("APP - Application got a unhandled MQTT event: %i\n", event);
break;
}
}
/*---------------------------------------------------------------------------*/
static int
construct_pub_topic(void)
{
int len = snprintf(pub_topic, BUFFER_SIZE, "iot-2/evt/%s/fmt/json",
conf->event_type_id);
/* len < 0: Error. Len >= BUFFER_SIZE: Buffer too small */
if(len < 0 || len >= BUFFER_SIZE) {
printf("Pub Topic: %d, Buffer %d\n", len, BUFFER_SIZE);
return 0;
}
return 1;
}
/*---------------------------------------------------------------------------*/
static int
construct_sub_topic(void)
{
int len = snprintf(sub_topic, BUFFER_SIZE, "iot-2/cmd/%s/fmt/json",
conf->cmd_type);
/* len < 0: Error. Len >= BUFFER_SIZE: Buffer too small */
if(len < 0 || len >= BUFFER_SIZE) {
printf("Sub Topic: %d, Buffer %d\n", len, BUFFER_SIZE);
return 0;
}
return 1;
}
/*---------------------------------------------------------------------------*/
static int
construct_client_id(void)
{
int len = snprintf(client_id, BUFFER_SIZE, "d:%s:%s:%02x%02x%02x%02x%02x%02x",
conf->org_id, conf->type_id,
linkaddr_node_addr.u8[0], linkaddr_node_addr.u8[1],
linkaddr_node_addr.u8[2], linkaddr_node_addr.u8[5],
linkaddr_node_addr.u8[6], linkaddr_node_addr.u8[7]);
/* len < 0: Error. Len >= BUFFER_SIZE: Buffer too small */
if(len < 0 || len >= BUFFER_SIZE) {
printf("Client ID: %d, Buffer %d\n", len, BUFFER_SIZE);
return 0;
}
return 1;
}
/*---------------------------------------------------------------------------*/
static void
update_config(void)
{
if(construct_client_id() == 0) {
/* Fatal error. Client ID larger than the buffer */
state = MQTT_CLIENT_STATE_CONFIG_ERROR;
return;
}
if(construct_sub_topic() == 0) {
/* Fatal error. Topic larger than the buffer */
state = MQTT_CLIENT_STATE_CONFIG_ERROR;
return;
}
if(construct_pub_topic() == 0) {
/* Fatal error. Topic larger than the buffer */
state = MQTT_CLIENT_STATE_CONFIG_ERROR;
return;
}
/* Reset the counter */
seq_nr_value = 0;
state = MQTT_CLIENT_STATE_INIT;
/*
* Schedule next timer event ASAP
*
* If we entered an error state then we won't do anything when it fires.
*
* Since the error at this stage is a config error, we will only exit this
* error state if we get a new config.
*/
etimer_set(&publish_periodic_timer, 0);
return;
}
/*---------------------------------------------------------------------------*/
static int
init_config()
{
/* Populate configuration with default values */
memset(conf, 0, sizeof(mqtt_client_config_t));
memcpy(conf->org_id, CC26XX_WEB_DEMO_DEFAULT_ORG_ID, 11);
memcpy(conf->type_id, CC26XX_WEB_DEMO_DEFAULT_TYPE_ID, 7);
memcpy(conf->event_type_id, CC26XX_WEB_DEMO_DEFAULT_EVENT_TYPE_ID, 7);
memcpy(conf->broker_ip, broker_ip, strlen(broker_ip));
memcpy(conf->cmd_type, CC26XX_WEB_DEMO_DEFAULT_SUBSCRIBE_CMD_TYPE, 1);
conf->broker_port = CC26XX_WEB_DEMO_DEFAULT_BROKER_PORT;
conf->pub_interval = CC26XX_WEB_DEMO_DEFAULT_PUBLISH_INTERVAL;
conf->def_rt_ping_interval = CC26XX_WEB_DEMO_DEFAULT_RSSI_MEAS_INTERVAL;
return 1;
}
/*---------------------------------------------------------------------------*/
static void
register_http_post_handlers(void)
{
httpd_simple_register_post_handler(&org_id_handler);
httpd_simple_register_post_handler(&type_id_handler);
httpd_simple_register_post_handler(&event_type_id_handler);
httpd_simple_register_post_handler(&cmd_type_handler);
httpd_simple_register_post_handler(&auth_token_handler);
httpd_simple_register_post_handler(&interval_handler);
httpd_simple_register_post_handler(&port_handler);
httpd_simple_register_post_handler(&ip_addr_handler);
httpd_simple_register_post_handler(&reconnect_handler);
httpd_simple_register_post_handler(&ping_interval_handler);
}
/*---------------------------------------------------------------------------*/
static void
subscribe(void)
{
/* Publish MQTT topic in IBM quickstart format */
mqtt_status_t status;
status = mqtt_subscribe(&conn, NULL, sub_topic, MQTT_QOS_LEVEL_0);
DBG("APP - Subscribing!\n");
if(status == MQTT_STATUS_OUT_QUEUE_FULL) {
DBG("APP - Tried to subscribe but command queue was full!\n");
}
}
/*---------------------------------------------------------------------------*/
static void
publish(void)
{
/* Publish MQTT topic in IBM quickstart format */
int len;
int remaining = APP_BUFFER_SIZE;
seq_nr_value++;
buf_ptr = app_buffer;
len = snprintf(buf_ptr, remaining,
"{"
"\"d\":{"
"\"myName\":\"%s\","
"\"Seq #\":%d,"
"\"Uptime (sec)\":%lu",
BOARD_STRING, seq_nr_value, clock_seconds());
if(len < 0 || len >= remaining) {
printf("Buffer too short. Have %d, need %d + \\0\n", remaining, len);
return;
}
remaining -= len;
buf_ptr += len;
/* Put our Default route's string representation in a buffer */
char def_rt_str[64];
memset(def_rt_str, 0, sizeof(def_rt_str));
cc26xx_web_demo_ipaddr_sprintf(def_rt_str, sizeof(def_rt_str),
uip_ds6_defrt_choose());
len = snprintf(buf_ptr, remaining, ",\"Def Route\":\"%s\",\"RSSI (dBm)\":%d",
def_rt_str, def_rt_rssi);
if(len < 0 || len >= remaining) {
printf("Buffer too short. Have %d, need %d + \\0\n", remaining, len);
return;
}
remaining -= len;
buf_ptr += len;
memcpy(&def_route, uip_ds6_defrt_choose(), sizeof(uip_ip6addr_t));
for(reading = cc26xx_web_demo_sensor_first();
reading != NULL; reading = reading->next) {
if(reading->publish && reading->raw != CC26XX_SENSOR_READING_ERROR) {
len = snprintf(buf_ptr, remaining,
",\"%s (%s)\":%s", reading->descr, reading->units,
reading->converted);
if(len < 0 || len >= remaining) {
printf("Buffer too short. Have %d, need %d + \\0\n", remaining, len);
return;
}
remaining -= len;
buf_ptr += len;
}
}
len = snprintf(buf_ptr, remaining, "}}");
if(len < 0 || len >= remaining) {
printf("Buffer too short. Have %d, need %d + \\0\n", remaining, len);
return;
}
mqtt_publish(&conn, NULL, pub_topic, (uint8_t *)app_buffer,
strlen(app_buffer), MQTT_QOS_LEVEL_0, MQTT_RETAIN_OFF);
DBG("APP - Publish!\n");
}
/*---------------------------------------------------------------------------*/
static void
connect_to_broker(void)
{
/* Connect to MQTT server */
mqtt_connect(&conn, conf->broker_ip, conf->broker_port,
conf->pub_interval * 3);
state = MQTT_CLIENT_STATE_CONNECTING;
}
/*---------------------------------------------------------------------------*/
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);
}
/*---------------------------------------------------------------------------*/
static void
state_machine(void)
{
switch(state) {
case MQTT_CLIENT_STATE_INIT:
/* If we have just been configured register MQTT connection */
mqtt_register(&conn, &mqtt_client_process, client_id, mqtt_event,
MQTT_CLIENT_MAX_SEGMENT_SIZE);
/*
* If we are not using the quickstart service (thus we are an IBM
* registered device), we need to provide user name and password
*/
if(strncasecmp(conf->org_id, QUICKSTART, strlen(conf->org_id)) != 0) {
if(strlen(conf->auth_token) == 0) {
printf("User name set, but empty auth token\n");
state = MQTT_CLIENT_STATE_ERROR;
break;
} else {
mqtt_set_username_password(&conn, "use-token-auth",
conf->auth_token);
}
}
/* _register() will set auto_reconnect. We don't want that. */
conn.auto_reconnect = 0;
connect_attempt = 1;
/*
* Wipe out the default route so we'll republish it every time we switch to
* a new broker
*/
memset(&def_route, 0, sizeof(def_route));
state = MQTT_CLIENT_STATE_REGISTERED;
DBG("Init\n");
/* Continue */
case MQTT_CLIENT_STATE_REGISTERED:
if(uip_ds6_get_global(ADDR_PREFERRED) != NULL) {
/* Registered and with a public IP. Connect */
DBG("Registered. Connect attempt %u\n", connect_attempt);
ping_parent();
connect_to_broker();
}
etimer_set(&publish_periodic_timer, CC26XX_WEB_DEMO_NET_CONNECT_PERIODIC);
return;
break;
case MQTT_CLIENT_STATE_CONNECTING:
leds_on(CC26XX_WEB_DEMO_STATUS_LED);
ctimer_set(&ct, CONNECTING_LED_DURATION, publish_led_off, NULL);
/* Not connected yet. Wait */
DBG("Connecting (%u)\n", connect_attempt);
break;
case MQTT_CLIENT_STATE_CONNECTED:
/* Don't subscribe unless we are a registered device */
if(strncasecmp(conf->org_id, QUICKSTART, strlen(conf->org_id)) == 0) {
DBG("Using 'quickstart': Skipping subscribe\n");
state = MQTT_CLIENT_STATE_PUBLISHING;
}
/* Continue */
case MQTT_CLIENT_STATE_PUBLISHING:
/* If the timer expired, the connection is stable. */
if(timer_expired(&connection_life)) {
/*
* Intentionally using 0 here instead of 1: We want RECONNECT_ATTEMPTS
* attempts if we disconnect after a successful connect
*/
connect_attempt = 0;
}
if(mqtt_ready(&conn) && conn.out_buffer_sent) {
/* Connected. Publish */
if(state == MQTT_CLIENT_STATE_CONNECTED) {
subscribe();
state = MQTT_CLIENT_STATE_PUBLISHING;
} else {
leds_on(CC26XX_WEB_DEMO_STATUS_LED);
ctimer_set(&ct, PUBLISH_LED_ON_DURATION, publish_led_off, NULL);
publish();
}
etimer_set(&publish_periodic_timer, conf->pub_interval);
DBG("Publishing\n");
/* Return here so we don't end up rescheduling the timer */
return;
} else {
/*
* Our publish timer fired, but some MQTT packet is already in flight
* (either not sent at all, or sent but not fully ACKd).
*
* This can mean that we have lost connectivity to our broker or that
* simply there is some network delay. In both cases, we refuse to
* trigger a new message and we wait for TCP to either ACK the entire
* packet after retries, or to timeout and notify us.
*/
DBG("Publishing... (MQTT state=%d, q=%u)\n", conn.state,
conn.out_queue_full);
}
break;
case MQTT_CLIENT_STATE_DISCONNECTED:
DBG("Disconnected\n");
if(connect_attempt < RECONNECT_ATTEMPTS ||
RECONNECT_ATTEMPTS == RETRY_FOREVER) {
/* Disconnect and backoff */
clock_time_t interval;
mqtt_disconnect(&conn);
connect_attempt++;
interval = connect_attempt < 3 ? RECONNECT_INTERVAL << connect_attempt :
RECONNECT_INTERVAL << 3;
DBG("Disconnected. Attempt %u in %lu ticks\n", connect_attempt, interval);
etimer_set(&publish_periodic_timer, interval);
state = MQTT_CLIENT_STATE_REGISTERED;
return;
} else {
/* Max reconnect attempts reached. Enter error state */
state = MQTT_CLIENT_STATE_ERROR;
DBG("Aborting connection after %u attempts\n", connect_attempt - 1);
}
break;
case MQTT_CLIENT_STATE_NEWCONFIG:
/* Only update config after we have disconnected */
if(conn.state == MQTT_CONN_STATE_NOT_CONNECTED) {
update_config();
DBG("New config\n");
/* update_config() scheduled next pass. Return */
return;
}
break;
case MQTT_CLIENT_STATE_CONFIG_ERROR:
/* Idle away. The only way out is a new config */
printf("Bad configuration.\n");
return;
case MQTT_CLIENT_STATE_ERROR:
default:
leds_on(CC26XX_WEB_DEMO_STATUS_LED);
/*
* 'default' should never happen.
*
* If we enter here it's because of some error. Stop timers. The only thing
* that can bring us out is a new config event
*/
printf("Default case: State=0x%02x\n", state);
return;
}
/* If we didn't return so far, reschedule ourselves */
etimer_set(&publish_periodic_timer, STATE_MACHINE_PERIODIC);
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(mqtt_client_process, ev, data)
{
PROCESS_BEGIN();
printf("CC26XX MQTT Client Process\n");
conf = &cc26xx_web_demo_config.mqtt_config;
if(init_config() != 1) {
PROCESS_EXIT();
}
register_http_post_handlers();
update_config();
def_rt_rssi = 0x8000000;
uip_icmp6_echo_reply_callback_add(&echo_reply_notification,
echo_reply_handler);
etimer_set(&echo_request_timer, conf->def_rt_ping_interval);
/* Main loop */
while(1) {
PROCESS_YIELD();
if(ev == sensors_event && data == CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER) {
if(state == MQTT_CLIENT_STATE_ERROR) {
connect_attempt = 1;
state = MQTT_CLIENT_STATE_REGISTERED;
}
}
if(ev == httpd_simple_event_new_config) {
/*
* Schedule next pass in a while. When HTTPD sends us this event, it is
* also in the process of sending the config page. Wait a little before
* reconnecting, so as to not cause congestion.
*/
etimer_set(&publish_periodic_timer, NEW_CONFIG_WAIT_INTERVAL);
}
if((ev == PROCESS_EVENT_TIMER && data == &publish_periodic_timer) ||
ev == PROCESS_EVENT_POLL ||
ev == cc26xx_web_demo_publish_event ||
(ev == sensors_event && data == CC26XX_WEB_DEMO_MQTT_PUBLISH_TRIGGER)) {
state_machine();
}
if(ev == PROCESS_EVENT_TIMER && data == &echo_request_timer) {
ping_parent();
etimer_set(&echo_request_timer, conf->def_rt_ping_interval);
}
if(ev == cc26xx_web_demo_load_config_defaults) {
init_config();
etimer_set(&publish_periodic_timer, NEW_CONFIG_WAIT_INTERVAL);
}
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
/**
* @}
*/

View file

@ -0,0 +1,74 @@
/*
* 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 cc26xx-web-demo
* @{
*
* \file
* Header file for the CC26xx web demo MQTT client functionality
*/
/*---------------------------------------------------------------------------*/
#ifndef MQTT_CLIENT_H_
#define MQTT_CLIENT_H_
/*---------------------------------------------------------------------------*/
#define MQTT_CLIENT_CONFIG_ORG_ID_LEN 32
#define MQTT_CLIENT_CONFIG_TYPE_ID_LEN 32
#define MQTT_CLIENT_CONFIG_AUTH_TOKEN_LEN 32
#define MQTT_CLIENT_CONFIG_EVENT_TYPE_ID_LEN 32
#define MQTT_CLIENT_CONFIG_CMD_TYPE_LEN 8
#define MQTT_CLIENT_CONFIG_IP_ADDR_STR_LEN 64
/*---------------------------------------------------------------------------*/
#define MQTT_CLIENT_RSSI_MEASURE_INTERVAL_MAX 86400 /* secs: 1 day */
#define MQTT_CLIENT_RSSI_MEASURE_INTERVAL_MIN 5 /* secs */
#define MQTT_CLIENT_PUBLISH_INTERVAL_MAX 86400 /* secs: 1 day */
#define MQTT_CLIENT_PUBLISH_INTERVAL_MIN 5 /* secs */
/*---------------------------------------------------------------------------*/
PROCESS_NAME(mqtt_client_process);
/*---------------------------------------------------------------------------*/
/**
* \brief Data structure declaration for the MQTT client configuration
*/
typedef struct mqtt_client_config {
char org_id[MQTT_CLIENT_CONFIG_ORG_ID_LEN];
char type_id[MQTT_CLIENT_CONFIG_TYPE_ID_LEN];
char auth_token[MQTT_CLIENT_CONFIG_AUTH_TOKEN_LEN];
char event_type_id[MQTT_CLIENT_CONFIG_EVENT_TYPE_ID_LEN];
char broker_ip[MQTT_CLIENT_CONFIG_IP_ADDR_STR_LEN];
char cmd_type[MQTT_CLIENT_CONFIG_CMD_TYPE_LEN];
clock_time_t pub_interval;
int def_rt_ping_interval;
uint16_t broker_port;
} mqtt_client_config_t;
/*---------------------------------------------------------------------------*/
#endif /* MQTT_CLIENT_H_ */
/*---------------------------------------------------------------------------*/
/**
* @}
*/

View file

@ -0,0 +1,344 @@
/*
* 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 cc26xx-web-demo
* @{
*
* \file
* A process which receives data over UART and transmits them over UDP
* to a pre-defined IPv6 address and port. It also listens on the same UDP
* port for messages, which it prints out over UART.
*
* For this example to work, you will have to modify the destination IPv6
* address by adjusting the set_dest_addr() macro below.
*
* To listen on your linux or OS X box:
* nc -6ulkw 1 REMOTE_PORT
*
* (REMOTE_PORT should be the actual value of the define below, e.g. 7777)
*
* Once netcat is up and listening, type something to the CC26xx's terminal
* Bear in mind that the datagram will only be sent after a 0x0a (LF) char
* has been received. Therefore, if you are on Win, do NOT use PuTTY for
* this purpose, since it does not send 0x0a as part of the line end. On
* Win XP use hyperterm. On Win 7 use some other software (e.g. Tera Term,
* which can be configured to send CRLF on enter keystrokes).
*
* To send data in the other direction from your linux or OS X box:
*
* nc -6u \<node IPv6 address\> REMOTE_PORT
*/
/*---------------------------------------------------------------------------*/
#include "contiki-conf.h"
#include "sys/process.h"
#include "dev/serial-line.h"
#include "net/ip/uip.h"
#include "net/ip/uip-udp-packet.h"
#include "net/ip/uiplib.h"
#include "lpm.h"
#include "net-uart.h"
#include "httpd-simple.h"
#include "ti-lib.h"
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
/*---------------------------------------------------------------------------*/
#define DEBUG DEBUG_NONE
#include "net/ip/uip-debug.h"
/*---------------------------------------------------------------------------*/
#define REMOTE_PORT 7777
#define MAX_MSG_SIZE 100
#define set_dest_addr() uip_ip6addr(&remote_addr, \
0xBBBB, 0x0000, 0x0000, 0x0000, \
0x3E07, 0x54FF, 0xFE74, 0x4885);
/*---------------------------------------------------------------------------*/
#define ADDRESS_CONVERSION_OK 1
#define ADDRESS_CONVERSION_ERROR 0
/*---------------------------------------------------------------------------*/
#ifndef MIN
#define MIN(n, m) (((n) < (m)) ? (n) : (m))
#endif
/*---------------------------------------------------------------------------*/
static struct uip_udp_conn *udp_conn = NULL;
static uint8_t buffer[MAX_MSG_SIZE];
static uint8_t msg_len;
static uip_ip6addr_t remote_addr;
/*---------------------------------------------------------------------------*/
#define IPV6_ADDR_STR_LEN 64
/*---------------------------------------------------------------------------*/
PROCESS(net_uart_process, "Net UART Process");
/*---------------------------------------------------------------------------*/
/*
* \brief Attempts to convert a string representation of an IPv6 address to a
* numeric one.
* \param buf The buffer with the string to be converted.
* \return ADDRESS_CONVERSION_OK or ADDRESS_CONVERSION_ERROR
*
* ToDo: Add support for NAT64 conversion in case the incoming address is a v4
* This is now supported in the current master, so when we pull it in this will
* be very straightforward.
*/
static int
set_new_ip_address(char *buf)
{
/*
* uiplib_ip6addrconv will immediately start writing into the supplied buffer
* even if it subsequently fails. Thus, pass an intermediate buffer
*/
uip_ip6addr_t tmp_addr;
int rv = uiplib_ip6addrconv(buf, &tmp_addr);
if(rv == ADDRESS_CONVERSION_OK) {
/* Conversion OK, copy to our main buffer */
memcpy(&remote_addr, &tmp_addr, sizeof(remote_addr));
PRINTF("Updated remote address ");
PRINT6ADDR(&remote_addr);
PRINTF("\n");
}
return rv;
}
/*---------------------------------------------------------------------------*/
static void
net_input(void)
{
if(uip_newdata()) {
memset(buffer, 0, MAX_MSG_SIZE);
msg_len = MIN(uip_datalen(), MAX_MSG_SIZE - 1);
/* Copy data */
memcpy(buffer, uip_appdata, msg_len);
printf("%s", (char *)buffer);
}
return;
}
/*---------------------------------------------------------------------------*/
/*
* In order to maintain UART input operation:
* - Keep the uart clocked in sleep and deep sleep
* - Keep the serial PD on in deep sleep
*/
static lpm_power_domain_lock_t lock;
/*---------------------------------------------------------------------------*/
static void
release_uart(void)
{
/* Release serial PD lock */
lpm_pd_lock_release(&lock);
/* Let the UART turn off during Sleep and Deep Sleep */
ti_lib_prcm_peripheral_sleep_disable(PRCM_PERIPH_UART0);
ti_lib_prcm_peripheral_deep_sleep_disable(PRCM_PERIPH_UART0);
ti_lib_prcm_load_set();
while(!ti_lib_prcm_load_get());
}
/*---------------------------------------------------------------------------*/
static void
keep_uart_on(void)
{
/* Keep the serial PD on */
lpm_pd_lock_obtain(&lock, PRCM_DOMAIN_SERIAL);
/* Keep the UART clock on during Sleep and Deep Sleep */
ti_lib_prcm_peripheral_sleep_enable(PRCM_PERIPH_UART0);
ti_lib_prcm_peripheral_deep_sleep_enable(PRCM_PERIPH_UART0);
ti_lib_prcm_load_set();
while(!ti_lib_prcm_load_get());
}
/*---------------------------------------------------------------------------*/
static int
remote_port_post_handler(char *key, int key_len, char *val, int val_len)
{
int rv;
if(key_len != strlen("net_uart_port") ||
strncasecmp(key, "net_uart_port", strlen("net_uart_port")) != 0) {
/* Not ours */
return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN;
}
rv = atoi(val);
if(rv <= 65535 && rv > 0) {
cc26xx_web_demo_config.net_uart.remote_port = (uint16_t)rv;
} else {
return HTTPD_SIMPLE_POST_HANDLER_ERROR;
}
return HTTPD_SIMPLE_POST_HANDLER_OK;
}
/*---------------------------------------------------------------------------*/
static int
remote_ipv6_post_handler(char *key, int key_len, char *val, int val_len)
{
int rv = HTTPD_SIMPLE_POST_HANDLER_UNKNOWN;
if(key_len != strlen("net_uart_ip") ||
strncasecmp(key, "net_uart_ip", strlen("net_uart_ip")) != 0) {
/* Not ours */
return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN;
}
if(val_len > IPV6_ADDR_STR_LEN) {
/* Ours but bad value */
rv = HTTPD_SIMPLE_POST_HANDLER_ERROR;
} else {
if(set_new_ip_address(val)) {
memset(cc26xx_web_demo_config.net_uart.remote_address, 0,
NET_UART_IP_ADDR_STRLEN);
memcpy(cc26xx_web_demo_config.net_uart.remote_address, val, val_len);
rv = HTTPD_SIMPLE_POST_HANDLER_OK;
}
}
return rv;
}
/*---------------------------------------------------------------------------*/
static int
on_off_post_handler(char *key, int key_len, char *val, int val_len)
{
int rv;
if(key_len != strlen("net_uart_on") ||
strncasecmp(key, "net_uart_on", strlen("net_uart_on")) != 0) {
/* Not ours */
return HTTPD_SIMPLE_POST_HANDLER_UNKNOWN;
}
rv = atoi(val);
/* Be pedantic: only accept 0 and 1, not just any non-zero value */
if(rv == 0) {
cc26xx_web_demo_config.net_uart.enable = 0;
release_uart();
} else if(rv == 1) {
cc26xx_web_demo_config.net_uart.enable = 1;
keep_uart_on();
} else {
return HTTPD_SIMPLE_POST_HANDLER_ERROR;
}
return HTTPD_SIMPLE_POST_HANDLER_OK;
}
/*---------------------------------------------------------------------------*/
HTTPD_SIMPLE_POST_HANDLER(remote_port, remote_port_post_handler);
HTTPD_SIMPLE_POST_HANDLER(remote_ipv6, remote_ipv6_post_handler);
HTTPD_SIMPLE_POST_HANDLER(on_off, on_off_post_handler);
/*---------------------------------------------------------------------------*/
static void
set_config_defaults(void)
{
/* Set a hard-coded destination address to start with */
set_dest_addr();
/* Set config defaults */
cc26xx_web_demo_ipaddr_sprintf(cc26xx_web_demo_config.net_uart.remote_address,
NET_UART_IP_ADDR_STRLEN, &remote_addr);
cc26xx_web_demo_config.net_uart.remote_port = REMOTE_PORT;
cc26xx_web_demo_config.net_uart.enable = 1;
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(net_uart_process, ev, data)
{
PROCESS_BEGIN();
printf("CC26XX Net UART Process\n");
set_config_defaults();
udp_conn = udp_new(NULL, UIP_HTONS(0), NULL);
udp_bind(udp_conn, UIP_HTONS(REMOTE_PORT));
if(udp_conn == NULL) {
printf("No UDP connection available, exiting the process!\n");
PROCESS_EXIT();
}
httpd_simple_register_post_handler(&remote_port_handler);
httpd_simple_register_post_handler(&remote_ipv6_handler);
httpd_simple_register_post_handler(&on_off_handler);
while(1) {
PROCESS_YIELD();
if(ev == serial_line_event_message) {
/*
* If the message contains a new IP address, save it and go back to
* waiting.
*/
if(set_new_ip_address((char *)data) == ADDRESS_CONVERSION_ERROR) {
/* Not an IP address in the message. Send to current destination */
memset(buffer, 0, MAX_MSG_SIZE);
/* We need to add a line feed, thus never fill the entire buffer */
msg_len = MIN(strlen(data), MAX_MSG_SIZE - 1);
memcpy(buffer, data, msg_len);
/* Add a line feed */
buffer[msg_len] = 0x0A;
msg_len++;
uip_udp_packet_sendto(
udp_conn, buffer, msg_len, &remote_addr,
UIP_HTONS(cc26xx_web_demo_config.net_uart.remote_port));
}
} else if(ev == tcpip_event) {
net_input();
} else if(ev == cc26xx_web_demo_config_loaded_event) {
/*
* New config. Check if it's possible to update the remote address.
* The port will have been updated already
*/
set_new_ip_address(cc26xx_web_demo_config.net_uart.remote_address);
if(cc26xx_web_demo_config.net_uart.enable == 1) {
keep_uart_on();
}
} else if(ev == cc26xx_web_demo_load_config_defaults) {
set_config_defaults();
}
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/
/**
* @}
* @}
*/

View file

@ -0,0 +1,48 @@
/*
* 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.
*/
#ifndef NET_UART_H_
#define NET_UART_H_
/*---------------------------------------------------------------------------*/
#include "net/ip/uip.h"
#include <stdint.h>
/*---------------------------------------------------------------------------*/
#define NET_UART_IP_ADDR_STRLEN 64
/*---------------------------------------------------------------------------*/
PROCESS_NAME(net_uart_process);
/*---------------------------------------------------------------------------*/
typedef struct net_uart_config_s {
char remote_address[NET_UART_IP_ADDR_STRLEN];
uint16_t remote_port;
uint8_t enable;
} net_uart_config_t;
/*---------------------------------------------------------------------------*/
#endif /* NET_UART_H_ */
/*---------------------------------------------------------------------------*/

View file

@ -0,0 +1,53 @@
/*
* 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.
*/
/*---------------------------------------------------------------------------*/
#ifndef PROJECT_CONF_H_
#define PROJECT_CONF_H_
/*---------------------------------------------------------------------------*/
/* Change to match your configuration */
#define NETSTACK_CONF_RDC contikimac_driver
#define IEEE802154_CONF_PANID 0xABCD
#define CC26XX_RF_CONF_CHANNEL 25
#define CC26XX_MODEL_CONF_CPU_VARIANT 2650 /* CC2650 */
#define CC26XX_RF_CONF_BLE_SUPPORT 1 /* Only available with CC2650 */
/*---------------------------------------------------------------------------*/
/* Enable/Disable Components of this Demo */
#define CC26XX_WEB_DEMO_CONF_MQTT_CLIENT 1
#define CC26XX_WEB_DEMO_CONF_6LBR_CLIENT 1
#define CC26XX_WEB_DEMO_CONF_COAP_SERVER 1
#define CC26XX_WEB_DEMO_CONF_NET_UART 1
/*---------------------------------------------------------------------------*/
/* Shrink the size of the uIP buffer, routing table and ND cache */
#define UIP_CONF_BUFFER_SIZE 900
#define NBR_TABLE_CONF_MAX_NEIGHBORS 8
#define UIP_CONF_MAX_ROUTES 8
/*---------------------------------------------------------------------------*/
#endif /* PROJECT_CONF_H_ */
/*---------------------------------------------------------------------------*/

View file

@ -0,0 +1,113 @@
/*
* Copyright (c) 2015, 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 Institute 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 INSTITUTE 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 INSTITUTE 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 cc26xx-web-demo
* @{
*
* \file
* CoAP resource to start/stop/configure BLE advertisements
*/
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include "rest-engine.h"
#include "er-coap.h"
#include "dev/cc26xx-rf.h"
#include <string.h>
#include <stdlib.h>
/*---------------------------------------------------------------------------*/
#define BLE_NAME_BUF_LEN 32
/*---------------------------------------------------------------------------*/
const char *forbidden_payload = "Name to advertise unspecified.\n"
"Use name=<name> in the request";
/*---------------------------------------------------------------------------*/
static void
res_ble_post_put_handler(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
size_t len = 0;
const char *text = NULL;
char name[BLE_NAME_BUF_LEN];
int success = 0;
int rv;
memset(name, 0, BLE_NAME_BUF_LEN);
len = REST.get_post_variable(request, "name", &text);
if(len > 0 && len < BLE_NAME_BUF_LEN) {
memcpy(name, text, len);
cc26xx_rf_ble_beacond_config(0, name);
success = 1;
}
len = REST.get_post_variable(request, "interval", &text);
rv = atoi(text);
if(rv > 0) {
cc26xx_rf_ble_beacond_config((clock_time_t)(rv * CLOCK_SECOND), NULL);
success = 1;
}
len = REST.get_post_variable(request, "mode", &text);
if(len) {
if(strncmp(text, "on", len) == 0) {
if(cc26xx_rf_ble_beacond_start()) {
success = 1;
} else {
REST.set_response_status(response, REST.status.FORBIDDEN);
REST.set_response_payload(response, forbidden_payload,
strlen(forbidden_payload));
return;
}
} else if(strncmp(text, "off", len) == 0) {
cc26xx_rf_ble_beacond_stop();
success = 1;
} else {
success = 0;
}
}
if(!success) {
REST.set_response_status(response, REST.status.BAD_REQUEST);
}
}
/*---------------------------------------------------------------------------*/
RESOURCE(res_ble_advd,
"title=\"BLE advd config: POST/PUT name=<name>&mode=on|off"
"&interval=<secs>\";rt=\"Control\"",
NULL,
res_ble_post_put_handler,
res_ble_post_put_handler,
NULL);
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -0,0 +1,179 @@
/*
* 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 cc26xx-web-demo
* @{
*
* \file
* CoAP resource handler for CC26XX software and hardware version
*/
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include "rest-engine.h"
#include "er-coap.h"
#include "sys/clock.h"
#include "cc26xx-model.h"
#include "coap-server.h"
#include "cc26xx-web-demo.h"
#include <string.h>
/*---------------------------------------------------------------------------*/
static void
res_get_handler_hw(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
unsigned int accept = -1;
REST.get_header_accept(request, &accept);
if(accept == -1 || accept == REST.type.TEXT_PLAIN) {
REST.set_header_content_type(response, REST.type.TEXT_PLAIN);
snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%s on CC%u", BOARD_STRING,
CC26XX_MODEL_CPU_VARIANT);
REST.set_response_payload(response, (uint8_t *)buffer, strlen((char *)buffer));
} else if(accept == REST.type.APPLICATION_JSON) {
REST.set_header_content_type(response, REST.type.APPLICATION_JSON);
snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{\"HW Ver\":\"%s on CC%u\"}",
BOARD_STRING, CC26XX_MODEL_CPU_VARIANT);
REST.set_response_payload(response, buffer, strlen((char *)buffer));
} else if(accept == REST.type.APPLICATION_XML) {
REST.set_header_content_type(response, REST.type.APPLICATION_XML);
snprintf((char *)buffer, REST_MAX_CHUNK_SIZE,
"<hw-ver val=\"%s on CC%u\"/>", BOARD_STRING,
CC26XX_MODEL_CPU_VARIANT);
REST.set_response_payload(response, buffer, strlen((char *)buffer));
} else {
REST.set_response_status(response, REST.status.NOT_ACCEPTABLE);
REST.set_response_payload(response, coap_server_supported_msg,
strlen(coap_server_supported_msg));
}
}
/*---------------------------------------------------------------------------*/
static void
res_get_handler_sw(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
unsigned int accept = -1;
REST.get_header_accept(request, &accept);
if(accept == -1 || accept == REST.type.TEXT_PLAIN) {
REST.set_header_content_type(response, REST.type.TEXT_PLAIN);
snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%s", CONTIKI_VERSION_STRING);
REST.set_response_payload(response, (uint8_t *)buffer, strlen((char *)buffer));
} else if(accept == REST.type.APPLICATION_JSON) {
REST.set_header_content_type(response, REST.type.APPLICATION_JSON);
snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{\"SW Ver\":\"%s\"}",
CONTIKI_VERSION_STRING);
REST.set_response_payload(response, buffer, strlen((char *)buffer));
} else if(accept == REST.type.APPLICATION_XML) {
REST.set_header_content_type(response, REST.type.APPLICATION_XML);
snprintf((char *)buffer, REST_MAX_CHUNK_SIZE,
"<sw-ver val=\"%s\"/>", CONTIKI_VERSION_STRING);
REST.set_response_payload(response, buffer, strlen((char *)buffer));
} else {
REST.set_response_status(response, REST.status.NOT_ACCEPTABLE);
REST.set_response_payload(response, coap_server_supported_msg,
strlen(coap_server_supported_msg));
}
}
/*---------------------------------------------------------------------------*/
static void
res_get_handler_uptime(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
unsigned int accept = -1;
REST.get_header_accept(request, &accept);
if(accept == -1 || accept == REST.type.TEXT_PLAIN) {
REST.set_header_content_type(response, REST.type.TEXT_PLAIN);
snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%lu", clock_seconds());
REST.set_response_payload(response, (uint8_t *)buffer, strlen((char *)buffer));
} else if(accept == REST.type.APPLICATION_JSON) {
REST.set_header_content_type(response, REST.type.APPLICATION_JSON);
snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{\"uptime\":%lu}",
clock_seconds());
REST.set_response_payload(response, buffer, strlen((char *)buffer));
} else if(accept == REST.type.APPLICATION_XML) {
REST.set_header_content_type(response, REST.type.APPLICATION_XML);
snprintf((char *)buffer, REST_MAX_CHUNK_SIZE,
"<uptime val=\"%lu\" unit=\"sec\"/>", clock_seconds());
REST.set_response_payload(response, buffer, strlen((char *)buffer));
} else {
REST.set_response_status(response, REST.status.NOT_ACCEPTABLE);
REST.set_response_payload(response, coap_server_supported_msg,
strlen(coap_server_supported_msg));
}
}
/*---------------------------------------------------------------------------*/
static void
res_post_handler_cfg_reset(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
cc26xx_web_demo_restore_defaults();
}
/*---------------------------------------------------------------------------*/
RESOURCE(res_device_sw,
"title=\"Software version\";rt=\"text\"",
res_get_handler_sw,
NULL,
NULL,
NULL);
/*---------------------------------------------------------------------------*/
RESOURCE(res_device_uptime,
"title=\"Uptime\";rt=\"seconds\"",
res_get_handler_uptime,
NULL,
NULL,
NULL);
/*---------------------------------------------------------------------------*/
RESOURCE(res_device_hw,
"title=\"Hardware version\";rt=\"text\"",
res_get_handler_hw,
NULL,
NULL,
NULL);
/*---------------------------------------------------------------------------*/
RESOURCE(res_device_cfg_reset,
"title=\"Reset Device Config: POST\";rt=\"Control\"",
NULL, res_post_handler_cfg_reset, NULL, NULL);
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -0,0 +1,110 @@
/*
* Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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 cc26xx-web-demo
* @{
*
* \file
* CoAP resource handler for the CC26xx LEDs. Slightly modified copy of
* the one found in Contiki's original CoAP example.
* \author
* Matthias Kovatsch <kovatsch@inf.ethz.ch> (original)
*/
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include "rest-engine.h"
#include "dev/leds.h"
#include <string.h>
/*---------------------------------------------------------------------------*/
static void
res_post_put_handler(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
size_t len = 0;
const char *color = NULL;
const char *mode = NULL;
uint8_t led = 0;
int success = 1;
if((len = REST.get_query_variable(request, "color", &color))) {
if(strncmp(color, "r", len) == 0) {
led = LEDS_RED;
} else if(strncmp(color, "g", len) == 0) {
led = LEDS_GREEN;
#if BOARD_SMARTRF06EB
} else if(strncmp(color, "y", len) == 0) {
led = LEDS_YELLOW;
} else if(strncmp(color, "o", len) == 0) {
led = LEDS_ORANGE;
#endif
} else {
success = 0;
}
} else {
success = 0;
}
if(success && (len = REST.get_post_variable(request, "mode", &mode))) {
if(strncmp(mode, "on", len) == 0) {
leds_on(led);
} else if(strncmp(mode, "off", len) == 0) {
leds_off(led);
} else {
success = 0;
}
} else {
success = 0;
}
if(!success) {
REST.set_response_status(response, REST.status.BAD_REQUEST);
}
}
/*---------------------------------------------------------------------------*/
/*
* A simple actuator example, depending on the color query parameter and post
* variable mode, corresponding led is activated or deactivated
*/
#if BOARD_SENSORTAG
#define RESOURCE_PARAMS "r|g"
#elif BOARD_SMARTRF06EB
#define RESOURCE_PARAMS "r|g|y|o"
#endif
RESOURCE(res_leds,
"title=\"LEDs: ?color=" RESOURCE_PARAMS ", POST/PUT mode=on|off\";rt=\"Control\"",
NULL,
res_post_put_handler,
res_post_put_handler,
NULL);
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -0,0 +1,269 @@
/*
* 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 cc26xx-web-demo
* @{
*
* \file
* CoAP resource handler for the Sensortag-CC26xx sensors
*/
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include "rest-engine.h"
#include "er-coap.h"
#include "cc26xx-web-demo.h"
#include "coap-server.h"
#include <stdio.h>
#include <stdint.h>
#include <string.h>
/*---------------------------------------------------------------------------*/
/*
* Generic resource handler for any sensor in this example. Ultimately gets
* called by all handlers and populates the CoAP response
*/
static void
res_get_handler_all(int sens_type, void *request, void *response,
uint8_t *buffer, uint16_t preferred_size, int32_t *offset)
{
unsigned int accept = -1;
const cc26xx_web_demo_sensor_reading_t *reading;
reading = cc26xx_web_demo_sensor_lookup(sens_type);
if(reading == NULL) {
REST.set_response_status(response, REST.status.NOT_FOUND);
REST.set_response_payload(response, coap_server_not_found_msg,
strlen(coap_server_not_found_msg));
return;
}
REST.get_header_accept(request, &accept);
if(accept == -1 || accept == REST.type.TEXT_PLAIN) {
REST.set_header_content_type(response, REST.type.TEXT_PLAIN);
snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%s", reading->converted);
REST.set_response_payload(response, (uint8_t *)buffer,
strlen((char *)buffer));
} else if(accept == REST.type.APPLICATION_JSON) {
REST.set_header_content_type(response, REST.type.APPLICATION_JSON);
snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{\"%s\":%s}",
reading->descr, reading->converted);
REST.set_response_payload(response, buffer, strlen((char *)buffer));
} else if(accept == REST.type.APPLICATION_XML) {
REST.set_header_content_type(response, REST.type.APPLICATION_XML);
snprintf((char *)buffer, REST_MAX_CHUNK_SIZE,
"<%s val=\"%s\" unit=\"%s\"/>", reading->xml_element,
reading->converted, reading->units);
REST.set_response_payload(response, buffer, strlen((char *)buffer));
} else {
REST.set_response_status(response, REST.status.NOT_ACCEPTABLE);
REST.set_response_payload(response, coap_server_supported_msg,
strlen(coap_server_supported_msg));
}
}
/*---------------------------------------------------------------------------*/
/* BatMon resources and handler: Temperature, Voltage */
static void
res_get_handler_batmon_temp(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_BATMON_TEMP, request, response,
buffer, preferred_size, offset);
}
/*---------------------------------------------------------------------------*/
static void
res_get_handler_batmon_volt(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_BATMON_VOLT, request, response,
buffer, preferred_size, offset);
}
/*---------------------------------------------------------------------------*/
RESOURCE(res_batmon_temp, "title=\"Battery Temp\";rt=\"C\"",
res_get_handler_batmon_temp, NULL, NULL, NULL);
/*---------------------------------------------------------------------------*/
RESOURCE(res_batmon_volt, "title=\"Battery Voltage\";rt=\"mV\"",
res_get_handler_batmon_volt, NULL, NULL, NULL);
/*---------------------------------------------------------------------------*/
#if BOARD_SENSORTAG
/*---------------------------------------------------------------------------*/
/* MPU resources and handler: Accelerometer and Gyro */
static void
res_get_handler_mpu_acc_x(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_MPU_ACC_X, request, response,
buffer, preferred_size, offset);
}
/*---------------------------------------------------------------------------*/
static void
res_get_handler_mpu_acc_y(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_MPU_ACC_Y, request, response,
buffer, preferred_size, offset);
}
/*---------------------------------------------------------------------------*/
static void
res_get_handler_mpu_acc_z(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_MPU_ACC_Z, request, response,
buffer, preferred_size, offset);
}
/*---------------------------------------------------------------------------*/
static void
res_get_handler_mpu_gyro_x(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_X, request, response,
buffer, preferred_size, offset);
}
/*---------------------------------------------------------------------------*/
static void
res_get_handler_mpu_gyro_y(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_Y, request, response,
buffer, preferred_size, offset);
}
/*---------------------------------------------------------------------------*/
static void
res_get_handler_mpu_gyro_z(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_MPU_GYRO_Z, request, response,
buffer, preferred_size, offset);
}
/*---------------------------------------------------------------------------*/
RESOURCE(res_mpu_acc_x, "title=\"Acc X\";rt=\"G\"", res_get_handler_mpu_acc_x,
NULL, NULL, NULL);
RESOURCE(res_mpu_acc_y, "title=\"Acc Y\";rt=\"G\"", res_get_handler_mpu_acc_y,
NULL, NULL, NULL);
RESOURCE(res_mpu_acc_z, "title=\"Acc Z\";rt=\"G\"", res_get_handler_mpu_acc_z,
NULL, NULL, NULL);
RESOURCE(res_mpu_gyro_x, "title=\"Gyro X\";rt=\"deg/sec\"",
res_get_handler_mpu_gyro_x, NULL, NULL, NULL);
RESOURCE(res_mpu_gyro_y, "title=\"Gyro Y\";rt=\"deg/sec\"",
res_get_handler_mpu_gyro_y, NULL, NULL, NULL);
RESOURCE(res_mpu_gyro_z, "title=\"Gyro Z\";rt=\"deg/sec\"",
res_get_handler_mpu_gyro_z, NULL, NULL, NULL);
/*---------------------------------------------------------------------------*/
/* TMP sensor resources and handlers: Object, Ambient */
static void
res_get_handler_obj_temp(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_TMP_OBJECT, request, response,
buffer, preferred_size, offset);
}
/*---------------------------------------------------------------------------*/
static void
res_get_handler_amb_temp(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_TMP_AMBIENT, request, response,
buffer, preferred_size, offset);
}
/*---------------------------------------------------------------------------*/
RESOURCE(res_tmp007_obj, "title=\"Temperature (Object)\";rt=\"C\"",
res_get_handler_obj_temp, NULL, NULL, NULL);
RESOURCE(res_tmp007_amb, "title=\"Temperature (Ambient)\";rt=\"C\"",
res_get_handler_amb_temp, NULL, NULL, NULL);
/*---------------------------------------------------------------------------*/
/* BMP sensor resources: Temperature, Pressure */
static void
res_get_handler_bmp_temp(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_BMP_TEMP, request, response,
buffer, preferred_size, offset);
}
/*---------------------------------------------------------------------------*/
static void
res_get_handler_bmp_press(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_BMP_PRES, request, response,
buffer, preferred_size, offset);
}
/*---------------------------------------------------------------------------*/
RESOURCE(res_bmp280_temp, "title=\"Barometer (Temperature)\";rt=\"C\"",
res_get_handler_bmp_temp, NULL, NULL, NULL);
RESOURCE(res_bmp280_press,
"title=\"Barometer (Pressure)\";rt=\"hPa (hectopascal / millibar)\"",
res_get_handler_bmp_press, NULL, NULL, NULL);
/*---------------------------------------------------------------------------*/
/* SHT21 sensor resources and handler: Temperature, Pressure */
static void
res_get_handler_sht_temp(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_SHT_TEMP, request, response,
buffer, preferred_size, offset);
}
/*---------------------------------------------------------------------------*/
static void
res_get_handler_sht_humidity(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_SHT_HUMIDITY, request, response,
buffer, preferred_size, offset);
}
/*---------------------------------------------------------------------------*/
RESOURCE(res_sht21_temp, "title=\"Temperature\";rt=\"C\"",
res_get_handler_sht_temp, NULL, NULL, NULL);
RESOURCE(res_sht21_hum, "title=\"Humidity\";rt=\"%RH\"",
res_get_handler_sht_humidity, NULL, NULL, NULL);
/*---------------------------------------------------------------------------*/
/* Illuminance resources and handler */
static void
res_get_handler_opt(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
res_get_handler_all(CC26XX_WEB_DEMO_SENSOR_OPT_LIGHT, request, response,
buffer, preferred_size, offset);
}
/*---------------------------------------------------------------------------*/
RESOURCE(res_opt3001_light, "title=\"Illuminance\";rt=\"Lux\"",
res_get_handler_opt, NULL, NULL, NULL);
/*---------------------------------------------------------------------------*/
#endif /* BOARD_SENSORTAG */
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -0,0 +1,114 @@
/*
* Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich
* 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 Institute 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 INSTITUTE 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 INSTITUTE 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.
*
* This file is part of the Contiki operating system.
*/
/*---------------------------------------------------------------------------*/
/**
* \addtogroup cc26xx-web-demo
* @{
*
* \file
* CoAP resource to toggle LEDs. Slightly modified copy of the one found
* in Contiki's original CoAP example.
* \author
* Matthias Kovatsch <kovatsch@inf.ethz.ch> (original)
*/
/*---------------------------------------------------------------------------*/
#include "contiki.h"
#include "rest-engine.h"
#include "dev/leds.h"
#include <string.h>
/*---------------------------------------------------------------------------*/
static void
res_post_handler_red(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
leds_toggle(LEDS_RED);
}
/*---------------------------------------------------------------------------*/
static void
res_post_handler_green(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
leds_toggle(LEDS_GREEN);
}
/*---------------------------------------------------------------------------*/
/* Toggles the red led */
RESOURCE(res_toggle_red,
"title=\"Red LED\";rt=\"Control\"",
NULL,
res_post_handler_red,
NULL,
NULL);
/* Toggles the green led */
RESOURCE(res_toggle_green,
"title=\"Green LED\";rt=\"Control\"",
NULL,
res_post_handler_green,
NULL,
NULL);
/*---------------------------------------------------------------------------*/
/* An additional 2 LEDs on the Srf */
#if BOARD_SMARTRF06EB
/*---------------------------------------------------------------------------*/
static void
res_post_handler_yellow(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
leds_toggle(LEDS_YELLOW);
}
/*---------------------------------------------------------------------------*/
static void
res_post_handler_orange(void *request, void *response, uint8_t *buffer,
uint16_t preferred_size, int32_t *offset)
{
leds_toggle(LEDS_ORANGE);
}
/*---------------------------------------------------------------------------*/
/* Toggles the yellow led */
RESOURCE(res_toggle_yellow,
"title=\"Yellow LED\";rt=\"Control\"",
NULL,
res_post_handler_yellow,
NULL,
NULL);
/* Toggles the orange led */
RESOURCE(res_toggle_orange,
"title=\"Orange LED\";rt=\"Control\"",
NULL,
res_post_handler_orange,
NULL,
NULL);
#endif
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -0,0 +1,45 @@
/*
* 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.
*/
/*---------------------------------------------------------------------------*/
#ifndef PROJECT_CONF_H_
#define PROJECT_CONF_H_
/*---------------------------------------------------------------------------*/
/* Disable button shutdown functionality */
#define BUTTON_SENSOR_CONF_ENABLE_SHUTDOWN 0
/*---------------------------------------------------------------------------*/
/* Change to match your configuration */
#define NETSTACK_CONF_RDC contikimac_driver
#define IEEE802154_CONF_PANID 0xABCD
#define CC26XX_RF_CONF_CHANNEL 25
#define CC26XX_MODEL_CONF_CPU_VARIANT 2650 /* CC2650 */
#define CC26XX_RF_CONF_BLE_SUPPORT 1 /* Only available with CC2650 */
/*---------------------------------------------------------------------------*/
#endif /* PROJECT_CONF_H_ */
/*---------------------------------------------------------------------------*/