@@ -475,7 +475,224 @@ void cbSignalTopic(char *data, uint16_t len) {
475
475
}
476
476
}
477
477
478
- // TODO: This should be moved into digitalGPIO!
478
+ /* *****************************************************************************************/
479
+ /* !
480
+ @brief Publishes an I2C response signal message to the broker.
481
+ @param msgi2cResponse
482
+ A pointer to an I2C response message typedef.
483
+ */
484
+ /* *****************************************************************************************/
485
+ void publishI2CResponse (wippersnapper_signal_v1_I2CResponse *msgi2cResponse) {
486
+ size_t msgSz;
487
+ pb_get_encoded_size (&msgSz, wippersnapper_signal_v1_I2CResponse_fields,
488
+ msgi2cResponse);
489
+ WS_DEBUG_PRINT (" Publishing Message: I2CResponse..." );
490
+ WS._mqtt ->publish (WS._topic_signal_i2c_device , WS._buffer_outgoing , msgSz, 1 );
491
+ WS_DEBUG_PRINTLN (" Published!" );
492
+ }
493
+
494
+ /* *****************************************************************************************/
495
+ /* !
496
+ @brief Encodes an wippersnapper_signal_v1_I2CResponse message.
497
+ @param msgi2cResponse
498
+ A pointer to an wippersnapper_signal_v1_I2CResponse.
499
+ @return True if encoded successfully, False otherwise.
500
+ */
501
+ /* *****************************************************************************************/
502
+ bool encodeI2CResponse (wippersnapper_signal_v1_I2CResponse *msgi2cResponse) {
503
+ memset (WS._buffer_outgoing , 0 , sizeof (WS._buffer_outgoing ));
504
+ pb_ostream_t ostream =
505
+ pb_ostream_from_buffer (WS._buffer_outgoing , sizeof (WS._buffer_outgoing ));
506
+ if (!pb_encode (&ostream, wippersnapper_signal_v1_I2CResponse_fields,
507
+ msgi2cResponse)) {
508
+ WS_DEBUG_PRINTLN (" ERROR: Unable to encode I2C response message!" );
509
+ return false ;
510
+ }
511
+ return true ;
512
+ }
513
+
514
+ /* *****************************************************************************************/
515
+ /* !
516
+ @brief Decodes an I2C signal request message and executes the
517
+ callback based on the message's tag. If successful,
518
+ publishes an I2C signal response back to the broker.
519
+ @param stream
520
+ Incoming data stream from buffer.
521
+ @param field
522
+ Protobuf message's tag type.
523
+ @param arg
524
+ Optional arguments from decoder calling function.
525
+ @returns True if decoded successfully, False otherwise.
526
+ */
527
+ /* *****************************************************************************************/
528
+ bool cbDecodeSignalRequestI2C (pb_istream_t *stream, const pb_field_t *field,
529
+ void **arg) {
530
+ bool is_success = true ;
531
+ WS_DEBUG_PRINTLN (" cbDecodeSignalRequestI2C" );
532
+ // Create I2C Response
533
+ wippersnapper_signal_v1_I2CResponse msgi2cResponse =
534
+ wippersnapper_signal_v1_I2CResponse_init_zero;
535
+ if (field->tag == wippersnapper_signal_v1_I2CRequest_req_i2c_init_tag) {
536
+ WS_DEBUG_PRINTLN (" I2C Init Request Found!" );
537
+ // Decode I2CInitRequest
538
+ wippersnapper_i2c_v1_I2CInitRequest msgI2cInitRequest =
539
+ wippersnapper_i2c_v1_I2CInitRequest_init_zero;
540
+ if (!pb_decode (stream, wippersnapper_i2c_v1_I2CInitRequest_fields,
541
+ &msgI2cInitRequest)) {
542
+ WS_DEBUG_PRINTLN (
543
+ " ERROR: Could not decode wippersnapper_i2c_v1_I2CInitRequest" );
544
+ return false ; // fail out
545
+ }
546
+
547
+ // Create a new I2C Component
548
+ if (msgI2cInitRequest.i2c_port_number == 0 ) {
549
+ WS._i2cPort0 = new WipperSnapper_Component_I2C (&msgI2cInitRequest);
550
+ WS.i2cComponents .push_back (WS._i2cPort0 );
551
+ // did we init. the port successfully?
552
+ is_success = WS._i2cPort0 ->isInitialized ();
553
+ } else if (msgI2cInitRequest.i2c_port_number == 1 ) {
554
+ WS._i2cPort1 = new WipperSnapper_Component_I2C (&msgI2cInitRequest);
555
+ // did we init. the port successfully?
556
+ is_success = WS._i2cPort1 ->isInitialized ();
557
+ WS.i2cComponents .push_back (WS._i2cPort1 );
558
+ } else {
559
+ WS_DEBUG_PRINTLN (" ERROR: Both I2C ports are in-use" );
560
+ is_success = false ;
561
+ }
562
+
563
+ // Pack I2CResponse message
564
+ msgi2cResponse.which_payload =
565
+ wippersnapper_signal_v1_I2CRequest_req_i2c_init_tag;
566
+ msgi2cResponse.payload .resp_i2c_init .is_initialized = is_success;
567
+
568
+ // Encode I2CResponse message
569
+ if (!encodeI2CResponse (&msgi2cResponse)) {
570
+ return false ;
571
+ }
572
+ } else if (field->tag ==
573
+ wippersnapper_signal_v1_I2CRequest_req_i2c_scan_tag) {
574
+ WS_DEBUG_PRINTLN (" I2C Scan Request" );
575
+
576
+ // Decode I2CScanRequest
577
+ wippersnapper_i2c_v1_I2CScanRequest msgScanReq =
578
+ wippersnapper_i2c_v1_I2CScanRequest_init_zero;
579
+ if (!pb_decode (stream, wippersnapper_i2c_v1_I2CScanRequest_fields,
580
+ &msgScanReq)) {
581
+ WS_DEBUG_PRINTLN (
582
+ " ERROR: Could not decode wippersnapper_i2c_v1_I2CScanRequest" );
583
+ return false ; // fail out if we can't decode the request
584
+ }
585
+
586
+ // Check if I2C components were previously initialized
587
+ if (!WS._i2cPort0 ->isInitialized () && !WS._i2cPort0 ->isInitialized ()) {
588
+ WS_DEBUG_PRINTLN (
589
+ " ERROR: I2C Ports were not initialized prior to scanning!" );
590
+ return false ;
591
+ }
592
+
593
+ // Perform I2C scan
594
+ wippersnapper_i2c_v1_I2CScanResponse scanResp =
595
+ wippersnapper_i2c_v1_I2CScanResponse_init_zero;
596
+ if (msgScanReq.i2c_port_number == 0 ) {
597
+ scanResp = WS._i2cPort0 ->scanAddresses ();
598
+ } else {
599
+ scanResp = WS._i2cPort1 ->scanAddresses ();
600
+ }
601
+ WS_DEBUG_PRINTLN (" Scan Complete!" );
602
+ WS_DEBUG_PRINT (" \t # of addresses found on bus: " );
603
+ WS_DEBUG_PRINTLN (scanResp.addresses_found_count );
604
+
605
+ // Pack I2CResponse
606
+ msgi2cResponse.which_payload =
607
+ wippersnapper_signal_v1_I2CResponse_resp_i2c_scan_tag;
608
+ memcpy (msgi2cResponse.payload .resp_i2c_scan .addresses_found ,
609
+ scanResp.addresses_found , sizeof (scanResp.addresses_found ));
610
+ msgi2cResponse.payload .resp_i2c_scan .addresses_found_count =
611
+ scanResp.addresses_found_count ;
612
+
613
+ // Encode I2C Response
614
+ if (!encodeI2CResponse (&msgi2cResponse)) {
615
+ return false ;
616
+ }
617
+ } else if (field->tag ==
618
+ wippersnapper_signal_v1_I2CRequest_req_i2c_device_init_tag) {
619
+ WS_DEBUG_PRINTLN (" I2C Device Init Request Found!" );
620
+ // Decode stream into an I2CDeviceInitRequest
621
+ wippersnapper_i2c_v1_I2CDeviceInitRequest msgI2CDeviceInitRequest =
622
+ wippersnapper_i2c_v1_I2CDeviceInitRequest_init_zero;
623
+ // Decode stream into struct, msgI2CDeviceInitRequest
624
+ if (!pb_decode (stream, wippersnapper_i2c_v1_I2CDeviceInitRequest_fields,
625
+ &msgI2CDeviceInitRequest)) {
626
+ WS_DEBUG_PRINTLN (" ERROR: Could not decode I2CDeviceInitRequest message." );
627
+ return false ; // fail out if we can't decode
628
+ }
629
+ // Attach device to I2C port
630
+ bool deviceInitSuccess = false ;
631
+ if (msgI2CDeviceInitRequest.i2c_port_number == 0 &&
632
+ WS._i2cPort0 ->isInitialized () == true ) {
633
+ deviceInitSuccess =
634
+ WS._i2cPort0 ->attachI2CDevice (&msgI2CDeviceInitRequest);
635
+ } else if (msgI2CDeviceInitRequest.i2c_port_number == 1 &&
636
+ WS._i2cPort1 ->isInitialized () == true ) {
637
+ deviceInitSuccess =
638
+ WS._i2cPort1 ->attachI2CDevice (&msgI2CDeviceInitRequest);
639
+ }
640
+ // Create response
641
+ msgi2cResponse = wippersnapper_signal_v1_I2CResponse_init_zero;
642
+ msgi2cResponse.which_payload =
643
+ wippersnapper_signal_v1_I2CResponse_resp_i2c_device_init_tag;
644
+ msgi2cResponse.payload .resp_i2c_device_init .is_success = deviceInitSuccess;
645
+ // Encode message
646
+ memset (WS._buffer_outgoing , 0 , sizeof (WS._buffer_outgoing ));
647
+ pb_ostream_t ostream = pb_ostream_from_buffer (WS._buffer_outgoing ,
648
+ sizeof (WS._buffer_outgoing ));
649
+ if (!pb_encode (&ostream, wippersnapper_signal_v1_I2CResponse_fields,
650
+ &msgi2cResponse)) {
651
+ WS_DEBUG_PRINTLN (" ERROR: Unable to encode I2C response message" );
652
+ return false ; // fail out if we cant encode
653
+ }
654
+ } else {
655
+ WS_DEBUG_PRINTLN (" ERROR: Undefined I2C message tag" );
656
+ return false ; // fail out, we didn't encode anything to publish
657
+ }
658
+ publishI2CResponse (&msgi2cResponse);
659
+ return is_success;
660
+ }
661
+
662
+ /* *************************************************************************/
663
+ /* !
664
+ @brief Called when i2c signal sub-topic receives a new message and
665
+ attempts to decode a signal request message.
666
+ @param data
667
+ Incoming data from MQTT broker.
668
+ @param len
669
+ Length of incoming data.
670
+ */
671
+ /* *************************************************************************/
672
+ void cbSignalI2CReq (char *data, uint16_t len) {
673
+ WS_DEBUG_PRINTLN (" * NEW MESSAGE [Topic: Signal-I2C]: " );
674
+ WS_DEBUG_PRINT (len);
675
+ WS_DEBUG_PRINTLN (" bytes." );
676
+ // zero-out current buffer
677
+ memset (WS._buffer , 0 , sizeof (WS._buffer ));
678
+ // copy mqtt data into buffer
679
+ memcpy (WS._buffer , data, len);
680
+ WS.bufSize = len;
681
+
682
+ // Zero-out existing I2C signal msg.
683
+ WS.msgSignalI2C = wippersnapper_signal_v1_I2CRequest_init_zero;
684
+
685
+ // Set up the payload callback, which will set up the callbacks for
686
+ // each oneof payload field once the field tag is known
687
+ WS.msgSignalI2C .cb_payload .funcs .decode = cbDecodeSignalRequestI2C;
688
+
689
+ // Decode I2C signal request
690
+ pb_istream_t istream = pb_istream_from_buffer (WS._buffer , WS.bufSize );
691
+ if (!pb_decode (&istream, wippersnapper_signal_v1_I2CRequest_fields,
692
+ &WS.msgSignalI2C ))
693
+ WS_DEBUG_PRINTLN (" ERROR: Unable to decode I2C message" );
694
+ }
695
+
479
696
/* ***************************************************************************/
480
697
/* !
481
698
@brief Handles MQTT messages on signal topic until timeout.
@@ -781,6 +998,18 @@ bool Wippersnapper::buildWSTopics() {
781
998
sizeof (char ) * strlen (WS._username ) + strlen (" /wprsnpr/" ) +
782
999
strlen (_device_uid) + strlen (TOPIC_SIGNALS) + strlen (" broker" ) + 1 );
783
1000
1001
+ // Topic for i2c signals from device to broker
1002
+ WS._topic_signal_i2c_brkr = (char *)malloc (
1003
+ sizeof (char ) * strlen (WS._username ) + +strlen (" /" ) + strlen (_device_uid) +
1004
+ strlen (" /wprsnpr/" ) + strlen (TOPIC_SIGNALS) + strlen (" broker" ) +
1005
+ strlen (TOPIC_I2C) + 1 );
1006
+
1007
+ // Topic for i2c signals from broker to device
1008
+ WS._topic_signal_i2c_device = (char *)malloc (
1009
+ sizeof (char ) * strlen (WS._username ) + +strlen (" /" ) + strlen (_device_uid) +
1010
+ strlen (" /wprsnpr/" ) + strlen (TOPIC_SIGNALS) + strlen (" device" ) +
1011
+ strlen (TOPIC_I2C) + 1 );
1012
+
784
1013
// Create global registration topic
785
1014
if (WS._topic_description ) {
786
1015
strcpy (WS._topic_description , WS._username );
@@ -854,6 +1083,32 @@ bool Wippersnapper::buildWSTopics() {
854
1083
is_success = false ;
855
1084
}
856
1085
1086
+ // Create device-to-broker i2c signal topic
1087
+ if (WS._topic_signal_i2c_brkr ) {
1088
+ strcpy (WS._topic_signal_i2c_brkr , WS._username );
1089
+ strcat (WS._topic_signal_i2c_brkr , TOPIC_WS);
1090
+ strcat (WS._topic_signal_i2c_brkr , _device_uid);
1091
+ strcat (WS._topic_signal_i2c_brkr , TOPIC_SIGNALS);
1092
+ strcat (WS._topic_signal_i2c_brkr , " broker" );
1093
+ strcat (WS._topic_signal_i2c_brkr , TOPIC_I2C);
1094
+ } else { // malloc failed
1095
+ WS._topic_signal_i2c_brkr = 0 ;
1096
+ is_success = false ;
1097
+ }
1098
+
1099
+ // Create broker-to-device i2c signal topic
1100
+ if (WS._topic_signal_i2c_device ) {
1101
+ strcpy (WS._topic_signal_i2c_device , WS._username );
1102
+ strcat (WS._topic_signal_i2c_device , TOPIC_WS);
1103
+ strcat (WS._topic_signal_i2c_device , _device_uid);
1104
+ strcat (WS._topic_signal_i2c_device , TOPIC_SIGNALS);
1105
+ strcat (WS._topic_signal_i2c_device , " device" );
1106
+ strcat (WS._topic_signal_i2c_device , TOPIC_I2C);
1107
+ } else { // malloc failed
1108
+ WS._topic_signal_i2c_device = 0 ;
1109
+ is_success = false ;
1110
+ }
1111
+
857
1112
return is_success;
858
1113
}
859
1114
@@ -869,6 +1124,12 @@ void Wippersnapper::subscribeWSTopics() {
869
1124
WS._mqtt ->subscribe (_topic_signal_brkr_sub);
870
1125
_topic_signal_brkr_sub->setCallback (cbSignalTopic);
871
1126
1127
+ // Subscribe to signal's I2C sub-topic
1128
+ _topic_signal_i2c_sub =
1129
+ new Adafruit_MQTT_Subscribe (WS._mqtt , WS._topic_signal_i2c_brkr , 1 );
1130
+ WS._mqtt ->subscribe (_topic_signal_i2c_sub);
1131
+ _topic_signal_i2c_sub->setCallback (cbSignalI2CReq);
1132
+
872
1133
// Subscribe to registration status topic
873
1134
_topic_description_sub =
874
1135
new Adafruit_MQTT_Subscribe (WS._mqtt , WS._topic_description_status , 1 );
@@ -1231,6 +1492,7 @@ ws_status_t Wippersnapper::run() {
1231
1492
WS._mqtt ->processPackets (10 );
1232
1493
feedWDT ();
1233
1494
1495
+ // TODO: Loop thru components
1234
1496
// Process digital inputs, digitalGPIO module
1235
1497
WS._digitalGPIO ->processDigitalInputs ();
1236
1498
feedWDT ();
@@ -1240,4 +1502,4 @@ ws_status_t Wippersnapper::run() {
1240
1502
feedWDT ();
1241
1503
1242
1504
return WS_NET_CONNECTED; // TODO: Make this funcn void!
1243
- }
1505
+ }
0 commit comments