From b0ca096624286b1e975eaaa816e38599933b7e84 Mon Sep 17 00:00:00 2001 From: Moose1301 <40875577+Moose1301@users.noreply.github.com> Date: Sat, 11 May 2024 15:19:48 -0400 Subject: [PATCH 01/30] add serialdriver for other platforms then windows --- src/canWrapper.cc | 159 ++++++++++++++++------------------------------ 1 file changed, 55 insertions(+), 104 deletions(-) diff --git a/src/canWrapper.cc b/src/canWrapper.cc index bd71daf..b32be7a 100644 --- a/src/canWrapper.cc +++ b/src/canWrapper.cc @@ -3,8 +3,15 @@ #include #include #include +#ifdef _WIN32 #include #include +#else + +#include "rev/Drivers/SerialPort/SerialDriver.h" +#endif + + #include #include #include @@ -12,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -21,34 +27,25 @@ #include "canWrapper.h" #include "DfuSeFile.h" -#define DEVICE_NOT_FOUND_ERROR "Device not found. Make sure to run getDevices()" +#define DEVICE_NOT_FOUND_ERROR "Device not found. Make sure to run getDevices()" -#define REV_COMMON_HEARTBEAT_ID 0x00502C0 -#define SPARK_HEARTBEAT_ID 0x2052C80 -#define HEARTBEAT_PERIOD_MS 20 - -#define SPARK_HEARTBEAT_LENGTH 8 -#define REV_COMMON_HEARTBEAT_LENGTH 1 -uint8_t disabledSparkHeartbeat[] = {0, 0, 0, 0, 0, 0, 0, 0}; -uint8_t disabledRevCommonHeartbeat[] = {0}; - -rev::usb::CandleWinUSBDriver* driver = new rev::usb::CandleWinUSBDriver(); +rev::usb::CANDriver* driver = +#ifdef _WIN32 + new rev::usb::CandleWinUSBDriver(); +#else + new rev::usb::SerialDriver(); +#endif std::set devicesRegisteredToHal; // TODO(Noah): Protect with mutex bool halInitialized = false; uint32_t m_notifier; std::mutex canDevicesMtx; -// These values should only be accessed while holding canDevicesMtx std::map> canDeviceMap; std::mutex watchdogMtx; -// These values should only be accessed while holding watchdogMtx std::vector heartbeatsRunning; -bool heartbeatTimeoutExpired = false; // Should only be changed in heartbeatsWatchdog() -std::map> revCommonHeartbeatMap; -std::map> sparkHeartbeatMap; -auto latestHeartbeatAck = std::chrono::steady_clock::now(); +auto latestHeartbeatAck = std::chrono::system_clock::now(); // Only call when holding canDevicesMtx void removeExtraDevicesFromDeviceMap(std::vector descriptors) { @@ -632,7 +629,6 @@ void waitForNotifierAlarm(const Napi::CallbackInfo& info) { int32_t status; HAL_UpdateNotifierAlarm(m_notifier, HAL_GetFPGATime(&status) + time, &status); - // TODO(Noah): Don't discard the returned value (this function is marked as [nodiscard]) HAL_WaitForNotifierAlarm(m_notifier, &status); cb.Call(info.Env().Global(), {info.Env().Null(), Napi::Number::New(info.Env(), status)}); } @@ -658,62 +654,33 @@ void writeDfuToBin(const Napi::CallbackInfo& info) { cb.Call(info.Env().Global(), {info.Env().Null(), Napi::Number::New(info.Env(), status)}); } -void cleanupHeartbeatsRunning() { - // Erase removed CAN buses from heartbeatsRunning - std::scoped_lock lock{watchdogMtx, canDevicesMtx}; - for(int i = 0; i < heartbeatsRunning.size(); i++) { - auto deviceIterator = canDeviceMap.find(heartbeatsRunning[i]); - if (deviceIterator == canDeviceMap.end()) { - heartbeatsRunning.erase(heartbeatsRunning.begin() + i); - } - } -} - void heartbeatsWatchdog() { while (true) { - std::this_thread::sleep_for (std::chrono::milliseconds(250)); + std::this_thread::sleep_for (std::chrono::seconds(1)); - cleanupHeartbeatsRunning(); + { + // Erase removed CAN buses from heartbeatsRunning + std::scoped_lock lock{watchdogMtx, canDevicesMtx}; + for(int i = 0; i < heartbeatsRunning.size(); i++) { + auto deviceIterator = canDeviceMap.find(heartbeatsRunning[i]); + if (deviceIterator == canDeviceMap.end()) { + heartbeatsRunning.erase(heartbeatsRunning.begin() + i); + } + } + } std::scoped_lock lock{watchdogMtx}; if (heartbeatsRunning.size() < 1) { break; } - auto now = std::chrono::steady_clock::now(); + auto now = std::chrono::system_clock::now(); std::chrono::duration elapsed_seconds = now-latestHeartbeatAck; - if (elapsed_seconds.count() >= 1 && !heartbeatTimeoutExpired) { - // The heartbeat timeout just expired - heartbeatTimeoutExpired = true; - for(int i = 0; i < heartbeatsRunning.size(); i++) { - if (sparkHeartbeatMap.contains(heartbeatsRunning[i])) { - // Clear the scheduled heartbeat that has outdated data so that the updated one gets sent out immediately - _sendCANMessage(heartbeatsRunning[i], SPARK_HEARTBEAT_ID, disabledSparkHeartbeat, SPARK_HEARTBEAT_LENGTH, -1); - - _sendCANMessage(heartbeatsRunning[i], SPARK_HEARTBEAT_ID, disabledSparkHeartbeat, SPARK_HEARTBEAT_LENGTH, HEARTBEAT_PERIOD_MS); - } - if (revCommonHeartbeatMap.contains(heartbeatsRunning[i])) { - // Clear the scheduled heartbeat that has outdated data so that the updated one gets sent out immediately - _sendCANMessage(heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, disabledRevCommonHeartbeat, REV_COMMON_HEARTBEAT_LENGTH, -1); - - _sendCANMessage(heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, disabledRevCommonHeartbeat, REV_COMMON_HEARTBEAT_LENGTH, HEARTBEAT_PERIOD_MS); - } - } - } else if (elapsed_seconds.count() < 1 && heartbeatTimeoutExpired) { - // The heartbeat timeout is newly un-expired - heartbeatTimeoutExpired = false; + if (elapsed_seconds.count() > 1) { + uint8_t sparkMaxHeartbeat[] = {0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t revCommonHeartbeat[] = {0}; for(int i = 0; i < heartbeatsRunning.size(); i++) { - if (auto heartbeatEntry = sparkHeartbeatMap.find(heartbeatsRunning[i]); heartbeatEntry != sparkHeartbeatMap.end()) { - // Clear the scheduled heartbeat that has outdated data so that the updated one gets sent out immediately - _sendCANMessage(heartbeatsRunning[i], SPARK_HEARTBEAT_ID, heartbeatEntry->second.data(), SPARK_HEARTBEAT_LENGTH, -1); - - _sendCANMessage(heartbeatsRunning[i], SPARK_HEARTBEAT_ID, heartbeatEntry->second.data(), SPARK_HEARTBEAT_LENGTH, HEARTBEAT_PERIOD_MS); - } - if (auto heartbeatEntry = revCommonHeartbeatMap.find(heartbeatsRunning[i]); heartbeatEntry != revCommonHeartbeatMap.end()) { - // Clear the scheduled heartbeat that has outdated data so that the updated one gets sent out immediately - _sendCANMessage(heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, heartbeatEntry->second.data(), REV_COMMON_HEARTBEAT_LENGTH, -1); - - _sendCANMessage(heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, heartbeatEntry->second.data(), REV_COMMON_HEARTBEAT_LENGTH, HEARTBEAT_PERIOD_MS); - } + _sendCANMessage(heartbeatsRunning[i], 0x2052C80, sparkMaxHeartbeat, 8, -1); + _sendCANMessage(heartbeatsRunning[i], 0x00502C0, revCommonHeartbeat, 1, -1); } } } @@ -721,7 +688,7 @@ void heartbeatsWatchdog() { void ackHeartbeats(const Napi::CallbackInfo& info) { std::scoped_lock lock{watchdogMtx}; - latestHeartbeatAck = std::chrono::steady_clock::now(); + latestHeartbeatAck = std::chrono::system_clock::now(); } // Params: @@ -736,19 +703,14 @@ void startRevCommonHeartbeat(const Napi::CallbackInfo& info) { if (deviceIterator == canDeviceMap.end()) return; } - std::array payload = {1}; + uint8_t payload[] = {1}; + _sendCANMessage(descriptor, 0x00502C0, payload, 1, 20); std::scoped_lock lock{watchdogMtx}; - if (!heartbeatTimeoutExpired) { - _sendCANMessage(descriptor, REV_COMMON_HEARTBEAT_ID, payload.data(), REV_COMMON_HEARTBEAT_LENGTH, HEARTBEAT_PERIOD_MS); - } - - revCommonHeartbeatMap[descriptor] = payload; - if (heartbeatsRunning.size() == 0) { heartbeatsRunning.push_back(descriptor); - latestHeartbeatAck = std::chrono::steady_clock::now(); + latestHeartbeatAck = std::chrono::system_clock::now(); std::thread hb(heartbeatsWatchdog); hb.detach(); } else { @@ -767,7 +729,7 @@ void setSparkMaxHeartbeatData(const Napi::CallbackInfo& info) { std::string descriptor = info[0].As().Utf8Value(); Napi::Array dataParam = info[1].As(); - std::array heartbeat = {0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t heartbeat[] = {0, 0, 0, 0, 0, 0, 0, 0}; { std::scoped_lock lock{canDevicesMtx}; @@ -775,45 +737,34 @@ void setSparkMaxHeartbeatData(const Napi::CallbackInfo& info) { if (deviceIterator == canDeviceMap.end()) return; } + _sendCANMessage(descriptor, 0x2052C80, heartbeat, 8, -1); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + int sum = 0; for (uint32_t i = 0; i < dataParam.Length(); i++) { heartbeat[i] = dataParam.Get(i).As().Uint32Value(); sum+= heartbeat[i]; } - std::scoped_lock lock{watchdogMtx}; - - if (!heartbeatTimeoutExpired) { - // Clear the scheduled heartbeat that has outdated data so that the updated one gets sent out immediately - _sendCANMessage(descriptor, SPARK_HEARTBEAT_ID, heartbeat.data(), SPARK_HEARTBEAT_LENGTH, -1); - - _sendCANMessage(descriptor, SPARK_HEARTBEAT_ID, heartbeat.data(), SPARK_HEARTBEAT_LENGTH, HEARTBEAT_PERIOD_MS); + if (sum == 0) { + _sendCANMessage(descriptor, 0x2052C80, heartbeat, 8, -1); } + else { + _sendCANMessage(descriptor, 0x2052C80, heartbeat, 8, 10); - sparkHeartbeatMap[descriptor] = heartbeat; + std::scoped_lock lock{watchdogMtx}; - if (heartbeatsRunning.size() == 0) { - heartbeatsRunning.push_back(descriptor); - latestHeartbeatAck = std::chrono::steady_clock::now(); - std::thread hb(heartbeatsWatchdog); - hb.detach(); - } else { - for(int i = 0; i < heartbeatsRunning.size(); i++) { - if (heartbeatsRunning[i].compare(descriptor) == 0) return; + if (heartbeatsRunning.size() == 0) { + heartbeatsRunning.push_back(descriptor); + latestHeartbeatAck = std::chrono::system_clock::now(); + std::thread hb(heartbeatsWatchdog); + hb.detach(); + } else { + for(int i = 0; i < heartbeatsRunning.size(); i++) { + if (heartbeatsRunning[i].compare(descriptor) == 0) return; + } + heartbeatsRunning.push_back(descriptor); } - heartbeatsRunning.push_back(descriptor); } } -void stopHeartbeats(const Napi::CallbackInfo& info) { - std::string descriptor = info[0].As().Utf8Value(); - bool sendDisabledHeartbeatsFirst = info[1].As().Value(); - - // 0 sends and then cancels, -1 cancels without sending - const int repeatPeriod = sendDisabledHeartbeatsFirst ? 0 : -1; - - std::scoped_lock lock{watchdogMtx}; - // Send disabled SPARK and REV common heartbeats and un-schedule them for the future - _sendCANMessage(descriptor, SPARK_HEARTBEAT_ID, disabledSparkHeartbeat, SPARK_HEARTBEAT_LENGTH, repeatPeriod); - _sendCANMessage(descriptor, REV_COMMON_HEARTBEAT_ID, disabledRevCommonHeartbeat, REV_COMMON_HEARTBEAT_LENGTH, repeatPeriod); -} From 5d0a1a516fcb802d264ea559e3e731ae0af835b0 Mon Sep 17 00:00:00 2001 From: QwertyChouskie Date: Sun, 2 Jun 2024 23:33:20 -0700 Subject: [PATCH 02/30] macOS: Compilation now succeeds, linking still fails though Tested on M3 Pro Apple Silicon (aarch64) --- binding.gyp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/binding.gyp b/binding.gyp index 919189e..245d357 100644 --- a/binding.gyp +++ b/binding.gyp @@ -37,6 +37,10 @@ 'RuntimeLibrary': 0 }, }, + "xcode_settings": { + "CLANG_CXX_LANGUAGE_STANDARD": "c++20", + "OTHER_CPLUSPLUSFLAGS": ["-fexceptions"] + }, "cflags_cc!": ["-std=c++20", '-fno-exceptions'], "cflags!": ["-std=c++20", '-fno-exceptions'], } From 7362fe8c10e43fb399c14ee915e14ece78b6db5a Mon Sep 17 00:00:00 2001 From: Garrett Summerfield Date: Wed, 5 Jun 2024 11:47:45 -0500 Subject: [PATCH 03/30] Manifest GitHub Actions workflows Manifest workflows, just to get checks of building and releases at least created. --- .github/workflows/build.yml | 34 +++++++++++++++++++++++++++++ .github/workflows/release.yml | 41 +++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..7beb4b4 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,34 @@ +name: Build + +on: + push: + branches: + - main + pull_request: + branches: + - '*' + +jobs: + build: + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.os }} + name: "Build - ${{ matrix.os }}" + + steps: + - uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install dependencies + run: npm install + + - name: Build + run: npm run build + + - name: Test + run: npm test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..dbccac1 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,41 @@ +name: Build + +on: + push: + branches: + - main + pull_request: + branches: + - '*' + +jobs: + build: + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.os }} + name: "Build - ${{ matrix.os }}" + + steps: + - uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install dependencies + run: npm install + + - name: Build + run: npm run build + + - name: Create release + uses: softprops/action-gh-release@v2 + with: + files: dist/* + tag_name: ${{ github.ref }} + name: ${{ github.ref }} + body: | + This is a release for version ${{ github.ref }}. + It contains the compiled files from the build process. \ No newline at end of file From 7278259fb05ed1483be110334bb745edd82607ff Mon Sep 17 00:00:00 2001 From: QwertyChouskie Date: Wed, 5 Jun 2024 19:44:12 -0700 Subject: [PATCH 04/30] build.yml: Install distutils https://github.com/actions/runner/issues/2958#issuecomment-2109524490 --- .github/workflows/build.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7beb4b4..0784151 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,6 +24,14 @@ jobs: with: node-version: '20' + - uses: actions/setup-python@v5 + with: + python-version: '3.10' + cache: 'pip' + - name: Install Python setup tools + run: | + pip install setuptools + - name: Install dependencies run: npm install From c58a3fdda81ff1ddee9b60cc013ab85db2c2c332 Mon Sep 17 00:00:00 2001 From: QwertyChouskie Date: Wed, 5 Jun 2024 19:48:53 -0700 Subject: [PATCH 05/30] build.yml: Disable caching `pip` (unbreak build) --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0784151..8b3e1cd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -27,7 +27,6 @@ jobs: - uses: actions/setup-python@v5 with: python-version: '3.10' - cache: 'pip' - name: Install Python setup tools run: | pip install setuptools From 439c5d08fd2ffc1c212f4a22404e31ca7610f370 Mon Sep 17 00:00:00 2001 From: QwertyChouskie Date: Wed, 5 Jun 2024 19:51:31 -0700 Subject: [PATCH 06/30] release.yml: Install distutils https://github.com/actions/runner/issues/2958#issuecomment-2109524490 --- .github/workflows/release.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index dbccac1..d7707cc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,6 +24,13 @@ jobs: with: node-version: '20' + - uses: actions/setup-python@v5 + with: + python-version: '3.10' + - name: Install Python setup tools + run: | + pip install setuptools + - name: Install dependencies run: npm install @@ -38,4 +45,4 @@ jobs: name: ${{ github.ref }} body: | This is a release for version ${{ github.ref }}. - It contains the compiled files from the build process. \ No newline at end of file + It contains the compiled files from the build process. From 92e225fd2b696cb8d4e0854f4623e3abc14eeab2 Mon Sep 17 00:00:00 2001 From: QwertyChouskie Date: Wed, 5 Jun 2024 19:52:09 -0700 Subject: [PATCH 07/30] release.yml: Fix action name --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d7707cc..f0ab771 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,4 +1,4 @@ -name: Build +name: Release on: push: From c67db7fbf74d82e71682f62f6f5a8477df2cdc66 Mon Sep 17 00:00:00 2001 From: Garrett Summerfield Date: Wed, 5 Jun 2024 21:54:01 -0500 Subject: [PATCH 08/30] Disable job cancel on build failure --- .github/workflows/build.yml | 8 +------- .github/workflows/release.yml | 3 ++- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8b3e1cd..184dc3f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,6 +11,7 @@ on: jobs: build: strategy: + fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] runs-on: ${{ matrix.os }} @@ -24,13 +25,6 @@ jobs: with: node-version: '20' - - uses: actions/setup-python@v5 - with: - python-version: '3.10' - - name: Install Python setup tools - run: | - pip install setuptools - - name: Install dependencies run: npm install diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f0ab771..2f69322 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,10 +11,11 @@ on: jobs: build: strategy: + fail-fast: false matrix: os: [ubuntu-latest, windows-latest, macos-latest] runs-on: ${{ matrix.os }} - name: "Build - ${{ matrix.os }}" + name: "Release - ${{ matrix.os }}" steps: - uses: actions/checkout@v4 From b54a7633dff5d23bfd2ce9b3fe498d3b38dbb379 Mon Sep 17 00:00:00 2001 From: Garrett Summerfield Date: Wed, 5 Jun 2024 21:55:38 -0500 Subject: [PATCH 09/30] Fix CI release job on every push to `main` --- .github/workflows/release.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2f69322..8db1f7d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,11 +2,8 @@ name: Release on: push: - branches: - - main - pull_request: - branches: - - '*' + tags: + - 'v*' jobs: build: From ab1a3c9ef0b4d9ad3de39049ba6e90916d0a158a Mon Sep 17 00:00:00 2001 From: Garrett Summerfield Date: Wed, 5 Jun 2024 22:05:18 -0500 Subject: [PATCH 10/30] Partial revert of commit `c67db7fbf74d82e71682f62f6f5a8477df2cdc66` --- .github/workflows/build.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 184dc3f..561cb72 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,6 +25,14 @@ jobs: with: node-version: '20' + - uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Install Python setup tools + run: | + pip install setuptools + - name: Install dependencies run: npm install From 45ab8d88415e5c4e285e62ce0ed545926122d1e0 Mon Sep 17 00:00:00 2001 From: Garrett Summerfield Date: Tue, 11 Jun 2024 21:22:41 -0500 Subject: [PATCH 11/30] Update download-CanBridge.mjs Points to the correct repository now instead of the upstream repository --- scripts/download-CanBridge.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/download-CanBridge.mjs b/scripts/download-CanBridge.mjs index 265caab..8c4da23 100644 --- a/scripts/download-CanBridge.mjs +++ b/scripts/download-CanBridge.mjs @@ -4,7 +4,7 @@ import axios from 'axios'; import AdmZip from 'adm-zip'; const canBridgeTag = "v2.3.0"; -const canBridgeReleaseAssetUrlPrefix = `https://github.com/REVrobotics/CANBridge/releases/download/${canBridgeTag}`; +const canBridgeReleaseAssetUrlPrefix = `https://github.com/unofficial-rev-port/CANBridge/releases/download/${canBridgeTag}`; const externalCompileTimeDepsPath = 'externalCompileTimeDeps'; const runtimeArtifactsPath = path.join('prebuilds', 'win32-x64'); From 50943a3fb7d02867f4a9b3b6561b5fc731c7a859 Mon Sep 17 00:00:00 2001 From: Garrett Summerfield Date: Sat, 22 Jun 2024 03:42:57 -0500 Subject: [PATCH 12/30] Major refactor for handling CANBridge Added proper support for macOS, Linux, ARM64, and ARM32 based systems. Rewrote handling artifacts from unzipping, to moving artifacts to correct directories based on what platforms are downloaded and what is currently running on. Added documentation to helper functions. --- scripts/download-CanBridge.mjs | 155 +++++++++++++++++++++++++++++---- 1 file changed, 137 insertions(+), 18 deletions(-) diff --git a/scripts/download-CanBridge.mjs b/scripts/download-CanBridge.mjs index 8c4da23..836d147 100644 --- a/scripts/download-CanBridge.mjs +++ b/scripts/download-CanBridge.mjs @@ -2,47 +2,128 @@ import * as fs from "fs"; import * as path from "path"; import axios from 'axios'; import AdmZip from 'adm-zip'; +import { platform, arch } from 'os'; -const canBridgeTag = "v2.3.0"; +const canBridgeTag = "v2.3.1"; const canBridgeReleaseAssetUrlPrefix = `https://github.com/unofficial-rev-port/CANBridge/releases/download/${canBridgeTag}`; const externalCompileTimeDepsPath = 'externalCompileTimeDeps'; -const runtimeArtifactsPath = path.join('prebuilds', 'win32-x64'); +const runtimeArtifactsPath = { + win: 'prebuilds/win32-x64', + osx: 'prebuilds/darwin-x64', + osxArm: 'prebuilds/darwin-arm64', + linux: 'prebuilds/linux-x64', + linuxArm: 'prebuilds/linux-arm64', + linuxArm32: 'prebuilds/linux-arm32' +}; const tempDir = 'temp'; try { - await Promise.all(Array.of( - downloadCanBridgeArtifact('CANBridge.lib', externalCompileTimeDepsPath), - downloadCanBridgeArtifact('CANBridge.dll', runtimeArtifactsPath), - downloadCanBridgeArtifact('wpiHal.lib', externalCompileTimeDepsPath), - downloadCanBridgeArtifact('wpiHal.dll', runtimeArtifactsPath), - downloadCanBridgeArtifact('wpiutil.lib', externalCompileTimeDepsPath), - downloadCanBridgeArtifact('wpiutil.dll', runtimeArtifactsPath), - downloadCanBridgeArtifact('headers.zip', tempDir), - )); - + // TODO: Do not hardcode the filenames, instead get them from the GitHub API -> Look at Octokit: https://github.com/octokit/octokit.js + await Promise.all([ + 'CANBridge-linuxarm32-LinuxARM32.zip', + 'CANBridge-linuxarm64-LinuxARM64.zip', + 'CANBridge-linuxx86-64-Linux64.zip', + 'CANBridge-osxuniversal-MacOS64.zip', + 'CANBridge-osxuniversal-MacOSARM64.zip', + 'CANBridge-windowsx86-64-Win64.zip', + 'headers.zip' + ].map(filename => downloadCanBridgeArtifact(filename))); console.log("CANBridge download completed"); - console.log("Extracting headers"); + + console.log("Extracting headers"); + const zipFiles = fs.readdirSync(tempDir).filter(filename => filename.endsWith('.zip') && filename !== 'headers.zip'); + for (const filename of zipFiles) { + await unzipCanBridgeArtifact(filename, tempDir); + } const headersZip = new AdmZip(path.join(tempDir, "headers.zip")); + headersZip.extractAllTo(path.join(externalCompileTimeDepsPath, 'include')); + console.log("Headers extracted"); + + moveRuntimeDeps(); - await headersZip.extractAllTo(path.join(externalCompileTimeDepsPath, 'include')); + moveCompileTimeDeps(); } catch (e) { if (axios.isAxiosError(e) && e.request) { - console.error(`Failed to download CANBridge file ${e.request.protocol}//${e.request.host}/${e.request.path}`); + console.error(`Failed to download CANBridge file ${e.request.protocol}//${e.request.host}${e.request.path}`); } else { - console.error(`Failed to download CANBridge`); + console.error(`Other error occurred: ${e.message}`); // For non-axios errors, the stacktrace will likely be helpful throw e; } process.exit(1); } finally { if (fs.existsSync(tempDir)) { - fs.rmSync(tempDir, { recursive: true }); + fs.rmSync(tempDir, { recursive: true, force: true}); } } -async function downloadCanBridgeArtifact(filename, destDir) { +/** + * Move external compile time dependencies to the correct directory + * + * This function is used to move the external compile time dependencies to the correct directory based on the platform and architecture from downloaded artifacts + */ +function moveCompileTimeDeps() { + console.log("Moving external compile time dependencies to correct directories"); + if (platform() === 'win32') { + const deps = ['CANBridge.lib', 'wpiHal.lib', 'wpiutil.lib']; + deps.forEach(dep => moveExternalCompileTimeDeps(path.join('win32-x64', dep))); + } else if (platform() === 'darwin') { + const deps = ['libCANBridge.a']; + const archDepMap = { + x64: 'darwin-x64', + arm64: 'darwin-arm64' + }; + deps.forEach(dep => moveExternalCompileTimeDeps(path.join(archDepMap[arch()], dep))); + } else if (platform() === 'linux') { + const deps = ['libCANBridge.a']; + const archDepMap = { + x64: 'linux-x64', + arm64: 'linux-arm64', + arm: 'linux-arm32' + }; + deps.forEach(dep => moveExternalCompileTimeDeps(path.join(archDepMap[arch()], dep))); + } + console.log("External compile time dependencies moved to correct directories"); +} + +/** + * Move runtime dependencies to the correct directory + * + * This function is used to move the runtime dependencies to the correct directory based on the platform and architecture from downloaded artifacts + */ +function moveRuntimeDeps() { + console.log("Moving artifacts to correct directories"); + if (platform() === 'win32') { + const deps = ['CANBridge.dll', 'wpiHal.dll', 'wpiutil.dll']; + deps.forEach(dep => moveRuntimeArtifactsDeps(path.join('win32-x64', dep), runtimeArtifactsPath.win)); + } else if (platform() === 'darwin') { + const deps = ['libCANBridge.dylib', 'libwpiHal.dylib', 'libwpiutil.dylib']; + const archDepMap = { + x64: runtimeArtifactsPath.osx, + arm64: runtimeArtifactsPath.osxArm + }; + deps.forEach(dep => moveRuntimeArtifactsDeps(path.join(archDepMap[arch()], dep), archDepMap[arch()])); + } else if (platform() === 'linux') { + const deps = ['libCANBridge.so', 'libwpiHal.so', 'libwpiutil.so']; + const archDepMap = { + x64: runtimeArtifactsPath.linux, + arm64: runtimeArtifactsPath.linuxArm, + arm: runtimeArtifactsPath.linuxArm32 + }; + deps.forEach(dep => moveRuntimeArtifactsDeps(path.join(archDepMap[arch()], dep), archDepMap[arch()])); + } + console.log("CANBridge artifacts moved to correct directories"); +} + +/** + * Download artifacts from the CANBridge GitHub release page + * + * @param {*} filename filename of the artifact to download + * @param {*} destDir destination directory to save the artifact, defaults to tempDir + */ +async function downloadCanBridgeArtifact(filename, destDir = tempDir) { fs.mkdirSync(destDir, { recursive: true }); const response = await axios.get(`${canBridgeReleaseAssetUrlPrefix}/${filename}`, { responseType: "stream" }); const fileStream = fs.createWriteStream(`${destDir}/${filename}`); @@ -51,3 +132,41 @@ async function downloadCanBridgeArtifact(filename, destDir) { fileStream.on('finish', resolve); }); } + +/** + * Unzip the CANBridge artifacts + * + * @param {string} filename - filename of the artifact to unzip + * @param {string} destDir - destination directory to unzip the artifact + */ +async function unzipCanBridgeArtifact(filename, destDir) { + const zip = new AdmZip(`${destDir}/${filename}`); + let filepath; + if (filename.includes('linuxarm32')) filepath = "linux-arm32"; + else if (filename.includes('linuxarm64')) filepath = "linux-arm64"; + else if (filename.includes('linuxx86-64')) filepath = "linux-x64"; + else if (filename.includes('MacOS64')) filepath = "darwin-x64"; + else if (filename.includes('MacOSARM64')) filepath = "darwin-arm64"; + else if (filename.includes('windowsx86-64')) filepath = "win32-x64"; + zip.extractAllTo(`${destDir}/${filepath}`); +} + +/** + * Move runtime artifacts to the correct directory + * + * @param {*} filename filename of the artifact to move + * @param {*} destDir destination directory to save the artifact + */ +function moveRuntimeArtifactsDeps(filename, destDir) { + fs.mkdirSync(destDir, { recursive: true }); + fs.renameSync(path.join(tempDir, filename), path.join(destDir, path.basename(filename))); +} + +/** + * Move External Compile Time Dependencies to the correct directory + * + * @param {*} filename filename of the artifact to move + */ +function moveExternalCompileTimeDeps(filename) { + fs.renameSync(path.join(tempDir, filename), path.join(externalCompileTimeDepsPath, path.basename(filename))); +} \ No newline at end of file From 3929fbd560343ce5deb6d4e133ef2159092135b1 Mon Sep 17 00:00:00 2001 From: Garrett Summerfield Date: Sat, 22 Jun 2024 05:21:27 -0500 Subject: [PATCH 13/30] Fix multiarch movement for CANBridge --- scripts/download-CanBridge.mjs | 38 +++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/scripts/download-CanBridge.mjs b/scripts/download-CanBridge.mjs index 836d147..faab9e6 100644 --- a/scripts/download-CanBridge.mjs +++ b/scripts/download-CanBridge.mjs @@ -54,9 +54,9 @@ try { } process.exit(1); } finally { - if (fs.existsSync(tempDir)) { - fs.rmSync(tempDir, { recursive: true, force: true}); - } + //if (fs.existsSync(tempDir)) { + // fs.rmSync(tempDir, { recursive: true, force: true}); + //} } /** @@ -66,6 +66,9 @@ try { */ function moveCompileTimeDeps() { console.log("Moving external compile time dependencies to correct directories"); + if (!fs.existsSync(externalCompileTimeDepsPath)) { + fs.mkdirSync(externalCompileTimeDepsPath, { recursive: true }); + } if (platform() === 'win32') { const deps = ['CANBridge.lib', 'wpiHal.lib', 'wpiutil.lib']; deps.forEach(dep => moveExternalCompileTimeDeps(path.join('win32-x64', dep))); @@ -95,24 +98,31 @@ function moveCompileTimeDeps() { */ function moveRuntimeDeps() { console.log("Moving artifacts to correct directories"); + if (!fs.existsSync('prebuilds')) { + fs.mkdirSync('prebuilds', { recursive: true }); + } if (platform() === 'win32') { const deps = ['CANBridge.dll', 'wpiHal.dll', 'wpiutil.dll']; deps.forEach(dep => moveRuntimeArtifactsDeps(path.join('win32-x64', dep), runtimeArtifactsPath.win)); } else if (platform() === 'darwin') { const deps = ['libCANBridge.dylib', 'libwpiHal.dylib', 'libwpiutil.dylib']; - const archDepMap = { - x64: runtimeArtifactsPath.osx, - arm64: runtimeArtifactsPath.osxArm - }; - deps.forEach(dep => moveRuntimeArtifactsDeps(path.join(archDepMap[arch()], dep), archDepMap[arch()])); + if (arch() === 'x64') { + deps.forEach(dep => moveRuntimeArtifactsDeps(path.join('darwin-x64', dep), runtimeArtifactsPath.osx)); + } + if (arch() === 'arm64') { + deps.forEach(dep => moveRuntimeArtifactsDeps(path.join('darwin-arm64', dep), runtimeArtifactsPath.osxArm)); + } } else if (platform() === 'linux') { const deps = ['libCANBridge.so', 'libwpiHal.so', 'libwpiutil.so']; - const archDepMap = { - x64: runtimeArtifactsPath.linux, - arm64: runtimeArtifactsPath.linuxArm, - arm: runtimeArtifactsPath.linuxArm32 - }; - deps.forEach(dep => moveRuntimeArtifactsDeps(path.join(archDepMap[arch()], dep), archDepMap[arch()])); + if (arch() === 'x64') { + deps.forEach(dep => moveRuntimeArtifactsDeps(path.join('linux-x64', dep), runtimeArtifactsPath.linux)); + } + if (arch() === 'arm64') { + deps.forEach(dep => moveRuntimeArtifactsDeps(path.join('linux-arm64', dep), runtimeArtifactsPath.linuxArm)); + } + if (arch() === 'arm') { + deps.forEach(dep => moveRuntimeArtifactsDeps(path.join('linux-arm32', dep), runtimeArtifactsPath.linuxArm32)); + } } console.log("CANBridge artifacts moved to correct directories"); } From b609d9625d52f8b7fd4475b3d9c5fadb7e93e71b Mon Sep 17 00:00:00 2001 From: Garrett Summerfield Date: Sun, 23 Jun 2024 00:19:50 -0500 Subject: [PATCH 14/30] Add macOS and Linux platforms New platforms are able to link and build. Tested on macOS. --- binding.gyp | 55 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/binding.gyp b/binding.gyp index 245d357..85bce16 100644 --- a/binding.gyp +++ b/binding.gyp @@ -5,7 +5,7 @@ 'sources': [ 'src/addon.cc', 'src/canWrapper.cc', - ], + ], 'include_dirs': [ "src/", "externalCompileTimeDeps/include", @@ -15,21 +15,46 @@ "NAPI_VERSION=<(napi_build_version)" ], 'dependencies': [" Date: Sun, 23 Jun 2024 01:28:23 -0500 Subject: [PATCH 15/30] Enable exception handling to allow Linux compilation Enabling exceptions for the compiler causes the project to build without issues, as the compiler would not like having no exception support similar to how macOS operates. --- binding.gyp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/binding.gyp b/binding.gyp index 85bce16..f9d764d 100644 --- a/binding.gyp +++ b/binding.gyp @@ -66,8 +66,8 @@ "CLANG_CXX_LANGUAGE_STANDARD": "c++20", "OTHER_CPLUSPLUSFLAGS": ["-fexceptions"] }, - "cflags_cc!": ["-std=c++20", '-fno-exceptions'], - "cflags!": ["-std=c++20", '-fno-exceptions'], + "cflags_cc": ["-std=c++20", '-fexceptions'], + "cflags": ["-std=c++20", '-fexceptions'], } ] } From 70988aa738f5f9cd6c23ef950e2882491cea5ace Mon Sep 17 00:00:00 2001 From: QwertyChouskie Date: Sun, 23 Jun 2024 22:37:17 -0700 Subject: [PATCH 16/30] Unbreak macOS arm64 build Might need more work but at least it doesn't error --- scripts/download-CanBridge.mjs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/scripts/download-CanBridge.mjs b/scripts/download-CanBridge.mjs index faab9e6..695f52b 100644 --- a/scripts/download-CanBridge.mjs +++ b/scripts/download-CanBridge.mjs @@ -106,12 +106,7 @@ function moveRuntimeDeps() { deps.forEach(dep => moveRuntimeArtifactsDeps(path.join('win32-x64', dep), runtimeArtifactsPath.win)); } else if (platform() === 'darwin') { const deps = ['libCANBridge.dylib', 'libwpiHal.dylib', 'libwpiutil.dylib']; - if (arch() === 'x64') { - deps.forEach(dep => moveRuntimeArtifactsDeps(path.join('darwin-x64', dep), runtimeArtifactsPath.osx)); - } - if (arch() === 'arm64') { - deps.forEach(dep => moveRuntimeArtifactsDeps(path.join('darwin-arm64', dep), runtimeArtifactsPath.osxArm)); - } + deps.forEach(dep => moveRuntimeArtifactsDeps(path.join('darwin-x64', dep), runtimeArtifactsPath.osx)); } else if (platform() === 'linux') { const deps = ['libCANBridge.so', 'libwpiHal.so', 'libwpiutil.so']; if (arch() === 'x64') { From 75266289ed0d0e9034ca58f76e77731fd9dda79d Mon Sep 17 00:00:00 2001 From: QwertyChouskie Date: Sun, 23 Jun 2024 22:57:53 -0700 Subject: [PATCH 17/30] Fix some warnings --- src/canWrapper.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/canWrapper.cc b/src/canWrapper.cc index b32be7a..2eb3645 100644 --- a/src/canWrapper.cc +++ b/src/canWrapper.cc @@ -239,7 +239,7 @@ Napi::Object receiveMessage(const Napi::CallbackInfo& info) { size_t messageSize = message->GetSize(); const uint8_t* messageData = message->GetData(); Napi::Array napiMessage = Napi::Array::New(env, messageSize); - for (int i = 0; i < messageSize; i++) { + for (size_t i = 0; i < messageSize; i++) { napiMessage[i] = messageData[i]; } Napi::Object messageInfo = Napi::Object::New(env); @@ -332,7 +332,7 @@ Napi::Number openStreamSession(const Napi::CallbackInfo& info) { try { rev::usb::CANStatus status = device->OpenStreamSession(&sessionHandle, filter, maxSize); if (status != rev::usb::CANStatus::kOk) { - Napi::Error::New(env, "Opening stream session failed with error code "+(int)status).ThrowAsJavaScriptException(); + Napi::Error::New(env, "Opening stream session failed with error code "+std::to_string((int)status)).ThrowAsJavaScriptException(); } else { return Napi::Number::New(env, sessionHandle); } @@ -661,7 +661,7 @@ void heartbeatsWatchdog() { { // Erase removed CAN buses from heartbeatsRunning std::scoped_lock lock{watchdogMtx, canDevicesMtx}; - for(int i = 0; i < heartbeatsRunning.size(); i++) { + for(size_t i = 0; i < heartbeatsRunning.size(); i++) { auto deviceIterator = canDeviceMap.find(heartbeatsRunning[i]); if (deviceIterator == canDeviceMap.end()) { heartbeatsRunning.erase(heartbeatsRunning.begin() + i); @@ -678,7 +678,7 @@ void heartbeatsWatchdog() { if (elapsed_seconds.count() > 1) { uint8_t sparkMaxHeartbeat[] = {0, 0, 0, 0, 0, 0, 0, 0}; uint8_t revCommonHeartbeat[] = {0}; - for(int i = 0; i < heartbeatsRunning.size(); i++) { + for(size_t i = 0; i < heartbeatsRunning.size(); i++) { _sendCANMessage(heartbeatsRunning[i], 0x2052C80, sparkMaxHeartbeat, 8, -1); _sendCANMessage(heartbeatsRunning[i], 0x00502C0, revCommonHeartbeat, 1, -1); } @@ -714,7 +714,7 @@ void startRevCommonHeartbeat(const Napi::CallbackInfo& info) { std::thread hb(heartbeatsWatchdog); hb.detach(); } else { - for(int i = 0; i < heartbeatsRunning.size(); i++) { + for(size_t i = 0; i < heartbeatsRunning.size(); i++) { if (heartbeatsRunning[i].compare(descriptor) == 0) return; } heartbeatsRunning.push_back(descriptor); @@ -760,7 +760,7 @@ void setSparkMaxHeartbeatData(const Napi::CallbackInfo& info) { std::thread hb(heartbeatsWatchdog); hb.detach(); } else { - for(int i = 0; i < heartbeatsRunning.size(); i++) { + for(size_t i = 0; i < heartbeatsRunning.size(); i++) { if (heartbeatsRunning[i].compare(descriptor) == 0) return; } heartbeatsRunning.push_back(descriptor); From 4b14281cc1d251e6c3c0371befcac616b051b464 Mon Sep 17 00:00:00 2001 From: Garrett Summerfield Date: Sun, 30 Jun 2024 18:39:01 -0500 Subject: [PATCH 18/30] Partial fix for Windows build regression On Windows builds, there was an issue with dependencies not copying and therefore not linking when building native modules, this is now fixed. --- binding.gyp | 9 +++++++++ package.json | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/binding.gyp b/binding.gyp index f9d764d..7b0becf 100644 --- a/binding.gyp +++ b/binding.gyp @@ -38,6 +38,15 @@ '<(module_root_dir)/externalCompileTimeDeps/wpiHal.lib', '<(module_root_dir)/externalCompileTimeDeps/wpiutil.lib', ], + 'copies': [{ + 'destination': './build/Release', + 'files': [ + # These files were placed in the prebuilds folder by download-CanBridge.mjs + '<(module_root_dir)/prebuilds/win32-x64/CANBridge.dll', + '<(module_root_dir)/prebuilds/win32-x64/wpiHal.dll', + '<(module_root_dir)/prebuilds/win32-x64/wpiutil.dll', + ] + }], }], ['OS=="linux"', { 'libraries': [ diff --git a/package.json b/package.json index cb53514..bb9ca15 100644 --- a/package.json +++ b/package.json @@ -24,9 +24,9 @@ "typescript": "^5.0.2" }, "scripts": { - "install": "node-gyp-build \"node scripts/download-CanBridge.mjs\"", + "install": "node scripts/download-CanBridge.mjs && node-gyp rebuild", "prepublishOnly": "node scripts/download-CanBridge.mjs && tsc && prebuildify --napi", - "pretest": "node-gyp-build && tsc", + "pretest": "node-gyp rebuild && tsc", "test": "node --napi-modules test/test_binding.js" }, "engines": { From 823082537901f7307520ce317cfa6b1e388b0e7c Mon Sep 17 00:00:00 2001 From: Garrett Summerfield Date: Sun, 30 Jun 2024 21:21:37 -0500 Subject: [PATCH 19/30] chore: Bump CANBridge tag Removed duplicated builds and renamed builds of CANBridge. --- scripts/download-CanBridge.mjs | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/scripts/download-CanBridge.mjs b/scripts/download-CanBridge.mjs index 695f52b..bff8ec3 100644 --- a/scripts/download-CanBridge.mjs +++ b/scripts/download-CanBridge.mjs @@ -4,14 +4,13 @@ import axios from 'axios'; import AdmZip from 'adm-zip'; import { platform, arch } from 'os'; -const canBridgeTag = "v2.3.1"; +const canBridgeTag = "v2.3.2"; const canBridgeReleaseAssetUrlPrefix = `https://github.com/unofficial-rev-port/CANBridge/releases/download/${canBridgeTag}`; const externalCompileTimeDepsPath = 'externalCompileTimeDeps'; const runtimeArtifactsPath = { win: 'prebuilds/win32-x64', - osx: 'prebuilds/darwin-x64', - osxArm: 'prebuilds/darwin-arm64', + osx: 'prebuilds/darwin-osxuniversal', linux: 'prebuilds/linux-x64', linuxArm: 'prebuilds/linux-arm64', linuxArm32: 'prebuilds/linux-arm32' @@ -21,11 +20,10 @@ const tempDir = 'temp'; try { // TODO: Do not hardcode the filenames, instead get them from the GitHub API -> Look at Octokit: https://github.com/octokit/octokit.js await Promise.all([ - 'CANBridge-linuxarm32-LinuxARM32.zip', - 'CANBridge-linuxarm64-LinuxARM64.zip', + 'CANBridge-linuxarm32.zip', + 'CANBridge-linuxarm64.zip', 'CANBridge-linuxx86-64-Linux64.zip', - 'CANBridge-osxuniversal-MacOS64.zip', - 'CANBridge-osxuniversal-MacOSARM64.zip', + 'CANBridge-osxuniversal-macOS.zip', 'CANBridge-windowsx86-64-Win64.zip', 'headers.zip' ].map(filename => downloadCanBridgeArtifact(filename))); @@ -74,11 +72,7 @@ function moveCompileTimeDeps() { deps.forEach(dep => moveExternalCompileTimeDeps(path.join('win32-x64', dep))); } else if (platform() === 'darwin') { const deps = ['libCANBridge.a']; - const archDepMap = { - x64: 'darwin-x64', - arm64: 'darwin-arm64' - }; - deps.forEach(dep => moveExternalCompileTimeDeps(path.join(archDepMap[arch()], dep))); + deps.forEach(dep => moveExternalCompileTimeDeps(path.join('darwin-osxuniversal', dep))); } else if (platform() === 'linux') { const deps = ['libCANBridge.a']; const archDepMap = { @@ -106,7 +100,7 @@ function moveRuntimeDeps() { deps.forEach(dep => moveRuntimeArtifactsDeps(path.join('win32-x64', dep), runtimeArtifactsPath.win)); } else if (platform() === 'darwin') { const deps = ['libCANBridge.dylib', 'libwpiHal.dylib', 'libwpiutil.dylib']; - deps.forEach(dep => moveRuntimeArtifactsDeps(path.join('darwin-x64', dep), runtimeArtifactsPath.osx)); + deps.forEach(dep => moveRuntimeArtifactsDeps(path.join('darwin-osxuniversal', dep), runtimeArtifactsPath.osx)); } else if (platform() === 'linux') { const deps = ['libCANBridge.so', 'libwpiHal.so', 'libwpiutil.so']; if (arch() === 'x64') { @@ -150,8 +144,7 @@ async function unzipCanBridgeArtifact(filename, destDir) { if (filename.includes('linuxarm32')) filepath = "linux-arm32"; else if (filename.includes('linuxarm64')) filepath = "linux-arm64"; else if (filename.includes('linuxx86-64')) filepath = "linux-x64"; - else if (filename.includes('MacOS64')) filepath = "darwin-x64"; - else if (filename.includes('MacOSARM64')) filepath = "darwin-arm64"; + else if (filename.includes('osxuniversal')) filepath = "darwin-osxuniversal"; else if (filename.includes('windowsx86-64')) filepath = "win32-x64"; zip.extractAllTo(`${destDir}/${filepath}`); } From c67f0e385335d6dfe00798306c821a95cb3ff49f Mon Sep 17 00:00:00 2001 From: Garrett Summerfield Date: Sun, 30 Jun 2024 21:46:01 -0500 Subject: [PATCH 20/30] fix: Reimplement stopHeartbeats function to fix MSVC builds The stopHeartbeats function was removed in a previous commit, which caused MSVC builds to break. This commit re-adds the function to fix the build. The function will need to be reimplemented with the current codebase, as of right now this does nothing. --- src/canWrapper.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/canWrapper.cc b/src/canWrapper.cc index 2eb3645..a499d05 100644 --- a/src/canWrapper.cc +++ b/src/canWrapper.cc @@ -768,3 +768,11 @@ void setSparkMaxHeartbeatData(const Napi::CallbackInfo& info) { } } +/** + * This function was removed from commit b0ca096624286b1e975eaaa816e38599933b7e84, which broke MSVC builds. + * It has been re-added here to fix the build. + */ +void stopHeartbeats(const Napi::CallbackInfo& info) { + //! TODO: Reimplement this function with current codebase + Napi::Env env = info.Env(); +} \ No newline at end of file From 3f673e60541753fb33cc359910633c858c0c9889 Mon Sep 17 00:00:00 2001 From: QwertyChouskie Date: Sun, 30 Jun 2024 21:26:59 -0700 Subject: [PATCH 21/30] binding.gyp: Change `darwin-x64` to `darwin-osxuniversal` Fixes failure on macOS after this was changed elsewhere --- binding.gyp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/binding.gyp b/binding.gyp index 7b0becf..cc044cf 100644 --- a/binding.gyp +++ b/binding.gyp @@ -25,9 +25,9 @@ 'destination': './build/Release', 'files': [ # These files were placed in the prebuilds folder by download-CanBridge.mjs - '<(module_root_dir)/prebuilds/darwin-x64/libCANBridge.dylib', - '<(module_root_dir)/prebuilds/darwin-x64/libwpiHal.dylib', - '<(module_root_dir)/prebuilds/darwin-x64/libwpiutil.dylib', + '<(module_root_dir)/prebuilds/darwin-osxuniversal/libCANBridge.dylib', + '<(module_root_dir)/prebuilds/darwin-osxuniversal/libwpiHal.dylib', + '<(module_root_dir)/prebuilds/darwin-osxuniversal/libwpiutil.dylib', ] }], }], From 90e89261d7620fd140e804a28dc54506a0273185 Mon Sep 17 00:00:00 2001 From: Garrett Summerfield Date: Sun, 30 Jun 2024 23:59:39 -0500 Subject: [PATCH 22/30] chore: Bump CANBridge tag --- scripts/download-CanBridge.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/download-CanBridge.mjs b/scripts/download-CanBridge.mjs index bff8ec3..5326863 100644 --- a/scripts/download-CanBridge.mjs +++ b/scripts/download-CanBridge.mjs @@ -4,7 +4,7 @@ import axios from 'axios'; import AdmZip from 'adm-zip'; import { platform, arch } from 'os'; -const canBridgeTag = "v2.3.2"; +const canBridgeTag = "v2.3.3"; const canBridgeReleaseAssetUrlPrefix = `https://github.com/unofficial-rev-port/CANBridge/releases/download/${canBridgeTag}`; const externalCompileTimeDepsPath = 'externalCompileTimeDeps'; From 5140afcfc71980bda87a8dbd163c9d0025e19875 Mon Sep 17 00:00:00 2001 From: Garrett Summerfield Date: Mon, 1 Jul 2024 00:01:25 -0500 Subject: [PATCH 23/30] chore: Update build workflow to include pretest step --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 561cb72..9eab028 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -36,8 +36,8 @@ jobs: - name: Install dependencies run: npm install - - name: Build - run: npm run build + - name: Pretest + run: npm run pretest - name: Test run: npm test From 79ab7e69cde068f25c33d7b0e82d9935df1d7786 Mon Sep 17 00:00:00 2001 From: Garrett Summerfield Date: Mon, 1 Jul 2024 00:36:00 -0500 Subject: [PATCH 24/30] Update `README.md` Updated compile instructions and formatting. --- README.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4a39dd2..b8c56bb 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,21 @@ This package enables Node.js applications to use a CAN bus over USB. -## Making a release +## Compiling + +### Prerequisites + +- Supported version of NodeJS (preferably a LTS version) +- A C/C++ compiler that supports C++20 +- Internet connection to pull from upstream [CANBridge](https://github.com/unofficial-rev-port/CANBridge) + +### Steps + +1. Clone repository +2. Run `npm i` to install dependencies and compile the Node APIs +3. To test, run `npm run pretest` to prepare the testing and `npm test` to actually perform the testing of the repository + +## Making a release (for repository owners) 1. Check out the `main` branch 2. Update `version` field in `package.json` @@ -10,6 +24,6 @@ This package enables Node.js applications to use a CAN bus over USB. 4. Commit change to git 5. Run `git tag v` 6. Run `git push` -7. Run `git push --tags` +7. Run `git push --tags` 8. Run `npm publish --access public` 9. Create a new release on GitHub with an explanation of the changes From 571282753fded1fc0bfb0e3fc7b035661bf43a24 Mon Sep 17 00:00:00 2001 From: QwertyChouskie Date: Mon, 1 Jul 2024 03:11:02 -0700 Subject: [PATCH 25/30] Fix exceptions on macOS EXCEPTIONS GO BRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR it's 3am and i need sleep i spent way too long on this stupid bug but thats how code goes anyways good night --- binding.gyp | 5 ++++- package-lock.json | 4 ++-- package.json | 2 +- scripts/download-CanBridge.mjs | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/binding.gyp b/binding.gyp index cc044cf..819c101 100644 --- a/binding.gyp +++ b/binding.gyp @@ -73,7 +73,10 @@ }, "xcode_settings": { "CLANG_CXX_LANGUAGE_STANDARD": "c++20", - "OTHER_CPLUSPLUSFLAGS": ["-fexceptions"] + 'GCC_ENABLE_CPP_EXCEPTIONS': 'YES', + 'GCC_ENABLE_CPP_RTTI': 'YES', + "OTHER_CPLUSPLUSFLAGS": ["-fexceptions"], + # 'MACOSX_DEPLOYMENT_TARGET': '14.0', }, "cflags_cc": ["-std=c++20", '-fexceptions'], "cflags": ["-std=c++20", '-fexceptions'], diff --git a/package-lock.json b/package-lock.json index fa80b81..ee78611 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@rev-robotics/can-bridge", - "version": "3.2.0", + "version": "3.2.6", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@rev-robotics/can-bridge", - "version": "3.2.0", + "version": "3.2.6", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index bb9ca15..9f74dd2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@rev-robotics/can-bridge", - "version": "3.2.0", + "version": "3.2.6", "author": "REV Robotics", "description": "Access CAN Data from a USB device in Node.js", "license": "MIT", diff --git a/scripts/download-CanBridge.mjs b/scripts/download-CanBridge.mjs index 5326863..591e02c 100644 --- a/scripts/download-CanBridge.mjs +++ b/scripts/download-CanBridge.mjs @@ -4,7 +4,7 @@ import axios from 'axios'; import AdmZip from 'adm-zip'; import { platform, arch } from 'os'; -const canBridgeTag = "v2.3.3"; +const canBridgeTag = "v2.3.6"; const canBridgeReleaseAssetUrlPrefix = `https://github.com/unofficial-rev-port/CANBridge/releases/download/${canBridgeTag}`; const externalCompileTimeDepsPath = 'externalCompileTimeDeps'; From c9232a44e47b345d15437e442a2a1d2b8f9c048d Mon Sep 17 00:00:00 2001 From: Garrett Summerfield Date: Tue, 2 Jul 2024 14:09:09 -0500 Subject: [PATCH 26/30] chore: Update npm dependencies Bump node-gyp-build to version 4.8.0 and node-gyp to version 10.1.0 in package.json. --- package-lock.json | 336 ++++++++++++++++++++++++---------------------- package.json | 8 +- 2 files changed, 176 insertions(+), 168 deletions(-) diff --git a/package-lock.json b/package-lock.json index ee78611..80fd42a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -69,18 +69,18 @@ } }, "node_modules/@types/adm-zip": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.0.tgz", - "integrity": "sha512-FCJBJq9ODsQZUNURo5ILAQueuA8WJhRvuihS3ke2iI25mJlfV2LK8jG2Qj2z2AWg8U0FtWWqBHVRetceLskSaw==", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.5.tgz", + "integrity": "sha512-YCGstVMjc4LTY5uK9/obvxBya93axZOVOyf2GSUulADzmLhYE45u2nAssCs/fWBs1Ifq5Vat75JTPwd5XZoPJw==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/node": { - "version": "16.18.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.18.tgz", - "integrity": "sha512-fwGw1uvQAzabxL1pyoknPlJIF2t7+K90uTqynleKRx24n3lYcxWa3+KByLhgkF8GEAK2c7hC8Ki0RkNM5H15jQ==", + "version": "16.18.101", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.101.tgz", + "integrity": "sha512-AAsx9Rgz2IzG8KJ6tXd6ndNkVcu+GYB6U/SnFAaokSPNx2N7dcIIfnighYUNumvj6YS2q39Dejz5tT0NCV7CWA==", "dev": true }, "node_modules/abbrev": { @@ -90,12 +90,12 @@ "dev": true }, "node_modules/adm-zip": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz", - "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==", + "version": "0.5.14", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.14.tgz", + "integrity": "sha512-DnyqqifT4Jrcvb8USYjp6FHtBpEIz1mnXu6pTRHZ0RL69LbQYiO+0lDFg5+OKA7U29oWSs3a/i8fhn8ZcceIWg==", "dev": true, "engines": { - "node": ">=6.0" + "node": ">=12.0" } }, "node_modules/agent-base": { @@ -111,13 +111,11 @@ } }, "node_modules/agentkeepalive": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", - "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", "dev": true, "dependencies": { - "debug": "^4.1.0", - "depd": "^2.0.0", "humanize-ms": "^1.2.1" }, "engines": { @@ -156,6 +154,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "deprecated": "This package is no longer supported.", "dev": true, "dependencies": { "delegates": "^1.0.0", @@ -172,12 +171,12 @@ "dev": true }, "node_modules/axios": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.0.tgz", - "integrity": "sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", "dev": true, "dependencies": { - "follow-redirects": "^1.15.0", + "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } @@ -295,6 +294,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -374,9 +374,9 @@ "dev": true }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -405,15 +405,6 @@ "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", "dev": true }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -463,10 +454,16 @@ "util-extend": "^1.0.1" } }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "dev": true, "funding": [ { @@ -525,6 +522,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "deprecated": "This package is no longer supported.", "dev": true, "dependencies": { "aproba": "^1.0.3 || ^2.0.0", @@ -544,6 +542,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -675,6 +674,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, "dependencies": { "once": "^1.3.0", @@ -687,11 +687,18 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", - "dev": true + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", @@ -714,6 +721,12 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true + }, "node_modules/lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", @@ -916,9 +929,9 @@ } }, "node_modules/node-abi": { - "version": "3.33.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.33.0.tgz", - "integrity": "sha512-7GGVawqyHF4pfd0YFybhv/eM9JwTtPqx0mAanQ146O3FlSh3pA24zf9IRQTOsfTSqXTNzPSP5iagAJ94jjuVog==", + "version": "3.65.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.65.0.tgz", + "integrity": "sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==", "dev": true, "dependencies": { "semver": "^7.3.5" @@ -928,17 +941,18 @@ } }, "node_modules/node-addon-api": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.0.0.tgz", - "integrity": "sha512-GyHvgPvUXBvAkXa0YvYnhilSB1A+FRYMpIVggKzPZqdaZfevZOuzfWzyvgzOwRLHBeo/MMswmJFsrNF4Nw1pmA==" + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==" }, "node_modules/node-gyp": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.1.tgz", - "integrity": "sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.1.tgz", + "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==", "dev": true, "dependencies": { "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", "glob": "^7.1.4", "graceful-fs": "^4.2.6", "make-fetch-happen": "^10.0.3", @@ -957,9 +971,9 @@ } }, "node_modules/node-gyp-build": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", - "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", + "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==", "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", @@ -997,6 +1011,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "deprecated": "This package is no longer supported.", "dev": true, "dependencies": { "are-we-there-yet": "^3.0.0", @@ -1130,6 +1145,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "dependencies": { "glob": "^7.1.3" @@ -1169,13 +1185,10 @@ "optional": true }, "node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -1183,18 +1196,6 @@ "node": ">=10" } }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -1218,16 +1219,16 @@ } }, "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "dev": true, "dependencies": { - "ip": "^2.0.0", + "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" }, "engines": { - "node": ">= 10.13.0", + "node": ">= 10.0.0", "npm": ">= 3.0.0" } }, @@ -1245,6 +1246,12 @@ "node": ">= 10" } }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true + }, "node_modules/ssri": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", @@ -1293,14 +1300,14 @@ } }, "node_modules/tar": { - "version": "6.1.13", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", - "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", "dev": true, "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", - "minipass": "^4.0.0", + "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" @@ -1344,25 +1351,25 @@ } }, "node_modules/tar/node_modules/minipass": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", - "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true, "engines": { "node": ">=8" } }, "node_modules/typescript": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz", - "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=12.20" + "node": ">=14.17" } }, "node_modules/unique-filename": { @@ -1472,18 +1479,18 @@ "dev": true }, "@types/adm-zip": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.0.tgz", - "integrity": "sha512-FCJBJq9ODsQZUNURo5ILAQueuA8WJhRvuihS3ke2iI25mJlfV2LK8jG2Qj2z2AWg8U0FtWWqBHVRetceLskSaw==", + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/@types/adm-zip/-/adm-zip-0.5.5.tgz", + "integrity": "sha512-YCGstVMjc4LTY5uK9/obvxBya93axZOVOyf2GSUulADzmLhYE45u2nAssCs/fWBs1Ifq5Vat75JTPwd5XZoPJw==", "dev": true, "requires": { "@types/node": "*" } }, "@types/node": { - "version": "16.18.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.18.tgz", - "integrity": "sha512-fwGw1uvQAzabxL1pyoknPlJIF2t7+K90uTqynleKRx24n3lYcxWa3+KByLhgkF8GEAK2c7hC8Ki0RkNM5H15jQ==", + "version": "16.18.101", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.101.tgz", + "integrity": "sha512-AAsx9Rgz2IzG8KJ6tXd6ndNkVcu+GYB6U/SnFAaokSPNx2N7dcIIfnighYUNumvj6YS2q39Dejz5tT0NCV7CWA==", "dev": true }, "abbrev": { @@ -1493,9 +1500,9 @@ "dev": true }, "adm-zip": { - "version": "0.5.10", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.10.tgz", - "integrity": "sha512-x0HvcHqVJNTPk/Bw8JbLWlWoo6Wwnsug0fnYYro1HBrjxZ3G7/AZk7Ahv8JwDe1uIcz8eBqvu86FuF1POiG7vQ==", + "version": "0.5.14", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.14.tgz", + "integrity": "sha512-DnyqqifT4Jrcvb8USYjp6FHtBpEIz1mnXu6pTRHZ0RL69LbQYiO+0lDFg5+OKA7U29oWSs3a/i8fhn8ZcceIWg==", "dev": true }, "agent-base": { @@ -1508,13 +1515,11 @@ } }, "agentkeepalive": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", - "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", "dev": true, "requires": { - "debug": "^4.1.0", - "depd": "^2.0.0", "humanize-ms": "^1.2.1" } }, @@ -1557,12 +1562,12 @@ "dev": true }, "axios": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.0.tgz", - "integrity": "sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", "dev": true, "requires": { - "follow-redirects": "^1.15.0", + "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } @@ -1709,9 +1714,9 @@ "dev": true }, "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, "requires": { "ms": "2.1.2" @@ -1729,12 +1734,6 @@ "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", "dev": true }, - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true - }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -1781,10 +1780,16 @@ "util-extend": "^1.0.1" } }, + "exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, "follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "dev": true }, "form-data": { @@ -1947,11 +1952,15 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", - "dev": true + "ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "requires": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + } }, "is-fullwidth-code-point": { "version": "3.0.0", @@ -1971,6 +1980,12 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true + }, "lru-cache": { "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", @@ -2123,26 +2138,27 @@ "dev": true }, "node-abi": { - "version": "3.33.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.33.0.tgz", - "integrity": "sha512-7GGVawqyHF4pfd0YFybhv/eM9JwTtPqx0mAanQ146O3FlSh3pA24zf9IRQTOsfTSqXTNzPSP5iagAJ94jjuVog==", + "version": "3.65.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.65.0.tgz", + "integrity": "sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==", "dev": true, "requires": { "semver": "^7.3.5" } }, "node-addon-api": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.0.0.tgz", - "integrity": "sha512-GyHvgPvUXBvAkXa0YvYnhilSB1A+FRYMpIVggKzPZqdaZfevZOuzfWzyvgzOwRLHBeo/MMswmJFsrNF4Nw1pmA==" + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", + "integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==" }, "node-gyp": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.1.tgz", - "integrity": "sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==", + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.1.tgz", + "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==", "dev": true, "requires": { "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", "glob": "^7.1.4", "graceful-fs": "^4.2.6", "make-fetch-happen": "^10.0.3", @@ -2155,9 +2171,9 @@ } }, "node-gyp-build": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz", - "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==" + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz", + "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==" }, "nopt": { "version": "6.0.0", @@ -2306,24 +2322,10 @@ "optional": true }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - } - } + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true }, "set-blocking": { "version": "2.0.0", @@ -2344,12 +2346,12 @@ "dev": true }, "socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "dev": true, "requires": { - "ip": "^2.0.0", + "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" } }, @@ -2364,6 +2366,12 @@ "socks": "^2.6.2" } }, + "sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true + }, "ssri": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", @@ -2403,23 +2411,23 @@ } }, "tar": { - "version": "6.1.13", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.13.tgz", - "integrity": "sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", "dev": true, "requires": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", - "minipass": "^4.0.0", + "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" }, "dependencies": { "minipass": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.5.tgz", - "integrity": "sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true } } @@ -2458,9 +2466,9 @@ } }, "typescript": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.2.tgz", - "integrity": "sha512-wVORMBGO/FAs/++blGNeAVdbNKtIh1rbBL2EyQ1+J9lClJ93KiiKe8PmFIVdXhHcyv44SL9oglmfeSsndo0jRw==", + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", + "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", "dev": true }, "unique-filename": { diff --git a/package.json b/package.json index 9f74dd2..ea0eb82 100644 --- a/package.json +++ b/package.json @@ -12,21 +12,21 @@ }, "dependencies": { "node-addon-api": "^6.0.0", - "node-gyp-build": "^4.6.0" + "node-gyp-build": "^4.8.0" }, "devDependencies": { "@types/adm-zip": "^0.5.0", "@types/node": "^16.18.18", "adm-zip": "^0.5.10", "axios": "^1.3.6", - "node-gyp": "^9.3.1", + "node-gyp": "^10.1.0", "prebuildify": "^5.0.1", "typescript": "^5.0.2" }, "scripts": { - "install": "node scripts/download-CanBridge.mjs && node-gyp rebuild", + "install": "node-gyp-build \"node scripts/download-CanBridge.mjs\"", "prepublishOnly": "node scripts/download-CanBridge.mjs && tsc && prebuildify --napi", - "pretest": "node-gyp rebuild && tsc", + "pretest": "node-gyp-build && tsc", "test": "node --napi-modules test/test_binding.js" }, "engines": { From 9a442f4f1827dd9560845caa1a6a7b94bbdba963 Mon Sep 17 00:00:00 2001 From: Garrett Summerfield Date: Sat, 6 Jul 2024 23:49:14 -0500 Subject: [PATCH 27/30] ci: Remove `setuptools` step Removal of `setuptools` install step due to bumped `node-gyp` version. --- .github/workflows/build.yml | 7 ++----- .github/workflows/release.yml | 8 +++----- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9eab028..03a7920 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,14 +25,11 @@ jobs: with: node-version: '20' - - uses: actions/setup-python@v5 + - name: Set up Python + uses: actions/setup-python@v5 with: python-version: '3.10' - - name: Install Python setup tools - run: | - pip install setuptools - - name: Install dependencies run: npm install diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8db1f7d..d02d6a9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,7 +6,7 @@ on: - 'v*' jobs: - build: + release: strategy: fail-fast: false matrix: @@ -22,12 +22,10 @@ jobs: with: node-version: '20' - - uses: actions/setup-python@v5 + - name: Set up Python + uses: actions/setup-python@v5 with: python-version: '3.10' - - name: Install Python setup tools - run: | - pip install setuptools - name: Install dependencies run: npm install From 822a51052688c1a09fbbf61eb6ee75fc407d5e04 Mon Sep 17 00:00:00 2001 From: Garrett Summerfield Date: Wed, 17 Jul 2024 19:18:26 -0500 Subject: [PATCH 28/30] Revert changes made to `canWrapper.cc` On commit b0ca096624286b1e975eaaa816e38599933b7e84, there were many unintended changes made to this file. This reverts those changes. --- src/canWrapper.cc | 173 ++++++++++++++++++++++++++++------------------ 1 file changed, 107 insertions(+), 66 deletions(-) diff --git a/src/canWrapper.cc b/src/canWrapper.cc index a499d05..c7ca114 100644 --- a/src/canWrapper.cc +++ b/src/canWrapper.cc @@ -3,15 +3,8 @@ #include #include #include -#ifdef _WIN32 #include #include -#else - -#include "rev/Drivers/SerialPort/SerialDriver.h" -#endif - - #include #include #include @@ -19,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -27,25 +21,34 @@ #include "canWrapper.h" #include "DfuSeFile.h" -#define DEVICE_NOT_FOUND_ERROR "Device not found. Make sure to run getDevices()" +#define DEVICE_NOT_FOUND_ERROR "Device not found. Make sure to run getDevices()" -rev::usb::CANDriver* driver = -#ifdef _WIN32 - new rev::usb::CandleWinUSBDriver(); -#else - new rev::usb::SerialDriver(); -#endif +#define REV_COMMON_HEARTBEAT_ID 0x00502C0 +#define SPARK_HEARTBEAT_ID 0x2052C80 +#define HEARTBEAT_PERIOD_MS 20 + +#define SPARK_HEARTBEAT_LENGTH 8 +#define REV_COMMON_HEARTBEAT_LENGTH 1 +uint8_t disabledSparkHeartbeat[] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint8_t disabledRevCommonHeartbeat[] = {0}; + +rev::usb::CandleWinUSBDriver* driver = new rev::usb::CandleWinUSBDriver(); std::set devicesRegisteredToHal; // TODO(Noah): Protect with mutex bool halInitialized = false; uint32_t m_notifier; std::mutex canDevicesMtx; +// These values should only be accessed while holding canDevicesMtx std::map> canDeviceMap; std::mutex watchdogMtx; +// These values should only be accessed while holding watchdogMtx std::vector heartbeatsRunning; -auto latestHeartbeatAck = std::chrono::system_clock::now(); +bool heartbeatTimeoutExpired = false; // Should only be changed in heartbeatsWatchdog() +std::map> revCommonHeartbeatMap; +std::map> sparkHeartbeatMap; +auto latestHeartbeatAck = std::chrono::steady_clock::now(); // Only call when holding canDevicesMtx void removeExtraDevicesFromDeviceMap(std::vector descriptors) { @@ -239,7 +242,7 @@ Napi::Object receiveMessage(const Napi::CallbackInfo& info) { size_t messageSize = message->GetSize(); const uint8_t* messageData = message->GetData(); Napi::Array napiMessage = Napi::Array::New(env, messageSize); - for (size_t i = 0; i < messageSize; i++) { + for (int i = 0; i < messageSize; i++) { napiMessage[i] = messageData[i]; } Napi::Object messageInfo = Napi::Object::New(env); @@ -332,7 +335,7 @@ Napi::Number openStreamSession(const Napi::CallbackInfo& info) { try { rev::usb::CANStatus status = device->OpenStreamSession(&sessionHandle, filter, maxSize); if (status != rev::usb::CANStatus::kOk) { - Napi::Error::New(env, "Opening stream session failed with error code "+std::to_string((int)status)).ThrowAsJavaScriptException(); + Napi::Error::New(env, "Opening stream session failed with error code "+(int)status).ThrowAsJavaScriptException(); } else { return Napi::Number::New(env, sessionHandle); } @@ -629,6 +632,7 @@ void waitForNotifierAlarm(const Napi::CallbackInfo& info) { int32_t status; HAL_UpdateNotifierAlarm(m_notifier, HAL_GetFPGATime(&status) + time, &status); + // TODO(Noah): Don't discard the returned value (this function is marked as [nodiscard]) HAL_WaitForNotifierAlarm(m_notifier, &status); cb.Call(info.Env().Global(), {info.Env().Null(), Napi::Number::New(info.Env(), status)}); } @@ -654,33 +658,62 @@ void writeDfuToBin(const Napi::CallbackInfo& info) { cb.Call(info.Env().Global(), {info.Env().Null(), Napi::Number::New(info.Env(), status)}); } +void cleanupHeartbeatsRunning() { + // Erase removed CAN buses from heartbeatsRunning + std::scoped_lock lock{watchdogMtx, canDevicesMtx}; + for(int i = 0; i < heartbeatsRunning.size(); i++) { + auto deviceIterator = canDeviceMap.find(heartbeatsRunning[i]); + if (deviceIterator == canDeviceMap.end()) { + heartbeatsRunning.erase(heartbeatsRunning.begin() + i); + } + } +} + void heartbeatsWatchdog() { while (true) { - std::this_thread::sleep_for (std::chrono::seconds(1)); - - { - // Erase removed CAN buses from heartbeatsRunning - std::scoped_lock lock{watchdogMtx, canDevicesMtx}; - for(size_t i = 0; i < heartbeatsRunning.size(); i++) { - auto deviceIterator = canDeviceMap.find(heartbeatsRunning[i]); - if (deviceIterator == canDeviceMap.end()) { - heartbeatsRunning.erase(heartbeatsRunning.begin() + i); - } - } - } + std::this_thread::sleep_for (std::chrono::milliseconds(250)); + + cleanupHeartbeatsRunning(); std::scoped_lock lock{watchdogMtx}; if (heartbeatsRunning.size() < 1) { break; } - auto now = std::chrono::system_clock::now(); + auto now = std::chrono::steady_clock::now(); std::chrono::duration elapsed_seconds = now-latestHeartbeatAck; - if (elapsed_seconds.count() > 1) { - uint8_t sparkMaxHeartbeat[] = {0, 0, 0, 0, 0, 0, 0, 0}; - uint8_t revCommonHeartbeat[] = {0}; - for(size_t i = 0; i < heartbeatsRunning.size(); i++) { - _sendCANMessage(heartbeatsRunning[i], 0x2052C80, sparkMaxHeartbeat, 8, -1); - _sendCANMessage(heartbeatsRunning[i], 0x00502C0, revCommonHeartbeat, 1, -1); + if (elapsed_seconds.count() >= 1 && !heartbeatTimeoutExpired) { + // The heartbeat timeout just expired + heartbeatTimeoutExpired = true; + for(int i = 0; i < heartbeatsRunning.size(); i++) { + if (sparkHeartbeatMap.contains(heartbeatsRunning[i])) { + // Clear the scheduled heartbeat that has outdated data so that the updated one gets sent out immediately + _sendCANMessage(heartbeatsRunning[i], SPARK_HEARTBEAT_ID, disabledSparkHeartbeat, SPARK_HEARTBEAT_LENGTH, -1); + + _sendCANMessage(heartbeatsRunning[i], SPARK_HEARTBEAT_ID, disabledSparkHeartbeat, SPARK_HEARTBEAT_LENGTH, HEARTBEAT_PERIOD_MS); + } + if (revCommonHeartbeatMap.contains(heartbeatsRunning[i])) { + // Clear the scheduled heartbeat that has outdated data so that the updated one gets sent out immediately + _sendCANMessage(heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, disabledRevCommonHeartbeat, REV_COMMON_HEARTBEAT_LENGTH, -1); + + _sendCANMessage(heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, disabledRevCommonHeartbeat, REV_COMMON_HEARTBEAT_LENGTH, HEARTBEAT_PERIOD_MS); + } + } + } else if (elapsed_seconds.count() < 1 && heartbeatTimeoutExpired) { + // The heartbeat timeout is newly un-expired + heartbeatTimeoutExpired = false; + for(int i = 0; i < heartbeatsRunning.size(); i++) { + if (auto heartbeatEntry = sparkHeartbeatMap.find(heartbeatsRunning[i]); heartbeatEntry != sparkHeartbeatMap.end()) { + // Clear the scheduled heartbeat that has outdated data so that the updated one gets sent out immediately + _sendCANMessage(heartbeatsRunning[i], SPARK_HEARTBEAT_ID, heartbeatEntry->second.data(), SPARK_HEARTBEAT_LENGTH, -1); + + _sendCANMessage(heartbeatsRunning[i], SPARK_HEARTBEAT_ID, heartbeatEntry->second.data(), SPARK_HEARTBEAT_LENGTH, HEARTBEAT_PERIOD_MS); + } + if (auto heartbeatEntry = revCommonHeartbeatMap.find(heartbeatsRunning[i]); heartbeatEntry != revCommonHeartbeatMap.end()) { + // Clear the scheduled heartbeat that has outdated data so that the updated one gets sent out immediately + _sendCANMessage(heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, heartbeatEntry->second.data(), REV_COMMON_HEARTBEAT_LENGTH, -1); + + _sendCANMessage(heartbeatsRunning[i], REV_COMMON_HEARTBEAT_ID, heartbeatEntry->second.data(), REV_COMMON_HEARTBEAT_LENGTH, HEARTBEAT_PERIOD_MS); + } } } } @@ -688,7 +721,7 @@ void heartbeatsWatchdog() { void ackHeartbeats(const Napi::CallbackInfo& info) { std::scoped_lock lock{watchdogMtx}; - latestHeartbeatAck = std::chrono::system_clock::now(); + latestHeartbeatAck = std::chrono::steady_clock::now(); } // Params: @@ -703,18 +736,23 @@ void startRevCommonHeartbeat(const Napi::CallbackInfo& info) { if (deviceIterator == canDeviceMap.end()) return; } - uint8_t payload[] = {1}; - _sendCANMessage(descriptor, 0x00502C0, payload, 1, 20); + std::array payload = {1}; std::scoped_lock lock{watchdogMtx}; + if (!heartbeatTimeoutExpired) { + _sendCANMessage(descriptor, REV_COMMON_HEARTBEAT_ID, payload.data(), REV_COMMON_HEARTBEAT_LENGTH, HEARTBEAT_PERIOD_MS); + } + + revCommonHeartbeatMap[descriptor] = payload; + if (heartbeatsRunning.size() == 0) { heartbeatsRunning.push_back(descriptor); - latestHeartbeatAck = std::chrono::system_clock::now(); + latestHeartbeatAck = std::chrono::steady_clock::now(); std::thread hb(heartbeatsWatchdog); hb.detach(); } else { - for(size_t i = 0; i < heartbeatsRunning.size(); i++) { + for(int i = 0; i < heartbeatsRunning.size(); i++) { if (heartbeatsRunning[i].compare(descriptor) == 0) return; } heartbeatsRunning.push_back(descriptor); @@ -729,7 +767,7 @@ void setSparkMaxHeartbeatData(const Napi::CallbackInfo& info) { std::string descriptor = info[0].As().Utf8Value(); Napi::Array dataParam = info[1].As(); - uint8_t heartbeat[] = {0, 0, 0, 0, 0, 0, 0, 0}; + std::array heartbeat = {0, 0, 0, 0, 0, 0, 0, 0}; { std::scoped_lock lock{canDevicesMtx}; @@ -737,42 +775,45 @@ void setSparkMaxHeartbeatData(const Napi::CallbackInfo& info) { if (deviceIterator == canDeviceMap.end()) return; } - _sendCANMessage(descriptor, 0x2052C80, heartbeat, 8, -1); - std::this_thread::sleep_for(std::chrono::milliseconds(50)); - int sum = 0; for (uint32_t i = 0; i < dataParam.Length(); i++) { heartbeat[i] = dataParam.Get(i).As().Uint32Value(); sum+= heartbeat[i]; } - if (sum == 0) { - _sendCANMessage(descriptor, 0x2052C80, heartbeat, 8, -1); + std::scoped_lock lock{watchdogMtx}; + + if (!heartbeatTimeoutExpired) { + // Clear the scheduled heartbeat that has outdated data so that the updated one gets sent out immediately + _sendCANMessage(descriptor, SPARK_HEARTBEAT_ID, heartbeat.data(), SPARK_HEARTBEAT_LENGTH, -1); + + _sendCANMessage(descriptor, SPARK_HEARTBEAT_ID, heartbeat.data(), SPARK_HEARTBEAT_LENGTH, HEARTBEAT_PERIOD_MS); } - else { - _sendCANMessage(descriptor, 0x2052C80, heartbeat, 8, 10); - std::scoped_lock lock{watchdogMtx}; + sparkHeartbeatMap[descriptor] = heartbeat; - if (heartbeatsRunning.size() == 0) { - heartbeatsRunning.push_back(descriptor); - latestHeartbeatAck = std::chrono::system_clock::now(); - std::thread hb(heartbeatsWatchdog); - hb.detach(); - } else { - for(size_t i = 0; i < heartbeatsRunning.size(); i++) { - if (heartbeatsRunning[i].compare(descriptor) == 0) return; - } - heartbeatsRunning.push_back(descriptor); + if (heartbeatsRunning.size() == 0) { + heartbeatsRunning.push_back(descriptor); + latestHeartbeatAck = std::chrono::steady_clock::now(); + std::thread hb(heartbeatsWatchdog); + hb.detach(); + } else { + for(int i = 0; i < heartbeatsRunning.size(); i++) { + if (heartbeatsRunning[i].compare(descriptor) == 0) return; } + heartbeatsRunning.push_back(descriptor); } } -/** - * This function was removed from commit b0ca096624286b1e975eaaa816e38599933b7e84, which broke MSVC builds. - * It has been re-added here to fix the build. - */ void stopHeartbeats(const Napi::CallbackInfo& info) { - //! TODO: Reimplement this function with current codebase - Napi::Env env = info.Env(); + std::string descriptor = info[0].As().Utf8Value(); + bool sendDisabledHeartbeatsFirst = info[1].As().Value(); + + // 0 sends and then cancels, -1 cancels without sending + const int repeatPeriod = sendDisabledHeartbeatsFirst ? 0 : -1; + + std::scoped_lock lock{watchdogMtx}; + // Send disabled SPARK and REV common heartbeats and un-schedule them for the future + _sendCANMessage(descriptor, SPARK_HEARTBEAT_ID, disabledSparkHeartbeat, SPARK_HEARTBEAT_LENGTH, repeatPeriod); + _sendCANMessage(descriptor, REV_COMMON_HEARTBEAT_ID, disabledRevCommonHeartbeat, REV_COMMON_HEARTBEAT_LENGTH, repeatPeriod); } \ No newline at end of file From 9827e489a5ffcb48a4623abaee3503dda04b532a Mon Sep 17 00:00:00 2001 From: Garrett Summerfield Date: Mon, 12 Aug 2024 19:06:54 -0500 Subject: [PATCH 29/30] [ci skip] chore: Rename release workflow job --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8db1f7d..c534ba4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -6,7 +6,7 @@ on: - 'v*' jobs: - build: + release: strategy: fail-fast: false matrix: From 0ef46b6c76d1b86bfe65c4b959eac5fadc116be6 Mon Sep 17 00:00:00 2001 From: QwertyChouskie Date: Thu, 22 Aug 2024 01:01:20 -0700 Subject: [PATCH 30/30] Remove `CanBridgeInitializationError` custom error It just made it harder to get the actual error and actual stack trace. --- lib/binding.ts | 61 ++++++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 37 deletions(-) diff --git a/lib/binding.ts b/lib/binding.ts index a00f655..c376dd8 100644 --- a/lib/binding.ts +++ b/lib/binding.ts @@ -33,15 +33,6 @@ export enum ThreadPriority { PriorityError } -export class CanBridgeInitializationError extends Error { - cause: any; - - constructor(cause: any) { - super("Failed to load the CANBridge native addon. This is likely a packaging problem, or perhaps the Visual Studio C++ redistributable package is not installed. See cause field for details."); - this.cause = cause; - } -} - export class CanBridge { getDevices: () => Promise; registerDeviceToHAL: (descriptor:string, messageId:Number, messageMask:number) => number; @@ -67,34 +58,30 @@ export class CanBridge { ackHeartbeats: () => void; constructor() { - try { - const addon = require('node-gyp-build')(path.join(__dirname, '..')); - - this.getDevices = promisify(addon.getDevices); - this.registerDeviceToHAL = addon.registerDeviceToHAL; - this.unregisterDeviceFromHAL = promisify(addon.unregisterDeviceFromHAL); - this.receiveMessage = addon.receiveMessage; - this.openStreamSession = addon.openStreamSession; - this.readStreamSession = addon.readStreamSession; - this.closeStreamSession = addon.closeStreamSession; - this.getCANDetailStatus = addon.getCANDetailStatus; - this.sendCANMessage = addon.sendCANMessage; - this.sendHALMessage = addon.sendHALMessage; - this.initializeNotifier = addon.initializeNotifier; - this.waitForNotifierAlarm = promisify(addon.waitForNotifierAlarm); - this.stopNotifier = addon.stopNotifier; - this.writeDfuToBin = promisify(addon.writeDfuToBin); - this.openHALStreamSession = addon.openHALStreamSession; - this.readHALStreamSession = addon.readHALStreamSession; - this.closeHALStreamSession = addon.closeHALStreamSession; - this.setThreadPriority = addon.setThreadPriority; - this.setSparkMaxHeartbeatData = addon.setSparkMaxHeartbeatData; - this.startRevCommonHeartbeat = addon.startRevCommonHeartbeat; - this.ackHeartbeats = addon.ackHeartbeats; - this.stopHeartbeats = addon.stopHeartbeats; - } catch (e: any) { - throw new CanBridgeInitializationError(e); - } + const addon = require('node-gyp-build')(path.join(__dirname, '..')); + + this.getDevices = promisify(addon.getDevices); + this.registerDeviceToHAL = addon.registerDeviceToHAL; + this.unregisterDeviceFromHAL = promisify(addon.unregisterDeviceFromHAL); + this.receiveMessage = addon.receiveMessage; + this.openStreamSession = addon.openStreamSession; + this.readStreamSession = addon.readStreamSession; + this.closeStreamSession = addon.closeStreamSession; + this.getCANDetailStatus = addon.getCANDetailStatus; + this.sendCANMessage = addon.sendCANMessage; + this.sendHALMessage = addon.sendHALMessage; + this.initializeNotifier = addon.initializeNotifier; + this.waitForNotifierAlarm = promisify(addon.waitForNotifierAlarm); + this.stopNotifier = addon.stopNotifier; + this.writeDfuToBin = promisify(addon.writeDfuToBin); + this.openHALStreamSession = addon.openHALStreamSession; + this.readHALStreamSession = addon.readHALStreamSession; + this.closeHALStreamSession = addon.closeHALStreamSession; + this.setThreadPriority = addon.setThreadPriority; + this.setSparkMaxHeartbeatData = addon.setSparkMaxHeartbeatData; + this.startRevCommonHeartbeat = addon.startRevCommonHeartbeat; + this.ackHeartbeats = addon.ackHeartbeats; + this.stopHeartbeats = addon.stopHeartbeats; } }