27
27
#define SPARK_HEARTBEAT_ID 0x2052C80
28
28
#define HEARTBEAT_PERIOD_MS 20
29
29
30
+ #define SPARK_HEARTBEAT_LENGTH 8
31
+ #define REV_COMMON_HEARTBEAT_LENGTH 1
32
+ uint8_t disabledSparkHeartbeat[] = {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
33
+ uint8_t disabledRevCommonHeartbeat[] = {0 };
34
+
30
35
rev::usb::CandleWinUSBDriver* driver = new rev::usb::CandleWinUSBDriver();
31
36
32
37
std::set<std::string> devicesRegisteredToHal; // TODO(Noah): Protect with mutex
@@ -41,8 +46,8 @@ std::mutex watchdogMtx;
41
46
// These values should only be accessed while holding watchdogMtx
42
47
std::vector<std::string> heartbeatsRunning;
43
48
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;
49
+ std::map<std::string, std::array<uint8_t , REV_COMMON_HEARTBEAT_LENGTH >> revCommonHeartbeatMap;
50
+ std::map<std::string, std::array<uint8_t , SPARK_HEARTBEAT_LENGTH >> sparkHeartbeatMap;
46
51
auto latestHeartbeatAck = std::chrono::steady_clock::now();
47
52
48
53
// Only call when holding canDevicesMtx
@@ -653,20 +658,22 @@ void writeDfuToBin(const Napi::CallbackInfo& info) {
653
658
cb.Call (info.Env ().Global (), {info.Env ().Null (), Napi::Number::New (info.Env (), status)});
654
659
}
655
660
661
+ void cleanupHeartbeatsRunning () {
662
+ // Erase removed CAN buses from heartbeatsRunning
663
+ std::scoped_lock lock{watchdogMtx, canDevicesMtx};
664
+ for (int i = 0 ; i < heartbeatsRunning.size (); i++) {
665
+ auto deviceIterator = canDeviceMap.find (heartbeatsRunning[i]);
666
+ if (deviceIterator == canDeviceMap.end ()) {
667
+ heartbeatsRunning.erase (heartbeatsRunning.begin () + i);
668
+ }
669
+ }
670
+ }
671
+
656
672
void heartbeatsWatchdog () {
657
673
while (true ) {
658
674
std::this_thread::sleep_for (std::chrono::milliseconds (250 ));
659
675
660
- {
661
- // Erase removed CAN buses from heartbeatsRunning
662
- std::scoped_lock lock{watchdogMtx, canDevicesMtx};
663
- for (int i = 0 ; i < heartbeatsRunning.size (); i++) {
664
- auto deviceIterator = canDeviceMap.find (heartbeatsRunning[i]);
665
- if (deviceIterator == canDeviceMap.end ()) {
666
- heartbeatsRunning.erase (heartbeatsRunning.begin () + i);
667
- }
668
- }
669
- }
676
+ cleanupHeartbeatsRunning ();
670
677
671
678
std::scoped_lock lock{watchdogMtx};
672
679
@@ -677,20 +684,18 @@ void heartbeatsWatchdog() {
677
684
if (elapsed_seconds.count () >= 1 && !heartbeatTimeoutExpired) {
678
685
// The heartbeat timeout just expired
679
686
heartbeatTimeoutExpired = true ;
680
- uint8_t disabledSparkHeartbeat[] = {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
681
- uint8_t disabledRevCommonHeartbeat[] = {0 };
682
687
for (int i = 0 ; i < heartbeatsRunning.size (); i++) {
683
688
if (sparkHeartbeatMap.contains (heartbeatsRunning[i])) {
684
689
// Clear the scheduled heartbeat that has outdated data so that the updated one gets sent out immediately
685
- _sendCANMessage (heartbeatsRunning[i], SPARK_HEARTBEAT_ID, disabledSparkHeartbeat, 8 , -1 );
690
+ _sendCANMessage (heartbeatsRunning[i], SPARK_HEARTBEAT_ID, disabledSparkHeartbeat, SPARK_HEARTBEAT_LENGTH , -1 );
686
691
687
- _sendCANMessage (heartbeatsRunning[i], SPARK_HEARTBEAT_ID, disabledSparkHeartbeat, 8 , HEARTBEAT_PERIOD_MS);
692
+ _sendCANMessage (heartbeatsRunning[i], SPARK_HEARTBEAT_ID, disabledSparkHeartbeat, SPARK_HEARTBEAT_LENGTH , HEARTBEAT_PERIOD_MS);
688
693
}
689
694
if (revCommonHeartbeatMap.contains (heartbeatsRunning[i])) {
690
695
// Clear the scheduled heartbeat that has outdated data so that the updated one gets sent out immediately
691
- _sendCANMessage (heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, disabledRevCommonHeartbeat, 1 , -1 );
696
+ _sendCANMessage (heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, disabledRevCommonHeartbeat, REV_COMMON_HEARTBEAT_LENGTH , -1 );
692
697
693
- _sendCANMessage (heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, disabledRevCommonHeartbeat, 1 , HEARTBEAT_PERIOD_MS);
698
+ _sendCANMessage (heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, disabledRevCommonHeartbeat, REV_COMMON_HEARTBEAT_LENGTH , HEARTBEAT_PERIOD_MS);
694
699
}
695
700
}
696
701
} else if (elapsed_seconds.count () < 1 && heartbeatTimeoutExpired) {
@@ -699,15 +704,15 @@ void heartbeatsWatchdog() {
699
704
for (int i = 0 ; i < heartbeatsRunning.size (); i++) {
700
705
if (auto heartbeatEntry = sparkHeartbeatMap.find (heartbeatsRunning[i]); heartbeatEntry != sparkHeartbeatMap.end ()) {
701
706
// Clear the scheduled heartbeat that has outdated data so that the updated one gets sent out immediately
702
- _sendCANMessage (heartbeatsRunning[i], SPARK_HEARTBEAT_ID, heartbeatEntry->second .data (), 8 , -1 );
707
+ _sendCANMessage (heartbeatsRunning[i], SPARK_HEARTBEAT_ID, heartbeatEntry->second .data (), SPARK_HEARTBEAT_LENGTH , -1 );
703
708
704
- _sendCANMessage (heartbeatsRunning[i], SPARK_HEARTBEAT_ID, heartbeatEntry->second .data (), 8 , HEARTBEAT_PERIOD_MS);
709
+ _sendCANMessage (heartbeatsRunning[i], SPARK_HEARTBEAT_ID, heartbeatEntry->second .data (), SPARK_HEARTBEAT_LENGTH , HEARTBEAT_PERIOD_MS);
705
710
}
706
711
if (auto heartbeatEntry = revCommonHeartbeatMap.find (heartbeatsRunning[i]); heartbeatEntry != revCommonHeartbeatMap.end ()) {
707
712
// Clear the scheduled heartbeat that has outdated data so that the updated one gets sent out immediately
708
- _sendCANMessage (heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, heartbeatEntry->second .data (), 1 , -1 );
713
+ _sendCANMessage (heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, heartbeatEntry->second .data (), REV_COMMON_HEARTBEAT_LENGTH , -1 );
709
714
710
- _sendCANMessage (heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, heartbeatEntry->second .data (), 1 , HEARTBEAT_PERIOD_MS);
715
+ _sendCANMessage (heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, heartbeatEntry->second .data (), REV_COMMON_HEARTBEAT_LENGTH , HEARTBEAT_PERIOD_MS);
711
716
}
712
717
}
713
718
}
@@ -731,12 +736,12 @@ void startRevCommonHeartbeat(const Napi::CallbackInfo& info) {
731
736
if (deviceIterator == canDeviceMap.end ()) return ;
732
737
}
733
738
734
- std::array<uint8_t , 1 > payload = {1 };
739
+ std::array<uint8_t , REV_COMMON_HEARTBEAT_LENGTH > payload = {1 };
735
740
736
741
std::scoped_lock lock{watchdogMtx};
737
742
738
743
if (!heartbeatTimeoutExpired) {
739
- _sendCANMessage (descriptor, REV_COMMON_HEARTBEAT_ID, payload.data (), 1 , HEARTBEAT_PERIOD_MS);
744
+ _sendCANMessage (descriptor, REV_COMMON_HEARTBEAT_ID, payload.data (), REV_COMMON_HEARTBEAT_LENGTH , HEARTBEAT_PERIOD_MS);
740
745
}
741
746
742
747
revCommonHeartbeatMap[descriptor] = payload;
@@ -762,7 +767,7 @@ void setSparkMaxHeartbeatData(const Napi::CallbackInfo& info) {
762
767
std::string descriptor = info[0 ].As <Napi::String>().Utf8Value ();
763
768
Napi::Array dataParam = info[1 ].As <Napi::Array>();
764
769
765
- std::array<uint8_t , 8 > heartbeat = {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
770
+ std::array<uint8_t , SPARK_HEARTBEAT_LENGTH > heartbeat = {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
766
771
767
772
{
768
773
std::scoped_lock lock{canDevicesMtx};
@@ -780,9 +785,9 @@ void setSparkMaxHeartbeatData(const Napi::CallbackInfo& info) {
780
785
781
786
if (!heartbeatTimeoutExpired) {
782
787
// Clear the scheduled heartbeat that has outdated data so that the updated one gets sent out immediately
783
- _sendCANMessage (descriptor, SPARK_HEARTBEAT_ID, heartbeat.data (), 8 , -1 );
788
+ _sendCANMessage (descriptor, SPARK_HEARTBEAT_ID, heartbeat.data (), SPARK_HEARTBEAT_LENGTH , -1 );
784
789
785
- _sendCANMessage (descriptor, SPARK_HEARTBEAT_ID, heartbeat.data (), 8 , HEARTBEAT_PERIOD_MS);
790
+ _sendCANMessage (descriptor, SPARK_HEARTBEAT_ID, heartbeat.data (), SPARK_HEARTBEAT_LENGTH , HEARTBEAT_PERIOD_MS);
786
791
}
787
792
788
793
sparkHeartbeatMap[descriptor] = heartbeat;
@@ -799,3 +804,16 @@ void setSparkMaxHeartbeatData(const Napi::CallbackInfo& info) {
799
804
heartbeatsRunning.push_back (descriptor);
800
805
}
801
806
}
807
+
808
+ void stopHeartbeats (const Napi::CallbackInfo& info) {
809
+ std::string descriptor = info[0 ].As <Napi::String>().Utf8Value ();
810
+ bool sendDisabledHeartbeatsFirst = info[1 ].As <Napi::Boolean >().Value ();
811
+
812
+ // 0 sends and then cancels, -1 cancels without sending
813
+ const int repeatPeriod = sendDisabledHeartbeatsFirst ? 0 : -1 ;
814
+
815
+ std::scoped_lock lock{watchdogMtx};
816
+ // Send disabled SPARK and REV common heartbeats and un-schedule them for the future
817
+ _sendCANMessage (descriptor, SPARK_HEARTBEAT_ID, disabledSparkHeartbeat, SPARK_HEARTBEAT_LENGTH, repeatPeriod);
818
+ _sendCANMessage (descriptor, REV_COMMON_HEARTBEAT_ID, disabledRevCommonHeartbeat, REV_COMMON_HEARTBEAT_LENGTH, repeatPeriod);
819
+ }
0 commit comments