Skip to content

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

enum thsq_reason {

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 32 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);

Button actions module

The button actions module implements a set of commonly triggered device
actions by monitoring for button clicks.
Normal button clicks are available to handle at will by the application via the
THSQ_BUTTONACTION event. Button click series that are followed with a long press
trigger system operations such as 0) sending sensor data and BLE auth beacons,
1) push real good, 2) soft-unbonding, and 3) rebooting device.

void thsq_buttonactions_booted(int button_down);
void thsq_buttonactions_register(int button_down);

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
thsq_lighting_set_lamp() (for lamps), 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.

Type definition of the lighting module callback function

typedef void (*thsq_lighting_callback_fn)(const uint8_t *rgb, int len, const char *reason);

void thsq_lighting_init(void);
void thsq_lighting_set_lamp(void);
struct thsq_lighting_callback {
  struct thsq_lighting_callback *next;
  thsq_lighting_callback_fn callback;
struct thsq_schedule;
void thsq_lighting_add_callback(struct thsq_lighting_callback *c, thsq_lighting_callback_fn f);
void thsq_lighting_set_default_lschedule(uint8_t *sched, int len);
void thsq_schedule_set_default(struct thsq_schedule *s, uint8_t *sched, int len);
void thsq_schedule_build_schedule_action(uint8_t *buf, int mon, int tue,
                                         int wed, int thu, int fri, int sat,
                                         int sun, uint8_t hours,
                                         uint8_t minutes, uint8_t red,
                                         uint8_t green, uint8_t blue);
void thsq_lighting_post_lights_variable(int active);

void thsq_lighting_lan_control_init(void);

Network time synchronization

If the device is time synchronized as indicated by thsq_has_time() == 1,
then thsq_get_time() returns the current Unix time (UTC) and
thsq_get_timezone_offset() the current timezone's seconds offset from UTC.
thsq_get_time_fine() returns the current Unix time in clock_time_t precision.

int thsq_has_time(void);
uint32_t thsq_get_time(void);
int32_t thsq_get_timezone_offset(void);
void thsq_set_time(uint32_t utc, int32_t tz_offset);
uint64_t thsq_get_time_high_precision(void);

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

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

Bootloader configuration

The booloader can beconfigured with
up the flash chip configuration for the bootloader.

On platforms using cc13xx or cc26xx, the call has the following syntax:
where each pin is named eg IOID_2 for the DIO_2 pin.
Don't forget to include #include "ti-lib.h".

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 */

  uint8_t secure_boot_aes[16]; /* secure boot AES key */

  uint8_t reserved[9];

extern struct thsq_bootloader_params bootloaderparams;
#define BOOTLOADERPARAMS_OVERRIDE(active, conf, miso, mosi, clk, cs)    \
    struct thsq_bootloader_params bootloaderparams \
    __attribute__ ((section(".bootloaderparams")))   \
    __attribute__ ((used))                    \
    = {active, conf, miso, mosi, clk, cs, \
       { 0xff, 0xff, 0xff, 0xff, \
         0xff, 0xff, 0xff, 0xff, \
         0xff, 0xff, 0xff, 0xff, \
         0xff, 0xff, 0xff, 0xff }, \
       { 0xff, 0xff, 0xff, 0xff, \
         0xff, 0xff, 0xff, 0xff, \
         0xff }}

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

  BOOTLOADERPARAMS_OVERRIDE(1, 1, 0xff, 0xff, 0xff, 0xff)

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);
enum thsq_err thsq_dset(const char *key, int val);
enum thsq_err thsq_dset_str(const char *key, const char *str);
enum thsq_err thsq_sset(const char *key, int val);
enum thsq_err thsq_sset_str(const char *key, const char *str);
enum thsq_err thsq_sset_printf(const char *key, const char *format, ...);
enum thsq_err thsq_sset_ptr(const char *key, const uint8_t *val, uint16_t vallen, int important);
enum thsq_err thsq_sset_ptr_timestamp(uint32_t timestamp, const char *key, const uint8_t *val, uint16_t vallen, int important);
int thsq_get(const char *key);
int thsq_get_to_buf(const char *key, uint8_t *buf, int buflen);

int thsq_equals(const char *key, const uint8_t *match, int matchlen);
int thsq_equals_str(const char *key, const char *match);

Get configuration options via d variable

Given that a d variable with the name "key" exists, and the value
has the string "substr" followed by a ':' character, this function
returns the long integer value that follows the ':' character.

long thsq_get_substr_long_arg(const char *key, const char *substr, int argnum, long default_val);

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);

Set device default power variable value, d.power

void thsq_set_default_power_conf(const char *powerconf);

Disable the requirement for a valid digital signature for over-the-air firmware updates

By default, all binaries loaded over the air have a digital
signature that ensures that they were produced by the same entity
the produced the product they operate in. While this is essential
for deployed products, it may be problematic during product
development, before a solid key management policy has been

This function allows the user application to override the
requirement for a valid digital signature. After calling this
function, the device will accept invalid signatures when loading
binaries over the air.

void thsq_disable_digital_signature(void);

Undocumented functions

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

Queue important variables module

The queue important variable module enables an application to queue up
timestamped important variables that are later sent to the server.
A queue is defined using the THSQ_QUEUE() macro, and must be initialized
using thsq_queue_init() before used. New data is added to the queue
with the thsq_queue_add() function.

#include "lib/list.h"
#include "lib/memb.h"
#include "sys/cc.h"

#define THSQ_QUEUE(name, structure, elements, send_callback) \
  struct CC_CONCAT(name,_meta) { \
    struct CC_CONCAT(name,_meta) *next; \
    clock_time_t timestamp; \
    const char *key; \
    structure data; \
  }; \
  MEMB(CC_CONCAT(name,_memb), struct CC_CONCAT(name,_meta), elements); \
  LIST(CC_CONCAT(name,_list)); \
  static struct thsq_queue name = { \
    NULL, \
    sizeof(structure), \
    0, \
    send_callback, \
    &CC_CONCAT(name,_memb), \
    (list_t *)&CC_CONCAT(name,_list) \

struct thsq_queue;
typedef int (* thsq_queue_send_callback_t)(struct thsq_queue *q, uint32_t timestamp, const char *key, void *data); /* Returns 1 if sent */
struct thsq_queue {
  struct thsq_queue *next;
  int size;
  uint16_t internal;
  thsq_queue_send_callback_t send_callback;
  struct memb *memb;
  list_t *list;

void thsq_queue_init(struct thsq_queue *q);
int thsq_queue_free(struct thsq_queue *q); /* Number of available queue elements */
int thsq_queue_used(struct thsq_queue *q); /* Number of used queue elements */
enum thsq_err thsq_queue_add(struct thsq_queue *q, const char *key, void *element); /* Add new element to queue, returns 0 at success */
void thsq_queue_pause(struct thsq_queue *q, int paused); /* Pause sending data from queue */

void thsq_queue_send_reject_when_full(struct thsq_queue *q, int enabled); /* Reject elements when queue is full, instead of dropping oldest elements */
void thsq_queue_dont_pack_same_keys(struct thsq_queue *q, int dontpack);

Xmem queue xmem module

The xmem queue module enables an application to store application data in a queue in xmem.
As opposed to the regular queue module, elements that are stored in xmem survive device reboots.
Xmem also offers more data to be stored.
Features include: * Can store elements prior to receiving time synch * Support sending multiple elements in a single data packet, via thsq-queue * Similar API as thsq-queue

typedef int16_t thsq_xmem_page_t;

struct thsq_xmem_timestamps {
  uint32_t utc;
  clock_time_t clock;
} __attribute__((aligned(4)));

struct thsq_xmem_aes_ctx {
  uint8_t cbcmac[16];
  uint32_t ctr;
  uint32_t addr;
  thsq_xmem_page_t page;
} __attribute__((aligned(4)));

struct thsq_xmem_queue_header {
  uint8_t flags;
  uint8_t keyidx;
  struct thsq_xmem_timestamps timestamps;

struct thsq_xmem_stats {
  int16_t count_writes_left;
  int16_t count_sends_left;

  uint16_t count_waiting;
  uint16_t count_discarded;
  uint16_t count_acked;

  uint32_t count_tot_writes;
  uint32_t count_tot_sends;
  uint32_t count_tot_acks;
  uint32_t count_bad_entries;
  uint32_t count_not_found;
  uint32_t count_queue_full;
} __attribute__((aligned(4)));

struct thsq_xmem_queue;
typedef enum thsq_err (* thsq_xmem_queue_send_callback_t)(struct thsq_xmem_queue *q, uint32_t timestamp, const char *key, void *data);

#define THSQ_XMEM_QUEUE(name, structure, send_callback, startpage, nrpages) \
  static struct thsq_xmem_queue name = { \
    NULL, \
    MIN(sizeof(structure),THSQ_XMEM_MAX_PAYLOAD_SIZE), \
    send_callback, \
    startpage, \
    nrpages, \
    { 0 }, \
    { 0 }, 0, \
    { { 0 }, 0, 0, 0 }, { { 0 }, 0, 0, 0 }, \
    0 \

struct thsq_xmem_queue {
  struct thsq_xmem_queue *next;
  int data_size;
  thsq_xmem_queue_send_callback_t send_callback;

  thsq_xmem_page_t xmem_start_page;
  thsq_xmem_page_t xmem_nr_pages;

  struct thsq_xmem_stats stats;

  char key_memory[THSQ_XMEM_KEY_MEMORY_LENGTH];
  int key_count;

  struct thsq_xmem_aes_ctx aes_write;
  struct thsq_xmem_aes_ctx aes_read;

  uint8_t flags;

enum thsq_err thsq_xmem_queue_init(struct thsq_xmem_queue *xq);
enum thsq_err thsq_xmem_queue_validate(struct thsq_xmem_queue *q);

unsigned int thsq_xmem_queue_nr_used(struct thsq_xmem_queue *q);
unsigned int thsq_xmem_queue_nr_discarded(struct thsq_xmem_queue *q);
unsigned int thsq_xmem_queue_nr_acked(struct thsq_xmem_queue *q);
unsigned int thsq_xmem_queue_nr_waiting(struct thsq_xmem_queue *q);
unsigned int thsq_xmem_queue_nr_total(struct thsq_xmem_queue *q);
unsigned int thsq_xmem_queue_nr_free(struct thsq_xmem_queue *q);
uint32_t thsq_xmem_queue_nr_tot_writes(struct thsq_xmem_queue *q);
uint32_t thsq_xmem_queue_nr_tot_sends(struct thsq_xmem_queue *q);
uint32_t thsq_xmem_queue_nr_tot_acks(struct thsq_xmem_queue *q);
uint32_t thsq_xmem_queue_nr_bad_entries(struct thsq_xmem_queue *q);
uint32_t thsq_xmem_queue_nr_not_found(struct thsq_xmem_queue *q);
uint32_t thsq_xmem_queue_nr_queue_full(struct thsq_xmem_queue *q);
int thsq_xmem_queue_nr_keys(struct thsq_xmem_queue *q);

enum thsq_err thsq_xmem_queue_format(struct thsq_xmem_queue *q);
enum thsq_err thsq_xmem_queue_add(struct thsq_xmem_queue *q, const char* variable, void *element);

void thsq_xmem_queue_enable_remote_commands(void);

The GPIO input module

enum thsq_gpi_pull_type {
struct thsq_gpi_conf;
typedef void (* thsq_gpi_callback_t)(struct thsq_gpi_conf *c, int val);
struct thsq_gpi_conf {
  struct thsq_gpi_conf *next;
  uint32_t pin;
  volatile uint8_t triggered, triggered_val;
  uint8_t last_val;
  thsq_gpi_callback_t callback_interrupt;
  thsq_gpi_callback_t callback_user;
  clock_time_t debouncetimeout;
  struct etimer debouncetimer;
void thsq_gpi_cc26xx_cc13xx_conf(struct thsq_gpi_conf *c, uint32_t pin,
                                 enum thsq_gpi_pull_type pulltype,
                                 thsq_gpi_callback_t cb_interrupt,
                                 thsq_gpi_callback_t cb_user,
                                 clock_time_t debouncetimeout);
void thsq_gpi_unconf(struct thsq_gpi_conf *c);
int thsq_gpi_value(struct thsq_gpi_conf *c);

void thsq_stats_blink_network_state(void);

The GPIO output module

struct thsq_gpo_conf;
struct thsq_gpo_conf {
  uint32_t pin;
void thsq_gpo_cc26xx_cc13xx_conf(struct thsq_gpo_conf *c, uint32_t pin);
void thsq_gpo_unconf(struct thsq_gpo_conf *c);
void thsq_gpo_set_value(struct thsq_gpo_conf *c, int val);

The ADC module

The ADC modules uses the built-in ADC for conversions. The implementation
and details vary depending on platform.

On CC13xx (eg CC1310, CC1352P), a conversion is blocking, and uses the 4.3V
internal reference. Since the ADC is 12-bit, the resulting range is
0..4096 LSB. To convert to mV, scale by 4300/4096. By default, the shortest
conversion time is used.

struct thsq_adc_conf {
  uint32_t pin;
  uint8_t sampletime;
void thsq_adc_cc26xx_cc13xx_conf(struct thsq_adc_conf *c, uint32_t pin);
void thsq_adc_unconf(struct thsq_adc_conf *c);
uint16_t thsq_adc_value(struct thsq_adc_conf *c);

The I2C module

struct thsq_i2c_conf {
  uint8_t slave_address;
  uint8_t interface;
  uint32_t pin_sda;
  uint32_t pin_scl;
  uint32_t speed;
void thsq_i2c_cc26xx_cc13xx_conf(struct thsq_i2c_conf *c,
                                 uint8_t slave_address,
                                 uint32_t sda, uint32_t scl,
                                 uint32_t speed);
void thsq_i2c_unconf(struct thsq_i2c_conf *c);
int thsq_i2c_write_read(struct thsq_i2c_conf *c, uint8_t *out, int outlen,
                        uint8_t *in, int inlen);

The SPI module

struct thsq_spi_conf {
  uint32_t cs; /* if IOID_UNUSED, caller handles this pin */
  uint32_t miso;
  uint32_t mosi;
  uint32_t clk;
  uint32_t speed; /* has a default, but can be overridden before any rw-call */
  uint32_t mode;

enum thsq_spi_mode {
  /* note: don't change order since this follows x0/x2 drivers */

#define THSQ_SPI_DEFAULT_SPEED 4000000ul

void thsq_spi_conf(struct thsq_spi_conf *c,
                   uint32_t cs, uint32_t miso, uint32_t mosi, uint32_t clk,
                   uint32_t speed, enum thsq_spi_mode mode);
void thsq_spi_unconf(struct thsq_spi_conf *c);
int thsq_spi_write_read(struct thsq_spi_conf *c, const uint8_t *out, int outlen,
                        uint8_t *in, int inlen);
int thsq_spi_write_read_with_prefix(struct thsq_spi_conf *c, const uint8_t *preout,
                        int preoutlen, const uint8_t *out, int outlen, uint8_t *in, int inlen);
int thsq_spi_transfer(struct thsq_spi_conf *c, const uint8_t *from,
                      uint8_t *to, int len);

/* Legacy function, for backwards compability */
void thsq_spi_cc26xx_cc13xx_conf(struct thsq_spi_conf *c, uint32_t cs,
                                 uint32_t miso, uint32_t mosi, uint32_t clk);

The PWM module

The PWM module provides a simple way to configure pulse-width modulation (PWM) pins.

struct thsq_pwm_conf {
  uint8_t port;
  int pin;
  int dutycycle;
  uint8_t timer;
  uint32_t gpt_base;
  unsigned long freq;
  int configured;
  int running;

void thsq_pwm_cc2538_conf(struct thsq_pwm_conf *c, uint8_t port, uint8_t pin,
                          uint8_t timer, unsigned long freq, int dutycycle);
void thsq_pwm_cc26xx_cc13xx_conf(struct thsq_pwm_conf *c, int pin,
                                 unsigned long freq, uint32_t gpt_base,
                                 int dutycycle);
void thsq_pwm_set_dutycycle(struct thsq_pwm_conf *c, int dutycycle);
void thsq_pwm_set_freq(struct thsq_pwm_conf *c, int freq);

The schedule module

struct thsq_schedule;

typedef void (* thsq_schedule_callback_t)(struct thsq_schedule *s, uint8_t *payload, int len);

struct thsq_schedule {
  struct thsq_schedule *next;
  int payload_length;
  thsq_schedule_callback_t cb;
  const char *varname;
  struct ctimer next_wakeup;

void thsq_schedule_init(struct thsq_schedule *s, const char *varname, thsq_schedule_callback_t callback);

void thsq_scheduled_offline_init(void);

enum thsq_err {
   THSQ_ERR_OK            =  1,
   THSQ_ERR_BUFSIZE       = -1,
   THSQ_ERR_ALLOC         = -3,
   THSQ_ERR_FATAL         = -8,

#define THSQ_ERR_IS_ERROR(err) ((err) < 0)

enum thsq_err thsq_dset_ptr(const char *key, const uint8_t *val, uint16_t vallen);
enum thsq_err thsq_sset_str_important(const char *key, const char *str);
enum thsq_err thsq_sset_printf_important(const char *key, const char *format, ...);
enum thsq_err thsq_sset_printf_important_timestamp(uint32_t timestamp, const char *key, const char *format, ...);
enum thsq_err thsq_sset_ulong(const char *key, uint32_t val);
int32_t thsq_get_long(const char *key);
int thsq_exists(const char *key);

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

void thsq_set_bond_key(const uint8_t *key);
void thsq_set_fingerprint(const char *host, const uint8_t *fingerprint);
void thsq_set_server_certificate(const uint8_t *cert);

  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 flags,
                                  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);


 * 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.

int thsq_get_current_state(void);

 * Apply lighting settings from before last reboot, if such can successfully be
 * retrieved. This depends on for how long the device was powered off or in reset.
void thsq_lighting_apply_last(void);

typedef enum thsq_lighting_prio {
  THSQ_LIGHTING_PRIO_0 = 0, /* lowest prio */
  THSQ_LIGHTING_PRIO_4 = 4, /* max prio */
} thsq_lighting_prio_t;

void thsq_lighting_set_lights(thsq_lighting_prio_t prio, int r, int g, int b, uint32_t dur);

void thsq_lighting_set_default_zone_control(thsq_lighting_prio_t prio, uint32_t duration);
void thsq_lighting_set_default_switch(thsq_lighting_prio_t prio, uint32_t duration);
void thsq_lighting_set_default_pir(thsq_lighting_prio_t prio, uint32_t duration, int red, int green, int blue);
void thsq_lighting_set_default_schedule(thsq_lighting_prio_t prio);
void thsq_lighting_set_default_lc(thsq_lighting_prio_t prio, uint32_t duration);

const char *thsq_zones_get_zone(void);

/* lighting event types */
enum thsq_lighting_type {

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

void thsq_gpio_push_input_events(int enabled); /* s.gpi */
void thsq_gpio_push_adc_periodically(int enabled); /* s.adc */
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);

/* Make the GPIO module listen to events from the lighting module. */
void thsq_gpio_attach_lighting(void);
void thsq_gpio_trigger_pir_on_gpio(int trigger);
void thsq_gpio_trigger_switch_on_gpio(int trigger);

struct thsq_pwm_conf *thsq_gpio_get_pwm_red(void);
struct thsq_pwm_conf *thsq_gpio_get_pwm_green(void);
struct thsq_pwm_conf *thsq_gpio_get_pwm_blue(void);

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

void thsq_sniffer_init(void);

long thsq_get_long_arg(const char *key, int argnum, long na);

/* THSQ_POWER_LEVEL_DUTYCYCLED: Device tries to preserve power by keeping radio receiver off when possible.
 * THSQ_POWER_LEVEL_ALWAYS_ON: Device keeps radio receiver on all the time. */
enum thsq_power_level {
enum thsq_power_level thsq_get_power_level(void);
void thsq_set_power_level(enum thsq_power_level p);
void thsq_set_default_power_level(enum thsq_power_level p);

enum thsq_freq_conf {
enum thsq_freq_conf thsq_get_freq_conf(void);
void thsq_set_freq_conf(enum thsq_freq_conf f);
void thsq_set_default_freq_conf(enum thsq_freq_conf f);

void thsq_peui_init(void);
void thsq_feui_init(void);
void thsq_stats_dbgstats_init(void);
void thsq_mesh_debug_init(void);

struct thsq_chunk;

typedef void (* thsq_chunk_callback_t)(struct thsq_chunk *c, void *ptr, uint32_t count, int maxsize);

struct thsq_chunk {
  struct thsq_chunk *next;
  const char *name;
  void *ptr;
  thsq_chunk_callback_t callback;
  uint32_t count;

void thsq_chunk_init(struct thsq_chunk *c, const char *name, thsq_chunk_callback_t callback, void *ptr);
int thsq_chunk_send(struct thsq_chunk *c, const uint8_t *data, int datalen);
int thsq_chunk_send_timestamp(struct thsq_chunk *c, const uint8_t *data, int datalen, uint32_t timestamp);

void thsq_enable_invites(void);
void thsq_enable_configurable_server_addresses(void);

void thsq_invite(uint8_t txpower, char *bondid);
void thsq_listen_for_bond_messages(clock_time_t duration);
void thsq_listen_for_bond_messages_always(void);
void thsq_listen_for_bond_messages_never(void);
void thsq_request_invite(void);

void thsq_prod_init(void);
void thsq_prod_default_commands(void);
void thsq_prod_comm_commands(void);
void thsq_prod_set_progress(char *code, const char *fmt, ...);
#define thsq_prod_set_error(...) thsq_prod_set_progress("err", __VA_ARGS__)
void thsq_prod_runner_serial_init(void);
void thsq_prod_runner_standalone_init(const char *tests);
#define THSQ_PROD_CODE(msg, code) \
  ((size_t)len >= 4 + strlen(code) && strncmp(msg, "test", 4) == 0 && strncmp(&msg[4], code, strlen(code)) == 0)
#define THSQ_PROD_CODE_DONE(msg) \
  THSQ_PROD_CODE(msg, "done")

void thsq_txpower_init(void);

struct thsq_dc {
  struct energest_extension e;

typedef void (*thsq_ble_scan_callback_fn)(const uint8_t *buf, int len, int rssi);
void thsq_ble_enable_background_scan(thsq_ble_scan_callback_fn callback);
void thsq_ble_whitelist(uint8_t *adv_address);

void thsq_dc_on(struct thsq_dc *);
void thsq_dc_off(struct thsq_dc *);
void thsq_dc_add(struct thsq_dc *);

void thsq_set_default_server(void);
void thsq_set_server(const char *newserver);

#define thsq_fft_scalar int16_t
typedef struct {
    thsq_fft_scalar r;
    thsq_fft_scalar i;
} thsq_fft_freq;
int thsq_fft_run(thsq_fft_scalar *samples, int len, thsq_fft_freq *output);
int16_t thsq_fft_hannwdw_128(int index, int16_t val);

int thsq_cbor_append_indefarr(uint8_t *buf, uint8_t *end);
int thsq_cbor_append_indefmap(uint8_t *buf, uint8_t *end);
int thsq_cbor_append_break(uint8_t *buf, uint8_t *end);
int thsq_cbor_append_str(uint8_t *buf, uint8_t *end, const char *str);
int thsq_cbor_append_int(uint8_t *buf, uint8_t *end, int32_t val);
int thsq_cbor_append_float(uint8_t *buf, uint8_t *end, float val);
int thsq_cbor_append_true(uint8_t *buf, uint8_t *end);
int thsq_cbor_append_false(uint8_t *buf, uint8_t *end);

enum thsq_rf_interface_type {
  THSQ_RF_INTERFACE_BLE, /* secondary radio interface */

enum thsq_rf_callback_event {

typedef void (*thsq_rf_callback_fn)(enum thsq_rf_interface_type interface, enum thsq_rf_callback_event event);
struct thsq_rf_callback {
  struct thsq_rf_callback *next;
  thsq_rf_callback_fn callback;

void thsq_rf_add_callback(struct thsq_rf_callback *c, thsq_rf_callback_fn f);

void thsq_rf_blacklist_channels(const char *blacklist_hex, int blacklist_len);
void thsq_rf_override_freqhopping_channels(const uint32_t *freqs, int num, int *sync);

 * Parse an ASCII string with hex data into a binary buffer.
int thsq_parse_hex(const char *hexstring, int hexstringlen, uint8_t *buffer, int bufferlen);

void thsq_remotecontrol_init(void);
void thsq_gateway_rssi_logging_init(void);
void thsq_rplconf_init(void);

struct thsq_minmax_uint32 {
  uint32_t min, max;
  uint32_t min_timestamp, max_timestamp;
  uint64_t sum;
  uint32_t count;
  double ewma;
  uint8_t ewma_initialized;

struct thsq_minmax_int32 {
  int32_t min, max;
  uint32_t min_timestamp, max_timestamp;
  uint64_t sum;
  uint32_t count;
  double ewma;
  uint8_t ewma_initialized;

struct thsq_minmax_float {
  float min, max;
  uint32_t min_timestamp, max_timestamp;
  float sum;
  uint32_t count;
  double ewma;
  uint8_t ewma_initialized;

void thsq_minmax_uint32_update(struct thsq_minmax_uint32 *minmax, uint32_t data, double ewma_alpha);
void thsq_minmax_int32_update(struct thsq_minmax_int32 *minmax, int32_t data, double ewma_alpha);
void thsq_minmax_float_update(struct thsq_minmax_float *minmax, float data, double ewma_alpha);
void thsq_minmax_uint32_init(struct thsq_minmax_uint32 *minmax);
void thsq_minmax_int32_init(struct thsq_minmax_int32 *minmax);
void thsq_minmax_float_init(struct thsq_minmax_float *minmax);

void thsq_range_mapper_init(void);
int thsq_range_mapper_is_running(void);
void thsq_range_mapper_start(void);
void thsq_range_mapper_stop(void);

void thsq_ble_transfer_init(void);
void thsq_ble_transfer_enable(void (* callback)(const uint8_t *data, int datalen));
void thsq_ble_transfer_disable(void);
int thsq_ble_transfer_is_enabled(void);

void thsq_force_radio_on(int force);

#endif /* THSQ_H */