3
3
#include < rev/CANMessage.h>
4
4
#include < rev/CANStatus.h>
5
5
#include < rev/CANBridgeUtils.h>
6
+ #ifdef _WIN32
6
7
#include < rev/Drivers/CandleWinUSB/CandleWinUSBDriver.h>
7
8
#include < rev/Drivers/CandleWinUSB/CandleWinUSBDevice.h>
9
+ #else
10
+
11
+ #include " rev/Drivers/SerialPort/SerialDriver.h"
12
+ #endif
13
+
14
+
8
15
#include < utils/ThreadUtils.h>
9
16
#include < hal/HAL.h>
10
17
#include < hal/CAN.h>
11
18
#include < napi.h>
12
19
#include < thread>
13
20
#include < chrono>
14
21
#include < map>
15
- #include < array>
16
22
#include < vector>
17
23
#include < set>
18
24
#include < exception>
21
27
#include " canWrapper.h"
22
28
#include " DfuSeFile.h"
23
29
24
- #define DEVICE_NOT_FOUND_ERROR " Device not found. Make sure to run getDevices()"
30
+ #define DEVICE_NOT_FOUND_ERROR " Device not found. Make sure to run getDevices()"
25
31
26
- #define REV_COMMON_HEARTBEAT_ID 0x00502C0
27
- #define SPARK_HEARTBEAT_ID 0x2052C80
28
- #define HEARTBEAT_PERIOD_MS 20
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
-
35
- rev::usb::CandleWinUSBDriver* driver = new rev::usb::CandleWinUSBDriver();
32
+ rev::usb::CANDriver* driver =
33
+ #ifdef _WIN32
34
+ new rev::usb::CandleWinUSBDriver();
35
+ #else
36
+ new rev::usb::SerialDriver();
37
+ #endif
36
38
37
39
std::set<std::string> devicesRegisteredToHal; // TODO(Noah): Protect with mutex
38
40
bool halInitialized = false ;
39
41
uint32_t m_notifier;
40
42
41
43
std::mutex canDevicesMtx;
42
- // These values should only be accessed while holding canDevicesMtx
43
44
std::map<std::string, std::shared_ptr<rev::usb::CANDevice>> canDeviceMap;
44
45
45
46
std::mutex watchdogMtx;
46
- // These values should only be accessed while holding watchdogMtx
47
47
std::vector<std::string> heartbeatsRunning;
48
- bool heartbeatTimeoutExpired = false ; // Should only be changed in heartbeatsWatchdog()
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;
51
- auto latestHeartbeatAck = std::chrono::steady_clock::now();
48
+ auto latestHeartbeatAck = std::chrono::system_clock::now();
52
49
53
50
// Only call when holding canDevicesMtx
54
51
void removeExtraDevicesFromDeviceMap (std::vector<std::string> descriptors) {
@@ -632,7 +629,6 @@ void waitForNotifierAlarm(const Napi::CallbackInfo& info) {
632
629
int32_t status;
633
630
634
631
HAL_UpdateNotifierAlarm (m_notifier, HAL_GetFPGATime (&status) + time, &status);
635
- // TODO(Noah): Don't discard the returned value (this function is marked as [nodiscard])
636
632
HAL_WaitForNotifierAlarm (m_notifier, &status);
637
633
cb.Call (info.Env ().Global (), {info.Env ().Null (), Napi::Number::New (info.Env (), status)});
638
634
}
@@ -658,70 +654,41 @@ void writeDfuToBin(const Napi::CallbackInfo& info) {
658
654
cb.Call (info.Env ().Global (), {info.Env ().Null (), Napi::Number::New (info.Env (), status)});
659
655
}
660
656
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
-
672
657
void heartbeatsWatchdog () {
673
658
while (true ) {
674
- std::this_thread::sleep_for (std::chrono::milliseconds ( 250 ));
659
+ std::this_thread::sleep_for (std::chrono::seconds ( 1 ));
675
660
676
- cleanupHeartbeatsRunning ();
661
+ {
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
+ }
677
671
678
672
std::scoped_lock lock{watchdogMtx};
679
673
680
674
if (heartbeatsRunning.size () < 1 ) { break ; }
681
675
682
- auto now = std::chrono::steady_clock ::now ();
676
+ auto now = std::chrono::system_clock ::now ();
683
677
std::chrono::duration<double > elapsed_seconds = now-latestHeartbeatAck;
684
- if (elapsed_seconds.count () >= 1 && !heartbeatTimeoutExpired) {
685
- // The heartbeat timeout just expired
686
- heartbeatTimeoutExpired = true ;
687
- for (int i = 0 ; i < heartbeatsRunning.size (); i++) {
688
- if (sparkHeartbeatMap.contains (heartbeatsRunning[i])) {
689
- // Clear the scheduled heartbeat that has outdated data so that the updated one gets sent out immediately
690
- _sendCANMessage (heartbeatsRunning[i], SPARK_HEARTBEAT_ID, disabledSparkHeartbeat, SPARK_HEARTBEAT_LENGTH, -1 );
691
-
692
- _sendCANMessage (heartbeatsRunning[i], SPARK_HEARTBEAT_ID, disabledSparkHeartbeat, SPARK_HEARTBEAT_LENGTH, HEARTBEAT_PERIOD_MS);
693
- }
694
- if (revCommonHeartbeatMap.contains (heartbeatsRunning[i])) {
695
- // Clear the scheduled heartbeat that has outdated data so that the updated one gets sent out immediately
696
- _sendCANMessage (heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, disabledRevCommonHeartbeat, REV_COMMON_HEARTBEAT_LENGTH, -1 );
697
-
698
- _sendCANMessage (heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, disabledRevCommonHeartbeat, REV_COMMON_HEARTBEAT_LENGTH, HEARTBEAT_PERIOD_MS);
699
- }
700
- }
701
- } else if (elapsed_seconds.count () < 1 && heartbeatTimeoutExpired) {
702
- // The heartbeat timeout is newly un-expired
703
- heartbeatTimeoutExpired = false ;
678
+ if (elapsed_seconds.count () > 1 ) {
679
+ uint8_t sparkMaxHeartbeat[] = {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
680
+ uint8_t revCommonHeartbeat[] = {0 };
704
681
for (int i = 0 ; i < heartbeatsRunning.size (); i++) {
705
- if (auto heartbeatEntry = sparkHeartbeatMap.find (heartbeatsRunning[i]); heartbeatEntry != sparkHeartbeatMap.end ()) {
706
- // Clear the scheduled heartbeat that has outdated data so that the updated one gets sent out immediately
707
- _sendCANMessage (heartbeatsRunning[i], SPARK_HEARTBEAT_ID, heartbeatEntry->second .data (), SPARK_HEARTBEAT_LENGTH, -1 );
708
-
709
- _sendCANMessage (heartbeatsRunning[i], SPARK_HEARTBEAT_ID, heartbeatEntry->second .data (), SPARK_HEARTBEAT_LENGTH, HEARTBEAT_PERIOD_MS);
710
- }
711
- if (auto heartbeatEntry = revCommonHeartbeatMap.find (heartbeatsRunning[i]); heartbeatEntry != revCommonHeartbeatMap.end ()) {
712
- // Clear the scheduled heartbeat that has outdated data so that the updated one gets sent out immediately
713
- _sendCANMessage (heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, heartbeatEntry->second .data (), REV_COMMON_HEARTBEAT_LENGTH, -1 );
714
-
715
- _sendCANMessage (heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, heartbeatEntry->second .data (), REV_COMMON_HEARTBEAT_LENGTH, HEARTBEAT_PERIOD_MS);
716
- }
682
+ _sendCANMessage (heartbeatsRunning[i], 0x2052C80 , sparkMaxHeartbeat, 8 , -1 );
683
+ _sendCANMessage (heartbeatsRunning[i], 0x00502C0 , revCommonHeartbeat, 1 , -1 );
717
684
}
718
685
}
719
686
}
720
687
}
721
688
722
689
void ackHeartbeats (const Napi::CallbackInfo& info) {
723
690
std::scoped_lock lock{watchdogMtx};
724
- latestHeartbeatAck = std::chrono::steady_clock ::now ();
691
+ latestHeartbeatAck = std::chrono::system_clock ::now ();
725
692
}
726
693
727
694
// Params:
@@ -736,19 +703,14 @@ void startRevCommonHeartbeat(const Napi::CallbackInfo& info) {
736
703
if (deviceIterator == canDeviceMap.end ()) return ;
737
704
}
738
705
739
- std::array<uint8_t , REV_COMMON_HEARTBEAT_LENGTH> payload = {1 };
706
+ uint8_t payload[] = {1 };
707
+ _sendCANMessage (descriptor, 0x00502C0 , payload, 1 , 20 );
740
708
741
709
std::scoped_lock lock{watchdogMtx};
742
710
743
- if (!heartbeatTimeoutExpired) {
744
- _sendCANMessage (descriptor, REV_COMMON_HEARTBEAT_ID, payload.data (), REV_COMMON_HEARTBEAT_LENGTH, HEARTBEAT_PERIOD_MS);
745
- }
746
-
747
- revCommonHeartbeatMap[descriptor] = payload;
748
-
749
711
if (heartbeatsRunning.size () == 0 ) {
750
712
heartbeatsRunning.push_back (descriptor);
751
- latestHeartbeatAck = std::chrono::steady_clock ::now ();
713
+ latestHeartbeatAck = std::chrono::system_clock ::now ();
752
714
std::thread hb (heartbeatsWatchdog);
753
715
hb.detach ();
754
716
} else {
@@ -767,53 +729,42 @@ void setSparkMaxHeartbeatData(const Napi::CallbackInfo& info) {
767
729
std::string descriptor = info[0 ].As <Napi::String>().Utf8Value ();
768
730
Napi::Array dataParam = info[1 ].As <Napi::Array>();
769
731
770
- std::array< uint8_t , SPARK_HEARTBEAT_LENGTH> heartbeat = {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
732
+ uint8_t heartbeat[] = {0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 };
771
733
772
734
{
773
735
std::scoped_lock lock{canDevicesMtx};
774
736
auto deviceIterator = canDeviceMap.find (descriptor);
775
737
if (deviceIterator == canDeviceMap.end ()) return ;
776
738
}
777
739
740
+ _sendCANMessage (descriptor, 0x2052C80 , heartbeat, 8 , -1 );
741
+ std::this_thread::sleep_for (std::chrono::milliseconds (50 ));
742
+
778
743
int sum = 0 ;
779
744
for (uint32_t i = 0 ; i < dataParam.Length (); i++) {
780
745
heartbeat[i] = dataParam.Get (i).As <Napi::Number>().Uint32Value ();
781
746
sum+= heartbeat[i];
782
747
}
783
748
784
- std::scoped_lock lock{watchdogMtx};
785
-
786
- if (!heartbeatTimeoutExpired) {
787
- // Clear the scheduled heartbeat that has outdated data so that the updated one gets sent out immediately
788
- _sendCANMessage (descriptor, SPARK_HEARTBEAT_ID, heartbeat.data (), SPARK_HEARTBEAT_LENGTH, -1 );
789
-
790
- _sendCANMessage (descriptor, SPARK_HEARTBEAT_ID, heartbeat.data (), SPARK_HEARTBEAT_LENGTH, HEARTBEAT_PERIOD_MS);
749
+ if (sum == 0 ) {
750
+ _sendCANMessage (descriptor, 0x2052C80 , heartbeat, 8 , -1 );
791
751
}
752
+ else {
753
+ _sendCANMessage (descriptor, 0x2052C80 , heartbeat, 8 , 10 );
792
754
793
- sparkHeartbeatMap[descriptor] = heartbeat ;
755
+ std::scoped_lock lock{watchdogMtx} ;
794
756
795
- if (heartbeatsRunning.size () == 0 ) {
796
- heartbeatsRunning.push_back (descriptor);
797
- latestHeartbeatAck = std::chrono::steady_clock::now ();
798
- std::thread hb (heartbeatsWatchdog);
799
- hb.detach ();
800
- } else {
801
- for (int i = 0 ; i < heartbeatsRunning.size (); i++) {
802
- if (heartbeatsRunning[i].compare (descriptor) == 0 ) return ;
757
+ if (heartbeatsRunning.size () == 0 ) {
758
+ heartbeatsRunning.push_back (descriptor);
759
+ latestHeartbeatAck = std::chrono::system_clock::now ();
760
+ std::thread hb (heartbeatsWatchdog);
761
+ hb.detach ();
762
+ } else {
763
+ for (int i = 0 ; i < heartbeatsRunning.size (); i++) {
764
+ if (heartbeatsRunning[i].compare (descriptor) == 0 ) return ;
765
+ }
766
+ heartbeatsRunning.push_back (descriptor);
803
767
}
804
- heartbeatsRunning.push_back (descriptor);
805
768
}
806
769
}
807
770
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