-
Notifications
You must be signed in to change notification settings - Fork 1
/
m20_strain_ble.c
416 lines (353 loc) · 11.3 KB
/
m20_strain_ble.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
/*
* M20_Strain_BLE_fsm.c
*
* Created on: 27 nov. 2022
* Author: carlo
*/
#include "m20_strain_ble.h"
#define EM4WU_EM4WUEN_NUM (3)
#define EM4WU_EM4WUEN_MASK (1 << EM4WU_EM4WUEN_NUM)
/*
* Callback declaration
*/
static void change_mode_callback(uint8_t intNo);
static void ready_to_retrieve_callback(uint8_t intNo);
static void sleeptimer_callback(sl_sleeptimer_timer_handle_t* handle, void* data);
/*
* Auxiliar function declaration
*/
// TODO: Check types!!
static void convertToMicroVStrain(float* result, int32_t data);
static void convertToMicroVTemp(float* result, int32_t data);
/*
* Enumeration that defines the FSM states
*/
enum states {
SLEEPING,
WAKING_UP,
ASKING_FOR_DATA,
RETRIEVING_DATA,
SENDING_DATA,
TO_SLEEP
};
/*
* Local variables
*/
static uint8_t sensorsReadCheck = 1;
static uint8_t* data_ready_flag = 0;
static uint8_t* change_mode_flag = 0;
/*
* Guard function declaration
*/
static int check_wakeup_timer(fsm_t* this);
static int check_change_mode(fsm_t* this);
static int check_wakeup_completed(fsm_t* this);
static int check_all_data_retrieved(fsm_t* this);
static int check_data_sent_continuous(fsm_t* this);
static int check_data_ready(fsm_t* this);
static int check_data_retrieved(fsm_t* this);
static int check_data_sent_not_continuous(fsm_t* this);
static int check_sleep_not_possible(fsm_t* this);
static int check_sleep_possible(fsm_t* this);
static int check_continuous_mode(fsm_t* this);
/*
* Transition function declaration
*/
static void wake_up(fsm_t* this);
static void ask_for_next_data(fsm_t* this);
static void ask_again(fsm_t* this);
static void power_down_interface_send_data(fsm_t* this);
static void retrieve_data(fsm_t* this);
static void reset_timer_sleep(fsm_t* this);
static void try_to_sleep(fsm_t* this);
static void reset_no_timer(fsm_t* this);
/*
* Transition table
*/
static fsm_trans_t app_fsm_tt[] = {
{ SLEEPING, check_wakeup_timer, WAKING_UP, wake_up},
{ SLEEPING, check_change_mode, WAKING_UP, wake_up},
{ WAKING_UP, check_wakeup_completed, ASKING_FOR_DATA, ask_for_next_data},
{ ASKING_FOR_DATA, check_all_data_retrieved, SENDING_DATA, power_down_interface_send_data},
{ ASKING_FOR_DATA, check_data_ready, RETRIEVING_DATA, retrieve_data},
{ RETRIEVING_DATA, check_data_retrieved, ASKING_FOR_DATA, ask_for_next_data},
{ SENDING_DATA, check_data_sent_continuous, WAKING_UP, ask_again},
{ SENDING_DATA, check_data_sent_not_continuous, TO_SLEEP, try_to_sleep},
{ TO_SLEEP, check_sleep_not_possible, TO_SLEEP, try_to_sleep},
{ TO_SLEEP, check_sleep_possible, SLEEPING, reset_timer_sleep},
{ TO_SLEEP, check_continuous_mode, SLEEPING, reset_no_timer},
{ -1, NULL, -1, NULL},
};
/**************************************************************************//**
* @brief BURTC Handler
*****************************************************************************/
static int wakeupTimer = 0;
void BURTC_IRQHandler(void)
{
BURTC_IntClear(BURTC_IF_COMP); // compare match
wakeupTimer = 1;
}
/*
* Guard funtions
*/
static int
check_wakeup_timer(fsm_t* this){
app_fsm_t* p_this = this->user_data;
return p_this->wakeup_timer_flag;
}
static int
check_change_mode(fsm_t* this){
app_fsm_t* p_this = this->user_data;
return p_this->change_mode_flag;
}
static int
check_wakeup_completed(fsm_t* this){
app_fsm_t* p_this = this->user_data;
return p_this->wakeup_completed_flag;
}
static int
check_all_data_retrieved(fsm_t* this){
app_fsm_t* p_this = this->user_data;
return (p_this->num_data_retrieved == 4);
}
static int
check_data_ready(fsm_t* this){
app_fsm_t* p_this = this->user_data;
return p_this->data_ready_flag && !(p_this->num_data_retrieved == 4);
}
static int
check_data_retrieved(fsm_t* this){
app_fsm_t* p_this = this->user_data;
p_this->data_retrieved_flag = sensorsReadCheck;
p_this->num_data_retrieved++;
return p_this->data_retrieved_flag;
}
static int
check_data_sent_not_continuous(fsm_t* this){
app_fsm_t* p_this = this->user_data;
return p_this->data_sent_flag && !p_this->change_mode_flag;
}
static int
check_data_sent_continuous(fsm_t* this){
app_fsm_t* p_this = this->user_data;
return p_this->data_sent_flag && p_this->change_mode_flag;
}
static int
check_sleep_not_possible(fsm_t* this){
app_fsm_t* p_this = this->user_data;
return !p_this->sleep_possible_flag && !p_this->change_mode_flag;
}
static int
check_sleep_possible(fsm_t* this){
app_fsm_t* p_this = this->user_data;
return p_this->sleep_possible_flag && !p_this->change_mode_flag && p_this->tmr_flag;
}
static int
check_continuous_mode(fsm_t* this){
app_fsm_t* p_this = this->user_data;
return p_this->change_mode_flag;
}
/*
* FSM transition functions
*/
static void
wake_up(fsm_t* this){
app_fsm_t* p_this = this->user_data;
p_this->wakeup_timer_flag = 0;
GPIO_EM4DisablePinWakeup(EM4WU_EM4WUEN_MASK << _GPIO_EM4WUEN_EM4WUEN_SHIFT);
// Determine whether reset is due to pin (switch to continuous mode) or timer (slow mode)
EMU_UnlatchPinRetention();
uint32_t resetCause = RMU_ResetCauseGet();
RMU_ResetCauseClear();
if (resetCause & EMU_RSTCAUSE_EM4){
app_log_info("Reset cause is EM4\n");
if (wakeupTimer == 1) {
p_this->change_mode_flag = 0;
app_log_info("Wake up through timer\n");
wakeupTimer = 0;
} else{
p_this->change_mode_flag = 1;
app_log_info("Wake up through GPIO\n");
}
}
// Bridge on pin high
GPIO_PinOutSet(SL_EMLIB_GPIO_INIT_BRIDGEON_PORT, SL_EMLIB_GPIO_INIT_BRIDGEON_PIN);
// Check registers from sensors through SPI
int status;
ads1220_t* ads1220 = p_this->ads1220;
status = ads1220->begin(ads1220);
if(status == 0){
app_log_info("Sensor register read correctly\n");
p_this->wakeup_completed_flag = 1;
} else{
app_log_info("Sensor register read incorrectly\n");
}
}
static void
ask_for_next_data(fsm_t* this){
app_fsm_t* p_this = this->user_data;
p_this->wakeup_completed_flag = 0;
p_this->data_retrieved_flag = 0;
p_this->data_ready_flag = 0; // for safety
ads1220_t* ads1220 = p_this->ads1220;
// Select next sensor to be read
int nextSensor = p_this->num_data_retrieved;
// Send info to ADS1220 (mux)
if(nextSensor < 3){
// Ask for strain data
// TODO: Should change reg0
GPIO_PinOutClear(SL_EMLIB_GPIO_INIT_BRIDGEON_PORT, SL_EMLIB_GPIO_INIT_BRIDGEON_PIN);
ads1220->temp_sense_on(ads1220);
ads1220->start_conv(ads1220);
} else if(nextSensor == 3){
// Ask for temp data
GPIO_PinOutClear(SL_EMLIB_GPIO_INIT_BRIDGEON_PORT, SL_EMLIB_GPIO_INIT_BRIDGEON_PIN);
ads1220->temp_sense_on(ads1220);
ads1220->start_conv(ads1220);
}
}
static void
ask_again(fsm_t* this){
app_fsm_t* p_this = this->user_data;
p_this->data_sent_flag = 0;
p_this->wakeup_completed_flag = 1;
// Sensor should already be powered up
}
static void
retrieve_data(fsm_t* this){
app_fsm_t* p_this = this->user_data;
p_this->data_ready_flag = 0;
p_this->data_retrieved_flag = 0;
// Retrieve data through SPI
// TODO: think how to activate flag to change state. Now it is a blocking activity run in ADS1220 private method (so guard function returns 1 always)
ads1220_t* ads1220 = p_this->ads1220;
p_this->sensor_data[p_this->num_data_retrieved] = ads1220->read_data_samples(ads1220);
}
static void
power_down_interface_send_data(fsm_t* this){
app_fsm_t* p_this = this->user_data;
p_this->num_data_retrieved = 0;
sl_status_t sc;
// Power down
ads1220_t* ads1220 = p_this->ads1220;
ads1220->temp_sense_off(ads1220);
// Convert each measurement into physical units
float result[4];
// convertToMicroVStrain(&result[0], p_this->sensor_data[0]);
// convertToMicroVStrain(&result[1], p_this->sensor_data[1]);
// convertToMicroVStrain(&result[2], p_this->sensor_data[2]);
convertToMicroVTemp(&result[0], p_this->sensor_data[0]);
convertToMicroVTemp(&result[1], p_this->sensor_data[1]);
convertToMicroVTemp(&result[2], p_this->sensor_data[2]);
convertToMicroVTemp(&result[3], p_this->sensor_data[3]);
// Send data through BLE
sc = sl_bt_torque_send_data((uint8_t*)result, 4*sizeof(float));
if(sc == SL_STATUS_OK){
app_log_info("Attribute send: 0x%f\n", result[0]);
app_log_info("Attribute send: 0x%f\n", result[1]);
app_log_info("Attribute send: 0x%f\n", result[2]);
app_log_info("Attribute send: 0x%f\n", result[3]);
p_this->data_sent_flag = 1;
}
}
static void
try_to_sleep(fsm_t* this){
app_fsm_t* p_this = this->user_data;
p_this->data_sent_flag = 0;
bool aux;
sl_sleeptimer_is_timer_running(p_this->tmr, &aux);
if (!aux){
uint32_t timeout = sl_sleeptimer_ms_to_tick(20000);
sl_sleeptimer_start_timer(p_this->tmr, timeout, sleeptimer_callback, p_this, 1, SL_SLEEPTIMER_NO_HIGH_PRECISION_HF_CLOCKS_REQUIRED_FLAG);
}
p_this->sleep_possible_flag = 1;
}
static void
reset_timer_sleep(fsm_t* this){
app_fsm_t* p_this = this->user_data;
p_this->sleep_possible_flag = 0;
p_this->tmr_flag = 0;
sl_sleeptimer_stop_timer(p_this->tmr);
// Close connections before going to sleep
for(int i = 0; i < p_this->nConnections; i++){
sl_bt_connection_close(p_this->connections[i]);
}
GPIO_EM4EnablePinWakeup(EM4WU_EM4WUEN_MASK << _GPIO_EM4WUEN_EM4WUEN_SHIFT, 0);
EMU_EnterEM4();
}
static void
reset_no_timer(fsm_t* this){
app_fsm_t* p_this = this->user_data;
p_this->sleep_possible_flag = 0;
p_this->tmr_flag = 0;
sl_sleeptimer_stop_timer(p_this->tmr);
EMU_EnterEM4();
}
/*
* FSM initialization
*/
fsm_t*
new_app_fsm(app_fsm_t* user_data, SPIDRV_Handle_t spi_handle, uint8_t* connections, int* nConnections){
// Initialized data
user_data->sensor_data[0] = 0;
user_data->sensor_data[1] = 0;
user_data->sensor_data[2] = 0;
user_data->sensor_data[3] = 0;
// Initilize handler
user_data->spi_handle = spi_handle;
sl_sleeptimer_timer_handle_t* tmr = malloc(sizeof(sl_sleeptimer_timer_handle_t));
user_data->tmr = tmr;
// Initialize flags
user_data->wakeup_timer_flag = 1; // to activate the FSM
user_data->wakeup_completed_flag = 0;
user_data->data_ready_flag = 0;
user_data->data_retrieved_flag = 0;
user_data->data_sent_flag = 0;
user_data->sleep_possible_flag = 0;
user_data->num_data_retrieved = 0;
user_data->change_mode_flag = 0;
user_data->tmr_flag = 0;
// BLE data
user_data->connections = connections;
user_data->nConnections = nConnections;
// ads1220 init
user_data->ads1220 = init_ads1220(user_data->spi_handle);
// GPIO Interruptions
GPIOINT_CallbackRegister(1, change_mode_callback);
change_mode_flag = &(user_data->change_mode_flag);
GPIOINT_CallbackRegister(2, ready_to_retrieve_callback);
data_ready_flag = &(user_data->data_ready_flag);
return fsm_new(SLEEPING, app_fsm_tt, user_data);
}
/*
* Callbacks
*/
static void
change_mode_callback(uint8_t intNo){
if (intNo == 1){
*change_mode_flag = !(*change_mode_flag);
}
}
static void
ready_to_retrieve_callback(uint8_t intNo){
if (intNo == 2){
*data_ready_flag = 1;
// app_log_info("Data ready\n");
}
}
static void
sleeptimer_callback(sl_sleeptimer_timer_handle_t* handle, void* data){
app_fsm_t* p_this = data;
p_this->tmr_flag = 1;
}
/*
* Auxiliar functions
*/
static void
convertToMicroVStrain(float* result, int32_t data){
*result = (float) ((data*VFSR*1000000)/FSR);
}
static void
convertToMicroVTemp(float* result, int32_t data){
*result = (float)(data >> 10)*0.03125;
}