Skip to content

Commit 52a8bd7

Browse files
committed
[SD] Implement buffered JSON stream writes to sd card, refactoring along logging, basic file creation implementaiton
1 parent 0e0cda4 commit 52a8bd7

File tree

5 files changed

+115
-70
lines changed

5 files changed

+115
-70
lines changed

platformio.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ lib_deps =
7979
https://github.com/adafruit/WiFiNINA.git
8080
https://github.com/Starmbi/hp_BH1750.git
8181
https://github.com/adafruit/RTClib.git
82+
https://github.com/bblanchon/ArduinoStreamUtils.git
8283

8384
; Common build environment for ESP32 platform
8485
[common:esp32]

src/Wippersnapper_V2.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,7 +1094,11 @@ void Wippersnapper_V2::pingBrokerV2() {
10941094
@brief Feeds the WDT to prevent hardware reset.
10951095
*/
10961096
/*******************************************************/
1097-
void Wippersnapper_V2::feedWDTV2() { Watchdog.reset(); }
1097+
void Wippersnapper_V2::feedWDTV2() {
1098+
// TODO: This is a temporary fix for watchdog.reset() not firing
1099+
// Watchdog.reset();
1100+
esp_task_wdt_reset();
1101+
}
10981102

10991103
/********************************************************/
11001104
/*!
@@ -1264,10 +1268,10 @@ void Wippersnapper_V2::connectV2() {
12641268
*/
12651269
/**************************************************************************/
12661270
ws_status_t Wippersnapper_V2::runV2() {
1271+
WsV2.feedWDTV2();
12671272
if (!WsV2._sdCardV2->mode_offline) {
12681273
// Handle networking functions
12691274
runNetFSMV2();
1270-
WsV2.feedWDTV2();
12711275
pingBrokerV2();
12721276
// Process all incoming packets from Wippersnapper_V2 MQTT Broker
12731277
WsV2._mqttV2->processPackets(10);

src/Wippersnapper_demo.ino.cpp

Lines changed: 0 additions & 34 deletions
This file was deleted.

src/provisioning/sdcard/ws_sdcard.cpp

Lines changed: 100 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -406,15 +406,13 @@ bool ws_sdcard::parseConfigFile() {
406406
return false;
407407
}
408408

409-
// Configure the status LED
410-
float brightness = exportedFromDevice["statusLEDBrightness"];
411-
setStatusLEDBrightness(brightness);
412-
413409
// Mock the check-in process using the JSON's values
414410
CheckIn(exportedFromDevice["totalGPIOPins"],
415411
exportedFromDevice["totalAnalogPins"],
416412
exportedFromDevice["referenceVoltage"]);
417413

414+
setStatusLEDBrightness(exportedFromDevice["statusLEDBrightness"]);
415+
418416
// Initialize and configure RTC
419417
const char *json_rtc = exportedFromDevice["rtc"];
420418
if (json_rtc == nullptr) {
@@ -427,6 +425,23 @@ bool ws_sdcard::parseConfigFile() {
427425
return false;
428426
}
429427

428+
// Create new logging file on device from the RTC's timestamp
429+
#ifndef OFFLINE_MODE_DEBUG
430+
// TODO: Refactor this out into a func
431+
// TODO: Implement a counter within the log funcs to track # of lines in the
432+
// file and implement a MAX_LINE cutoff
433+
String logFilename = "log_" + String(GetTimestamp()) + ".json";
434+
_log_filename = logFilename.c_str();
435+
File32 file;
436+
if (!file.open(_log_filename, FILE_WRITE)) {
437+
WS_DEBUG_PRINTLN(
438+
"[SD] FATAL - Failed to create initial logging file on SD card!");
439+
return false;
440+
}
441+
WS_DEBUG_PRINT("[SD] Created new log file on SD card: ");
442+
WS_DEBUG_PRINTLN(_log_filename);
443+
#endif
444+
430445
// Parse the "components" array into a JsonObject
431446
JsonArray components_ar = doc["components"].as<JsonArray>();
432447
if (components_ar.isNull()) {
@@ -522,7 +537,6 @@ bool ws_sdcard::parseConfigFile() {
522537
*/
523538
/**************************************************************************/
524539
uint32_t ws_sdcard::GetTimestamp() {
525-
// Obtain RTC timestamp (TODO - refactor this out)
526540
DateTime now;
527541
if (_rtc_ds3231 != nullptr)
528542
now = _rtc_ds3231->now();
@@ -531,7 +545,7 @@ uint32_t ws_sdcard::GetTimestamp() {
531545
else if (_rtc_pcf8523 != nullptr)
532546
now = _rtc_pcf8523->now();
533547
else {
534-
// TODO! implement software millis() version of now() and unixtime()
548+
now = _rtc_soft->now();
535549
}
536550

537551
if (_wokwi_runner)
@@ -629,6 +643,30 @@ const char *SensorTypeToString(wippersnapper_sensor_SensorType sensorType) {
629643
}
630644
}
631645

646+
void ws_sdcard::BuildJSONDoc(JsonDocument &doc, const char *pin, float value,
647+
wippersnapper_sensor_SensorType read_type) {
648+
doc["timestamp"] = GetTimestamp();
649+
doc["pin"] = pin;
650+
doc["value"] = value;
651+
doc["si_unit"] = SensorTypeToString(read_type);
652+
}
653+
654+
void ws_sdcard::BuildJSONDoc(JsonDocument &doc, const char *pin, uint16_t value,
655+
wippersnapper_sensor_SensorType read_type) {
656+
doc["timestamp"] = GetTimestamp();
657+
doc["pin"] = pin;
658+
doc["value"] = value;
659+
doc["si_unit"] = SensorTypeToString(read_type);
660+
}
661+
662+
void ws_sdcard::BuildJSONDoc(JsonDocument &doc, const char *pin, bool value,
663+
wippersnapper_sensor_SensorType read_type) {
664+
doc["timestamp"] = GetTimestamp();
665+
doc["pin"] = pin;
666+
doc["value"] = value;
667+
doc["si_unit"] = SensorTypeToString(read_type);
668+
}
669+
632670
/**************************************************************************/
633671
/*!
634672
@brief Logs a GPIO sensor event to the SD card.
@@ -644,20 +682,29 @@ const char *SensorTypeToString(wippersnapper_sensor_SensorType sensorType) {
644682
bool ws_sdcard::LogGPIOSensorEventToSD(
645683
uint8_t pin, float value, wippersnapper_sensor_SensorType read_type) {
646684
// Get the pin name in the correct format ("A0", "A1", etc.)
685+
// TODO: Maybe send c_pin_name to sprintf and include A/D specifier from here?
647686
char c_pin_name[12];
648687
sprintf(c_pin_name, "A%d", pin);
649688

650-
// Get the RTC's timestamp
651-
uint32_t timestamp = GetTimestamp();
652-
653689
// Create the JSON document
654690
JsonDocument doc;
691+
BuildJSONDoc(doc, c_pin_name, value, read_type);
655692

656-
doc["timestamp"] = timestamp;
657-
doc["pin"] = c_pin_name;
658-
doc["value"] = value;
659-
doc["si_unit"] = SensorTypeToString(read_type);
660-
serializeJson(doc, Serial);
693+
// Serialize the JSON document
694+
#ifndef OFFLINE_MODE_DEBUG
695+
// TODO: Make this an attempt to open and return false on failure
696+
File32 file = _sd.open("log.json", FILE_WRITE);
697+
BufferingPrint bufferedFile(file, 64); // Add buffering to the file
698+
serializeJson(doc, file); // Serialize the JSON to the file in 64-byte chunks
699+
// TODO: I am not sure if this works, consult PDF ch 4.7
700+
bufferedFile.print("\n");
701+
bufferedFile.flush(); // Send the remaining bytes
702+
#else
703+
serializeJson(doc, Serial); // TODO: Add buffering here, too?
704+
Serial.print("\n"); // JSON requires a newline at the end of each log line
705+
#endif
706+
707+
// TODO: Does this need to be a boolean?
661708
return true;
662709
}
663710

@@ -679,17 +726,25 @@ bool ws_sdcard::LogGPIOSensorEventToSD(
679726
char c_pin_name[12];
680727
sprintf(c_pin_name, "A%d", pin);
681728

682-
// Get the RTC's timestamp
683-
uint32_t timestamp = GetTimestamp();
684-
685-
// Append to the file in JSONL format
729+
// Create the JSON document
686730
JsonDocument doc;
687-
doc["timestamp"] = timestamp;
688-
doc["pin"] = c_pin_name;
689-
doc["value"] = value;
690-
doc["si_unit"] = SensorTypeToString(read_type);
691-
serializeJson(doc, Serial);
692-
Serial.println(""); // JSON requires a newline at the end of each log line
731+
BuildJSONDoc(doc, c_pin_name, value, read_type);
732+
733+
// Serialize the JSON document
734+
#ifndef OFFLINE_MODE_DEBUG
735+
// TODO: Make this an attempt to open and return false on failure
736+
File32 file = _sd.open("log.json", FILE_WRITE);
737+
BufferingPrint bufferedFile(file, 64); // Add buffering to the file
738+
serializeJson(doc, file); // Serialize the JSON to the file in 64-byte chunks
739+
// TODO: I am not sure if this works, consult PDF ch 4.7
740+
bufferedFile.print("\n");
741+
bufferedFile.flush(); // Send the remaining bytes
742+
#else
743+
serializeJson(doc, Serial); // TODO: Add buffering here, too?
744+
Serial.print("\n"); // JSON requires a newline at the end of each log line
745+
#endif
746+
747+
// TODO: Does this need to be a boolean?
693748
return true;
694749
}
695750

@@ -709,19 +764,30 @@ bool ws_sdcard::LogGPIOSensorEventToSD(
709764
uint8_t pin, bool value, wippersnapper_sensor_SensorType read_type) {
710765
// Get the pin name in the correct format ("A0", "A1", etc.)
711766
char c_pin_name[12];
712-
sprintf(c_pin_name, "A%d", pin);
713-
714-
// Get the RTC's timestamp
715-
uint32_t timestamp = GetTimestamp();
767+
sprintf(c_pin_name, "D%d", pin);
716768

717769
// Create the JSON document
718770
JsonDocument doc;
719-
doc["timestamp"] = timestamp;
720-
doc["pin"] = c_pin_name;
721-
doc["value"] = value;
722-
doc["si_unit"] = SensorTypeToString(read_type);
723-
serializeJson(doc, Serial);
724-
Serial.println("");
771+
BuildJSONDoc(doc, c_pin_name, value, read_type);
772+
773+
// Serialize the JSON document
774+
#ifndef OFFLINE_MODE_DEBUG
775+
// TODO: Make this an attempt to open and return false on failure
776+
File32 file;
777+
if (!_sd.open("log.json", FILE_WRITE)) {
778+
WS_DEBUG_PRINTLN("[SD] FATAL Error - Unable to open JSON log file!");
779+
}
780+
BufferingPrint bufferedFile(file, 64); // Add buffering to the file
781+
serializeJson(doc, file); // Serialize the JSON to the file in 64-byte chunks
782+
// TODO: I am not sure if this works, consult PDF ch 4.7
783+
bufferedFile.print("\n");
784+
bufferedFile.flush(); // Send the remaining bytes
785+
#else
786+
serializeJson(doc, Serial); // TODO: Add buffering here, too?
787+
Serial.print("\n"); // JSON requires a newline at the end of each log line
788+
#endif
789+
790+
// TODO: Does this need to be a boolean?
725791
return true;
726792
}
727793

src/provisioning/sdcard/ws_sdcard.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#define WS_SDCARD_H
1717
#include "RTClib.h"
1818
#include "SdFat.h"
19+
#include "StreamUtils.h"
1920
#include "Wippersnapper_V2.h"
2021

2122
#define SD_FAT_TYPE 3
@@ -53,6 +54,12 @@ class ws_sdcard {
5354
int num_sensors, const char *sensor_type_1,
5455
const char *sensor_type_2);
5556

57+
void BuildJSONDoc(JsonDocument &doc, const char *pin, float value,
58+
wippersnapper_sensor_SensorType read_type);
59+
void BuildJSONDoc(JsonDocument &doc, const char *pin, uint16_t value,
60+
wippersnapper_sensor_SensorType read_type);
61+
void BuildJSONDoc(JsonDocument &doc, const char *pin, bool value,
62+
wippersnapper_sensor_SensorType read_type);
5663
bool LogGPIOSensorEventToSD(uint8_t pin, float value,
5764
wippersnapper_sensor_SensorType read_type);
5865
bool LogGPIOSensorEventToSD(uint8_t pin, bool value,
@@ -78,6 +85,7 @@ class ws_sdcard {
7885
bool _use_test_data; ///< True if sample data is being used to test, instead
7986
///< of serial input, False otherwise.
8087
bool _wokwi_runner; ///< True if `exportedBy` key is "wokwi", otherwise False
88+
const char *_log_filename; ///< Path to the log file
8189
RTC_DS3231 *_rtc_ds3231 = nullptr; ///< DS3231 RTC object
8290
RTC_DS1307 *_rtc_ds1307 = nullptr; ///< DS1307 RTC object
8391
RTC_PCF8523 *_rtc_pcf8523 = nullptr; ///< PCF8523 RTC object

0 commit comments

Comments
 (0)