/
main.c
425 lines (394 loc) · 12.7 KB
/
main.c
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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
#include <mchck.h>
#include <nrf/nrf.h>
#include <stdlib.h>
#include <string.h>
#include "config.h"
#include "version.h"
#include "power.h"
#include "acquire.h"
#include "sensor.h"
#include "blink.h"
#include "sensors/conductivity.h"
#include "usb_console.h"
#include "nv_config.h"
#include "sample_store.h"
#include "radio.h"
#include "sensor_iter.h"
/*
* command processing
*/
static char cmd_buffer[32];
static volatile bool command_queued = false;
#define OUT usb_console_printf
static void
reply_finished(void *cbdata)
{
command_queued = false;
}
static void
finish_reply()
{
usb_console_printf("\n");
usb_console_flush(reply_finished, NULL);
}
/*
* live sensor sample dumping
*/
static volatile bool verbose = false;
struct sensor_listener listener;
static void
on_sample_cb(struct sensor *sensor, uint32_t time,
uint8_t measurable, accum value, void *cbdata)
{
if (verbose)
printf("%d %d %3.4k\n", sensor->sensor_id, measurable, value);
}
/*
* stored sample printing
*/
static struct sample sample_buffer;
static volatile unsigned int sample_idx = 0;
static volatile unsigned int sample_end = 0;
static struct spiflash_transaction sample_read_trans;
static void print_stored_sample(void *cbdata);
static void
print_sample(const struct sample *sample)
{
usb_console_printf("%10d %2d %2d %4.4k\n",
sample->time, sample->sensor_id,
sample->measurable, sample->value);
}
static void
get_stored_sample(void *cbdata)
{
int ret = sample_store_read(&sample_read_trans,
&sample_buffer, sample_idx, 1,
print_stored_sample, NULL);
if (ret != 0) {
OUT("error\n");
finish_reply();
}
}
static void
print_stored_sample(void *cbdata)
{
print_sample(&sample_buffer);
if (sample_idx < sample_end - 1) {
sample_idx++;
usb_console_flush(get_stored_sample, NULL);
} else {
finish_reply();
}
}
/*
* SPI flash commands
*/
static void
flash_id_cb(void *cbdata, uint8_t mfg_id, uint8_t memtype, uint8_t capacity)
{
OUT("flash: mfg=%x memtype=%x capacity=%x\n",
mfg_id, memtype, capacity);
finish_reply();
}
static void
flash_status_cb(void *cbdata, uint8_t status)
{
OUT("flash: status=%02x\n", status);
finish_reply();
}
// `s` command: list sensors
static void
print_sensor(void *cbdata)
{
struct sensor **s = cbdata;
if (*s == NULL) {
finish_reply();
} else {
OUT("%2d\t%20s\n",
(*s)->sensor_id,
(*s)->name);
usb_console_flush(print_sensor, s+1);
}
}
// `m` command: list measurables of sensor
struct list_measurables_state {
struct sensor *sensor;
unsigned int measurable_idx;
} list_measurables_state;
static void
print_measurable(void *cbdata)
{
struct sensor *s = list_measurables_state.sensor;
if (list_measurables_state.measurable_idx < s->type->n_measurables) {
struct measurable *m = &s->type->measurables[list_measurables_state.measurable_idx];
OUT("%2d\t%20s\t%20s\n",
m->id,
m->name ? m->name : "unknown",
m->unit ? m->unit : "unknown");
list_measurables_state.measurable_idx++;
usb_console_flush(print_measurable, NULL);
} else {
finish_reply();
}
}
// `l` command: last sensor value
struct measurable_iterator last_sample_iter;
static void
last_sensor_sample(void *cbdata)
{
if (meas_iter_next(&last_sample_iter)) {
struct sensor *s = meas_iter_get_sensor(&last_sample_iter);
struct measurable *m = meas_iter_get_measurable(&last_sample_iter);
accum value = sensor_get_value(s, m->id);
OUT("%d %10d %2d %2.4k\n",
s->last_sample_time,
s->sensor_id,
m->id,
value);
usb_console_flush(last_sensor_sample, s+1);
} else {
finish_reply();
}
}
static void
nv_configuration_saved(void *cbdata)
{
OUT("saved\n");
finish_reply();
}
static void
nv_configuration_reloaded(void *cbdata)
{
OUT("loaded\n");
finish_reply();
}
struct spiflash_transaction get_id_transaction;
static void
process_command()
{
bool unknown = false;
const char *data = cmd_buffer;
switch (data[0]) {
case 'a': // acquisition status
if (data[1] == '=') {
if (data[2] == '0')
stop_acquire();
else
start_acquire();
}
OUT("acquiring = %d\n", acquire_running);
finish_reply();
break;
case 'f': // force a sample
take_sample();
finish_reply();
break;
case 'v': // enable verbose mode (dump every sample)
if (data[1] == '=')
verbose = data[2] == '1';
OUT("verbose = %d\n", verbose);
finish_reply();
break;
case 'r': // enable radio report mode (dump every sample)
if (data[1] == '=') {
if (data[2] == '1')
radio_enable();
else
radio_disable();
}
OUT("radio = %d\n", radio_get_enabled());
finish_reply();
break;
case 'F': // identify FLASH device
if (data[1] == 'i') {
spiflash_get_id(&onboard_flash, &get_id_transaction,
flash_id_cb, NULL);
} else if (data[1] == 's') {
spiflash_get_status(&onboard_flash, &get_id_transaction,
flash_status_cb, NULL);
} else {
OUT("unknown command\n");
finish_reply();
}
break;
case 'g': // get stored samples
{
char *pos;
sample_idx = strtoul(&data[2], &pos, 10);
sample_end = sample_idx + strtoul(&pos[1], NULL, 10);
if (sample_end - sample_idx > 0)
get_stored_sample(NULL);
else
finish_reply();
break;
}
case 't': // RTC time
if (data[1] == '=') {
uint32_t time = strtoul(&data[2], NULL, 10);
rtc_set_time(time);
rtc_start_counter();
}
OUT("RTC time = %lu\n", rtc_get_time());
finish_reply();
break;
case 'T': // sample period in milliseconds
if (data[1] == '=') {
uint32_t time = strtoul(&data[2], NULL, 10);
set_sample_period(time);
nv_config.sample_period = get_sample_period();
}
OUT("sample period = %d\n", get_sample_period());
finish_reply();
break;
case 'S': // store acquired samples
if (data[1] == '=')
acquire_store = data[2] == '1';
OUT("store = %d\n", acquire_store);
finish_reply();
break;
case 's': // list sensors
print_sensor(sensors);
break;
case 'm': // list measurables
{
uint32_t sensor_id = strtoul(&data[2], NULL, 10);
struct sensor **s=sensors;
while (*s) {
if ((*s)->sensor_id == sensor_id) {
list_measurables_state.sensor = *s;
list_measurables_state.measurable_idx = 0;
print_measurable(NULL);
break;
}
s++;
}
if (*s == NULL) {
OUT("unknown sensor\n");
finish_reply();
}
break;
}
case 'l': // list last sensor values
meas_iter_init(&last_sample_iter);
last_sensor_sample(sensors);
break;
case 'n': // fetch stored sample count
if (data[1] == '!') {
sample_store_reset();
}
OUT("sample count = %d\n", sample_store_get_count());
finish_reply();
break;
case 'V': // fetch firmware version
OUT("version = %s\n", commit_id);
finish_reply();
break;
case 'I': // fetch device ID
OUT("device id = %x-%x-%x-%x\n",
SIM.uidl, SIM.uidml, SIM.uidmh, SIM.uidh);
finish_reply();
break;
case 'p': // enter power-save mode
if (data[1] == '!') {
OUT("powersave = 1\n");
finish_reply();
enter_low_power_mode();
}
break;
case 'N':
switch (data[1]) {
case 'B': // acquire-on-boot flag
if (data[2] == '=')
nv_config.acquire_on_boot = data[3] == '1';
OUT("acquire on boot = %d\n", nv_config.acquire_on_boot);
finish_reply();
break;
case 'N': // friendly name of device
if (data[2] == '=') {
strncpy(nv_config.name, &data[3], sizeof(nv_config.name));
}
OUT("device name = %s\n", &nv_config.name);
finish_reply();
break;
case 'S': // save non-volatile configuration
nv_config_save(nv_configuration_saved, NULL);
break;
case 'R': // reload non-volatile configuration
nv_config_reload(nv_configuration_reloaded);
break;
default:
unknown = true;
}
break;
default:
unknown = true;
}
if (unknown) {
OUT("unknown command\n");
finish_reply();
}
}
static void
console_line_recvd(const char *cmd, size_t len)
{
// notify power-management of activity
power_notify_activity();
if (cmd[0] == '!') {
usb_console_reset();
command_queued = false;
return;
}
if (command_queued)
return;
strncpy(cmd_buffer, cmd, sizeof(cmd_buffer));
command_queued = true;
process_command();
}
static void
nv_config_available()
{
// begin acquiring if so-configured
if (nv_config.acquire_on_boot) {
set_sample_period(nv_config.sample_period);
start_acquire();
}
}
void
main(void)
{
config_pins();
timeout_init();
power_init();
// 222uA
spi_init();
// 223uA
spiflash_pins_init();
// 297uA
pin_change_init();
// 298uA
rtc_init();
// 298uA
sample_store_init();
// 223uA
usb_console_line_recvd_cb = console_line_recvd;
// usb console is initialized by power.c
acquire_init();
//radio_init();
sensor_listen(&listener, on_sample_cb, NULL);
start_blink(5, 100, 100);
// load non-volatile configuration
nv_config_reload(nv_config_available);
// 219uA
// event loop
while (true) {
bool can_deep_sleep = low_power_mode
&& spi_is_idle() && acquire_can_stop();
SCB.scr.sleepdeep = can_deep_sleep;
LLWU.wuf1 = 0xff;
LLWU.wuf2 = 0xff;
LLWU.mwuf = 0xff;
__asm__("wfi");
if (SMC.pmctrl.stopa)
onboard_led(1);
}
}