12
12
#include < thread>
13
13
#include < chrono>
14
14
#include < map>
15
+ #include < array>
15
16
#include < vector>
16
17
#include < set>
17
18
#include < exception>
@@ -33,10 +34,15 @@ bool halInitialized = false;
33
34
uint32_t m_notifier;
34
35
35
36
std::mutex canDevicesMtx;
37
+ // These values should only be accessed while holding canDevicesMtx
36
38
std::map<std::string, std::shared_ptr<rev::usb::CANDevice>> canDeviceMap;
37
39
38
40
std::mutex watchdogMtx;
41
+ // These values should only be accessed while holding watchdogMtx
39
42
std::vector<std::string> heartbeatsRunning;
43
+ bool heartbeatTimeoutExpired = false ; // Should only be changed in heartbeatsWatchdog()
44
+ std::map<std::string, std::array<uint8_t , 1 >> revCommonHeartbeatMap;
45
+ std::map<std::string, std::array<uint8_t , 8 >> sparkHeartbeatMap;
40
46
auto latestHeartbeatAck = std::chrono::steady_clock::now();
41
47
42
48
// Only call when holding canDevicesMtx
@@ -667,12 +673,29 @@ void heartbeatsWatchdog() {
667
673
668
674
auto now = std::chrono::steady_clock::now ();
669
675
std::chrono::duration<double > elapsed_seconds = now-latestHeartbeatAck;
670
- if (elapsed_seconds.count () > 1 ) {
671
- uint8_t sparkMaxHeartbeat[] = {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
672
- uint8_t revCommonHeartbeat[] = {0 };
676
+ if (elapsed_seconds.count () >= 1 && !heartbeatTimeoutExpired) {
677
+ // The heartbeat timeout just expired
678
+ heartbeatTimeoutExpired = true ;
679
+ uint8_t disabledSparkHeartbeat[] = {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
680
+ uint8_t disabledRevCommonHeartbeat[] = {0 };
673
681
for (int i = 0 ; i < heartbeatsRunning.size (); i++) {
674
- _sendCANMessage (heartbeatsRunning[i], SPARK_HEARTBEAT_ID, sparkMaxHeartbeat, 8 , -1 );
675
- _sendCANMessage (heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, revCommonHeartbeat, 1 , -1 );
682
+ if (sparkHeartbeatMap.contains (heartbeatsRunning[i])) {
683
+ _sendCANMessage (heartbeatsRunning[i], SPARK_HEARTBEAT_ID, disabledSparkHeartbeat, 8 , HEARTBEAT_PERIOD_MS);
684
+ }
685
+ if (revCommonHeartbeatMap.contains (heartbeatsRunning[i])) {
686
+ _sendCANMessage (heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, disabledRevCommonHeartbeat, 1 , HEARTBEAT_PERIOD_MS);
687
+ }
688
+ }
689
+ } else if (elapsed_seconds.count () < 1 && heartbeatTimeoutExpired) {
690
+ // The heartbeat timeout is newly un-expired
691
+ heartbeatTimeoutExpired = false ;
692
+ for (int i = 0 ; i < heartbeatsRunning.size (); i++) {
693
+ if (auto heartbeatEntry = sparkHeartbeatMap.find (heartbeatsRunning[i]); heartbeatEntry != sparkHeartbeatMap.end ()) {
694
+ _sendCANMessage (heartbeatsRunning[i], SPARK_HEARTBEAT_ID, heartbeatEntry->second .data (), 8 , HEARTBEAT_PERIOD_MS);
695
+ }
696
+ if (auto heartbeatEntry = revCommonHeartbeatMap.find (heartbeatsRunning[i]); heartbeatEntry != revCommonHeartbeatMap.end ()) {
697
+ _sendCANMessage (heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, heartbeatEntry->second .data (), 1 , HEARTBEAT_PERIOD_MS);
698
+ }
676
699
}
677
700
}
678
701
}
@@ -695,10 +718,11 @@ void startRevCommonHeartbeat(const Napi::CallbackInfo& info) {
695
718
if (deviceIterator == canDeviceMap.end ()) return ;
696
719
}
697
720
698
- uint8_t payload[] = {1 };
699
- _sendCANMessage (descriptor, REV_COMMON_HEARTBEAT_ID, payload, 1 , HEARTBEAT_PERIOD_MS);
721
+ std::array< uint8_t , 1 > payload = {1 };
722
+ _sendCANMessage (descriptor, REV_COMMON_HEARTBEAT_ID, payload. data () , 1 , HEARTBEAT_PERIOD_MS);
700
723
701
724
std::scoped_lock lock{watchdogMtx};
725
+ revCommonHeartbeatMap[descriptor] = payload;
702
726
703
727
if (heartbeatsRunning.size () == 0 ) {
704
728
heartbeatsRunning.push_back (descriptor);
@@ -721,7 +745,7 @@ void setSparkMaxHeartbeatData(const Napi::CallbackInfo& info) {
721
745
std::string descriptor = info[0 ].As <Napi::String>().Utf8Value ();
722
746
Napi::Array dataParam = info[1 ].As <Napi::Array>();
723
747
724
- uint8_t heartbeat[] = {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
748
+ std::array< uint8_t , 8 > heartbeat = {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
725
749
726
750
{
727
751
std::scoped_lock lock{canDevicesMtx};
@@ -730,32 +754,28 @@ void setSparkMaxHeartbeatData(const Napi::CallbackInfo& info) {
730
754
}
731
755
732
756
// Clear the scheduled heartbeat that has outdated data so that the updated one gets sent out immediately
733
- _sendCANMessage (descriptor, SPARK_HEARTBEAT_ID, heartbeat, 8 , -1 );
757
+ _sendCANMessage (descriptor, SPARK_HEARTBEAT_ID, heartbeat. data () , 8 , -1 );
734
758
735
759
int sum = 0 ;
736
760
for (uint32_t i = 0 ; i < dataParam.Length (); i++) {
737
761
heartbeat[i] = dataParam.Get (i).As <Napi::Number>().Uint32Value ();
738
762
sum+= heartbeat[i];
739
763
}
740
764
741
- if (sum == 0 ) {
742
- _sendCANMessage (descriptor, SPARK_HEARTBEAT_ID, heartbeat, 8 , -1 );
743
- }
744
- else {
745
- _sendCANMessage (descriptor, SPARK_HEARTBEAT_ID, heartbeat, 8 , HEARTBEAT_PERIOD_MS);
765
+ _sendCANMessage (descriptor, SPARK_HEARTBEAT_ID, heartbeat.data (), 8 , HEARTBEAT_PERIOD_MS);
746
766
747
- std::scoped_lock lock{watchdogMtx};
767
+ std::scoped_lock lock{watchdogMtx};
768
+ sparkHeartbeatMap[descriptor] = heartbeat;
748
769
749
- if (heartbeatsRunning.size () == 0 ) {
750
- heartbeatsRunning.push_back (descriptor);
751
- latestHeartbeatAck = std::chrono::steady_clock::now ();
752
- std::thread hb (heartbeatsWatchdog);
753
- hb.detach ();
754
- } else {
755
- for (int i = 0 ; i < heartbeatsRunning.size (); i++) {
756
- if (heartbeatsRunning[i].compare (descriptor) == 0 ) return ;
757
- }
758
- heartbeatsRunning.push_back (descriptor);
770
+ if (heartbeatsRunning.size () == 0 ) {
771
+ heartbeatsRunning.push_back (descriptor);
772
+ latestHeartbeatAck = std::chrono::steady_clock::now ();
773
+ std::thread hb (heartbeatsWatchdog);
774
+ hb.detach ();
775
+ } else {
776
+ for (int i = 0 ; i < heartbeatsRunning.size (); i++) {
777
+ if (heartbeatsRunning[i].compare (descriptor) == 0 ) return ;
759
778
}
779
+ heartbeatsRunning.push_back (descriptor);
760
780
}
761
781
}
0 commit comments