5#include <nanopb/pb_decode.h>
7static const uint8_t chipSelect_pin = 7;
8static UserConfiguration uc = UserConfiguration_init_zero;
9static char dataFileFilename[256];
11static void printCardInfo(
void);
12static void printFileInfo(File f);
13static void printFileContents(File f);
14static bool microsd_detect_card(
void);
18 type = Esp32Command_microsd_command_tag;
24 Log.traceln(
"ModuleMicroSD::OnReceive");
27 if (cmd.which_command != Esp32Command_microsd_command_tag) {
31 Log.traceln(
"MicroSDCommand type: %d", cmd.command.microsd_command.type);
34 switch (cmd.command.microsd_command.type) {
35 case MicroSDCommand_Type_SAVE:
36 Log.traceln(
"Calling SAVE");
39 case MicroSDCommand_Type_USERCONFIG:
40 Log.traceln(
"Calling USERCONFIG");
43 case MicroSDCommand_Type_LOG:
44 Log.traceln(
"Calling LOG");
48 Log.warningln(
"MicroSD command type not found!");
54 Log.traceln(
"ModuleMicroSD::OnRequest");
55 memcpy(
buffer, request_buffer, request_buffer_len);
56 return request_buffer_len;
59void ModuleMicroSD::Save(
const Esp32Command& cmd) {
60 static uint32_t last_ts = 0;
62 MicroSDCommand microsd_cmd = MicroSDCommand_init_zero;
63 microsd_cmd.type = MicroSDCommand_Type_SAVE;
65 Log.traceln(
"ModuleMicroSD::Save");
67 Log.verbose(
"microsd_command.filename: %s\r\n",
68 cmd.command.microsd_command.filename);
69 Log.verbose(
"microsd_command.type: %u\r\n", cmd.command.microsd_command.type);
70 if (cmd.command.microsd_command.which_data == MicroSDCommand_meas_tag) {
71 Log.verbose(
"microsd_command.which_data: %u (%s)\r\n",
72 cmd.command.microsd_command.which_data,
73 "MicroSDCommand_meas_tag");
74 }
else if (cmd.command.microsd_command.which_data == MicroSDCommand_uc_tag) {
75 Log.verbose(
"microsd_command.which_data: %u (%s)\r\n",
76 cmd.command.microsd_command.which_data,
77 "MicroSDCommand_uc_tag");
79 Log.verbose(
"microsd_command.which_data: %u (%s)\r\n",
80 cmd.command.microsd_command.which_data,
"UNKNOWN");
93 if (!microsd_detect_card()) {
94 Log.error(
"Aborting save to micro SD card.\r\n");
95 microsd_cmd.rc = MicroSDCommand_ReturnCode_ERROR_MICROSD_NOT_INSERTED;
101 if (!SD.begin(chipSelect_pin)) {
103 "Failed to begin, make sure that a FAT32 formatted SD card is "
104 "inserted. Aborting save to micro SD card.\r\n");
106 MicroSDCommand_ReturnCode_ERROR_FILE_SYSTEM_NOT_MOUNTABLE;
109 if (cmd.command.microsd_command.data.meas.has_meta) {
110 Log.verbose(
"meas.meta.cell_id: %u\r\n",
111 cmd.command.microsd_command.data.meas.meta.cell_id);
112 Log.verbose(
"meas.meta.logger_id: %u\r\n",
113 cmd.command.microsd_command.data.meas.meta.logger_id);
114 Log.verbose(
"meas.meta.ts: %u\r\n",
115 cmd.command.microsd_command.data.meas.meta.ts);
117 Log.verbose(
"meas.which_measurement: %u\r\n",
118 cmd.command.microsd_command.data.meas.which_measurement);
119 switch (cmd.command.microsd_command.data.meas.which_measurement) {
120 case Measurement_power_tag:
123 cmd.command.microsd_command.data.meas.measurement.power.voltage,
124 cmd.command.microsd_command.data.meas.measurement.power
127 case Measurement_teros12_tag:
130 cmd.command.microsd_command.data.meas.measurement.teros12
132 cmd.command.microsd_command.data.meas.measurement.teros12.ec,
133 cmd.command.microsd_command.data.meas.measurement.teros12.temp);
135 case Measurement_phytos31_tag:
136 Log.verbose(
",%lf,%lf",
137 cmd.command.microsd_command.data.meas.measurement
139 cmd.command.microsd_command.data.meas.measurement
140 .phytos31.leaf_wetness);
142 case Measurement_bme280_tag:
143 Log.verbose(
",%u,%d,%u",
144 cmd.command.microsd_command.data.meas.measurement.bme280
146 cmd.command.microsd_command.data.meas.measurement.bme280
148 cmd.command.microsd_command.data.meas.measurement.bme280
151 case Measurement_teros21_tag:
154 cmd.command.microsd_command.data.meas.measurement.teros21
156 cmd.command.microsd_command.data.meas.measurement.teros21.temp);
158 case Measurement_sen0308_tag:
159 Log.verbose(
",%lf,%lf",
160 cmd.command.microsd_command.data.meas.measurement
162 cmd.command.microsd_command.data.meas.measurement
165 case Measurement_sen0257_tag:
166 Log.verbose(
",%lf,%lf",
167 cmd.command.microsd_command.data.meas.measurement
169 cmd.command.microsd_command.data.meas.measurement
172 case Measurement_yfs210c_tag:
175 cmd.command.microsd_command.data.meas.measurement.yfs210c.flow);
177 case Measurement_pcap02_tag:
178 Log.verbose(
",%lf", cmd.command.microsd_command.data.meas
179 .measurement.pcap02.capacitance);
181 case Measurement_meta_tag:
184 cmd.command.microsd_command.data.meas.which_measurement);
188 "Unrecognized measurement type: %d\r\n",
189 cmd.command.microsd_command.data.meas.which_measurement);
190 microsd_cmd.rc = MicroSDCommand_ReturnCode_ERROR_GENERAL;
194 dataFile = SD.open(dataFileFilename, FILE_APPEND);
196 Log.error(
"Failed to open '%s' with '%s'\r\n", dataFileFilename,
198 microsd_cmd.rc = MicroSDCommand_ReturnCode_ERROR_FILE_NOT_OPENED;
199 strncpy(microsd_cmd.filename, dataFileFilename,
200 sizeof(microsd_cmd.filename));
202 Log.trace(
"Successfully opened '%s' with '%s'\r\n", dataFileFilename,
207 if (cmd.command.microsd_command.data.meas.meta.ts != last_ts) {
209 cmd.command.microsd_command.data.meas.meta.ts);
215 switch (cmd.command.microsd_command.data.meas.which_measurement) {
216 case Measurement_power_tag:
219 cmd.command.microsd_command.data.meas.measurement.power.voltage,
220 cmd.command.microsd_command.data.meas.measurement.power
223 case Measurement_teros12_tag:
226 cmd.command.microsd_command.data.meas.measurement.teros12
228 cmd.command.microsd_command.data.meas.measurement.teros12.ec,
229 cmd.command.microsd_command.data.meas.measurement.teros12.temp);
231 case Measurement_phytos31_tag:
233 cmd.command.microsd_command.data.meas.measurement
235 cmd.command.microsd_command.data.meas.measurement
236 .phytos31.leaf_wetness);
238 case Measurement_bme280_tag:
240 cmd.command.microsd_command.data.meas.measurement
242 cmd.command.microsd_command.data.meas.measurement
244 cmd.command.microsd_command.data.meas.measurement
247 case Measurement_teros21_tag:
250 cmd.command.microsd_command.data.meas.measurement.teros21
252 cmd.command.microsd_command.data.meas.measurement.teros21.temp);
254 case Measurement_sen0308_tag:
256 cmd.command.microsd_command.data.meas.measurement
258 cmd.command.microsd_command.data.meas.measurement
261 case Measurement_sen0257_tag:
263 cmd.command.microsd_command.data.meas.measurement
265 cmd.command.microsd_command.data.meas.measurement
268 case Measurement_yfs210c_tag:
271 cmd.command.microsd_command.data.meas.measurement.yfs210c.flow);
273 case Measurement_pcap02_tag:
274 dataFile.printf(
",%lf", cmd.command.microsd_command.data.meas
275 .measurement.pcap02.capacitance);
278 Log.error(
"Unrecognized measurement type: %d\r\n",
279 cmd.command.microsd_command.data.meas.which_measurement);
280 microsd_cmd.rc = MicroSDCommand_ReturnCode_ERROR_GENERAL;
285 Log.trace(
"Wrote to and closed '%s'\r\n", dataFileFilename);
287 last_ts = cmd.command.microsd_command.data.meas.meta.ts;
293 sizeof(request_buffer));
296void ModuleMicroSD::UserConfig(
const Esp32Command& cmd) {
298 MicroSDCommand microsd_cmd = MicroSDCommand_init_zero;
299 microsd_cmd.type = MicroSDCommand_Type_USERCONFIG;
301 Log.traceln(
"ModuleMicroSD::UserConfig");
303 memcpy(&uc, &cmd.command.microsd_command.data.uc,
sizeof(UserConfiguration));
306 if (!microsd_detect_card()) {
307 Log.error(
"Aborting save to micro SD card.\r\n");
308 microsd_cmd.rc = MicroSDCommand_ReturnCode_ERROR_MICROSD_NOT_INSERTED;
314 if (!SD.begin(chipSelect_pin)) {
316 "Failed to begin, make sure that a FAT32 formatted SD card is "
317 "inserted. Aborting save to micro SD card.\r\n");
319 MicroSDCommand_ReturnCode_ERROR_FILE_SYSTEM_NOT_MOUNTABLE;
322 char userConfigFileFilename[
sizeof(dataFileFilename)] = {0};
323 strncpy(userConfigFileFilename, cmd.command.microsd_command.filename,
324 sizeof(userConfigFileFilename));
325 strncat(userConfigFileFilename,
".userconfig",
sizeof(
".userconfig"));
326 File userConfigFile = SD.open(userConfigFileFilename, FILE_WRITE);
327 if (!userConfigFile) {
328 Log.error(
"Failed to open '%s' with '%s'\r\n", userConfigFileFilename,
330 microsd_cmd.rc = MicroSDCommand_ReturnCode_ERROR_FILE_NOT_OPENED;
331 strncpy(microsd_cmd.filename, userConfigFileFilename,
332 sizeof(microsd_cmd.filename));
335 userConfigFile.printf(
"logger_id=%d\r\n", uc.logger_id);
336 userConfigFile.printf(
"cell_id=%d\r\n", uc.cell_id);
337 char upload_method_s[][18] = {
"Uploadmethod_LoRa",
"Uploadmethod_WiFi",
339 userConfigFile.printf(
"Upload_method=%d (%s)\r\n", uc.Upload_method,
340 upload_method_s[uc.Upload_method]);
342 userConfigFile.printf(
"Upload_interval=%d\r\n", uc.Upload_interval);
343 userConfigFile.printf(
"enabled_sensors_count=%d\r\n",
344 uc.enabled_sensors_count);
346 char enabled_sensors_s[][9] = {
347 "Voltage",
"Current",
"Teros12",
"Teros21",
"BME280",
348 "Phytos31",
"SEN0308",
"SEN0257",
"YFS210C",
"PCAP02"};
349 for (
int i = 0;
i < uc.enabled_sensors_count;
i++) {
350 userConfigFile.printf(
"enabled_sensors[%d]=%d (%s)\r\n",
i,
351 uc.enabled_sensors[
i], enabled_sensors_s[
i]);
354 userConfigFile.printf(
"Voltage_Slope=%lf\r\n", uc.Voltage_Slope);
355 userConfigFile.printf(
"Voltage_Offset=%lf\r\n", uc.Voltage_Offset);
356 userConfigFile.printf(
"Current_Slope=%lf\r\n", uc.Current_Slope);
357 userConfigFile.printf(
"Current_Offset=%lf\r\n", uc.Current_Offset);
358 userConfigFile.printf(
"WiFi_SSID=%s\r\n", uc.WiFi_SSID);
359 userConfigFile.printf(
"WiFi_Password=%s\r\n", uc.WiFi_Password);
360 userConfigFile.printf(
"API_Endpoint_URL=%s\r\n", uc.API_Endpoint_URL);
361 userConfigFile.printf(
"API_Endpoint_Port=%d\r\n", uc.API_Endpoint_Port);
363 userConfigFile.close();
366 strncpy(dataFileFilename, cmd.command.microsd_command.filename,
367 sizeof(dataFileFilename));
369 File
dataFile = SD.open(dataFileFilename, FILE_WRITE);
371 Log.error(
"Failed to open '%s' with '%s'\r\n", dataFileFilename,
373 microsd_cmd.rc = MicroSDCommand_ReturnCode_ERROR_FILE_NOT_OPENED;
374 strncpy(microsd_cmd.filename, dataFileFilename,
375 sizeof(microsd_cmd.filename));
379 for (
int i = 0;
i < uc.enabled_sensors_count;
i++) {
380 switch (uc.enabled_sensors[
i]) {
381 case EnabledSensor_Voltage:
382 case EnabledSensor_Current:
383 dataFile.printf(
",voltage,current");
385 case EnabledSensor_Teros12:
386 dataFile.printf(
",vwc_Teros12,ec_Teros12,temp_Teros12");
388 case EnabledSensor_Teros21:
389 dataFile.printf(
",matricpotential_Teros21,temp_Teros21");
391 case EnabledSensor_BME280:
393 ",pressure_BME280,temperature_BME280,humidity_BME280");
395 case EnabledSensor_Phytos31:
396 dataFile.printf(
",voltage_Phytos31,leaf_wetness_Phytos31");
398 case EnabledSensor_SEN0308:
399 dataFile.printf(
",voltage_SEN0308,humidity_SEN0308");
401 case EnabledSensor_SEN0257:
402 dataFile.printf(
",voltage_SEN0257,pressure_SEN0257");
404 case EnabledSensor_YFS210C:
407 case EnabledSensor_PCAP02:
408 dataFile.printf(
",capacitance_PCAP02");
411 dataFile.printf(
",ERROR Unknown sensor type");
412 microsd_cmd.rc = MicroSDCommand_ReturnCode_ERROR_GENERAL;
424 sizeof(request_buffer));
427void ModuleMicroSD::WriteLog(
const Esp32Command& cmd) {
429 MicroSDCommand microsd_cmd = MicroSDCommand_init_zero;
430 microsd_cmd.type = MicroSDCommand_Type_LOG;
432 Log.traceln(
"ModuleMicroSD::WriteLog");
435 const char* base = cmd.command.microsd_command.filename;
437 if (!microsd_detect_card()) {
438 Log.error(
"Aborting log to micro SD card.\r\n");
439 microsd_cmd.rc = MicroSDCommand_ReturnCode_ERROR_MICROSD_NOT_INSERTED;
442 if (!SD.begin(chipSelect_pin)) {
444 "Failed to begin, make sure that a FAT32 formatted SD card is "
445 "inserted. Aborting log to micro SD card.\r\n");
447 MicroSDCommand_ReturnCode_ERROR_FILE_SYSTEM_NOT_MOUNTABLE;
449 Log.verbose(
"microsd_command.log: %s\r\n",
450 cmd.command.microsd_command.data.log);
453 static char logFileFilename[32] =
"";
456 if (strlen(logFileFilename) == 0) {
461 snprintf(logFileFilename,
sizeof(logFileFilename),
"/%s.%d.txt", base,
465 if (!SD.exists(logFileFilename)) {
468 Log.verbose(
"File name \"%s\" already exsits! Trying next index.");
477 File logFile = SD.open(logFileFilename, FILE_APPEND);
480 Log.error(
"Failed to open '%s' with '%s'\r\n", logFileFilename,
483 microsd_cmd.rc = MicroSDCommand_ReturnCode_ERROR_FILE_NOT_OPENED;
484 strncpy(microsd_cmd.filename, logFileFilename,
485 sizeof(microsd_cmd.filename));
488 logFile.println(cmd.command.microsd_command.data.log);
491 Log.trace(
"Wrote to and closed '%s'\r\n", logFileFilename);
498 sizeof(request_buffer));
501static void printCardInfo(
void) {
502 Log.verbose(
"\r\n-----Card info START-----\r\n");
503 Log.verbose(
"sectors, sector size, total size: %zd * %zd = %llu\r\n",
504 SD.numSectors(), SD.sectorSize(), SD.cardSize());
505 String sdcard_type_t_strings[] = {
"CARD_NONE",
"CARD_MMC",
"CARD_SD",
506 "CARD_SDHC",
"CARD_UNKNOWN"};
507 Log.verbose(
"card type: (%d) %s\r\n", SD.cardType(),
508 sdcard_type_t_strings[SD.cardType()]);
509 Log.verbose(
"bytes used / total: %llu / %llu\r\n", SD.usedBytes(),
511 Log.verbose(
"-----Card info END-----\r\n\r\n");
514static void printFileInfo(File f) {
515 Log.verbose(
"\r\n-----File info START-----\r\n");
516 Log.verbose(
"available: %d\r\n", f.available());
517 Log.verbose(
"timeout: %lu\r\n", f.getTimeout());
518 Log.verbose(
"name: %s\r\n", f.name());
519 Log.verbose(
"path: %s\r\n", f.path());
520 Log.verbose(
"position: %zd\r\n", f.position());
521 Log.verbose(
"size: %zd\r\n", f.size());
522 Log.verbose(
"-----File info END-----\r\n\r\n");
525static void printFileContents(File f) {
526 Log.verbose(
"\r\n-----%s START-----\r\n", f.path());
531 Log.verbose(
"[%d]:\t", line++);
534 Log.verbose(
"%c", c);
535 }
while (f.available());
536 Log.verbose(
"\r\n-----%s END-----\r\n", f.path());
539static bool microsd_detect_card(
void) {
540 const uint8_t cardDetect_pin = 10;
542 pinMode(cardDetect_pin, INPUT_PULLUP);
543 int pinState = digitalRead(cardDetect_pin);
544 pinMode(cardDetect_pin, INPUT);
547 if (pinState == LOW) {
548 Log.trace(
"Card detected.\r\n");
551 Log.error(
"Card NOT detected.\r\n");
size_t OnRequest(uint8_t *buffer)
void OnReceive(const Esp32Command &cmd)
size_t EncodeMicroSDCommand(const MicroSDCommand *microsd_cmd, uint8_t *buffer, size_t size)
Encodes a MicroSDCommand.
Module for accessing the microSD card.