From 2ba22ccf85859c2d75df9c18e7aa7b85d2ef46c8 Mon Sep 17 00:00:00 2001 From: NoahAndrews Date: Thu, 6 Aug 2020 15:08:09 -0500 Subject: [PATCH] Initial version --- binding.gyp | 7 ++- lib/binding.ts | 8 ++- src/EnterFirmwareUpdateMode.cc | 92 ++++++++++++++++++++++++++++++++++ src/EnterFirmwareUpdateMode.h | 8 +++ src/addon.cc | 10 ++++ src/cbus.cc | 27 ---------- test/test_binding.js | 18 +++---- 7 files changed, 126 insertions(+), 44 deletions(-) create mode 100644 src/EnterFirmwareUpdateMode.cc create mode 100644 src/EnterFirmwareUpdateMode.h create mode 100644 src/addon.cc delete mode 100644 src/cbus.cc diff --git a/binding.gyp b/binding.gyp index 9b28dad..71b8613 100644 --- a/binding.gyp +++ b/binding.gyp @@ -1,8 +1,11 @@ { 'targets': [ { - 'target_name': 'cbus-native', - 'sources': [ 'src/cbus.cc' ], + 'target_name': 'expansion-hub-fw-update-mode-native', + 'sources': [ + 'src/addon.cc', + 'src/EnterFirmwareUpdateMode.cc' + ], 'include_dirs': [ "src/", "d2xx/", diff --git a/lib/binding.ts b/lib/binding.ts index 101e9a6..b1388b7 100644 --- a/lib/binding.ts +++ b/lib/binding.ts @@ -1,6 +1,4 @@ -const addon = require('../build/Release/cbus-native'); +import {promisify} from "util"; +const addon = require('../build/Release/expansion-hub-fw-update-mode-native'); -console.log("addon:"); -console.log(addon); - -exports.getFtdiDevices = addon.getFtdiDevices; +exports.enterExpansionHubFirmwareUpdateMode = promisify(addon.enterExpansionHubFirmwareUpdateMode); diff --git a/src/EnterFirmwareUpdateMode.cc b/src/EnterFirmwareUpdateMode.cc new file mode 100644 index 0000000..04a27d6 --- /dev/null +++ b/src/EnterFirmwareUpdateMode.cc @@ -0,0 +1,92 @@ +#include "EnterFirmwareUpdateMode.h" +#include +#include +#include +#include + +#define MODE_CBUS (0x20) + +// The reset and programming pins are active low. +#define MASK_PROGRAMMING_AND_RESET (0x30) +#define MASK_PROGRAMMING_ONLY (0x31) +#define MASK_RESET_ONLY (0x32) +#define MASK_NEITHER (0x33) + +class Worker: public Napi::AsyncWorker { + public: + Worker(Napi::Function& callback, std::string serial) + : Napi::AsyncWorker(callback), serial(serial) {} + + ~Worker() {} + + // Executed inside the worker-thread. + // It is not safe to access JS engine data structure + // here, so everything we need for input and output + // should go on `this`. + void Execute() { + FT_HANDLE ftHandle; + try { + FT_STATUS status; + + status = FT_OpenEx(&serial, FT_OPEN_BY_SERIAL_NUMBER, &ftHandle); + if (status != FT_OK) throw new std::runtime_error("Error opening " + serial); + + // Activate programming pin only + status = FT_SetBitMode(ftHandle, MASK_PROGRAMMING_ONLY, MODE_CBUS); + if (status != FT_OK) throw new std::runtime_error("Error setting programming pin"); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + + // Activate programming and reset pins + status = FT_SetBitMode(ftHandle, MASK_PROGRAMMING_AND_RESET, MODE_CBUS); + if (status != FT_OK) throw new std::runtime_error("Error setting reset pins"); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + + // Activate programming pin only + status = FT_SetBitMode(ftHandle, MASK_PROGRAMMING_ONLY, MODE_CBUS); + if (status != FT_OK) throw new std::runtime_error("Error un-setting reset pin"); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + + // Activate no pins + status = FT_SetBitMode(ftHandle, MASK_NEITHER, MODE_CBUS); + if (status != FT_OK) throw new std::runtime_error("Error un-setting programming pin"); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + + FT_Close(ftHandle); + } catch (const std::runtime_error& error) { + SetError(error.what()); + if (ftHandle) { + FT_Close(ftHandle); + } + return; + } + } + + private: + std::string serial; + std::string errorString; +}; + +void EnterFirmwareUpdateMode(const Napi::CallbackInfo& info) { + Napi::Env env = info.Env(); + + if (info.Length() != 2) { + Napi::TypeError::New(env, "Exactly 2 parameters must be provided") + .ThrowAsJavaScriptException(); + } + + if (!info[0].IsString()) { + Napi::TypeError::New(env, "First parameter is not a string") + .ThrowAsJavaScriptException(); + } + + if (!info[1].IsFunction()) { + Napi::TypeError::New(env, "Second parameter is not a function") + .ThrowAsJavaScriptException(); + } + + std::string serial = info[0].ToString().Utf8Value(); + Napi::Function callback = info[1].As(); + + Worker* worker = new Worker(callback, serial); + worker->Queue(); +} diff --git a/src/EnterFirmwareUpdateMode.h b/src/EnterFirmwareUpdateMode.h new file mode 100644 index 0000000..f75e481 --- /dev/null +++ b/src/EnterFirmwareUpdateMode.h @@ -0,0 +1,8 @@ +#ifndef ENTER_FIRMWARE_UPDATE_MODE +#define ENTER_FIRMWARE_UPDATE_MODE + +#include + +void EnterFirmwareUpdateMode(const Napi::CallbackInfo& info); + +#endif diff --git a/src/addon.cc b/src/addon.cc new file mode 100644 index 0000000..70344ee --- /dev/null +++ b/src/addon.cc @@ -0,0 +1,10 @@ +#include +#include "EnterFirmwareUpdateMode.h" + +Napi::Object Init(Napi::Env env, Napi::Object exports) { + exports.Set(Napi::String::New(env, "enterExpansionHubFirmwareUpdateMode"), + Napi::Function::New(env, EnterFirmwareUpdateMode)); + return exports; +} + +NODE_API_MODULE(addon, Init) diff --git a/src/cbus.cc b/src/cbus.cc deleted file mode 100644 index 78a045b..0000000 --- a/src/cbus.cc +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include - -using namespace Napi; - -Napi::Array GetFtdiDevices(const Napi::CallbackInfo& info) { - FT_STATUS ftStatus; - DWORD numDevs; - - // create the device information list - ftStatus = FT_CreateDeviceInfoList(&numDevs); - if (ftStatus == FT_OK) { - printf("Number of devices is %d\n", numDevs); - } else { - printf("Error calling FT_CreateDeviceInfoList: %d\n", ftStatus); - } - - return Napi::Array::Array(); -} - -Napi::Object Init(Napi::Env env, Napi::Object exports) { - exports.Set(Napi::String::New(env, "getFtdiDevices"), - Napi::Function::New(env, GetFtdiDevices)); - return exports; -} - -NODE_API_MODULE(cbus, Init) diff --git a/test/test_binding.js b/test/test_binding.js index befb5c1..fc8d3ce 100644 --- a/test/test_binding.js +++ b/test/test_binding.js @@ -1,16 +1,14 @@ -const cbus = require("../dist/binding.js"); +const binding = require("../dist/binding.js"); const assert = require("assert").strict; -console.log("cbus:"); -console.log(cbus); -assert(cbus.getFtdiDevices, "The expected function is undefined"); +assert(binding.enterExpansionHubFirmwareUpdateMode, "The expected function is undefined"); -function testBasic() +async function testBasic() { - const result = cbus.getFtdiDevices(); - assert.equal(result, [], "Unexpected value returned"); + // await binding.enterExpansionHubFirmwareUpdateMode("DQ16G720"); + await binding.enterExpansionHubFirmwareUpdateMode("DQ16"); } -assert.doesNotThrow(testBasic, Error, "testBasic threw an expection"); - -console.log("Tests passed- everything looks OK!"); +assert.doesNotReject(testBasic, Error, "testBasic threw an exception") + .then(() => console.log("Tests passed- everything looks OK!")) + .catch(error => console.log(`Tests failed: ${error}`));