Wirepas SDK
inventory_app_router/app.c
/* Copyright 2021 Wirepas Ltd. All Rights Reserved.
*
* See file LICENSE.txt for full license details.
*
*/
/*
* \file app.c
* \brief Headnode inventory application using directed-advertiser
*/
#include <string.h>
#include "api.h"
#include "power.h"
#include "advertiser.h"
#include "app_scheduler.h"
#include "pack.h"
#include "fifo.h"
#include "common.h"
#define NODE_HEADNODE_LL_ROLE \
app_lib_settings_create_role(APP_LIB_SETTINGS_ROLE_HEADNODE,APP_LIB_SETTINGS_ROLE_FLAG_LL)
#define SEND_CHECK_PERIOD_MS 500
// Source endpoint to send advertiser data
#define DIRADV_EP_SRC_DATA 248
typedef struct {
uint32_t src_addr;
uint32_t rcv_time;
adv_tag_data_t data;
} adv_data_type0_t;
typedef struct __attribute__ ((packed))
{
uint8_t src_addr[NODE_ADDRESS_SIZE];
union {
int8_t rssi; //these fields have the same size;
uint8_t otap_seq;
uint8_t voltage;
uint8_t seq;
};
} adv_data_type1_t;
typedef struct __attribute__ ((packed))
{
uint8_t type;
uint8_t msg_count;
adv_data_type1_t data[MSG_TYPE2_MAX_ITEMS];
}adv_data_type2_t;
typedef struct
{
uint8_t ack_data[TAG_APP_CFG_SIZE];
uint16_t send_check_ms;
uint32_t send_timeout_us;
uint8_t payload_type;
} settings_t;
typedef struct __attribute__ ((packed))
{
uint8_t magic;
uint8_t ack_data[TAG_APP_CFG_SIZE];
uint8_t send_check; // x10 ms
uint8_t send_timeout; // x100ms
uint8_t payload_type;
} app_config_data_t;
#define TYPE0_BUF_MAX 150
#define TYPE0_TIMEOUT_US (2 * 1000 * 1000)
#define SEND_CHECK_SCALLING 10
#define SEND_TIMEOUT_SCALLING 100000
#define RSSI_TO_dBm(x)(x/2-127)
static fifo_t m_fifo_type0;
static adv_data_type0_t m_data_type0[TYPE0_BUF_MAX];
static settings_t m_settings;
static app_lib_data_send_res_e res __attribute__((unused));
static uint8_t m_msg_count = 0;
static uint32_t m_rcv_count = 0;
static uint16_t m_appcfg_filter_id[2];
static bool appAckDataCb(const ack_gen_input_t * in, ack_gen_output_t * out)
{
(void) in;
out->data = &m_settings.ack_data;
out->length = sizeof(m_settings.ack_data);
return true;
}
static void appCfgDataCb(uint16_t type, uint8_t length, uint8_t * bytes)
{
app_config_data_t app_data;
uint8_t magic = *bytes;
bool valid = false;
if (type == INVENTORY_APPCFG_TLV_TYPE)
{
valid = (magic == 0xAD) && (length == sizeof(app_config_data_t));
}
#ifdef ENABLE_LEGACY_APPCFG
{
valid = (magic == 0xAD) && (sizeof(app_config_data_t) <= sizeof(app_config_data_t));
}
#endif
if (valid)
{
memcpy(&app_data, bytes, sizeof(app_config_data_t));
memcpy(m_settings.ack_data, app_data.ack_data, sizeof(m_settings.ack_data));
if (app_data.send_check > 0)
{
m_settings.send_check_ms = app_data.send_check * SEND_CHECK_SCALLING;
}
if (app_data.send_timeout > 0)
{
m_settings.send_timeout_us = app_data.send_timeout * SEND_TIMEOUT_SCALLING;
}
switch (app_data.payload_type)
{
case ADV_TYPE2:
case ADV_TYPE3:
case ADV_TYPE4:
case ADV_TYPE5:
case ADV_TYPE6:
m_settings.payload_type = app_data.payload_type;
break;
default: //setting not changed
break;
}
}
else
{
}
}
static
{
if ((data->src_endpoint == DIRADV_EP_SRC_DATA) &&
(data->num_bytes > 1))
{
uint8_t type = *data->bytes;
m_rcv_count++;
switch (type)
{
case ADV_TYPE0:
{
if (data->num_bytes >= sizeof(adv_tag_data_t))
{
adv_data_type0_t r;
r.src_addr = data->src_address;
r.rcv_time = lib_time->getTimestampHp();
memcpy(&r.data, data->bytes, sizeof(adv_tag_data_t));
fifo_push(&m_fifo_type0, &r);
}
break;
}
}
}
}
static bool check_data_timeout(fifo_t * f, uint32_t timeout)
{
adv_data_type0_t * r;
uint32_t delta;
r = (adv_data_type0_t *) fifo_get_tail(f);
if (r != NULL)
{
delta = lib_time->getTimeDiffUs(r->rcv_time, lib_time->getTimestampHp());
if (delta > timeout)
{
return true;
}
}
return false;
}
static uint8_t pack_msg( adv_data_type2_t * payload, uint8_t payload_type, uint32_t msg_count)
{
if(fifo_size(&m_fifo_type0) == 0)
{
return 0;
}
uint8_t count = 0;
adv_data_type0_t ad;
adv_data_type1_t * pd;
payload->type = payload_type | MSG_TYPE2_PREFIX;
payload->msg_count = (uint8_t) (msg_count & 0xFF);
while ( count < MSG_TYPE2_MAX_ITEMS )
{
if ( fifo_pop(&m_fifo_type0, &ad) )
{
pd = &payload->data[count];
Pack_packLe(&pd->src_addr, ad.src_addr, NODE_ADDRESS_SIZE);
switch ( payload_type )
{
case ADV_TYPE2:
pd->rssi = ad.data.rssi;
break;
case ADV_TYPE3:
pd->otap_seq = ad.data.proc_otap_seq;
break;
case ADV_TYPE4:
pd->otap_seq = ad.data.stored_otap_seq;
break;
case ADV_TYPE5:
pd->voltage = ad.data.voltage;
break;
case ADV_TYPE6:
pd->seq = (uint8_t) (ad.data.seq & 0x00FF);
break;
default:
return 0;
}
count++;
}
else
{
break;
}
}
return (sizeof(adv_data_type2_t) - sizeof(adv_data_type1_t) * (MSG_TYPE2_MAX_ITEMS - count));
}
static uint32_t send_data(void)
{
uint16_t len = fifo_size(&m_fifo_type0);
if ( len == 0 || \
((len < MSG_TYPE2_MAX_ITEMS) && !check_data_timeout(&m_fifo_type0, m_settings.send_timeout_us)))
{
return m_settings.send_check_ms;
}
uint8_t payload[102];
uint8_t payload_len = 0;
m_msg_count++;
switch (m_settings.payload_type)
{
case ADV_TYPE2:
case ADV_TYPE3:
case ADV_TYPE4:
case ADV_TYPE5:
case ADV_TYPE6:
payload_len = pack_msg((adv_data_type2_t *) &payload, \
m_settings.payload_type, m_msg_count);
break;
default:
payload_len = 0;
}
if (payload_len == 0)
{
return m_settings.send_check_ms;
}
// Send the data packet
data.bytes = (uint8_t*) &payload;
data.num_bytes = payload_len;
data.src_endpoint = DIRADV_AGR_EP;
data.dest_endpoint = DIRADV_AGR_EP;
data.delay = 0;
data.tracking_id = m_msg_count;
res = lib_data->sendData(&data);
(void) res; // !!! add check for data send
return m_settings.send_check_ms;
}
static bool node_init(void)
{
bool ret = true;
if (lib_settings->setNodeRole(NODE_HEADNODE_LL_ROLE)!= APP_RES_OK)
{
ret = false;
}
{
ret = false;
}
return ret;
}
static void sentDataCb(const app_lib_data_sent_status_t * status)
{
}
static void set_callbacks(void)
{
lib_data->setDataReceivedCb(dataReceivedCb);
lib_advertiser->setRouterAckGenCb(appAckDataCb);
lib_data->setDataSentCb(sentDataCb);
}
void App_init(const app_global_functions_t * functions)
{
shared_app_config_filter_t app_config_filter;
fifo_init(&m_fifo_type0, m_data_type0, sizeof(adv_data_type0_t), TYPE0_BUF_MAX);
memset(m_settings.ack_data, 0, sizeof(m_settings.ack_data));
m_settings.send_check_ms = SEND_CHECK_PERIOD_MS;
m_settings.send_timeout_us = TYPE0_TIMEOUT_US;
m_settings.payload_type = ADV_TYPE2;
App_Scheduler_addTask(send_data, SEND_CHECK_PERIOD_MS);
set_callbacks();
app_config_filter.type = INVENTORY_APPCFG_TLV_TYPE;
app_config_filter.cb = appCfgDataCb;
app_config_filter.call_cb_always = false;
if (Shared_Appconfig_addFilter(&app_config_filter, &m_appcfg_filter_id[0])
{
}
#ifdef ENABLE_LEGACY_APPCFG
//register for legacy mode also
if (Shared_Appconfig_addFilter(&app_config_filter, &m_appcfg_filter_id[1])
{
}
#endif
if(node_init())
{
lib_state->startStack();
}
else
{
lib_state->stopStack();
}
}
app_lib_data_received_t::num_bytes
size_t num_bytes
Definition: data.h:249
DIRADV_EP_DEST
#define DIRADV_EP_DEST
Headnode acknowledges the packet by using this destination endpoint.
Definition: advertiser.h:49
APP_LIB_DATA_SEND_FLAG_TRACK
@ APP_LIB_DATA_SEND_FLAG_TRACK
Definition: data.h:106
app_lib_data_to_send_t
A struct for lib_data->sendData().
Definition: data.h:288
App_Scheduler_init
void App_Scheduler_init(void)
Initialize scheduler.
pack.h
power.h
Shared_Appconfig_init
shared_app_config_res_e Shared_Appconfig_init(void)
Initialize the shared app config library library.
Pack_packLe
void Pack_packLe(void *bytes, uint32_t value, size_t num_bytes)
Convert native unsigned integer to 1 to 4 little endian bytes.
node_configuration.h
ack_gen_output_t::data
void * data
Definition: advertiser.h:101
SHARED_APP_CONFIG_RES_OK
@ SHARED_APP_CONFIG_RES_OK
Definition: shared_appconfig.h:18
app_lib_data_send_res_e
app_lib_data_send_res_e
A result code returned from lib_data->sendData().
Definition: data.h:140
shared_app_config_filter_t::cb
shared_app_config_received_cb_f cb
Definition: shared_appconfig.h:69
app_lib_data_to_send_t::dest_address
app_addr_t dest_address
Definition: data.h:295
ack_gen_input_t
Input data structure for callback function set by lib_advertiser->setRouterAckGenCb().
Definition: advertiser.h:71
APP_RES_OK
@ APP_RES_OK
Definition: app.h:204
app_lib_data_to_send_t::tracking_id
app_lib_data_tracking_id_t tracking_id
Definition: data.h:303
SHARED_APP_CONFIG_INCOMPATIBLE_FILTER
#define SHARED_APP_CONFIG_INCOMPATIBLE_FILTER
Value to use to receive incompatible raw app_config Ie, if the app config is not recognized by this l...
Definition: shared_appconfig.h:39
app_scheduler.h
ack_gen_output_t::length
uint8_t length
Definition: advertiser.h:104
ack_gen_output_t
Output structure for for callback function set by lib_advertiser->setRouterAckGenCb().
Definition: advertiser.h:97
Shared_Appconfig_addFilter
shared_app_config_res_e Shared_Appconfig_addFilter(shared_app_config_filter_t *filter, uint16_t *filter_id)
Add a new app config type filter to the list. If the item is already in the list it is only updated.
app_lib_data_to_send_t::qos
app_lib_data_qos_e qos
Definition: data.h:305
APP_LIB_DATA_RECEIVE_RES_HANDLED
@ APP_LIB_DATA_RECEIVE_RES_HANDLED
Definition: data.h:188
app_lib_data_to_send_t::delay
uint32_t delay
Definition: data.h:299
configureNodeFromBuildParameters
__STATIC_INLINE app_res_e configureNodeFromBuildParameters()
Wrapper on top of configureNode to get parameters from build system and hardcoded values from chip (f...
Definition: node_configuration.h:233
shared_appconfig.h
app_lib_data_to_send_t::flags
uint8_t flags
Definition: data.h:307
app_lib_data_receive_res_e
app_lib_data_receive_res_e
Return value of data reception callback.
Definition: data.h:184
app_lib_data_received_t::src_endpoint
uint8_t src_endpoint
Definition: data.h:259
app_lib_data_received_t::dest_endpoint
uint8_t dest_endpoint
Definition: data.h:261
app_lib_data_received_t::bytes
const uint8_t * bytes
Definition: data.h:247
shared_app_config_filter_t
Structure holding all parameters for app config type filtering.
Definition: shared_appconfig.h:60
advertiser.h
APP_ADDR_ANYSINK
@ APP_ADDR_ANYSINK
Definition: app.h:236
app_lib_data_received_t::src_address
app_addr_t src_address
Definition: data.h:251
app_lib_data_received_t
Struct passed to data reception callback functions.
Definition: data.h:244
app_global_functions_t
List of global functions, passed to App_entrypoint()
Definition: app.h:157
shared_app_config_filter_t::call_cb_always
bool call_cb_always
Definition: shared_appconfig.h:74
APP_LIB_DATA_QOS_HIGH
@ APP_LIB_DATA_QOS_HIGH
Definition: data.h:93
shared_app_config_filter_t::type
uint16_t type
Definition: shared_appconfig.h:64
app_lib_data_sent_status_t
Struct to tracking callback function.
Definition: data.h:325
api.h