forked from OceanographyforEveryone/OpenCTD
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcommand_mode.cpp
359 lines (311 loc) · 13.5 KB
/
command_mode.cpp
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
#include "Adafruit_USBD_CDC.h"
#include <cmath>
#include "command_mode.hpp"
#include "indicator_light.hpp"
#include "power_control.hpp"
#include "utility_functions.hpp"
#include "clock.hpp"
#include "config_storage.hpp"
#include "time.h"
#include "sd_usb_passthrough.hpp"
#include "sd_format_card.hpp"
// -----------------------------------
// ------- Global Variables ----------
// -----------------------------------
SensorTypes command_mode_active_sensor = SensorTypes::NONE;
UserCommand latest_user_command = {
String(""), // full_cmd
String(""), // cmd_name
String(""), // value1_string
NAN, // value1_number
String(""), // value2_string
NAN, // value2_number
};
uint16_t latest_cmd_cursor_index = 0; // keeps track of where in the latest_cmd string to insert the next character.
bool cmd_read_fully = true; // keeps track of whether we have recieved a full cmd form the user's computer yet (or only a few characters);
bool cmd_ready = false;
bool debug_mode = false;
const __FlashStringHelper *cmd_general_help_msg = F(
"\n"
"\n"
"+---------+---------- Available Commands -----------------+ \n"
"light | Calibrate the light sensor and view measurements \n"
"----------+------------------------------------------------ \n"
"temp | Calibrate the temperature probes and view measurements \n"
"----------+------------------------------------------------ \n"
"pressure | Calibrate the pressure sensor and view measurements \n"
"----------+------------------------------------------------ \n"
"ec | Calibrate the conductivity sensor and view measurements \n"
"----------+------------------------------------------------ \n"
// "debug - toggle debuging mode off/on: debugging mode prints helpful info to the serial monitor while logging.\n" // note debug mode is now always onn
"clock | Sets the current time.\n"
" | Command format: clock;Jul 06 2022;19: 06: 56 \n"
"----------+--+--------------------------------------------- \n"
"log_interval | Sets the delay (in seconds) between rows in the csv log \n"
" | NOTE: Each sensors will update up to its maximum \n"
" | sample rate even if log_interval is faster \n"
" | Command format: log_interval;0.5 \n"
"----------+--+--------------------------------------------- \n"
"raw | Toggle logging uncalibrated instead of calibrated sensor values\n"
" | Make sure this is OFF before deploying!\n"
"----------+------------------------------------------------ \n"
"wipe | Format the SD card. Will DELETE ALL saved data, calibrations, & files! \n"
" | Backup any data and saved_calibrations folder first if you need them! \n"
"----------+------------------------------------------------ \n"
"q | quit/exit command mode and re-enable usb passthrough.\n"
"+---------+-----------------------------------------------+");
// -----------------------------------------
// ------------- Functions -----------------
// -----------------------------------------
uint16_t serial_input_timeout_counter = 0; // counter to keep track of the full message recived timeout
void read_serial_input_characters() {
cmd_ready = false;
if (Serial.available()) { // if a new character is available
serial_input_timeout_counter = 0; // reset the timeout counter since we have a new avalilable char (ie: the start of a new cmd).
cmd_read_fully = false;
}
while (cmd_read_fully == false) {
char inchar = 0; // set a char placeholder for the next recived charter as the null character: askii character code = 0
if (Serial.available())
inchar = (char)Serial.read(); // if a new character is still available, get the new char
if (inchar == '\n' or inchar == '\r' or latest_cmd_cursor_index == FULL_CMD_MAX_LENGTH - 1 or serial_input_timeout_counter >= serial_input_timeout_max_count) { // if the char is a return (\n) or line feed (\r) or the string has filled up all available memory for this string, stop,reset the cursor and return true.
// if the command is done, finish up the string and mark that the command is complete:
cmd_read_fully = true;
cmd_ready = true;
latest_cmd_cursor_index = 0; // reset the cursor position back to 0;
} else if (inchar != 0) {
// otherwise (if the char isn't the null character, 0) add the new character to the full cmd string:
if (latest_cmd_cursor_index == 0) latest_user_command.full_cmd = "";
latest_user_command.full_cmd += inchar; // add the new char to the string;
latest_cmd_cursor_index++; // move the cursor forward;
}
serial_input_timeout_counter++;
}
}
String parse_command() {
size_t full_cmd_len = latest_user_command.full_cmd.length();
latest_user_command.full_cmd.toLowerCase();
// for (size_t i = 0; i <= full_cmd_len; i++)
// { // set all char to lower case.
// temp_cmd[i] = tolower(temp_cmd[i]); // avoid "Sleep" ≠ "sleep"
// }
// latest_user_command.value1_string = ;
// latest_user_command.value2_string = emptystring;
latest_user_command.value1_number = NAN;
latest_user_command.value2_number = NAN;
// Extract the first part of the command
int delimiter1 = latest_user_command.full_cmd.indexOf(";");
int delimiter2 = latest_user_command.full_cmd.indexOf(";", delimiter1 + 1);
Serial.print(delimiter1); Serial.print(",");
Serial.println(delimiter2);
latest_user_command.cmd_name = latest_user_command.full_cmd.substring(0, delimiter1);
if (delimiter1 > 0) {
latest_user_command.value1_string = latest_user_command.full_cmd.substring(delimiter1 + 1, delimiter2);
} else {
latest_user_command.value1_string = "";
}
if (delimiter2 > 0) {
latest_user_command.value2_string = latest_user_command.full_cmd.substring(delimiter2 + 1, full_cmd_len);
} else {
latest_user_command.value2_string = "";
}
// Extract the second number part of the command
if (latest_user_command.value1_string.length() != 0) {
latest_user_command.value1_number = atof(latest_user_command.value1_string.c_str());
}
// Extract the thrid number part of the command
if (latest_user_command.value2_string.length() != 0) {
latest_user_command.value1_number = atof(latest_user_command.value2_string.c_str());
}
Serial.println(latest_user_command.full_cmd);
Serial.println(latest_user_command.cmd_name);
Serial.println(latest_user_command.value1_number * 100);
Serial.println(latest_user_command.value1_number * 100);
return latest_user_command.cmd_name;
}
// Function to clear the arduino serial plotter window by writing a-lot of zeros to the serial console.
void clear_plot_screen() {
for (uint16_t i = 0; i < 200; i++)
Serial.println("0");
}
bool process_command() {
parse_command();
// q: Quit/Exit
if (String("q") == latest_user_command.cmd_name) {
command_mode_active_sensor = SensorTypes::NONE;
return true;
}
// d: Disable USB Passthrough (until restart)
if (String("d") == latest_user_command.cmd_name) {
sd_usb_passthrough_clear_read_flag();
return true;
}
// raw: Toggle raw mode - ignores all calibrations & saves raw sensor measurements to SD Card instead.
if (String("raw") == latest_user_command.cmd_name) {
onboard_config.log_raw_values = !onboard_config.log_raw_values;
print(F("Raw (uncalibrated) logging mode is "));
if (onboard_config.log_raw_values == true) {
println("on - Make sure this is OFF before deploying!");
} else {
println("off");
}
write_onboard_config();
return true;
}
// clock: Get or set the current clock date & time
// - command format: clock,Jul 06 2022,09:32:50
if (String("clock") == latest_user_command.cmd_name) {
if (latest_user_command.value1_string.length() == 0) {
// Print the current time if no value is provided
clock_print_time();
println("To set the time, use the command format: clock;Jul 06 2022;09:32:50");
} else {
// parse the given date & time and apply it to the RTC clock adjustment.
latest_user_command.value1_string[0] = toupper(latest_user_command.value1_string[0]); // capitalize the month
Serial.println(latest_user_command.value1_string.length());
Serial.println(latest_user_command.value2_string.length());
if (latest_user_command.value1_string.length() == 11 and latest_user_command.value2_string.length() == 8) {
DateTime realDate = DateTime(latest_user_command.value1_string.c_str(), latest_user_command.value2_string.c_str());
time_t t = realDate.unixtime();
println(ctime(&t));
rtc.adjust(realDate);
} else {
println("Date/Time not formatted correctly! Make sure to add leading zero to day, hour, minutes and seconds if any are only one digit.");
}
}
return true;
}
// log_interval: set the number of seconds between saved log entries on the SD Card
// - command format: log_interval,0.8
if (String("log_interval") == latest_user_command.cmd_name) {
onboard_config.seconds_between_log_events = latest_user_command.value1_number;
write_onboard_config();
return true;
}
// wipe: erase and format the SD Card using the SDFat Library tool
if (String("wipe") == latest_user_command.cmd_name) {
format_sd_card();
println("Please turn the CTD Off & On");
return true;
}
// debug: Toggle extra logging and Serial print statements functionality like Battery charge and Avialable Memory
else if (String("debug") == latest_user_command.cmd_name) {
debug_mode = !debug_mode;
// onboard_config.debugging_mode_on = debug_mode;
print(F("Debuging mode is "));
utility_nicely_print_bool(debug_mode);
// write_onboard_config();
return true;
}
// light: Switch to light sensor live viewing/calibrating command mode
#if ENABLE_LIGHT_SENSOR
if (String("light") == latest_user_command.cmd_name) {
clear_plot_screen();
command_mode_active_sensor = SensorTypes::LIGHT;
}
#endif
// ec: Switch to conductivity sensor live viewing/calibrating command mode
#if ENABLE_CONDUCTIVITY_SENSOR
if (String("ec") == latest_user_command.cmd_name) {
clear_plot_screen();
command_mode_active_sensor = SensorTypes::CONDUCTIVITY;
}
#endif
// temp: Switch to temperature sensor live viewing/calibrating command mode
#if ENABLE_TEMP_PROBE
if (String("temp") == latest_user_command.cmd_name) {
clear_plot_screen();
command_mode_active_sensor = SensorTypes::TEMP;
}
#endif
// pressure: Switch to pressure sensor live viewing/calibrating command mode
#if ENABLE_PRESSURE_SENSOR
if (String("pressure") == latest_user_command.cmd_name) {
clear_plot_screen();
command_mode_active_sensor = SensorTypes::PRESS;
}
#endif
// -------------------------------------------------
#if ENABLE_LIGHT_SENSOR
if (command_mode_active_sensor == SensorTypes::LIGHT) {
return light_sensor_user_command_handler(latest_user_command, cmd_general_help_msg);
}
#endif
#if ENABLE_CONDUCTIVITY_SENSOR
if (command_mode_active_sensor == SensorTypes::CONDUCTIVITY) {
return ec_i2c_user_command_handler(latest_user_command, cmd_general_help_msg);
}
#endif
#if ENABLE_TEMP_PROBE
if (command_mode_active_sensor == SensorTypes::TEMP) {
return temp_sensor_user_command_handler(latest_user_command, cmd_general_help_msg);
}
#endif
#if ENABLE_PRESSURE_SENSOR
if (command_mode_active_sensor == SensorTypes::PRESS) {
return pressure_sensor_user_command_handler(latest_user_command, cmd_general_help_msg);
}
#endif
// -------------------------------------------------
println(cmd_general_help_msg);
return true;
}
// void command_mode_loop() {
// // bool should_exit =
// // if (should_exit)
// // return;
// // || millis() > command_mode_last_activity_time + COMMAND_MODE_TIMEOUT
// // unsigned long int command_mode_last_activity_time = millis();
// // while (true) {
// // // power_ctrl_check_switch();;
// // // if the timeout runs out, exit command mode:
// // break;
// // }
// // if (!cmd_ready && command_mode_active_sensor == SensorTypes::NONE)
// // continue;
// // // handle command:
// // command_mode_last_activity_time = millis();
// // bool should_exit = process_command();
// // if (should_exit)
// // break;
// // }
// }
bool handle_user_commands() {
// Exit early if no computer is connected by USB cable.
if (!usb_is_connected())
return false;
// check for new characters from serial monitor (user's computer):
read_serial_input_characters();
// if a full command is ready to be processed
if (cmd_ready) {
sd_usb_passthrough_disable(); // disable sd passthrough which might interfere with writing the config / calibration files while in command mode.
process_command(); // process command that triggered the command mode loop
sd_usb_passthrough_enable(); // Re-Enable SD USB Passthrough
return true;
}
#if ENABLE_LIGHT_SENSOR
if (command_mode_active_sensor == SensorTypes::LIGHT) {
light_sensor_show_live_data();
return true;
}
#endif
#if ENABLE_CONDUCTIVITY_SENSOR
if (command_mode_active_sensor == SensorTypes::CONDUCTIVITY) {
ec_i2c_show_live_data();
return true;
}
#endif
#if ENABLE_TEMP_PROBE
if (command_mode_active_sensor == SensorTypes::TEMP) {
temp_sensor_show_live_data();
return true;
}
#endif
#if ENABLE_PRESSURE_SENSOR
if (command_mode_active_sensor == SensorTypes::PRESS) {
pressure_sensor_show_live_data();
return true;
}
#endif
return false;
}