|
|
|
#include "reporting.h"
|
|
|
|
#include "datalink.h"
|
|
|
|
#include "serial.h"
|
|
|
|
#include "httpclient.h"
|
|
|
|
#include "ftoa.h"
|
|
|
|
|
|
|
|
#define RPT_CONF_MAGIC 0x24C595D5
|
|
|
|
|
|
|
|
ReportingResult rpt_result;
|
|
|
|
ReportingCfg rpt_conf;
|
|
|
|
|
|
|
|
static os_timer_t rpt_tim;
|
|
|
|
|
|
|
|
/** Timer cb */
|
|
|
|
static void FLASH_FN rpt_tim_cb(void *arg)
|
|
|
|
{
|
|
|
|
(void)arg;
|
|
|
|
// send report now...
|
|
|
|
if (rpt_conf.enabled) {
|
|
|
|
capture_and_report();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Stop / start timer & set interval based on rpt conf */
|
|
|
|
static FLASH_FN void set_timer(void)
|
|
|
|
{
|
|
|
|
os_timer_disarm(&rpt_tim);
|
|
|
|
|
|
|
|
if (rpt_conf.enabled) {
|
|
|
|
os_timer_setfn(&rpt_tim, rpt_tim_cb, NULL);
|
|
|
|
os_timer_arm(&rpt_tim, (int)(rpt_conf.interval * 1000), 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Fix unterminated strings, add magic, etc.. */
|
|
|
|
static FLASH_FN void normalize_rpt_conf(void)
|
|
|
|
{
|
|
|
|
// terminate strings
|
|
|
|
rpt_conf.feed[sizeof(rpt_conf.feed) - 1] = 0;
|
|
|
|
rpt_conf.key[sizeof(rpt_conf.key) - 1] = 0;
|
|
|
|
// set magic
|
|
|
|
rpt_conf.magic = RPT_CONF_MAGIC;
|
|
|
|
}
|
|
|
|
|
|
|
|
static FLASH_FN void dump_rpt_conf(void)
|
|
|
|
{
|
|
|
|
dbg("Enabled: %d | Interval: %d | Service: %s", rpt_conf.enabled, rpt_conf.interval, (rpt_conf.service == RPT_XIVELY ? "Xively" : "ThingSpeak"));
|
|
|
|
dbg("Key: %s | Feed: %s", rpt_conf.key, rpt_conf.feed);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Save reporting config to flash */
|
|
|
|
void FLASH_FN reporting_cfg_save(void)
|
|
|
|
{
|
|
|
|
normalize_rpt_conf(); // fix weirdness
|
|
|
|
|
|
|
|
info("Saving monitoring config");
|
|
|
|
dump_rpt_conf();
|
|
|
|
|
|
|
|
system_param_save_with_protect(0x3D, &rpt_conf, sizeof(ReportingCfg));
|
|
|
|
|
|
|
|
// start timer for the new interval time
|
|
|
|
set_timer();
|
|
|
|
|
|
|
|
info("Config saved.");
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Load the reporting config from flash */
|
|
|
|
void FLASH_FN reporting_cfg_load(void)
|
|
|
|
{
|
|
|
|
info("Loading monitoring config");
|
|
|
|
|
|
|
|
system_param_load(0x3D, 0, &rpt_conf, sizeof(ReportingCfg));
|
|
|
|
|
|
|
|
if (rpt_conf.magic != RPT_CONF_MAGIC) {
|
|
|
|
warn("Config block corrupted, reset to defaults.");
|
|
|
|
|
|
|
|
// invalid config, zero out
|
|
|
|
memset(&rpt_conf, 0, sizeof(ReportingCfg));
|
|
|
|
rpt_conf.magic = RPT_CONF_MAGIC;
|
|
|
|
|
|
|
|
// save fixed
|
|
|
|
reporting_cfg_save();
|
|
|
|
} else {
|
|
|
|
dump_rpt_conf();
|
|
|
|
}
|
|
|
|
|
|
|
|
set_timer();
|
|
|
|
|
|
|
|
info("Config loaded.");
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Called when response to Compare Ref is received */
|
|
|
|
static void FLASH_FN compare_ref_cb(SBMP_Endpoint *ep, SBMP_Datagram *dg, void **obj)
|
|
|
|
{
|
|
|
|
(void)obj;
|
|
|
|
sbmp_ep_remove_listener(ep, dg->session);
|
|
|
|
|
|
|
|
info("Measurement complete.");
|
|
|
|
|
|
|
|
rpt_result.success = (dg->type == DG_SUCCESS);
|
|
|
|
|
|
|
|
if (dg->type == DG_SUCCESS) {
|
|
|
|
PayloadParser pp = pp_start(dg->payload, dg->length);
|
|
|
|
rpt_result.deviation = pp_float(&pp);
|
|
|
|
rpt_result.i_rms = pp_float(&pp);
|
|
|
|
} else {
|
|
|
|
error("FAIL resp from sbmp.");
|
|
|
|
}
|
|
|
|
|
|
|
|
rpt_result.ready = true; // signal to waiting loop
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Send report from rpt_result */
|
|
|
|
static void FLASH_FN do_send_report(void)
|
|
|
|
{
|
|
|
|
info("Sending report...");
|
|
|
|
|
|
|
|
char buf[100];
|
|
|
|
char *bb = buf;
|
|
|
|
|
|
|
|
char url_buf[200];
|
|
|
|
char hdrs_buf[100];
|
|
|
|
|
|
|
|
switch (rpt_conf.service) {
|
|
|
|
case RPT_XIVELY:;
|
|
|
|
bb += sprintf(bb, "deviation,");
|
|
|
|
bb += my_ftoa(bb, rpt_result.deviation, 2);
|
|
|
|
bb += sprintf(bb, "\nI_rms,");
|
|
|
|
bb += my_ftoa(bb, rpt_result.i_rms, 2);
|
|
|
|
|
|
|
|
// URL
|
|
|
|
sprintf(url_buf, "http://api.xively.com/v2/feeds/%s.csv", rpt_conf.feed);
|
|
|
|
|
|
|
|
// Key
|
|
|
|
sprintf(hdrs_buf, "X-ApiKey: %s\r\n", rpt_conf.key);
|
|
|
|
|
|
|
|
http_put(url_buf, buf, hdrs_buf, http_callback_example);
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case RPT_THINGSPEAK:
|
|
|
|
warn("------- TODO: REPORT TO THINGSPEAK -------");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/** Immediately send report to xively / thingspeak */
|
|
|
|
bool FLASH_FN capture_and_report(void)
|
|
|
|
{
|
|
|
|
info("Starting reporting measurmenet...");
|
|
|
|
rpt_result.ready = false;
|
|
|
|
|
|
|
|
uint16_t sesn;
|
|
|
|
sbmp_ep_send_message(dlnk_ep, DG_REQUEST_COMPARE_REF, NULL, 0, &sesn, NULL);
|
|
|
|
sbmp_ep_add_listener(dlnk_ep, sesn, compare_ref_cb, NULL);
|
|
|
|
|
|
|
|
// poll & wait for response
|
|
|
|
const int timeout = 500;
|
|
|
|
for (uint32_t i = 0; i < timeout * 100; i++) {
|
|
|
|
uart_poll();
|
|
|
|
|
|
|
|
if (rpt_result.ready) {
|
|
|
|
if (rpt_result.success) {
|
|
|
|
do_send_report();
|
|
|
|
}
|
|
|
|
return true; // done
|
|
|
|
}
|
|
|
|
|
|
|
|
os_delay_us(10);
|
|
|
|
system_soft_wdt_feed(); // Feed the dog, or it'll bite.
|
|
|
|
}
|
|
|
|
|
|
|
|
// timeout - remove listener
|
|
|
|
error("Measure timeout - no resp received.");
|
|
|
|
sbmp_ep_remove_listener(dlnk_ep, sesn);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static bool capt_ref_done;
|
|
|
|
static bool capt_ref_success;
|
|
|
|
|
|
|
|
/** Callback for "store ref" */
|
|
|
|
static void FLASH_FN store_ref_cb(SBMP_Endpoint *ep, SBMP_Datagram *dg, void **obj)
|
|
|
|
{
|
|
|
|
(void)obj;
|
|
|
|
sbmp_ep_remove_listener(ep, dg->session);
|
|
|
|
|
|
|
|
capt_ref_done = true;
|
|
|
|
capt_ref_success = (dg->type == DG_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Capture reference vector for monitoring */
|
|
|
|
bool FLASH_FN capture_reporting_reference(void)
|
|
|
|
{
|
|
|
|
info("Capturing reference...");
|
|
|
|
|
|
|
|
uint16_t sesn;
|
|
|
|
sbmp_ep_send_message(dlnk_ep, DG_REQUEST_STORE_REF, NULL, 0, &sesn, NULL);
|
|
|
|
sbmp_ep_add_listener(dlnk_ep, sesn, store_ref_cb, NULL);
|
|
|
|
|
|
|
|
capt_ref_done = false;
|
|
|
|
capt_ref_success = false;
|
|
|
|
|
|
|
|
const int timeout = 500;
|
|
|
|
for (uint32_t i = 0; i < timeout * 100; i++) {
|
|
|
|
uart_poll();
|
|
|
|
|
|
|
|
if (capt_ref_done) {
|
|
|
|
return capt_ref_success; // done
|
|
|
|
}
|
|
|
|
|
|
|
|
os_delay_us(10);
|
|
|
|
system_soft_wdt_feed(); // Feed the dog, or it'll bite.
|
|
|
|
}
|
|
|
|
|
|
|
|
// timeout - remove listener
|
|
|
|
error("Ref capture timeout - no resp received.");
|
|
|
|
sbmp_ep_remove_listener(dlnk_ep, sesn);
|
|
|
|
return false;
|
|
|
|
}
|