@@ -53,21 +53,26 @@ Wippersnapper::Wippersnapper() {
53
53
_throttle_sub = 0 ;
54
54
55
55
// Init. component classes
56
-
57
- // DallasSemi (OneWire)
58
- WS._ds18x20Component = new ws_ds18x20 ();
59
56
// LEDC (ESP32-ONLY)
60
57
#ifdef ARDUINO_ARCH_ESP32
61
58
WS._ledc = new ws_ledc ();
62
59
#endif
63
- // Servo
64
- WS._servoComponent = new ws_servo ();
65
- // PWM
60
+
61
+ // PWM (Arch-specific implementations)
66
62
#ifdef ARDUINO_ARCH_ESP32
67
63
WS._pwmComponent = new ws_pwm (WS._ledc );
68
64
#else
69
65
WS._pwmComponent = new ws_pwm ();
70
66
#endif
67
+
68
+ // Servo
69
+ WS._servoComponent = new ws_servo ();
70
+
71
+ // UART
72
+ WS._uartComponent = new ws_uart ();
73
+
74
+ // DallasSemi (OneWire)
75
+ WS._ds18x20Component = new ws_ds18x20 ();
71
76
};
72
77
73
78
/* *************************************************************************/
@@ -1476,6 +1481,126 @@ void cbPixelsMsg(char *data, uint16_t len) {
1476
1481
WS_DEBUG_PRINTLN (" ERROR: Unable to decode pixel topic message" );
1477
1482
}
1478
1483
1484
+ /* *****************************************************************************************/
1485
+ /* !
1486
+ @brief Decodes a UART message and executes the callback based on the
1487
+ message's tag.
1488
+ @param stream
1489
+ Incoming data stream from buffer.
1490
+ @param field
1491
+ Protobuf message's tag type.
1492
+ @param arg
1493
+ Optional arguments from decoder calling function.
1494
+ @returns True if decoded successfully, False otherwise.
1495
+ */
1496
+ /* *****************************************************************************************/
1497
+ bool cbDecodeUARTMessage (pb_istream_t *stream, const pb_field_t *field,
1498
+ void **arg) {
1499
+ if (field->tag ==
1500
+ wippersnapper_signal_v1_UARTRequest_req_uart_device_attach_tag) {
1501
+ WS_DEBUG_PRINTLN (
1502
+ " [Message Type]: "
1503
+ " wippersnapper_signal_v1_UARTRequest_req_uart_device_attach_tag" );
1504
+
1505
+ // attempt to decode create message
1506
+ wippersnapper_uart_v1_UARTDeviceAttachRequest msgUARTInitReq =
1507
+ wippersnapper_uart_v1_UARTDeviceAttachRequest_init_zero;
1508
+ if (!pb_decode (stream, wippersnapper_uart_v1_UARTDeviceAttachRequest_fields,
1509
+ &msgUARTInitReq)) {
1510
+ WS_DEBUG_PRINTLN (
1511
+ " ERROR: Could not decode message of type: UARTDeviceAttachRequest!" );
1512
+ return false ;
1513
+ }
1514
+
1515
+ // Check if bus_info is within the message
1516
+ if (!msgUARTInitReq.has_bus_info ) {
1517
+ WS_DEBUG_PRINTLN (" ERROR: UART bus info not found within message!" );
1518
+ return false ;
1519
+ }
1520
+
1521
+ // Have we previously initialized the UART bus?
1522
+ if (!WS._uartComponent ->isUARTBusInitialized ())
1523
+ WS._uartComponent ->initUARTBus (&msgUARTInitReq); // Init. UART bus
1524
+
1525
+ // Attach UART device to the bus specified in the message
1526
+ bool did_begin = WS._uartComponent ->initUARTDevice (&msgUARTInitReq);
1527
+
1528
+ // Create a UARTResponse message
1529
+ wippersnapper_signal_v1_UARTResponse msgUARTResponse =
1530
+ wippersnapper_signal_v1_UARTResponse_init_zero;
1531
+ msgUARTResponse.which_payload =
1532
+ wippersnapper_signal_v1_UARTResponse_resp_uart_device_attach_tag;
1533
+ msgUARTResponse.payload .resp_uart_device_attach .is_success = did_begin;
1534
+ strcpy (msgUARTResponse.payload .resp_uart_device_attach .device_id ,
1535
+ msgUARTInitReq.device_id );
1536
+ memset (WS._buffer_outgoing , 0 , sizeof (WS._buffer_outgoing ));
1537
+ pb_ostream_t ostream = pb_ostream_from_buffer (WS._buffer_outgoing ,
1538
+ sizeof (WS._buffer_outgoing ));
1539
+ if (!pb_encode (&ostream, wippersnapper_signal_v1_UARTResponse_fields,
1540
+ &msgUARTResponse)) {
1541
+ WS_DEBUG_PRINTLN (" ERROR: Unable to encode UART response message!" );
1542
+ return false ;
1543
+ }
1544
+ size_t msgSz; // message's encoded size
1545
+ pb_get_encoded_size (&msgSz, wippersnapper_signal_v1_UARTResponse_fields,
1546
+ &msgUARTResponse);
1547
+ WS_DEBUG_PRINT (" PUBLISHING: UART Attach Response..." );
1548
+ WS._mqtt ->publish (WS._topic_signal_uart_device , WS._buffer_outgoing , msgSz,
1549
+ 1 );
1550
+ WS_DEBUG_PRINTLN (" Published!" );
1551
+
1552
+ } else if (field->tag ==
1553
+ wippersnapper_signal_v1_UARTRequest_req_uart_device_detach_tag) {
1554
+ WS_DEBUG_PRINTLN (" [New Message] UART Detach" );
1555
+ // attempt to decode uart detach request message
1556
+ wippersnapper_uart_v1_UARTDeviceDetachRequest msgUARTDetachReq =
1557
+ wippersnapper_uart_v1_UARTDeviceDetachRequest_init_zero;
1558
+ if (!pb_decode (stream, wippersnapper_uart_v1_UARTDeviceDetachRequest_fields,
1559
+ &msgUARTDetachReq)) {
1560
+ WS_DEBUG_PRINTLN (" ERROR: Could not decode message!" );
1561
+ return false ;
1562
+ }
1563
+ // detach UART device
1564
+ WS._uartComponent ->detachUARTDevice (&msgUARTDetachReq);
1565
+ WS_DEBUG_PRINTLN (" Detached uart device from bus" );
1566
+ } else {
1567
+ WS_DEBUG_PRINTLN (" ERROR: UART message type not found!" );
1568
+ return false ;
1569
+ }
1570
+ return true ;
1571
+ }
1572
+
1573
+ /* *************************************************************************/
1574
+ /* !
1575
+ @brief Called when the signal UART sub-topic receives a
1576
+ new message. Performs decoding.
1577
+ @param data
1578
+ Incoming data from MQTT broker.
1579
+ @param len
1580
+ Length of incoming data.
1581
+ */
1582
+ /* *************************************************************************/
1583
+ void cbSignalUARTReq (char *data, uint16_t len) {
1584
+ WS_DEBUG_PRINTLN (" * NEW MESSAGE on Signal of type UART: " );
1585
+ WS_DEBUG_PRINT (len);
1586
+ WS_DEBUG_PRINTLN (" bytes." );
1587
+ // zero-out current buffer
1588
+ memset (WS._buffer , 0 , sizeof (WS._buffer ));
1589
+ // copy mqtt data into buffer
1590
+ memcpy (WS._buffer , data, len);
1591
+ WS.bufSize = len;
1592
+
1593
+ // Set up the payload callback, which will set up the callbacks for
1594
+ // each oneof payload field once the field tag is known
1595
+ WS.msgSignalUART .cb_payload .funcs .decode = cbDecodeUARTMessage;
1596
+
1597
+ // Decode DS signal request
1598
+ pb_istream_t istream = pb_istream_from_buffer (WS._buffer , WS.bufSize );
1599
+ if (!pb_decode (&istream, wippersnapper_signal_v1_UARTRequest_fields,
1600
+ &WS.msgSignalUART ))
1601
+ WS_DEBUG_PRINTLN (" ERROR: Unable to decode UART Signal message" );
1602
+ }
1603
+
1479
1604
/* ***************************************************************************/
1480
1605
/* !
1481
1606
@brief Handles MQTT messages on signal topic until timeout.
@@ -2125,6 +2250,58 @@ bool Wippersnapper::generateWSTopics() {
2125
2250
return false ;
2126
2251
}
2127
2252
2253
+ // Create device-to-broker UART topic
2254
+
2255
+ // Calculate size for dynamic MQTT topic
2256
+ size_t topicLen = strlen (WS._username ) + strlen (" /" ) + strlen (_device_uid) +
2257
+ strlen (" /wprsnpr/" ) + strlen (TOPIC_SIGNALS) +
2258
+ strlen (" broker/uart" ) + 1 ;
2259
+
2260
+ // Allocate memory for dynamic MQTT topic
2261
+ #ifdef USE_PSRAM
2262
+ WS._topic_signal_uart_brkr = (char *)ps_malloc (topicLen);
2263
+ #else
2264
+ WS._topic_signal_uart_brkr = (char *)malloc (topicLen);
2265
+ #endif
2266
+
2267
+ // Generate the topic if memory was allocated successfully
2268
+ if (WS._topic_signal_uart_brkr != NULL ) {
2269
+ snprintf (WS._topic_signal_uart_brkr , topicLen, " %s/wprsnpr/%s%sbroker/uart" ,
2270
+ WS._username , _device_uid, TOPIC_SIGNALS);
2271
+ } else {
2272
+ WS_DEBUG_PRINTLN (" FATAL ERROR: Failed to allocate memory for UART topic!" );
2273
+ return false ;
2274
+ }
2275
+
2276
+ // Subscribe to signal's UART sub-topic
2277
+ _topic_signal_uart_sub =
2278
+ new Adafruit_MQTT_Subscribe (WS._mqtt , WS._topic_signal_uart_brkr , 1 );
2279
+ WS._mqtt ->subscribe (_topic_signal_uart_sub);
2280
+ // Set MQTT callback function
2281
+ _topic_signal_uart_sub->setCallback (cbSignalUARTReq);
2282
+
2283
+ // Create broker-to-device UART topic
2284
+ // Calculate size for dynamic MQTT topic
2285
+ topicLen = strlen (WS._username ) + strlen (" /" ) + strlen (_device_uid) +
2286
+ strlen (" /wprsnpr/" ) + strlen (TOPIC_SIGNALS) +
2287
+ strlen (" device/uart" ) + 1 ;
2288
+
2289
+ // Allocate memory for dynamic MQTT topic
2290
+ #ifdef USE_PSRAM
2291
+ WS._topic_signal_uart_device = (char *)ps_malloc (topicLen);
2292
+ #else
2293
+ WS._topic_signal_uart_device = (char *)malloc (topicLen);
2294
+ #endif
2295
+
2296
+ // Generate the topic if memory was allocated successfully
2297
+ if (WS._topic_signal_uart_device != NULL ) {
2298
+ snprintf (WS._topic_signal_uart_device , topicLen,
2299
+ " %s/wprsnpr/%s%sdevice/uart" , WS._username , _device_uid,
2300
+ TOPIC_SIGNALS);
2301
+ } else {
2302
+ WS_DEBUG_PRINTLN (" FATAL ERROR: Failed to allocate memory for UART topic!" );
2303
+ return false ;
2304
+ }
2128
2305
return true ;
2129
2306
}
2130
2307
@@ -2661,5 +2838,8 @@ ws_status_t Wippersnapper::run() {
2661
2838
// Process DS18x20 sensor events
2662
2839
WS._ds18x20Component ->update ();
2663
2840
2841
+ // Process UART sensor events
2842
+ WS._uartComponent ->update ();
2843
+
2664
2844
return WS_NET_CONNECTED; // TODO: Make this funcn void!
2665
2845
}
0 commit comments