Thingsquare firmware SDK header file

This is the main header file for the Thingsquare firmware SDK. It
contains headers for the functions that a user application can call.

User applications may also use other APIs provided by the underlying
Contiki OS as well as the hardware libraries for the specific
hardware platform used.

Copyright 2012-2017 Thingsquare AB

#ifndef THSQ_H
#define THSQ_H

Include files

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "contiki.h"
#include "contiki-lib.h"
#include "contiki-net.h"
#include "net/rpl/rpl.h"

Thingsquare event callbacks

A user application may provide one or more callback functions that
are called by the Thingsquare system when events occur. Examples of
events is when a new variable is set, a new command is received, or
when GPIO input changes.

Callback functions are added with the thsq_add_callback() function.

Thingsquare event definitions

Events of the enum thsq_reason type are passed along with the
callbacks.

enum thsq_reason {
  THSQ_ERROR,
  THSQ_PONG_RECEIVED,
  THSQ_KEYVAL,
  THSQ_AUTH,
  THSQ_SERVER_CONNECTED,
  THSQ_COMMAND,
  THSQ_ZONEMSG,
  THSQ_PERIOD,
  THSQ_GPIO_INPUT,
  THSQ_LIGHTING_CHANGED,
  THSQ_ACKED,
};

Type definition of the callback function

typedef void (*thsq_callback_fn)(enum thsq_reason reason, const char *str, int len);

Internal structure of the list of thsq callbacks

This data structure is to be configured as an opaque structure.

struct thsq_callback {
  struct thsq_callback *next;
  thsq_callback_fn callback;
};

Add a callback function

This function sets up a callback function to be called whenvever something happens.
The struct thsq_callback must be statically allocated by the caller.

void thsq_add_callback(struct thsq_callback *callback, thsq_callback_fn function);

Set platform name

The thsq_set_platform() function is used to inform the frontend what
platform the current device is running.

Typically, each customer's device type has a unique name that is used to
identify specific device behavior and firmware updates for the device.

The platform name is a non-NULL pointer to a printable-ASCII-string
that is NULL-terminated, and is at max (THSQ_MAX_VALLEN) bytes long including
the terminator.

void thsq_set_platform(const char *platform);

Serial line module

The serialline module captures input from the UART and posts them as a
s variable serial and writes serial output from the sout command
to the UART.

void thsq_serialline_init(void);

The powerconf power configuration module

The powerconf module interacts with the Power Settings button in the
Thingsquare frontend to easily set the power settings of a device.

The powerconf module listens for the d variable powerconf for a
a new configuration. If a correctly formatted powerconf variable is received,
the powerconf module sets the mode, period, stats, deadleaf, and
beacon variables accordingly, before deleting the powerconf variable.

void thsq_powerconf_init(void);

The lighting control module

The lighting control module is a framework that provides zoned
lighting, lighting schedules, and prioritized triggers for light
switches, PIR sensors, and local controls.

The lighting module is initialized with thsq_lighting_init() and
uses a complex set of local and remote control mechanism to achieve
zoned lighting triggers across zones as well as remote control and
time-synchronized schedules.

The user hooks into the lighting control module with a callback
function that is registered with the thsq_lighting_set_callback()
function. The lighting callback receives a set of red, green, and
blue dimming values from 0 to 100. The callback should set the
output device's dimming levels accordingly.

void thsq_lighting_init(void);
void thsq_lighting_set_callback(void (* c)(int r, int g, int b));

The general purpose I/O module

The general purpose I/O module provides a simple way to sample one
digital input pin and/or one analog input pin and to control one
digital output pin and/or one digital PWM output pin.

The general purpose I/O module uses a pin configuration setting that
can either be supplied via the d variable pinconf, which can be
set from the backend server, or from locally calling the function
thsq_gpio_set_default().

void thsq_gpio_init(void);
void thsq_gpio_set_default(const char *def);

Bootloader configuration

The booloader is configured with either of two functions:
BOOTLOADERPARAMS_OVERRIDE_XMEM_DISABLE(), which disables the
bootloader, and BOOTLOADERPARAMS_OVERRIDE_XMEM_CONF(), which sets
up the flash chip configuration for the bootloader.

struct thsq_bootloader_params
{
  uint8_t bootloaderparams_active; /* 0: false, 1: use config */

  /* xmem configuration */
  uint8_t xmem_conf; /* 0: use defaults, 1: use below, 2: disable */
  uint8_t xmem_miso; /* xmem SPI MISO */
  uint8_t xmem_mosi; /* xmem SPI MOSI */
  uint8_t xmem_clk; /* xmem SPI CLK */
  uint8_t xmem_cs; /* xmem SPI CS */
};

extern struct thsq_bootloader_params bootloaderparams;
#define BOOTLOADERPARAMS_OVERRIDE(...)       \
    struct thsq_bootloader_params bootloaderparams \
    __attribute__ ((section(".bootloaderparams")))   \
    __attribute__ ((used))                    \
    = { __VA_ARGS__ }

#define BOOTLOADERPARAMS_OVERRIDE_XMEM_CONF(miso, mosi, clk, cs) \
    BOOTLOADERPARAMS_OVERRIDE(1, 1, miso, mosi, clk, cs)
#define BOOTLOADERPARAMS_OVERRIDE_XMEM_DISABLE() \
    BOOTLOADERPARAMS_OVERRIDE(1, 2)

Server interaction functions

A device interacts with the backend server through a set of variables
and commands. Variables come in two forms: d variables and s
variables. d variables are shared between the device and the backend
and are synchronized when a device boots up. s variables are only
maintained on the server, but can be set from the device. Commands are
sent from the server to the device.

A device may set either d or s variables. After setting variables,
the new variables must be pushed to the server by calling the
thsq_push() function.

When a device received a new d variable, or a new value for an
existing variable, all application callbacks, that have been
previously registered with thsq_add_callback(), are called.

The value of a d variable may be read by calling the thsq_get() or
thsq_get_to_buf() functions.

A d variable is set with the thsq_dset() or thsq_dest_str()
functions. An s variable is set with the thsq_sset() or
thsq_sset_str() functions.

A variable must be at most THSQ_MAX_VALLEN bytes long.

void thsq_push(void);
int thsq_dset(const char *key, int val);
int thsq_dset_str(const char *key, const char *str);
int thsq_sset(const char *key, int val);
int thsq_sset_str(const char *key, const char *str);
int thsq_get(const char *key);
int thsq_get_to_buf(const char *key, uint8_t *buf, int buflen);

The maximum size of a variable value

#define THSQ_MAX_VALLEN 128

Set device default mode

A device may be in either of three modes: feather, connected, and
deadleaf. The default mode is feather. In feather mode, the
device is responsive to variables and commands from the backend. In
connected mode, the device maintains a TLS connection to the
backend. This is primarily used to send firmware updates to individual
devices. In deadleaf mode, the device is off most of the time and
wakes up only now and then to receive new data from the backend. In
deadleaf mode, a device does not route packets through the mesh.

The mode of a device may be set from the backend by setting the d
variable called mode. If no mode variable is set, the device
defaults to the mode that has been set by the
thsq_set_default_mode() function

void thsq_set_default_mode(const char *mode);

Undocumented functions

These functions should not be used in production code as they may change.

int thsq_dset_ptr(const char *key, const uint8_t *val, uint16_t vallen);
int thsq_sset_str_important(const char *key, const char *str);
int thsq_sset_ulong(const char *key, uint32_t val);
int32_t thsq_get_long(const char *key);
int thsq_query(const char *key);
int thsq_exists(const char *key);

void thsq_set_default_rpl_mode(enum rpl_mode mode);
void nvstorage_erase(void);
void thsq_bonding_release(void);
int thsq_bonding_is_bonded(void);
const char *thsq_platform(void);

/*
  flags field:

  +-------------------------------+
  | R | R | R | A | S | S | S | S |
  +-------------------------------+

  R: reserved
  A: auth
  S: state

  If A is set, the first 16 bytes of the data field contains the auth code.

  If state is 0, the first 4 bytes of the data field contains a random
  ID is to be used when inviting the device to the network. The
  remaining 22 bytes contains a the name of the platform.
*/

#define THSQ_BEACON_FLAG_AUTH                 0x10
#define THSQ_BEACON_FLAG_DATA                 0x20

struct thsq_beacon {
  uint8_t flags;
  uint8_t data[17];
};

/* Create a beacon message from the current thsq state in the supplied
   struct */
int thsq_beacon_create(struct thsq_beacon *b);
int thsq_beacon_create_databeacon(struct thsq_beacon *b,
                                  uint8_t *data, int datalen);

void thsq_beacon_send_advbeacon(uint8_t *advdata, int advlen);
void thsq_beacon_send_beacon(uint8_t *beacondata, int beaconlen);

#define THSQ_BEACON_MAX_PAYLOAD 31

/* Check the current state of the device. May be used for UI purposes, eg show
 * an error, or unbonded device. The current state can be retrieved
 * with `thsq_get_current_state()`. The following list is the set of states.
 */
#define THSQ_STATE_WAITING_FOR_BOND    0
#define THSQ_STATE_WAITING_FOR_MUCHA   1
#define THSQ_STATE_WAITING_FOR_RPL     2
#define THSQ_STATE_WAITING_FOR_MASTER  3
#define THSQ_STATE_WAITING_FOR_PONG    4
#define THSQ_STATE_WAITING_FOR_DNS     5
#define THSQ_STATE_WAITING_FOR_TLS     6
#define THSQ_STATE_WAITING_FOR_AUTH    7
#define THSQ_STATE_WAITING_FOR_NOTHING 8
#define THSQ_STATE_WAITING_FOR_CABLE   9
#define THSQ_STATE_WAITING_FOR_NETWORK 10

int thsq_get_current_state(void);

void thsq_lighting_apply_last(void);
void thsq_lighting_set_lights(int prio, int r, int g, int b, uint32_t dur);
int thsq_lighting_current_red(void);
int thsq_lighting_current_green(void);
int thsq_lighting_current_blue(void);

/* lighting event types */
enum thsq_lighting_type {
  THSQ_LIGHTING_PIR,
  THSQ_LIGHTING_SWITCH,
  THSQ_LIGHTING_LC,
  THSQ_LIGHTING_IDFY,
};

int thsq_lighting_send(enum thsq_lighting_type t,
                       const uint8_t *zones, int zoneslen,
                       const uint8_t *data, int datalen, int broadcast);

void thsq_gpio_push_input_events(int enabled);
rtimer_clock_t thsq_gpio_input_duration_high(void);
rtimer_clock_t thsq_gpio_input_timestamp(void);
void thsq_gpio_input_duration_reset(void);
void thsq_gpio_input_invert(int enabled);

int thsq_gpio_get_adc(void);
int thsq_gpio_get_gpio(void);
int thsq_gpio_set_gpio(int high);

#endif /* THSQ_H */