1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
/*
* Copyright (c) 2014-2016 Cesanta Software Limited
* All rights reserved
*/
#include "data.h"
#include <stdio.h>
#include <stdlib.h>
#include "gpio_if.h"
#include "bm222.h"
#include "tmp006.h"
#include "cs_dbg.h"
struct temp_data {
double ts;
double volt;
double temp;
};
struct conn_state {
struct temp_data td;
double last_sent_td;
unsigned char led;
double last_sent_led;
double last_sent_acc;
};
static int s_tmp006_addr;
static struct temp_data s_temp_data;
static struct bm222_ctx *s_accel_ctx;
void data_init_sensors(int tmp006_addr, int bm222_addr) {
s_tmp006_addr = tmp006_addr;
if (!tmp006_init(tmp006_addr, TMP006_CONV_2, false)) {
LOG(LL_ERROR, ("Failed to init temperature sensor"));
} else {
LOG(LL_INFO, ("Temperature sensor initialized"));
}
s_accel_ctx = bm222_init(bm222_addr);
if (s_accel_ctx == NULL) {
LOG(LL_ERROR, ("Failed to init accelerometer"));
} else {
LOG(LL_INFO, ("Accelerometer initialized"));
}
}
void data_collect(void) {
double volt = tmp006_read_sensor_voltage(s_tmp006_addr);
double temp = tmp006_read_die_temp(s_tmp006_addr);
if (volt != TMP006_INVALID_READING && temp != TMP006_INVALID_READING) {
s_temp_data.temp = temp;
s_temp_data.volt = volt;
s_temp_data.ts = mg_time();
LOG(LL_DEBUG, ("V = %lf mV, T = %lf C", volt, temp));
}
bm222_get_data(s_accel_ctx);
}
static void send_temp(struct mg_connection *nc, const struct temp_data *td) {
if (td->ts == 0) return;
mg_printf_websocket_frame(nc, WEBSOCKET_OP_TEXT,
"{\"t\": 0, \"ts\": %lf, \"sv\": %lf, \"dt\": %lf}",
td->ts, td->volt, td->temp);
}
static void send_led(struct mg_connection *nc, double ts, unsigned char led) {
if (ts == 0) return;
mg_printf_websocket_frame(nc, WEBSOCKET_OP_TEXT,
"{\"t\": 1, \"ts\": %lf, \"v\": %d}", ts, led);
}
static void send_acc_sample(struct mg_connection *nc,
const struct bm222_sample *s) {
if (s->ts == 0) return;
mg_printf_websocket_frame(
nc, WEBSOCKET_OP_TEXT,
"{\"t\": 2, \"ts\": %lf, \"x\": %d, \"y\": %d, \"z\": %d}", s->ts, s->x,
s->y, s->z);
}
static double send_acc_data_since(struct mg_connection *nc,
const struct bm222_ctx *ctx, double since) {
int i = (ctx->last_index + 1) % BM222_NUM_SAMPLES, n = BM222_NUM_SAMPLES;
double last_sent_ts = 0;
for (; n > 0; i = (i + 1) % BM222_NUM_SAMPLES, n--) {
const struct bm222_sample *s = ctx->data + i;
if (s->ts <= since) continue;
send_acc_sample(nc, s);
last_sent_ts = s->ts;
}
return last_sent_ts;
}
static void process_command(struct mg_connection *nc, unsigned char *data,
size_t len) {
// TODO(lsm): use proper JSON parser
int cmd, val;
if (sscanf((char *) data, "{\"t\":%d,\"v\":%d}", &cmd, &val) != 2) {
LOG(LL_ERROR, ("Invalid request: %.*s", (int) len, data));
return;
}
if (cmd == 1) {
switch (val) {
case '0': {
GPIO_IF_LedOff(MCU_RED_LED_GPIO);
break;
}
case '1': {
GPIO_IF_LedOn(MCU_RED_LED_GPIO);
break;
}
case '2': {
GPIO_IF_LedToggle(MCU_RED_LED_GPIO);
break;
}
default: {
LOG(LL_ERROR, ("Invalid value: %.*s", (int) len, data));
return;
}
}
} else {
LOG(LL_ERROR, ("Unknown command: %.*s", (int) len, data));
return;
}
}
void data_conn_handler(struct mg_connection *nc, int ev, void *ev_data) {
struct conn_state *cs = (struct conn_state *) nc->user_data;
if (cs == NULL) {
cs = (struct conn_state *) calloc(1, sizeof(*cs));
nc->user_data = cs;
}
switch (ev) {
case MG_EV_POLL:
case MG_EV_TIMER: {
const double now = mg_time();
const unsigned char led = GPIO_IF_LedStatus(MCU_RED_LED_GPIO);
/* Send if there was a change or repeat last data every second. */
if (s_temp_data.volt != cs->td.volt || s_temp_data.temp != cs->td.temp ||
now > cs->last_sent_td + 1.0) {
memcpy(&cs->td, &s_temp_data, sizeof(cs->td));
send_temp(nc, &cs->td);
cs->last_sent_td = now;
}
if (led != cs->led || now > cs->last_sent_led + 1.0) {
send_led(nc, now, led);
cs->led = led;
cs->last_sent_led = now;
}
if (s_accel_ctx != NULL) {
const struct bm222_sample *ls =
s_accel_ctx->data + s_accel_ctx->last_index;
if (cs->last_sent_acc == 0) {
send_acc_sample(nc, ls);
cs->last_sent_acc = ls->ts;
} else {
double last_sent_ts =
send_acc_data_since(nc, s_accel_ctx, cs->last_sent_acc);
if (last_sent_ts > 0) cs->last_sent_acc = last_sent_ts;
}
}
nc->ev_timer_time = now + 0.05;
break;
}
case MG_EV_WEBSOCKET_FRAME: {
struct websocket_message *wm = (struct websocket_message *) ev_data;
process_command(nc, wm->data, wm->size);
break;
}
case MG_EV_CLOSE: {
LOG(LL_INFO, ("%p closed", nc));
free(cs);
break;
}
}
}