@@ -157,6 +157,98 @@ void ws_sdcard::CheckIn(uint8_t max_digital_pins, uint8_t max_analog_pins,
157157 WsV2.analogio_controller ->SetRefVoltage (ref_voltage);
158158}
159159
160+ bool ws_sdcard::ParseDigitalIOAdd (
161+ wippersnapper_digitalio_DigitalIOAdd &msg_DigitalIOAdd, const char *pin,
162+ float period, bool value, const char *sample_mode, const char *direction,
163+ const char *pull) {
164+ bool rc = true ;
165+ strcpy (msg_DigitalIOAdd.pin_name , pin);
166+ msg_DigitalIOAdd.period = period;
167+ msg_DigitalIOAdd.value = value;
168+ // Determine the sample mode
169+ if (strcmp (sample_mode, " TIMER" ) == 0 ) {
170+ msg_DigitalIOAdd.sample_mode =
171+ wippersnapper_digitalio_DigitalIOSampleMode_DIGITAL_IO_SAMPLE_MODE_TIMER;
172+ } else if (strcmp (sample_mode, " EVENT" ) == 0 ) {
173+ msg_DigitalIOAdd.sample_mode =
174+ wippersnapper_digitalio_DigitalIOSampleMode_DIGITAL_IO_SAMPLE_MODE_EVENT;
175+ } else {
176+ WS_DEBUG_PRINTLN (" [SD] Parsing Error: Unknown sample mode found: " +
177+ String (sample_mode));
178+ }
179+
180+ // Determine the pin direction and pull
181+ if (strcmp (direction, " INPUT" ) == 0 ) {
182+ if (pull != nullptr ) {
183+ msg_DigitalIOAdd.gpio_direction =
184+ wippersnapper_digitalio_DigitalIODirection_DIGITAL_IO_DIRECTION_INPUT_PULL_UP;
185+ } else {
186+ msg_DigitalIOAdd.gpio_direction =
187+ wippersnapper_digitalio_DigitalIODirection_DIGITAL_IO_DIRECTION_INPUT;
188+ }
189+ } else if (strcmp (direction, " OUTPUT" ) == 0 ) {
190+ WS_DEBUG_PRINTLN (
191+ " [SD] Error - Can not set OUTPUT direction in offline mode!" );
192+ rc = false ;
193+ } else {
194+ WS_DEBUG_PRINTLN (" [SD] Parsing Error: Unknown direction found: " +
195+ String (direction));
196+ rc = false ;
197+ }
198+ return rc;
199+ }
200+
201+ wippersnapper_sensor_SensorType
202+ ws_sdcard::ParseSensorType (const char *sensor_type) {
203+ if (strcmp (sensor_type, " PIN_VALUE" ) == 0 ) {
204+ return wippersnapper_sensor_SensorType_SENSOR_TYPE_RAW;
205+ } else if (strcmp (sensor_type, " VOLTAGE" ) == 0 ) {
206+ return wippersnapper_sensor_SensorType_SENSOR_TYPE_VOLTAGE;
207+ } else if (strcmp (sensor_type, " ambient-temp-fahrenheit" ) == 0 ) {
208+ return wippersnapper_sensor_SensorType_SENSOR_TYPE_AMBIENT_TEMPERATURE_FAHRENHEIT;
209+ } else if (strcmp (sensor_type, " ambient-temp" ) == 0 ) {
210+ return wippersnapper_sensor_SensorType_SENSOR_TYPE_AMBIENT_TEMPERATURE;
211+ } else {
212+ return wippersnapper_sensor_SensorType_SENSOR_TYPE_UNSPECIFIED;
213+ }
214+ }
215+
216+ bool ws_sdcard::ParseAnalogIOAdd (
217+ wippersnapper_analogio_AnalogIOAdd &msg_AnalogIOAdd, const char *pin,
218+ float period, const char *mode) {
219+ strcpy (msg_AnalogIOAdd.pin_name , pin);
220+ msg_AnalogIOAdd.period = period;
221+ msg_AnalogIOAdd.read_mode = ParseSensorType (mode);
222+ if (msg_AnalogIOAdd.read_mode ==
223+ wippersnapper_sensor_SensorType_SENSOR_TYPE_UNSPECIFIED) {
224+ WS_DEBUG_PRINTLN (" [SD] Parsing Error: Unknown read mode found: " +
225+ String (mode));
226+ return false ;
227+ }
228+ return true ;
229+ }
230+
231+ bool ws_sdcard::ParseDS18X20Add (
232+ wippersnapper_ds18x20_Ds18x20Add &msg_DS18X20Add, const char *pin,
233+ int resolution, float period, int num_sensors, const char *sensor_type_1,
234+ char *sensor_type_2) {
235+ strcpy (msg_DS18X20Add.onewire_pin , pin);
236+ msg_DS18X20Add.sensor_resolution = resolution;
237+ msg_DS18X20Add.period = period;
238+ msg_DS18X20Add.sensor_types_count = num_sensors;
239+
240+ WS_DEBUG_PRINT (" [SD] msg_DS18X20Add.sensor_types_count: " );
241+ WS_DEBUG_PRINTLN (msg_DS18X20Add.sensor_types_count );
242+
243+ // Parse the first sensor type
244+ msg_DS18X20Add.sensor_types [0 ] = ParseSensorType (sensor_type_1);
245+ // Parse the second sensor type, if it exists
246+ if (num_sensors == 2 ) {
247+ msg_DS18X20Add.sensor_types [1 ] = ParseSensorType (sensor_type_2);
248+ }
249+ return true ;
250+ }
251+
160252/* *************************************************************************/
161253/* !
162254 @brief Searches for and parses the JSON configuration file and sets up
@@ -178,8 +270,7 @@ bool ws_sdcard::parseConfigFile() {
178270 if (_use_test_data == true ) {
179271 WS_DEBUG_PRINTLN (" [SD] Using SERIAL INPUT for JSON config..." );
180272 error = deserializeJson (doc, _serialInput.c_str (), max_json_len);
181- }
182- else {
273+ } else {
183274 WS_DEBUG_PRINTLN (" [SD] Using TEST DATA for JSON config..." );
184275 error = deserializeJson (doc, json_test_data, max_json_len);
185276 }
@@ -199,6 +290,13 @@ bool ws_sdcard::parseConfigFile() {
199290 return false ;
200291 }
201292
293+ // NOTE: This is only used by the CI runner, production builds do not run
294+ // this!
295+ const char *exportedBy = doc[" exportedBy" ];
296+ if (strcmp (exportedBy, " wokwi" ) == 0 ) {
297+ _wokwi_runner = true ;
298+ }
299+
202300 // Parse the exportedFromDevice array
203301 JsonObject exportedFromDevice = doc[" exportedFromDevice" ];
204302 if (exportedFromDevice.isNull ()) {
@@ -226,14 +324,19 @@ bool ws_sdcard::parseConfigFile() {
226324
227325 // Parse the "components" array into a JsonObject
228326 JsonArray components_ar = doc[" components" ].as <JsonArray>();
327+ if (components_ar.isNull ()) {
328+ WS_DEBUG_PRINTLN (" [SD] FATAL Parsing error - No components array found in "
329+ " JSON string!" );
330+ return false ;
331+ }
229332 int count = components_ar.size ();
230333 WS_DEBUG_PRINTLN (" [SD] Found " + String (count) + " components in JSON file!" );
231334
232- // Use the iterator feature of ArduinoJSON v7 to quickly iterate over
233- // components[]
335+ // Parse each component from JSON->PB and push into a shared buffer
234336 for (JsonObject component : doc[" components" ].as <JsonArray>()) {
235- // Create a new signal message
236- wippersnapper_signal_BrokerToDevice msg_signal_b2d;
337+ wippersnapper_signal_BrokerToDevice msg_signal_b2d =
338+ wippersnapper_signal_BrokerToDevice_init_default;
339+
237340 // Parse the component API type
238341 const char *component_api_type = component[" componentAPI" ];
239342 if (component_api_type == nullptr ) {
@@ -242,76 +345,40 @@ bool ws_sdcard::parseConfigFile() {
242345 return false ;
243346 }
244347
245- // This is enabled for wokwi-cli testing only
246- const char *exportedBy = doc[" exportedBy" ];
247- if (strcmp (exportedBy, " wokwi" ) == 0 ) {
248- _wokwi_runner = true ;
249- }
250-
251348 // Determine the component type and parse it into a PB message
252349 if (strcmp (component_api_type, " digitalio" ) == 0 ) {
253350 WS_DEBUG_PRINTLN (
254351 " [SD] DigitalIO component found, decoding JSON to PB..." );
255- // Parse the JSON component's fields into a new DigitalIOAdd message
352+
353+ // Parse: JSON->DigitalIOAdd
256354 wippersnapper_digitalio_DigitalIOAdd msg_DigitalIOAdd =
257355 wippersnapper_digitalio_DigitalIOAdd_init_default;
258- strcpy (msg_DigitalIOAdd.pin_name , component[" pinName" ]);
259- msg_DigitalIOAdd.period = component[" period" ];
260- msg_DigitalIOAdd.value = component[" value" ];
261- // Determine the sample mode
262- if (strcmp (component[" sampleMode" ], " TIMER" ) == 0 ) {
263- msg_DigitalIOAdd.sample_mode =
264- wippersnapper_digitalio_DigitalIOSampleMode_DIGITAL_IO_SAMPLE_MODE_TIMER;
265- } else if (strcmp (component[" sampleMode" ], " EVENT" ) == 0 ) {
266- msg_DigitalIOAdd.sample_mode =
267- wippersnapper_digitalio_DigitalIOSampleMode_DIGITAL_IO_SAMPLE_MODE_EVENT;
268- } else {
269- WS_DEBUG_PRINTLN (" [SD] Parsing Error: Unknown sample mode found: " +
270- String (component[" sampleMode" ]));
271- }
272- // Determine the pin direction and pull
273- if (strcmp (component[" direction" ], " INPUT" ) == 0 ) {
274- if (component[" pull" ] != nullptr ) {
275- msg_DigitalIOAdd.gpio_direction =
276- wippersnapper_digitalio_DigitalIODirection_DIGITAL_IO_DIRECTION_INPUT_PULL_UP;
277- } else {
278- msg_DigitalIOAdd.gpio_direction =
279- wippersnapper_digitalio_DigitalIODirection_DIGITAL_IO_DIRECTION_INPUT;
280- }
281- } else if (strcmp (component[" direction" ], " OUTPUT" ) == 0 ) {
356+ if (!ParseDigitalIOAdd (msg_DigitalIOAdd, component[" pinName" ],
357+ component[" period" ], component[" value" ],
358+ component[" sampleMode" ], component[" direction" ],
359+ component[" pull" ])) {
282360 WS_DEBUG_PRINTLN (
283- " [SD] Error - Can not set OUTPUT direction in offline mode!" );
284- return false ;
285- } else {
286- WS_DEBUG_PRINTLN (" [SD] Parsing Error: Unknown direction found: " +
287- String (component[" direction" ]));
361+ " [SD] FATAL Parsing error - Unable to parse DigitalIO component!" );
288362 return false ;
289363 }
290364
291- msg_signal_b2d = wippersnapper_signal_BrokerToDevice_init_zero;
365+ // Configure the signal message for the digitalio payload
292366 msg_signal_b2d.which_payload =
293367 wippersnapper_signal_BrokerToDevice_digitalio_add_tag;
294368 msg_signal_b2d.payload .digitalio_add = msg_DigitalIOAdd;
295369 } else if (strcmp (component_api_type, " analogio" ) == 0 ) {
296370 WS_DEBUG_PRINTLN (" [SD] AnalogIO component found, decoding JSON to PB..." );
297371 wippersnapper_analogio_AnalogIOAdd msg_AnalogIOAdd =
298372 wippersnapper_analogio_AnalogIOAdd_init_default;
299- strcpy (msg_AnalogIOAdd.pin_name , component[" pinName" ]);
300- msg_AnalogIOAdd.period = component[" period" ];
301- if (strcmp (component[" analogReadMode" ], " PIN_VALUE" ) == 0 ) {
302- msg_AnalogIOAdd.read_mode =
303- wippersnapper_sensor_SensorType_SENSOR_TYPE_RAW;
304- } else if (strcmp (component[" analogReadMode" ], " VOLTAGE" ) == 0 ) {
305- msg_AnalogIOAdd.read_mode =
306- wippersnapper_sensor_SensorType_SENSOR_TYPE_VOLTAGE;
307- } else {
308- // Unknown analog read mode, bail out
309- WS_DEBUG_PRINTLN (" [SD] Unknown analog read mode found: " +
310- String (component[" analogReadMode" ]));
373+
374+ // Parse: JSON->AnalogIOAdd
375+ if (!ParseAnalogIOAdd (msg_AnalogIOAdd, component[" pinName" ],
376+ component[" period" ], component[" analogReadMode" ])) {
377+ WS_DEBUG_PRINTLN (
378+ " [SD] FATAL Parsing error - Unable to parse AnalogIO component!" );
311379 return false ;
312380 }
313381
314- msg_signal_b2d = wippersnapper_signal_BrokerToDevice_init_zero;
315382 msg_signal_b2d.which_payload =
316383 wippersnapper_signal_BrokerToDevice_analogio_add_tag;
317384 msg_signal_b2d.payload .analogio_add = msg_AnalogIOAdd;
@@ -320,82 +387,19 @@ bool ws_sdcard::parseConfigFile() {
320387 // Create new DS18X20Add message
321388 wippersnapper_ds18x20_Ds18x20Add msg_DS18X20Add =
322389 wippersnapper_ds18x20_Ds18x20Add_init_default;
323- // Parse JSON into the DS18X20Add message
324- // TODO: This pattern should be refactored into a function like
325- // "ParseAndAssign(component["type"], msg_field)"
326- if (component[" pinName" ] != nullptr ) {
327- strcpy (msg_DS18X20Add.onewire_pin , component[" pinName" ]);
328- } else {
329- WS_DEBUG_PRINTLN (
330- " [SD] FATAL Parsing error - No pin name found in JSON string!" );
331- return false ;
332- }
333390
334- if (component[" sensorResolution" ] != nullptr ) {
335- msg_DS18X20Add.sensor_resolution = component[" sensorResolution" ];
336- } else {
337- WS_DEBUG_PRINTLN (" [SD] FATAL Parsing error - No sensor resolution "
338- " found in JSON string!" );
339- return false ;
340- }
341-
342- if (component[" period" ] != nullptr ) {
343- msg_DS18X20Add.period = component[" period" ];
344- } else {
391+ // Parse: JSON->DS18X20Add
392+ if (!ParseDS18X20Add (msg_DS18X20Add, component[" pinName" ],
393+ component[" sensorResolution" ], component[" period" ],
394+ component[" sensorTypeCount" ],
395+ component[" sensorType1" ],
396+ component[" sensorType2" ])) {
345397 WS_DEBUG_PRINTLN (
346- " [SD] FATAL Parsing error - No period found in JSON string !" );
398+ " [SD] FATAL Parsing error - Unable to parse DS18X20 component !" );
347399 return false ;
348400 }
349401
350- if (component[" sensorTypeCount" ] != nullptr ) {
351- msg_DS18X20Add.sensor_types_count = component[" sensorTypeCount" ];
352- } else {
353- WS_DEBUG_PRINTLN (" [SD] FATAL Parsing error - No sensor type count "
354- " found in JSON string!" );
355- return false ;
356- }
357-
358- WS_DEBUG_PRINT (" [SD] msg_DS18X20Add.sensor_types_count: " );
359- WS_DEBUG_PRINTLN (msg_DS18X20Add.sensor_types_count );
360-
361- // Parse the sensor types into the DS18X20Add message
362- // TODO: This structor needs a refactoring pass! It's too confusing
363- if (msg_DS18X20Add.sensor_types_count == 1 ||
364- msg_DS18X20Add.sensor_types_count == 2 ) {
365- if (strcmp (component[" sensorType1" ], " ambient-temp-fahrenheit" ) == 0 ) {
366- msg_DS18X20Add.sensor_types [0 ] =
367- wippersnapper_sensor_SensorType_SENSOR_TYPE_OBJECT_TEMPERATURE_FAHRENHEIT;
368- } else if (strcmp (component[" sensorType1" ], " ambient-temp" ) == 0 ) {
369- msg_DS18X20Add.sensor_types [0 ] =
370- wippersnapper_sensor_SensorType_SENSOR_TYPE_OBJECT_TEMPERATURE;
371- } else {
372- WS_DEBUG_PRINTLN (
373- " [SD] FATAL Parsing error - Unsupported ds18x sensor "
374- " type found in JSON!" );
375- return false ;
376- }
377- }
378- if (msg_DS18X20Add.sensor_types_count == 2 ) {
379- WS_DEBUG_PRINTLN (" [SD] Parsing sensor type 2..." );
380- if (component[" sensorType2" ] != nullptr ) {
381- if (strcmp (component[" sensorType2" ], " ambient-temp-fahrenheit" ) ==
382- 0 ) {
383- msg_DS18X20Add.sensor_types [1 ] =
384- wippersnapper_sensor_SensorType_SENSOR_TYPE_OBJECT_TEMPERATURE_FAHRENHEIT;
385- } else if (strcmp (component[" sensorType2" ], " ambient-temp" ) == 0 ) {
386- msg_DS18X20Add.sensor_types [1 ] =
387- wippersnapper_sensor_SensorType_SENSOR_TYPE_OBJECT_TEMPERATURE;
388- } else {
389- WS_DEBUG_PRINTLN (
390- " [SD] FATAL Parsing error - Unsupported ds18x sensor "
391- " type found in JSON!" );
392- return false ;
393- }
394- }
395- }
396-
397402 // Configure the signal message for the ds18x20 payload
398- msg_signal_b2d = wippersnapper_signal_BrokerToDevice_init_zero;
399403 msg_signal_b2d.which_payload =
400404 wippersnapper_signal_BrokerToDevice_ds18x20_add_tag;
401405 msg_signal_b2d.payload .ds18x20_add = msg_DS18X20Add;
0 commit comments